Rift.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Rift.Altar;
using Rift.Arena;
using Rift.Audio;
using Rift.Boss;
using Rift.Boss.Skills;
using Rift.Config;
using Rift.Gateway;
using Rift.Integration;
using Rift.Session;
using Rift.Util;
using Rift.VFX;
using Rift.Wave;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Rift
{
	[BepInPlugin("korCaptain.Rift", "Captain Rift", "0.2.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal const string Guid = "korCaptain.Rift";

		internal const string Name = "Captain Rift";

		internal const string Version = "0.2.3";

		internal static ManualLogSource Log;

		internal static RiftGlobalConfig Global;

		internal static List<TierConfig> Tiers;

		private void Awake()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			RiftConfigLoader.EnsureExtracted();
			Global = RiftConfigLoader.LoadGlobal();
			Tiers = RiftConfigLoader.LoadAllTiers();
			Log.LogInfo((object)$"[Rift] 컨피그 로드 완료: global={Global != null}, tiers={Tiers.Count}");
			ConfigManagerBridge.Bind(((BaseUnityPlugin)this).Config, Global);
			if (!Global.Enabled)
			{
				Log.LogInfo((object)"[Rift] rift_global.json의 enabled=false — Rift 기능 전체 비활성화");
				return;
			}
			SkillTreeBridge.DetectInstalled();
			RiftGatewayPrefab.Register();
			RiftArenaPrefab.Register();
			RiftAbandonStonePrefab.Register();
			RiftBedPrefab.Register();
			RiftEikthyrPrefab.Register();
			RiftGDKingPrefab.Register();
			GameObject val = new GameObject("RiftAbandonHotkey");
			Object.DontDestroyOnLoad((Object)(object)val);
			AbandonHotkeyComponent host = val.AddComponent<AbandonHotkeyComponent>();
			AudioFileLoader.LoadOnce((MonoBehaviour)(object)host);
			Harmony val2 = new Harmony("korCaptain.Rift");
			try
			{
				val2.PatchAll();
				Log.LogInfo((object)"[Rift] Harmony 패치 완료");
				CllcGuard.PatchSizeScaling(val2);
				CllcGuard.PatchExtraEffects(val2);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[Rift] Harmony 패치 실패: {arg}");
			}
			string text = "[Rift] Rift 0.2.3 Loaded!";
			try
			{
				Type type = typeof(BaseUnityPlugin).Assembly.GetType("BepInEx.ConsoleManager");
				MethodInfo methodInfo = type?.GetMethod("SetConsoleColor", BindingFlags.Static | BindingFlags.Public);
				TextWriter textWriter = type?.GetProperty("StandardOutStream", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) as TextWriter;
				if (methodInfo != null && textWriter != null)
				{
					methodInfo.Invoke(null, new object[1] { ConsoleColor.Cyan });
					textWriter.WriteLine(text);
					methodInfo.Invoke(null, new object[1] { ConsoleColor.Gray });
				}
				else
				{
					Log.LogMessage((object)text);
				}
			}
			catch
			{
				Log.LogMessage((object)text);
			}
		}
	}
}
namespace Rift.Wave
{
	internal static class ClearCoinRpc
	{
		private const string RpcName = "Rift.ClearCoin";

		internal static void Register()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.Register<string>("Rift.ClearCoin", (Action<long, string>)OnReceive);
			}
		}

		internal static void Broadcast(Vector3 dropAt, Vector3 arenaCenter, float radius, string tierId, long ownerId, long partnerPeerId)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (ZRoutedRpc.instance != null)
			{
				string text = string.Join("|", Vec(dropAt), Vec(arenaCenter), radius.ToString(CultureInfo.InvariantCulture), tierId, ownerId.ToString(CultureInfo.InvariantCulture), partnerPeerId.ToString(CultureInfo.InvariantCulture));
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Rift.ClearCoin", new object[1] { text });
			}
		}

		private static string Vec(Vector3 v)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", v.x, v.y, v.z);
		}

		private static Vector3 ParseVec(string text)
		{
			//IL_0032: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			string[] array = text.Split(',');
			return new Vector3(float.Parse(array[0], CultureInfo.InvariantCulture), float.Parse(array[1], CultureInfo.InvariantCulture), float.Parse(array[2], CultureInfo.InvariantCulture));
		}

		private static void OnReceive(long sender, string payload)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//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_00b8: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			try
			{
				string[] array = payload.Split('|');
				Vector3 floorCenter = ParseVec(array[0]);
				Vector3 val = ParseVec(array[1]);
				float num = float.Parse(array[2], CultureInfo.InvariantCulture);
				string tierId = array[3];
				long num2 = long.Parse(array[4], CultureInfo.InvariantCulture);
				long num3 = long.Parse(array[5], CultureInfo.InvariantCulture);
				bool flag = localPlayer.GetPlayerID() == num2;
				bool flag2 = num3 != 0L && ZDOMan.GetSessionID() == num3;
				if ((flag || flag2) && !(Vector3.Distance(((Component)localPlayer).transform.position, val) > num))
				{
					SkillTreeBridge.TryDropFirstClearCoin(floorCenter, tierId, localPlayer.GetPlayerID());
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] 코인 알림 처리 실패(무시): " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ZNet_Awake_ClearCoinRpcPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			ClearCoinRpc.Register();
			WaveClearHeal.Register();
			RecordStore.Register();
		}
	}
	internal class FloorWaveSpawner : MonoBehaviour
	{
		private class ScheduledWave
		{
			internal float At;

			internal string Prefab;

			internal int Count;

			internal int Level;

			internal int LevelMax;

			internal double Scale;

			internal double SpeedMult;

			internal bool IsBoss;

			internal bool Fired;
		}

		private const float CheckIntervalSeconds = 1f;

		internal float ArenaRadius = 25f;

		internal string TierId;

		internal long OwnerPlayerId;

		internal long PartnerPeerId;

		private List<FloorConfig> _floors;

		private int _floorIndex = -1;

		private readonly List<ScheduledWave> _schedule = new List<ScheduledWave>();

		private readonly List<Character> _alive = new List<Character>();

		private int _maxAlive = 40;

		private float _runStartTime;

		private float _activeElapsed;

		private bool _allWavesFired;

		private readonly Dictionary<Character, Vector3> _lastKnownPosition = new Dictionary<Character, Vector3>();

		private readonly HashSet<Character> _bosses = new HashSet<Character>();

		private bool _hasBossDeathPosition;

		private bool _hasLastDeathPosition;

		private Vector3 _bossDeathPosition;

		private Vector3 _lastDeathPosition;

		private float _clearWait;

		private const float FallLeakThreshold = 30f;

		private readonly Dictionary<float, Vector2> _clusterCenters = new Dictionary<float, Vector2>();

		private bool Party2 => PartnerPeerId != 0;

		private void Start()
		{
			TierConfig tierConfig = Plugin.Tiers?.Find((TierConfig t) => t.TierId == TierId);
			if (tierConfig == null || !tierConfig.Difficulties.TryGetValue("normal", out var value) || value.Floors.Count == 0)
			{
				Plugin.Log.LogError((object)("[Rift] FloorWaveSpawner: " + TierId + " 층 컨피그를 찾지 못해 웨이브를 시작하지 않음"));
				return;
			}
			_floors = value.Floors;
			_runStartTime = Time.time;
			StartFloor(0);
			((MonoBehaviour)this).InvokeRepeating("Tick", 1f, 1f);
		}

		private void StartFloor(int index)
		{
			_floorIndex = index;
			_schedule.Clear();
			_clusterCenters.Clear();
			_allWavesFired = false;
			FloorConfig floorConfig = _floors[index];
			_maxAlive = floorConfig.MaxAlive;
			int globalMaxAlive = Plugin.Global.Spawn.GlobalMaxAlive;
			if (globalMaxAlive > 0 && globalMaxAlive < _maxAlive)
			{
				_maxAlive = globalMaxAlive;
			}
			_clearWait = 0f;
			foreach (WaveConfig wave in floorConfig.Waves)
			{
				foreach (SpawnEntryConfig spawn in wave.Spawns)
				{
					_schedule.Add(new ScheduledWave
					{
						At = (float)wave.At,
						Prefab = spawn.Prefab,
						Count = spawn.Count,
						Level = spawn.Level,
						LevelMax = spawn.LevelMax,
						Scale = spawn.Scale,
						SpeedMult = spawn.SpeedMult,
						IsBoss = spawn.IsBoss
					});
				}
			}
			_activeElapsed = 0f;
			Plugin.Log.LogInfo((object)$"[Rift] {floorConfig.Floor}층 시작 — 웨이브 {_schedule.Count}개, maxAlive={_maxAlive}");
		}

		private void Tick()
		{
			RemoveDeadAndLeakedAlive();
			AdoptSplitChildren();
			List<Player> list = NearbyPlayers().ToList();
			if (list.Count == 0 || (Plugin.Global.Lives.PauseWaveOnAllDead && list.All((Player p) => ((Character)p).IsDead())))
			{
				return;
			}
			_activeElapsed += 1f;
			foreach (ScheduledWave item in _schedule)
			{
				if (!item.Fired && !(_activeElapsed < item.At))
				{
					item.Fired = true;
					SpawnWave(item);
				}
			}
			_allWavesFired = _schedule.All((ScheduledWave w) => w.Fired);
			if (_allWavesFired && _alive.Count == 0)
			{
				_clearWait += 1f;
				if (!(_clearWait < (float)Plugin.Global.Spawn.WaveClearDelaySeconds))
				{
					AdvanceFloor();
				}
				return;
			}
			if (_alive.Count > 0)
			{
				_clearWait = 0f;
			}
			if (!_allWavesFired)
			{
				ShowCountdownOverPlayers(list, _activeElapsed);
			}
		}

		private void AdoptSplitChildren()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			float num = ArenaRadius + (float)Plugin.Global.Arena.BoundaryMargin;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if ((Object)(object)allCharacter == (Object)null || allCharacter.IsPlayer() || allCharacter.IsTamed() || allCharacter.IsDead() || _alive.Contains(allCharacter))
				{
					continue;
				}
				Vector3 val = ((Component)allCharacter).transform.position - ((Component)this).transform.position;
				if (!(Mathf.Abs(val.y) > 30f))
				{
					Vector2 val2 = new Vector2(val.x, val.z);
					if (!(((Vector2)(ref val2)).magnitude > num))
					{
						_alive.Add(allCharacter);
						_lastKnownPosition[allCharacter] = ((Component)allCharacter).transform.position;
					}
				}
			}
		}

		private void RemoveDeadAndLeakedAlive()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			for (int num = _alive.Count - 1; num >= 0; num--)
			{
				Character val = _alive[num];
				if ((Object)(object)val == (Object)null || val.IsDead())
				{
					RecordDeathPosition(val);
					_alive.RemoveAt(num);
				}
				else if (((Component)val).transform.position.y < ((Component)this).transform.position.y - 30f)
				{
					Plugin.Log.LogWarning((object)("[Rift] 아레나 이탈(낙사 추정) 몬스터 강제 정리: " + ((Object)val).name));
					ZNetView component = ((Component)val).GetComponent<ZNetView>();
					if (component != null)
					{
						component.Destroy();
					}
					_alive.RemoveAt(num);
					_lastKnownPosition.Remove(val);
					_bosses.Remove(val);
				}
				else
				{
					_lastKnownPosition[val] = ((Component)val).transform.position;
				}
			}
		}

		private void RecordDeathPosition(Character character)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			Vector3 value;
			if ((Object)(object)character != (Object)null)
			{
				value = ((Component)character).transform.position;
			}
			else if (!_lastKnownPosition.TryGetValue(character, out value))
			{
				return;
			}
			_lastDeathPosition = value;
			_hasLastDeathPosition = true;
			if (_bosses.Contains(character))
			{
				_bossDeathPosition = value;
				_hasBossDeathPosition = true;
			}
			_lastKnownPosition.Remove(character);
			_bosses.Remove(character);
		}

		internal int DestroyAllAlive()
		{
			int num = 0;
			foreach (Character item in _alive)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				try
				{
					ZNetView component = ((Component)item).GetComponent<ZNetView>();
					if (component != null)
					{
						component.Destroy();
					}
					num++;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("[Rift] 몬스터 강제 삭제 실패(" + ((Object)item).name + "): " + ex.Message));
				}
			}
			_alive.Clear();
			return num;
		}

		private void AdvanceFloor()
		{
			if (Plugin.Global.General.HealOnWaveClear)
			{
				WaveClearHeal.Apply(NearbyPlayers());
			}
			int num = _floorIndex + 1;
			if (num >= _floors.Count)
			{
				Plugin.Log.LogInfo((object)"[Rift] 마지막 층까지 클리어 — 웨이브 스포너 정지");
				((MonoBehaviour)this).CancelInvoke("Tick");
				DropFirstClearCoin();
				SubmitSoloRecord();
				int valueOrDefault = (Plugin.Tiers?.Find((TierConfig t) => t.TierId == TierId)?.ClearReturnDelaySeconds).GetValueOrDefault();
				if (valueOrDefault > 0)
				{
					((Component)this).gameObject.AddComponent<RiftClearReturn>().Begin(valueOrDefault);
				}
			}
			else
			{
				int floor = _floors[num].Floor;
				BroadcastCenterMessage($"{floor}F Next Wave~!");
				StartFloor(num);
			}
		}

		private void SubmitSoloRecord()
		{
			if (!Party2)
			{
				Player val = Player.GetAllPlayers().Find((Player p) => (Object)(object)p != (Object)null && p.GetPlayerID() == OwnerPlayerId);
				if (!((Object)(object)val == (Object)null))
				{
					string job = (((Object)(object)val == (Object)(object)Player.m_localPlayer) ? SkillTreeBridge.TryGetJobName(val) : "");
					RecordStore.Submit(TierId, val.GetPlayerName(), job, Time.time - _runStartTime);
				}
			}
		}

		private void DropFirstClearCoin()
		{
			//IL_0032: 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_0043: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			if (SkillTreeBridge.IsInstalled && !string.IsNullOrEmpty(TierId) && OwnerPlayerId != 0)
			{
				string source;
				Vector3 val = ResolveCoinDropPosition(out source);
				Plugin.Log.LogInfo((object)$"[Rift] 스킬포인트 코인 드랍 위치: {source} {val}");
				ClearCoinRpc.Broadcast(val, ((Component)this).transform.position, ArenaRadius, TierId, OwnerPlayerId, PartnerPeerId);
			}
		}

		private Vector3 ResolveCoinDropPosition(out string source)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)this).transform.position;
			Vector3 val;
			if (_hasBossDeathPosition)
			{
				val = _bossDeathPosition;
				source = "보스 사망 위치";
			}
			else
			{
				if (!_hasLastDeathPosition)
				{
					source = "아레나 중앙";
					return position;
				}
				val = _lastDeathPosition;
				source = "마지막 사망 위치";
			}
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(val.x - position.x, val.z - position.z);
			if (((Vector2)(ref val2)).magnitude > ArenaRadius)
			{
				source += "(아레나 밖이라 중앙으로 대체)";
				return position;
			}
			return new Vector3(val.x, position.y, val.z);
		}

		private void ApplyHealth(Character character, ScheduledWave wave)
		{
			float num = character.GetMaxHealth();
			bool flag = false;
			float num2 = 1f;
			float num3 = 1f;
			TierConfig tierConfig = ((!wave.IsBoss) ? null : Plugin.Tiers?.Find((TierConfig t) => t.TierId == TierId));
			if (tierConfig != null)
			{
				if (tierConfig.BossHealthPercent > 0.0)
				{
					num = character.m_health * (float)Mathf.Max(1, character.GetLevel()) * (float)tierConfig.BossHealthPercent / 100f;
					flag = true;
				}
				num2 *= (float)tierConfig.BossDamagePercent / 100f;
				num3 *= Mathf.Clamp01(1f - (float)tierConfig.BossDamageReducePercent / 100f);
			}
			if (Party2)
			{
				num *= 1f + (float)Plugin.Global.General.Party2MobHealthPercent / 100f;
				flag = true;
				num2 *= 1f + (float)Plugin.Global.General.Party2AttackPowerPercent / 100f;
				num3 *= Mathf.Max(0f, 1f - (float)Plugin.Global.General.Party2DamageTakenReducePercent / 100f);
			}
			ZNetView nview = character.m_nview;
			ZDO val = ((nview != null) ? nview.GetZDO() : null);
			if (val != null)
			{
				if (num2 != 1f)
				{
					val.Set("Rift_AtkMult", num2);
				}
				if (num3 != 1f)
				{
					val.Set("Rift_TakenMult", num3);
				}
				double spawnInvulnSeconds = Plugin.Global.Spawn.SpawnInvulnSeconds;
				if (spawnInvulnSeconds > 0.0)
				{
					val.Set("Rift_InvulnUntil", (long)((ZNet.instance.GetTimeSeconds() + spawnInvulnSeconds) * 1000.0));
				}
			}
			if (flag)
			{
				character.SetMaxHealth(num);
				character.SetHealth(num);
			}
		}

		private Vector2 ClusterOffset(ScheduledWave wave)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)Plugin.Global.Spawn.ClusterRadius;
			if (wave.IsBoss || num <= 0f)
			{
				return Random.insideUnitCircle * (ArenaRadius * 0.8f);
			}
			if (!_clusterCenters.TryGetValue(wave.At, out var value))
			{
				value = Random.insideUnitCircle * (ArenaRadius * 0.6f);
				_clusterCenters[wave.At] = value;
			}
			return value + Random.insideUnitCircle * num;
		}

		private void SpawnWave(ScheduledWave wave)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = ZNetScene.instance.GetPrefab(wave.Prefab);
			if ((Object)(object)prefab == (Object)null)
			{
				Plugin.Log.LogError((object)("[Rift] 웨이브 스폰 실패 — 프리팹 없음: " + wave.Prefab));
				return;
			}
			int num = 0;
			for (int i = 0; i < wave.Count; i++)
			{
				if (_alive.Count >= _maxAlive)
				{
					Plugin.Log.LogInfo((object)$"[Rift] maxAlive({_maxAlive}) 도달 — 이번 웨이브 나머지 스킵(대기열은 다음 슬라이스)");
					break;
				}
				Vector2 val = ClusterOffset(wave);
				Vector3 val2 = ((Component)this).transform.position + new Vector3(val.x, 0.5f, val.y);
				GameObject val3 = Object.Instantiate<GameObject>(prefab, val2, Quaternion.identity);
				Character component = val3.GetComponent<Character>();
				if ((Object)(object)component != (Object)null)
				{
					int num2 = (wave.IsBoss ? (Plugin.Tiers?.Find((TierConfig t) => t.TierId == TierId)?.BossLevel).GetValueOrDefault() : 0);
					int num3 = ((num2 > 0) ? num2 : wave.Level);
					if (!wave.IsBoss && wave.LevelMax > wave.Level)
					{
						num3 = Random.Range(wave.Level, wave.LevelMax + 1);
					}
					if (!wave.IsBoss && Plugin.Global.Spawn.UseVanillaLevelScaling && Game.m_worldLevel > 0)
					{
						num3 += Game.m_worldLevel;
					}
					component.SetLevel(num3);
					if (wave.IsBoss)
					{
						CllcGuard.StripBossAffix(component);
					}
					ApplyHealth(component, wave);
					_alive.Add(component);
					if (component.IsBoss())
					{
						_bosses.Add(component);
					}
					if (wave.Scale > 0.0 && wave.Scale != 1.0)
					{
						ZNetView component2 = val3.GetComponent<ZNetView>();
						if (component2 != null)
						{
							component2.SetLocalScale(Vector3.one * (float)wave.Scale);
						}
					}
					if (!wave.IsBoss)
					{
						val3.AddComponent<MonsterSizeLock>().Init(prefab.transform.localScale.x, (float)Plugin.Global.Spawn.MaxSizeMultiplier);
					}
					if (wave.SpeedMult > 0.0 && wave.SpeedMult != 1.0)
					{
						component.m_speed *= (float)wave.SpeedMult;
						component.m_walkSpeed *= (float)wave.SpeedMult;
						component.m_runSpeed *= (float)wave.SpeedMult;
						component.m_swimSpeed *= (float)wave.SpeedMult;
						if ((Object)(object)component.m_animator != (Object)null)
						{
							Animator animator = component.m_animator;
							animator.speed *= (float)wave.SpeedMult;
						}
					}
				}
				MonsterAI component3 = val3.GetComponent<MonsterAI>();
				Player closestPlayer = Player.GetClosestPlayer(val2, ArenaRadius * 2f);
				if ((Object)(object)component3 != (Object)null && (Object)(object)closestPlayer != (Object)null)
				{
					component3.Wakeup();
					((BaseAI)component3).SetAlerted(true);
					component3.SetTarget((Character)(object)closestPlayer);
				}
				num++;
			}
			Plugin.Log.LogInfo((object)$"[Rift] 웨이브 스폰: {wave.Prefab} x{num}/{wave.Count} Lv{wave.Level}");
		}

		private void ShowCountdownOverPlayers(List<Player> present, float elapsed)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			ScheduledWave scheduledWave = _schedule.FirstOrDefault((ScheduledWave w) => !w.Fired);
			if (scheduledWave == null || (Object)(object)DamageText.instance == (Object)null)
			{
				return;
			}
			int num = Mathf.CeilToInt(scheduledWave.At - elapsed);
			if (num < 0)
			{
				return;
			}
			foreach (Player item in present)
			{
				Vector3 val = ((Component)item).transform.position + Vector3.up * 2.2f;
				DamageText.instance.ShowText((TextType)0, val, $"Next wave: {num}s", false);
			}
		}

		private void BroadcastCenterMessage(string text)
		{
			foreach (Player item in NearbyPlayers())
			{
				((Character)item).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		private IEnumerable<Player> NearbyPlayers()
		{
			foreach (Player player in Player.GetAllPlayers())
			{
				if (Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) <= ArenaRadius)
				{
					yield return player;
				}
			}
		}
	}
	internal class MonsterSizeLock : MonoBehaviour
	{
		private const float SettleSeconds = 1.5f;

		private float _limit;

		private float _target;

		private float _age;

		internal void Init(float baseScale, float max)
		{
			if (baseScale <= 0f || max <= 0f)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			_limit = baseScale * max;
			_target = baseScale;
		}

		private void LateUpdate()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)this).transform;
			float x = transform.localScale.x;
			_age += Time.deltaTime;
			if (_age < 1.5f)
			{
				float num = Mathf.Min(x, _limit);
				if (num > _target)
				{
					_target = num;
				}
			}
			float num2 = ((_age < 1.5f) ? Mathf.Min(x, _limit) : _target);
			if (Mathf.Abs(x - num2) > num2 * 0.001f)
			{
				transform.localScale *= num2 / x;
				Physics.SyncTransforms();
			}
		}
	}
	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	internal static class RiftDamagePatch
	{
		internal const string AttackKey = "Rift_AtkMult";

		internal const string TakenKey = "Rift_TakenMult";

		internal const string InvulnUntilKey = "Rift_InvulnUntil";

		[HarmonyPrefix]
		private static void Prefix(Character __instance, HitData hit)
		{
			if (hit == null)
			{
				return;
			}
			float num = Get(hit.GetAttacker(), "Rift_AtkMult");
			if (num != 1f)
			{
				hit.ApplyModifier(num);
			}
			ZDO val = (((Object)(object)__instance.m_nview != (Object)null) ? __instance.m_nview.GetZDO() : null);
			if (val != null)
			{
				float num2 = val.GetFloat("Rift_TakenMult", 1f);
				if (num2 != 1f)
				{
					hit.ApplyModifier(Mathf.Max(0f, num2));
				}
				long num3 = val.GetLong("Rift_InvulnUntil", 0L);
				if (num3 > 0 && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.GetTimeSeconds() * 1000.0 < (double)num3)
				{
					hit.ApplyModifier(0f);
				}
			}
		}

		private static float Get(Character c, string key)
		{
			ZDO val = (((Object)(object)c != (Object)null && (Object)(object)c.m_nview != (Object)null) ? c.m_nview.GetZDO() : null);
			return (val != null) ? val.GetFloat(key, 1f) : 1f;
		}
	}
	internal static class WaveClearHeal
	{
		private const string RpcName = "Rift.WaveHealFx";

		internal static void Register()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.Register<string>("Rift.WaveHealFx", (Action<long, string>)OnReceive);
			}
		}

		internal static void Apply(IEnumerable<Player> players)
		{
			List<string> list = new List<string>();
			foreach (Player player in players)
			{
				if (!((Object)(object)player == (Object)null) && !((Character)player).IsDead())
				{
					((Character)player).Heal(((Character)player).GetMaxHealth(), true);
					list.Add(player.GetPlayerID().ToString(CultureInfo.InvariantCulture));
				}
			}
			if (list.Count != 0)
			{
				Plugin.Log.LogInfo((object)$"[Rift] 웨이브 종료 체력 회복: {list.Count}명");
				if (SkillTreeBridge.IsInstalled && ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Rift.WaveHealFx", new object[1] { string.Join(",", list) });
				}
			}
		}

		private static void OnReceive(long sender, string payload)
		{
			try
			{
				HashSet<long> hashSet = new HashSet<long>();
				string[] array = payload.Split(',');
				foreach (string s in array)
				{
					if (long.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
					{
						hashSet.Add(result);
					}
				}
				foreach (Player allPlayer in Player.GetAllPlayers())
				{
					if (hashSet.Contains(allPlayer.GetPlayerID()))
					{
						SkillTreeBridge.TryPlayHealFx(allPlayer);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] 힐 연출 알림 처리 실패(무시): " + ex.Message));
			}
		}
	}
}
namespace Rift.VFX
{
	internal static class ProceduralVFX
	{
		private const int Segments = 48;

		private const float GroundRingWidth = 0.35f;

		private const float GroundBurstFlashDuration = 0.35f;

		private static readonly Color FillLightColor = new Color(0.7f, 1f, 0.55f, 0.18f);

		private static readonly Color FillDarkColor = new Color(0.1f, 0.55f, 0.08f, 0.8f);

		internal static GameObject CreateExpandingRing(MonoBehaviour host, Vector3 center, float startRadius, float endRadius, Color color, float duration, float height = 0.1f)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)host == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("Rift_ProceduralWave");
			host.StartCoroutine(ExpandingRingRoutine(val, center, startRadius, endRadius, color, duration, height));
			return val;
		}

		private static IEnumerator ExpandingRingRoutine(GameObject go, Vector3 center, float startRadius, float endRadius, Color color, float duration, float height)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			LineRenderer line = go.AddComponent<LineRenderer>();
			line.loop = true;
			line.positionCount = 48;
			line.useWorldSpace = true;
			float startWidth = (line.endWidth = 1.28f);
			line.startWidth = startWidth;
			Shader shader = Shader.Find("Sprites/Default") ?? Shader.Find("Legacy Shaders/Particles/Additive");
			if ((Object)(object)shader != (Object)null)
			{
				((Renderer)line).material = new Material(shader);
			}
			float elapsed = 0f;
			while (elapsed < duration && (Object)(object)go != (Object)null)
			{
				elapsed += Time.deltaTime;
				float t = Mathf.Clamp01(elapsed / duration);
				float radius = Mathf.Lerp(startRadius, endRadius, t * t);
				float alpha = ((t < 0.8f) ? 1f : ((1f - t) / 0.2f));
				Color c = (line.startColor = new Color(color.r, color.g, color.b, color.a * alpha));
				line.endColor = c;
				for (int i = 0; i < 48; i++)
				{
					float angle = (float)i / 48f * (float)Math.PI * 2f;
					line.SetPosition(i, center + new Vector3(Mathf.Cos(angle) * radius, height, Mathf.Sin(angle) * radius));
				}
				yield return null;
			}
			if ((Object)(object)go != (Object)null)
			{
				Object.Destroy((Object)(object)go);
			}
		}

		internal static GameObject CreateGroundBurst(MonoBehaviour host, Vector3 center, float radius, Color color, Color flashColor, float duration)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)host == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("Rift_GroundBurst");
			host.StartCoroutine(GroundBurstRoutine(val, center, radius, color, flashColor, duration));
			return val;
		}

		private static LineRenderer NewRing(GameObject parent, Shader shader, float width)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			GameObject val = new GameObject("ring");
			val.transform.SetParent(parent.transform, false);
			LineRenderer val2 = val.AddComponent<LineRenderer>();
			val2.loop = true;
			val2.positionCount = 48;
			val2.useWorldSpace = true;
			float startWidth = (val2.endWidth = width);
			val2.startWidth = startWidth;
			if ((Object)(object)shader != (Object)null)
			{
				((Renderer)val2).material = new Material(shader);
			}
			return val2;
		}

		private static void SetRing(LineRenderer line, Vector3 center, float radius, float height, Color c)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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)
			line.startColor = c;
			line.endColor = c;
			for (int i = 0; i < 48; i++)
			{
				float num = (float)i / 48f * (float)Math.PI * 2f;
				line.SetPosition(i, center + new Vector3(Mathf.Cos(num) * radius, height, Mathf.Sin(num) * radius));
			}
		}

		private static Mesh BuildDiscMesh()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			Vector3[] array = (Vector3[])(object)new Vector3[49];
			int[] array2 = new int[144];
			array[0] = Vector3.zero;
			for (int i = 0; i < 48; i++)
			{
				float num = (float)i / 48f * (float)Math.PI * 2f;
				array[i + 1] = new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num));
				array2[i * 3] = 0;
				array2[i * 3 + 1] = (i + 1) % 48 + 1;
				array2[i * 3 + 2] = i + 1;
			}
			Mesh val = new Mesh
			{
				name = "Rift_GroundDisc",
				vertices = array,
				triangles = array2
			};
			val.RecalculateBounds();
			return val;
		}

		private static IEnumerator GroundBurstRoutine(GameObject go, Vector3 center, float radius, Color color, Color flashColor, float duration)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Shader shader = Shader.Find("Sprites/Default") ?? Shader.Find("Legacy Shaders/Particles/Additive");
			LineRenderer rim = NewRing(go, shader, 0.525f);
			GameObject discGo = new GameObject("fill");
			discGo.transform.SetParent(go.transform, false);
			discGo.transform.position = center + Vector3.up * 0.08f;
			Mesh mesh = BuildDiscMesh();
			discGo.AddComponent<MeshFilter>().sharedMesh = mesh;
			Material discMat = new Material(shader);
			((Renderer)discGo.AddComponent<MeshRenderer>()).material = discMat;
			discGo.transform.localScale = Vector3.zero;
			float elapsed = 0f;
			while (elapsed < duration && (Object)(object)go != (Object)null)
			{
				elapsed += Time.deltaTime;
				float t = Mathf.Clamp01(elapsed / duration);
				SetRing(rim, center, radius, 0.1f, new Color(color.r, color.g, color.b, Mathf.Lerp(0.5f, 1f, t)));
				float r = radius * t;
				discGo.transform.localScale = new Vector3(r, 1f, r);
				discMat.color = Color.Lerp(FillLightColor, FillDarkColor, t);
				yield return null;
			}
			if ((Object)(object)go == (Object)null)
			{
				Object.Destroy((Object)(object)mesh);
				Object.Destroy((Object)(object)discMat);
				yield break;
			}
			discGo.transform.localScale = new Vector3(radius, 1f, radius);
			discMat.color = FillDarkColor;
			if (!((Object)(object)go == (Object)null))
			{
				float flash = 0f;
				while (flash < 0.35f && (Object)(object)go != (Object)null)
				{
					flash += Time.deltaTime;
					float t2 = Mathf.Clamp01(flash / 0.35f);
					SetRing(rim, center, Mathf.Lerp(radius * 0.9f, radius * 1.2f, t2), 0.15f, new Color(flashColor.r, flashColor.g, flashColor.b, 1f - t2));
					yield return null;
				}
				if ((Object)(object)go != (Object)null)
				{
					Object.Destroy((Object)(object)go);
				}
				Object.Destroy((Object)(object)mesh);
				Object.Destroy((Object)(object)discMat);
			}
		}
	}
}
namespace Rift.Util
{
	internal static class GameLanguage
	{
		internal static bool IsKorean => Localization.instance != null && Localization.instance.GetSelectedLanguage() == "Korean";

		internal static string CurrentCode
		{
			get
			{
				if (Localization.instance == null)
				{
					return "en";
				}
				return Localization.instance.GetSelectedLanguage() switch
				{
					"Korean" => "ko", 
					"Russian" => "ru", 
					"German" => "de", 
					"Portuguese_Brazilian" => "pt_BR", 
					"Chinese" => "zh-cn", 
					"Japanese" => "ja", 
					"Vietnamese" => "vi", 
					"Czech" => "cz", 
					_ => "en", 
				};
			}
		}
	}
	internal static class RiftLocalization
	{
		internal const string AltarEikthyrHover = "rift_altar_eikthyr_hover";

		internal const string AltarElderHover = "rift_altar_elder_hover";

		internal const string PartyLimit = "rift_party_limit";

		internal const string AltarBusy = "rift_altar_busy";

		internal const string RiftRestricted = "rift_restricted";

		internal const string BoardTitleSolo = "rift_board_title_solo";

		internal const string BoardColumns = "rift_board_columns";

		private static readonly Dictionary<string, Dictionary<string, string>> Table = new Dictionary<string, Dictionary<string, string>>
		{
			["rift_altar_eikthyr_hover"] = new Dictionary<string, string>
			{
				["ko"] = "에이크쉬르 트로피x2 균열오픈",
				["en"] = "Eikthyr Trophy x2 - Open Rift",
				["ru"] = "Трофей Айктюра x2 - открыть Разлом",
				["de"] = "Eikthyr-Trophäe x2 - Riss öffnen",
				["pt_BR"] = "Troféu de Eikthyr x2 - Abrir Fenda",
				["zh-cn"] = "艾克特尔战利品x2 - 开启裂隙",
				["ja"] = "エイクスュルのトロフィーx2 - 亀裂を開く",
				["vi"] = "Chiến lợi phẩm Eikthyr x2 - Mở Khe nứt",
				["cz"] = "Trofej Eikthyra x2 - Otevřít trhlinu"
			},
			["rift_altar_elder_hover"] = new Dictionary<string, string>
			{
				["ko"] = "엘더 트로피x2 균열오픈",
				["en"] = "The Elder Trophy x2 - Open Rift",
				["ru"] = "Трофей Старейшины x2 - открыть Разлом",
				["de"] = "Trophäe des Ältesten x2 - Riss öffnen",
				["pt_BR"] = "Troféu do Ancião x2 - Abrir Fenda",
				["zh-cn"] = "古树战利品x2 - 开启裂隙",
				["ja"] = "エルダーのトロフィーx2 - 亀裂を開く",
				["vi"] = "Chiến lợi phẩm Trưởng Lão x2 - Mở Khe nứt",
				["cz"] = "Trofej Staršího x2 - Otevřít trhlinu"
			},
			["rift_party_limit"] = new Dictionary<string, string>
			{
				["ko"] = "파티원 2인 까지만 균열을 열 수 있습니다",
				["en"] = "A Rift can only be opened by a party of up to 2",
				["ru"] = "Открыть Разлом может группа не более чем из 2 игроков",
				["de"] = "Ein Riss kann nur von einer Gruppe mit höchstens 2 Mitgliedern geöffnet werden",
				["pt_BR"] = "A Fenda só pode ser aberta por um grupo de até 2 jogadores",
				["zh-cn"] = "最多只能由2人队伍开启裂隙",
				["ja"] = "亀裂を開けるのはパーティー2人までです",
				["vi"] = "Chỉ nhóm tối đa 2 người mới có thể mở Khe nứt",
				["cz"] = "Trhlinu mohou otevřít nejvýše 2 členové skupiny"
			},
			["rift_altar_busy"] = new Dictionary<string, string>
			{
				["ko"] = "이미 다른 사람이 균열 진행중입니다",
				["en"] = "Someone else is already in a Rift here",
				["ru"] = "Здесь уже кто-то проходит Разлом",
				["de"] = "Hier ist bereits jemand in einem Riss",
				["pt_BR"] = "Outra pessoa já está em uma Fenda aqui",
				["zh-cn"] = "已有其他人正在进行裂隙",
				["ja"] = "すでに他の人が亀裂を進行中です",
				["vi"] = "Đã có người khác đang trong Khe nứt tại đây",
				["cz"] = "Někdo jiný už zde prochází trhlinou"
			},
			["rift_restricted"] = new Dictionary<string, string>
			{
				["ko"] = "균열 안에서는 건축과 제작을 할 수 없습니다",
				["en"] = "You cannot build or craft inside a Rift",
				["ru"] = "В Разломе нельзя строить и создавать предметы",
				["de"] = "Im Riss kann nicht gebaut oder hergestellt werden",
				["pt_BR"] = "Não é possível construir ou fabricar dentro da Fenda",
				["zh-cn"] = "裂隙内无法建造或制作",
				["ja"] = "亀裂の中では建築や製作ができません",
				["vi"] = "Không thể xây dựng hoặc chế tạo trong Khe nứt",
				["cz"] = "V trhlině nelze stavět ani vyrábět"
			},
			["rift_tier_meadows"] = new Dictionary<string, string>
			{
				["ko"] = "목초지 균열",
				["en"] = "Meadows Rift",
				["ru"] = "Разлом Лугов",
				["de"] = "Wiesen-Riss",
				["pt_BR"] = "Fenda dos Prados",
				["zh-cn"] = "草地裂隙",
				["ja"] = "平原の亀裂",
				["vi"] = "Khe nứt Đồng cỏ",
				["cz"] = "Trhlina luk"
			},
			["rift_tier_blackforest"] = new Dictionary<string, string>
			{
				["ko"] = "검은숲 균열",
				["en"] = "Black Forest Rift",
				["ru"] = "Разлом Чёрного леса",
				["de"] = "Schwarzwald-Riss",
				["pt_BR"] = "Fenda da Floresta Negra",
				["zh-cn"] = "黑森林裂隙",
				["ja"] = "黒い森の亀裂",
				["vi"] = "Khe nứt Rừng Đen",
				["cz"] = "Trhlina Černého lesa"
			},
			["rift_board_title_solo"] = new Dictionary<string, string>
			{
				["ko"] = "도전자 기록 - 1인",
				["en"] = "Challenger Records - Solo",
				["ru"] = "Рекорды - один игрок",
				["de"] = "Bestenliste - Solo",
				["pt_BR"] = "Recordes - Solo",
				["zh-cn"] = "挑战者记录 - 单人",
				["ja"] = "挑戦者記録 - ソロ",
				["vi"] = "Kỷ lục thử thách - Một người",
				["cz"] = "Rekordy - sólo"
			},
			["rift_board_columns"] = new Dictionary<string, string>
			{
				["ko"] = "순위|이름|직업|공략 시간",
				["en"] = "Rank|Name|Job|Time",
				["ru"] = "Место|Имя|Класс|Время",
				["de"] = "Rang|Name|Beruf|Zeit",
				["pt_BR"] = "Pos.|Nome|Classe|Tempo",
				["zh-cn"] = "排名|名称|职业|用时",
				["ja"] = "順位|名前|職業|タイム",
				["vi"] = "Hạng|Tên|Nghề|Thời gian",
				["cz"] = "Pořadí|Jméno|Povolání|Čas"
			}
		};

		internal static string Get(string key)
		{
			if (!Table.TryGetValue(key, out var value))
			{
				return key;
			}
			if (value.TryGetValue(GameLanguage.CurrentCode, out var value2))
			{
				return value2;
			}
			return value["en"];
		}
	}
	public static class RiftZone
	{
		public static bool BlockIfInRift()
		{
			if (!IsLocalPlayerInRift())
			{
				return false;
			}
			((Character)Player.m_localPlayer).Message((MessageType)2, RiftLocalization.Get("rift_restricted"), 0, (Sprite)null, false);
			return true;
		}

		internal static bool IsInsideActiveArena(Vector3 position)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			foreach (ArenaLifecycleComponent item in ArenaLifecycleComponent.Active)
			{
				if (!((Object)(object)item == (Object)null))
				{
					Vector3 val = position - ((Component)item).transform.position;
					Vector2 val2 = new Vector2(val.x, val.z);
					if (((Vector2)(ref val2)).magnitude <= 30f + (float)Plugin.Global.Arena.BoundaryMargin && Mathf.Abs(val.y) <= (float)Plugin.Global.Arena.BoundaryHeight)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static bool IsLocalPlayerInRift()
		{
			//IL_006a: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			long playerID = localPlayer.GetPlayerID();
			foreach (ArenaLifecycleComponent item in ArenaLifecycleComponent.Active)
			{
				if (!((Object)(object)item == (Object)null) && item.MemberIds.Contains(playerID))
				{
					Vector3 val = ((Component)localPlayer).transform.position - ((Component)item).transform.position;
					Vector2 val2 = new Vector2(val.x, val.z);
					if (((Vector2)(ref val2)).magnitude <= 30f + (float)Plugin.Global.Arena.BoundaryMargin && Mathf.Abs(val.y) <= (float)Plugin.Global.Arena.BoundaryHeight)
					{
						return true;
					}
				}
			}
			return false;
		}
	}
}
namespace Rift.Session
{
	internal class AbandonHotkeyComponent : MonoBehaviour
	{
		private void Update()
		{
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			if ((!Input.GetKey((KeyCode)308) && !Input.GetKey((KeyCode)307)) || !Input.GetKeyDown((KeyCode)120))
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && ReturnPositionRegistry.TryGet(localPlayer.GetPlayerID(), out var position))
			{
				long playerID = localPlayer.GetPlayerID();
				ArenaLifecycleComponent lifecycle = null;
				int slotIndex;
				bool flag = ArenaDeathState.TryGetSlotIndex(playerID, out slotIndex) && ArenaSpawnCoordinator.TryGetLifecycle(slotIndex, out lifecycle);
				ArenaDeathState.RestoreOriginalSpawnPoint(playerID);
				ReturnPositionRegistry.Clear(playerID);
				if (flag)
				{
					lifecycle.ForceDestroy();
				}
				else
				{
					Plugin.Log.LogWarning((object)$"[Rift] 알트+X 포기 — 아레나/슬롯 조회 실패, 강제 파괴 스킵됨(slotIndex={slotIndex})");
					ArenaDeathState.Clear(playerID);
				}
				Plugin.Log.LogInfo((object)"[Rift] 알트+X 포기 — 진입 전 위치로 귀환, 아레나 즉시 파괴");
				((Character)localPlayer).Message((MessageType)2, "Rift abandoned.", 0, (Sprite)null, false);
				((Character)localPlayer).TeleportTo(position, ((Component)localPlayer).transform.rotation, true);
			}
		}
	}
	internal static class ArenaDeathState
	{
		private static readonly HashSet<long> Party2Players = new HashSet<long>();

		private static readonly Dictionary<long, Vector3> ArenaPositions = new Dictionary<long, Vector3>();

		private static readonly Dictionary<long, int> DeathCounts = new Dictionary<long, int>();

		private static readonly Dictionary<long, int> SlotIndices = new Dictionary<long, int>();

		private static readonly Dictionary<long, bool> HadCustomSpawn = new Dictionary<long, bool>();

		private static readonly Dictionary<long, Vector3> PreviousSpawnPoints = new Dictionary<long, Vector3>();

		internal static int MaxDeaths => Plugin.Global?.Lives?.MaxDeaths ?? 3;

		internal static int MaxDeathsParty2 => Plugin.Global?.Lives?.MaxDeathsParty2 ?? 5;

		internal static int MaxDeathsFor(long playerId)
		{
			return Party2Players.Contains(playerId) ? MaxDeathsParty2 : MaxDeaths;
		}

		internal static void Register(long playerId, Vector3 arenaPosition, int slotIndex, bool hadCustomSpawn, Vector3 previousSpawnPoint, bool party2 = false)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (party2)
			{
				Party2Players.Add(playerId);
			}
			else
			{
				Party2Players.Remove(playerId);
			}
			ArenaPositions[playerId] = arenaPosition;
			DeathCounts[playerId] = 0;
			SlotIndices[playerId] = slotIndex;
			HadCustomSpawn[playerId] = hadCustomSpawn;
			PreviousSpawnPoints[playerId] = previousSpawnPoint;
		}

		internal static void RestoreOriginalSpawnPoint(long playerId)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
			if (HadCustomSpawn.TryGetValue(playerId, out var value) && value && PreviousSpawnPoints.TryGetValue(playerId, out var value2))
			{
				playerProfile.SetCustomSpawnPoint(value2);
			}
			else
			{
				playerProfile.ClearCustomSpawnPoint();
			}
		}

		internal static bool IsInArena(long playerId)
		{
			return ArenaPositions.ContainsKey(playerId);
		}

		internal static bool TryGetArenaPosition(long playerId, out Vector3 pos)
		{
			return ArenaPositions.TryGetValue(playerId, out pos);
		}

		internal static bool TryGetSlotIndex(long playerId, out int slotIndex)
		{
			return SlotIndices.TryGetValue(playerId, out slotIndex);
		}

		private static long CountKey(long playerId)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Global?.Lives?.PerPlayer ?? true)
			{
				return playerId;
			}
			if (!ArenaPositions.TryGetValue(playerId, out var value))
			{
				return playerId;
			}
			long num = playerId;
			foreach (KeyValuePair<long, Vector3> arenaPosition in ArenaPositions)
			{
				if (arenaPosition.Key < num)
				{
					Vector3 val = arenaPosition.Value - value;
					if (((Vector3)(ref val)).sqrMagnitude < 1f)
					{
						num = arenaPosition.Key;
					}
				}
			}
			return num;
		}

		internal static int RegisterDeath(long playerId)
		{
			long key = CountKey(playerId);
			DeathCounts.TryGetValue(key, out var value);
			value++;
			DeathCounts[key] = value;
			return value;
		}

		internal static bool TryGetDeathCount(long playerId, out int count)
		{
			return DeathCounts.TryGetValue(CountKey(playerId), out count);
		}

		internal static void Clear(long playerId)
		{
			Party2Players.Remove(playerId);
			ArenaPositions.Remove(playerId);
			DeathCounts.Remove(playerId);
			SlotIndices.Remove(playerId);
			HadCustomSpawn.Remove(playerId);
			PreviousSpawnPoints.Remove(playerId);
		}
	}
	internal class ArenaRespawnInvulnerability : MonoBehaviour
	{
		private Player _player;

		private Vector3 _startPos;

		private float _startTime;

		private float _duration;

		private Vector3 _arenaPos;

		private bool _hasArenaPos;

		private int _correctCount;

		private bool _logged;

		private int _enforceCount;

		private const float RespawnHeight = 10f;

		internal static Vector3 SafePosition(Vector3 arenaPos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			return arenaPos + Vector3.up * 10f;
		}

		internal static void PlaceAt(Player player, Vector3 pos)
		{
			//IL_0007: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			((Component)player).transform.position = pos;
			Rigidbody component = ((Component)player).GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.position = pos;
				component.linearVelocity = Vector3.zero;
			}
		}

		private void Start()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			_player = ((Component)this).GetComponent<Player>();
			if ((Object)(object)_player == (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			_hasArenaPos = ArenaDeathState.TryGetArenaPosition(_player.GetPlayerID(), out _arenaPos);
			if (_hasArenaPos && ((Component)this).transform.position.y < _arenaPos.y + 5f)
			{
				PlaceAt(_player, SafePosition(_arenaPos));
			}
			_startPos = ((Component)this).transform.position;
			_startTime = Time.time;
			_duration = (float)Plugin.Global.Lives.RespawnInvulnSeconds;
			RespawnPushRpc.Broadcast(((Component)this).transform.position, (float)Plugin.Global.Lives.RespawnPushRadius);
			_player.SetGodMode(true);
			Plugin.Log.LogInfo((object)$"[Rift] 부활 무적 시작({_duration:0.#}초, 이동/공격 시 해제)");
		}

		private void Update()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_player == (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			if (_hasArenaPos && Time.time - _startTime < 0.5f && ((Component)this).transform.position.y < _arenaPos.y + 5f)
			{
				PlaceAt(_player, SafePosition(_arenaPos));
				if (++_enforceCount == 1)
				{
					Plugin.Log.LogInfo((object)"[Rift] 부활 직후 위치가 낮아 10m 위로 재지정");
				}
				return;
			}
			if (!_logged && Time.time - _startTime > 1f)
			{
				_logged = true;
				Plugin.Log.LogInfo((object)$"[Rift] 부활 1초 후 위치 y={((Component)this).transform.position.y:0.0} arenaY={_arenaPos.y:0.0} onGround={((Character)_player).IsOnGround()}");
			}
			if (_hasArenaPos && ((Component)this).transform.position.y < _arenaPos.y - 1f)
			{
				Vector3 val = SafePosition(_arenaPos);
				PlaceAt(_player, val);
				_startPos = val;
				if (++_correctCount == 1)
				{
					Plugin.Log.LogWarning((object)$"[Rift] 부활 후 바닥 아래로 추락 감지, 위치 보정: {val}");
				}
			}
			else if (((Character)_player).IsOnGround() || !(Time.time - _startTime < _duration))
			{
				Vector3 moveDir = ((Character)_player).GetMoveDir();
				bool flag = ((Vector3)(ref moveDir)).magnitude > 0.1f;
				bool flag2 = ((Character)_player).InAttack();
				bool flag3 = Time.time - _startTime >= _duration;
				if (flag || flag2 || flag3)
				{
					_player.SetGodMode(false);
					Plugin.Log.LogInfo((object)$"[Rift] 부활 무적 해제(moved={flag} attacked={flag2} timeout={flag3})");
					Object.Destroy((Object)(object)this);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "CreateTombStone")]
	internal static class Player_CreateTombStone_ArenaPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(Player __instance)
		{
			if (!ArenaDeathState.IsInArena(__instance.GetPlayerID()))
			{
				return true;
			}
			LivesConfig lives = Plugin.Global.Lives;
			return !lives.KeepItemsOnDeath && lives.CreateTombstone;
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	internal static class Player_OnDeath_ArenaPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			long playerID = __instance.GetPlayerID();
			if (!ArenaDeathState.IsInArena(playerID))
			{
				return;
			}
			int num = ArenaDeathState.RegisterDeath(playerID);
			Plugin.Log.LogInfo((object)$"[Rift] 아레나 내 사망 {num}/{ArenaDeathState.MaxDeathsFor(playerID)}");
			if (num > ArenaDeathState.MaxDeathsFor(playerID))
			{
				ArenaDeathState.RestoreOriginalSpawnPoint(playerID);
				((Character)__instance).Message((MessageType)2, "Out of lives — ejected from the Rift.", 0, (Sprite)null, false);
				if (ArenaDeathState.TryGetSlotIndex(playerID, out var slotIndex) && ArenaSpawnCoordinator.TryGetLifecycle(slotIndex, out var lifecycle))
				{
					lifecycle.ForceDestroy();
				}
				else
				{
					Plugin.Log.LogWarning((object)$"[Rift] 목숨 소진 — 아레나/슬롯 조회 실패, 강제 파괴 스킵됨(slotIndex={slotIndex})");
				}
				ArenaDeathState.Clear(playerID);
				ReturnPositionRegistry.Clear(playerID);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class Player_OnSpawned_ArenaPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			long playerID = __instance.GetPlayerID();
			if (ArenaDeathState.IsInArena(playerID) && ArenaDeathState.TryGetArenaPosition(playerID, out var pos))
			{
				Vector3 val = ArenaRespawnInvulnerability.SafePosition(pos);
				Plugin.Log.LogInfo((object)$"[Rift] 부활 위치: target={val} before={((Component)__instance).transform.position}");
				ArenaRespawnInvulnerability.PlaceAt(__instance, val);
				((Component)__instance).gameObject.AddComponent<ArenaRespawnInvulnerability>();
			}
		}
	}
	[HarmonyPatch(typeof(Skills), "OnDeath")]
	internal static class Skills_OnDeath_ArenaPatch
	{
		[HarmonyPrefix]
		private static bool Prefix()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !ArenaDeathState.IsInArena(localPlayer.GetPlayerID()))
			{
				return true;
			}
			return !Plugin.Global.Lives.BlockSkillLoss;
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	internal static class Player_OnDeath_KeepBuffsPatch
	{
		private static readonly Dictionary<long, List<KeyValuePair<int, float>>> SavedEffects = new Dictionary<long, List<KeyValuePair<int, float>>>();

		internal static List<KeyValuePair<int, float>> Take(long playerId)
		{
			if (!SavedEffects.TryGetValue(playerId, out var value))
			{
				return null;
			}
			SavedEffects.Remove(playerId);
			return value;
		}

		[HarmonyPrefix]
		private static void Prefix(Player __instance, out List<Food> __state)
		{
			__state = null;
			long playerID = __instance.GetPlayerID();
			if (!ArenaDeathState.IsInArena(playerID) || !Plugin.Global.Lives.KeepBuffsOnDeath)
			{
				return;
			}
			__state = new List<Food>(__instance.GetFoods());
			List<KeyValuePair<int, float>> list = new List<KeyValuePair<int, float>>();
			SEMan sEMan = ((Character)__instance).GetSEMan();
			if (sEMan != null)
			{
				foreach (StatusEffect statusEffect in sEMan.GetStatusEffects())
				{
					if (!((Object)(object)statusEffect == (Object)null) && !(statusEffect.m_ttl <= 0f) && statusEffect.NameHash() != SEMan.s_statusEffectSoftDeath)
					{
						float remaningTime = statusEffect.GetRemaningTime();
						if (remaningTime > 0f)
						{
							list.Add(new KeyValuePair<int, float>(statusEffect.NameHash(), remaningTime));
						}
					}
				}
			}
			SavedEffects[playerID] = list;
		}

		[HarmonyPostfix]
		private static void Postfix(Player __instance, List<Food> __state)
		{
			if (__state != null)
			{
				List<Food> foods = __instance.GetFoods();
				foods.Clear();
				foods.AddRange(__state);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class Player_OnSpawned_RestoreBuffsPatch
	{
		private static readonly FieldInfo TimeField = AccessTools.Field(typeof(StatusEffect), "m_time");

		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			List<KeyValuePair<int, float>> list = Player_OnDeath_KeepBuffsPatch.Take(__instance.GetPlayerID());
			if (list == null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			SEMan sEMan = ((Character)__instance).GetSEMan();
			foreach (KeyValuePair<int, float> item in list)
			{
				StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(item.Key);
				if (!((Object)(object)statusEffect == (Object)null))
				{
					StatusEffect val = sEMan.AddStatusEffect(statusEffect, false, 0, 0f, (short)(-1));
					if ((Object)(object)val != (Object)null)
					{
						TimeField.SetValue(val, statusEffect.m_ttl - item.Value);
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(Game), "RequestRespawn")]
	internal static class Game_RequestRespawn_ArenaPatch
	{
		[HarmonyPrefix]
		private static void Prefix(ref float delay, bool afterDeath)
		{
			if (afterDeath)
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && ArenaDeathState.IsInArena(localPlayer.GetPlayerID()))
				{
					delay = (float)Plugin.Global.Lives.RespawnDelaySeconds;
				}
			}
		}
	}
	internal static class RespawnPushRpc
	{
		private const string RpcName = "Rift.RespawnPush";

		internal static void Register()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.Register<Vector3, float>("Rift.RespawnPush", (Action<long, Vector3, float>)OnReceive);
			}
		}

		internal static void Broadcast(Vector3 center, float radius)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (!(radius <= 0f) && ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Rift.RespawnPush", new object[2] { center, radius });
			}
		}

		private static void OnReceive(long sender, Vector3 center, float radius)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if ((Object)(object)allCharacter == (Object)null || allCharacter.IsPlayer() || allCharacter.IsDead() || (Object)(object)allCharacter.m_nview == (Object)null || !allCharacter.m_nview.IsOwner())
				{
					continue;
				}
				Vector3 val = ((Component)allCharacter).transform.position - center;
				val.y = 0f;
				if (!(((Vector3)(ref val)).magnitude >= radius))
				{
					Vector3 val2 = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.forward);
					Vector3 position = center + val2 * (radius + 0.5f);
					position.y = ((Component)allCharacter).transform.position.y;
					((Component)allCharacter).transform.position = position;
					if ((Object)(object)allCharacter.m_body != (Object)null)
					{
						allCharacter.m_body.position = position;
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ZNet_Awake_RespawnPushRpcPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			RespawnPushRpc.Register();
		}
	}
	internal static class ReturnPositionRegistry
	{
		private static readonly Dictionary<long, Vector3> Positions = new Dictionary<long, Vector3>();

		internal static void Set(long playerId, Vector3 position)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Positions[playerId] = position;
		}

		internal static bool TryGet(long playerId, out Vector3 position)
		{
			return Positions.TryGetValue(playerId, out position);
		}

		internal static void Clear(long playerId)
		{
			Positions.Remove(playerId);
		}
	}
	internal static class RiftBedPrefab
	{
		internal const string PrefabName = "Rift_Bed";

		internal static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += CreateAndRegister;
		}

		private static void CreateAndRegister()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= CreateAndRegister;
			GameObject val = new GameObject("Rift_Bed");
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			ZNetView val2 = val.AddComponent<ZNetView>();
			val2.m_persistent = true;
			Bed val3 = val.AddComponent<Bed>();
			val3.m_spawnPoint = val.transform;
			CustomPrefab val4 = new CustomPrefab(val, false);
			PrefabManager.Instance.AddPrefab(val4);
			val.SetActive(true);
		}

		internal static GameObject SpawnFor(Player player, Vector3 position)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = ZNetScene.instance.GetPrefab("Rift_Bed");
			if ((Object)(object)prefab == (Object)null)
			{
				Plugin.Log.LogError((object)"[Rift] Rift_Bed 프리팹을 찾을 수 없음 — 등록 실패했을 가능성");
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, position, Quaternion.identity);
			Bed component = val.GetComponent<Bed>();
			component.SetOwner(player.GetPlayerID(), player.GetPlayerName());
			Game.instance.GetPlayerProfile().SetCustomSpawnPoint(position);
			Plugin.Log.LogInfo((object)$"[Rift] {player.GetPlayerName()} 임시 부활 지점 설정: {position}");
			return val;
		}
	}
	internal class RiftClearReturn : MonoBehaviour
	{
		private const int CoinHintIntervalSeconds = 6;

		private const int MaxCoinWaitSeconds = 180;

		private int _remaining;

		private int _coinWaitSeconds;

		internal void Begin(int delaySeconds)
		{
			if (delaySeconds > 0 && _remaining <= 0)
			{
				_remaining = delaySeconds;
				Announce(GameLanguage.IsKorean ? $"{_remaining}초 후 리프트 위치로 이동합니다" : $"Returning to the Rift location in {_remaining}s", alsoChat: true);
				((MonoBehaviour)this).InvokeRepeating("TickCountdown", 1f, 1f);
			}
		}

		private void TickCountdown()
		{
			if (_remaining > 0)
			{
				_remaining--;
			}
			if (_remaining > 0)
			{
				Announce(GameLanguage.IsKorean ? $"{_remaining}" : $"{_remaining}", alsoChat: false);
			}
			else if (_coinWaitSeconds < 180 && SkillTreeBridge.IsCoinPending())
			{
				if (_coinWaitSeconds % 6 == 0)
				{
					Announce(GameLanguage.IsKorean ? "스킬포인트 코인을 획득하면 귀환합니다" : "Pick up the Skill Point coin to return", alsoChat: false);
				}
				_coinWaitSeconds++;
			}
			else
			{
				((MonoBehaviour)this).CancelInvoke("TickCountdown");
				ReturnLocalPlayer();
			}
		}

		private static void Announce(string text, bool alsoChat)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
				if (alsoChat)
				{
					((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
				}
			}
		}

		private void ReturnLocalPlayer()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			ArenaLifecycleComponent component = ((Component)this).GetComponent<ArenaLifecycleComponent>();
			if (!((Object)(object)localPlayer == (Object)null))
			{
				long playerID = localPlayer.GetPlayerID();
				if (ReturnPositionRegistry.TryGet(playerID, out var position))
				{
					ArenaDeathState.RestoreOriginalSpawnPoint(playerID);
					ReturnPositionRegistry.Clear(playerID);
					component?.ForceDestroy();
					Plugin.Log.LogInfo((object)"[Rift] 최종 클리어 — 진입 전 위치로 자동 귀환");
					((Character)localPlayer).TeleportTo(position, ((Component)localPlayer).transform.rotation, true);
				}
			}
		}
	}
	internal static class RiftDailyLimit
	{
		private const string KeyPrefix = "RiftLastUseDay_";

		internal static bool CanUseToday(Player player, string tierId)
		{
			int cooldownDays = Plugin.Global.General.CooldownDays;
			if (cooldownDays <= 0)
			{
				return true;
			}
			int currentDay = EnvMan.instance.GetCurrentDay();
			int lastDay;
			bool flag = !TryGetLastUseDay(player, tierId, out lastDay) || lastDay > currentDay || (long)currentDay - (long)lastDay >= cooldownDays;
			Plugin.Log.LogInfo((object)string.Format("[Rift] 일일 제한 판정: tier={0} 오늘={1} 마지막 사용={2} 대기일수={3} -> {4}", tierId, currentDay, TryGetLastUseDay(player, tierId, out var lastDay2) ? lastDay2.ToString() : "없음", cooldownDays, flag ? "사용 가능" : "차단"));
			return flag;
		}

		internal static void MarkUsedToday(Player player, string tierId)
		{
			if (!((Object)(object)player == (Object)null) && player.m_customData != null)
			{
				player.m_customData["RiftLastUseDay_" + tierId] = EnvMan.instance.GetCurrentDay().ToString();
			}
		}

		private static bool TryGetLastUseDay(Player player, string tierId, out int lastDay)
		{
			lastDay = 0;
			if ((Object)(object)player == (Object)null || player.m_customData == null)
			{
				return false;
			}
			string value;
			return player.m_customData.TryGetValue("RiftLastUseDay_" + tierId, out value) && int.TryParse(value, out lastDay);
		}
	}
}
namespace Rift.Integration
{
	internal static class CllcGuard
	{
		private static MethodInfo _getAffix;

		private static MethodInfo _setAffix;

		private static object _none;

		private static bool _resolved;

		private const string CllcGuid = "org.bepinex.plugins.creaturelevelcontrol";

		private static MethodInfo _setExtra2;

		private static MethodInfo _setInfusion2;

		private static object _extraNone;

		private static object _infusionNone;

		private static bool _inReset;

		internal static void StripBossAffix(Character boss)
		{
			if ((Object)(object)boss == (Object)null)
			{
				return;
			}
			try
			{
				if (Resolve())
				{
					object obj = _getAffix.Invoke(null, new object[1] { boss });
					if (obj != null && !obj.Equals(_none))
					{
						_setAffix.Invoke(null, new object[2] { boss, _none });
						Plugin.Log.LogInfo((object)$"[Rift] CLLC 보스 접미사 제거: {((Object)boss).name} ({obj})");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] CLLC 접미사 제거 실패: " + ex.Message));
			}
		}

		internal static void PatchSizeScaling(Harmony harmony)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_009b: Expected O, but got Unknown
			try
			{
				if (Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.creaturelevelcontrol", out var value))
				{
					MethodInfo methodInfo = AccessTools.Method(((object)value.Instance).GetType(), "calculateSizeIncrease", new Type[1] { typeof(Character) }, (Type[])null);
					if (methodInfo == null)
					{
						Plugin.Log.LogWarning((object)"[Rift] CLLC calculateSizeIncrease를 찾지 못해 크기 고정 건너뜀");
						return;
					}
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(CllcGuard), "SizePrefix", (Type[])null), new HarmonyMethod(typeof(CllcGuard), "SizePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Plugin.Log.LogInfo((object)"[Rift] CLLC 레벨 크기 증가 차단 패치 완료(균열 에이크쉬르)");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] CLLC 크기 패치 실패: " + ex.Message));
			}
		}

		private static bool SizePrefix(Character character, ref float __result)
		{
			if ((Object)(object)character != (Object)null && (((Object)character).name.StartsWith("Rift_Eikthyr") || ((Object)character).name.StartsWith("Rift_GDKing")))
			{
				__result = 1f;
				return false;
			}
			return true;
		}

		private static void SizePostfix(Character character, ref float __result)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)character == (Object)null) && !character.IsPlayer() && RiftZone.IsInsideActiveArena(((Component)character).transform.position))
			{
				__result = 1f;
			}
		}

		internal static void PatchExtraEffects(Harmony harmony)
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			try
			{
				if (!Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.creaturelevelcontrol", out var value))
				{
					return;
				}
				Type type = ((object)value.Instance).GetType().Assembly.GetType("CreatureLevelControl.API");
				if (type == null)
				{
					Plugin.Log.LogWarning((object)"[Rift] CLLC API를 찾지 못해 부가효과 차단 건너뜀");
					return;
				}
				int num = 0;
				MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
				foreach (MethodInfo methodInfo in methods)
				{
					bool flag = methodInfo.Name == "SetExtraEffectCreature";
					if (!flag && methodInfo.Name != "SetInfusionCreature")
					{
						continue;
					}
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 2 && parameters[1].ParameterType.IsEnum)
					{
						object obj = Enum.Parse(parameters[1].ParameterType, "None");
						if (flag)
						{
							_setExtra2 = methodInfo;
							_extraNone = obj;
						}
						else
						{
							_setInfusion2 = methodInfo;
							_infusionNone = obj;
						}
					}
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(CllcGuard), "ExtraEffectPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					num++;
				}
				Plugin.Log.LogInfo((object)$"[Rift] CLLC 부가효과/속성 차단 패치 완료({num}개)");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] CLLC 부가효과 패치 실패: " + ex.Message));
			}
		}

		private static void ExtraEffectPostfix(object[] __args)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (_inReset)
			{
				return;
			}
			Character val = (Character)((__args.Length != 0) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val == (Object)null || val.IsPlayer() || !RiftZone.IsInsideActiveArena(((Component)val).transform.position))
			{
				return;
			}
			_inReset = true;
			try
			{
				_setExtra2?.Invoke(null, new object[2] { val, _extraNone });
				_setInfusion2?.Invoke(null, new object[2] { val, _infusionNone });
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] CLLC 부가효과 초기화 실패: " + ex.Message));
			}
			finally
			{
				_inReset = false;
			}
		}

		private static bool Resolve()
		{
			if (_resolved)
			{
				return _getAffix != null;
			}
			_resolved = true;
			if (Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.creaturelevelcontrol", out var value))
			{
				Type type = ((object)value.Instance).GetType().Assembly.GetType("CreatureLevelControl.API");
				Type type2 = ((object)value.Instance).GetType().Assembly.GetType("CreatureLevelControl.BossAffix");
				if (type == null || type2 == null)
				{
					return false;
				}
				_getAffix = type.GetMethod("GetAffixBoss", BindingFlags.Static | BindingFlags.Public);
				_setAffix = type.GetMethod("SetAffixBoss", BindingFlags.Static | BindingFlags.Public);
				_none = Enum.ToObject(type2, 0);
				if (_getAffix == null || _setAffix == null)
				{
					_getAffix = null;
				}
				return _getAffix != null;
			}
			return false;
		}
	}
	internal static class SkillTreeBridge
	{
		internal const string SkillTreeGuid = "CaptainSkillTree.SkillTreeMod";

		private const string RewardTypeName = "CaptainSkillTree.SkillTree.RiftCoinReward";

		private const string DropMethodName = "TryDrop";

		private const string PartyTypeName = "CaptainSkillTree.MMO_System.PartyManager";

		private const string ActivePropertyName = "IsDropActive";

		private static MethodInfo _dropMethod;

		private static PropertyInfo _activeProperty;

		private static bool _resolved;

		private static MethodInfo _playOnPlayer;

		private static MethodInfo _playVfxMultiplayer;

		private static MethodInfo _getCurrentJob;

		private static FieldInfo _jobDisplayNames;

		internal static bool IsInstalled => Chainloader.PluginInfos.ContainsKey("CaptainSkillTree.SkillTreeMod");

		internal static void DetectInstalled()
		{
			Plugin.Log.LogInfo((object)(IsInstalled ? "[Rift] CaptainSkillTree 감지됨 — 소프트 연동 활성" : "[Rift] CaptainSkillTree 아직 없음/미설치 — 있으면 사용 시점에 다시 확인하며, 없으면 스킬포인트 지급만 스킵됨"));
		}

		internal static void TryDropFirstClearCoin(Vector3 floorCenter, string tierId, long ownerPlayerId)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (!IsInstalled)
			{
				return;
			}
			try
			{
				MethodInfo methodInfo = ResolveDropMethod();
				if (!(methodInfo == null))
				{
					methodInfo.Invoke(null, new object[3] { floorCenter, tierId, ownerPlayerId });
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] 스킬포인트 코인 드랍 호출 실패(무시): " + ex.Message));
			}
		}

		internal static bool IsCoinPending()
		{
			if (!IsInstalled)
			{
				return false;
			}
			try
			{
				Resolve();
				return _activeProperty != null && (bool)_activeProperty.GetValue(null, null);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] 스킬포인트 코인 상태 조회 실패(무시): " + ex.Message));
				return false;
			}
		}

		internal static List<long> GetOtherPartyPeerIds()
		{
			List<long> list = new List<long>();
			if (!IsInstalled)
			{
				return list;
			}
			try
			{
				if (!Chainloader.PluginInfos.TryGetValue("CaptainSkillTree.SkillTreeMod", out var value) || (Object)(object)value.Instance == (Object)null)
				{
					return list;
				}
				MethodInfo methodInfo = ((object)value.Instance).GetType().Assembly.GetType("CaptainSkillTree.MMO_System.PartyManager")?.GetMethod("GetOtherMembers", BindingFlags.Static | BindingFlags.Public);
				if (methodInfo == null)
				{
					return list;
				}
				if (methodInfo.Invoke(null, null) is IEnumerable enumerable)
				{
					foreach (object item in enumerable)
					{
						list.Add(((KeyValuePair<long, string>)item).Key);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] 파티 조회 실패(파티 없음으로 처리): " + ex.Message));
				list.Clear();
			}
			return list;
		}

		internal static void TryPlayHealFx(Player player)
		{
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || !IsInstalled)
			{
				return;
			}
			try
			{
				if (!Chainloader.PluginInfos.TryGetValue("CaptainSkillTree.SkillTreeMod", out var value) || (Object)(object)value.Instance == (Object)null)
				{
					return;
				}
				if (_playOnPlayer == null || _playVfxMultiplayer == null)
				{
					Assembly assembly = ((object)value.Instance).GetType().Assembly;
					_playOnPlayer = assembly.GetType("CaptainSkillTree.SimpleVFX")?.GetMethod("PlayOnPlayer", BindingFlags.Static | BindingFlags.Public, null, new Type[4]
					{
						typeof(Player),
						typeof(string),
						typeof(float),
						typeof(Vector3?)
					}, null);
					_playVfxMultiplayer = assembly.GetType("CaptainSkillTree.VFX.VFXManager")?.GetMethod("PlayVFXMultiplayer", BindingFlags.Static | BindingFlags.Public, null, new Type[6]
					{
						typeof(string),
						typeof(string),
						typeof(Vector3),
						typeof(Quaternion),
						typeof(float),
						typeof(float)
					}, null);
				}
				if (!(_playOnPlayer == null) && !(_playVfxMultiplayer == null))
				{
					_playOnPlayer.Invoke(null, new object[4]
					{
						player,
						"vfx_Potion_health_medium",
						0f,
						(object)new Vector3(0f, 0.5f, 0f)
					});
					_playVfxMultiplayer.Invoke(null, new object[6]
					{
						"",
						"sfx_Potion_health_large",
						((Component)player).transform.position,
						Quaternion.identity,
						2f,
						1f
					});
					object? obj = _playOnPlayer.Invoke(null, new object[4]
					{
						player,
						"buff_03a_aura",
						3f,
						(object)new Vector3(-0.3f, 1.5f, 0f)
					});
					GameObject val = (GameObject)((obj is GameObject) ? obj : null);
					if ((Object)(object)val != (Object)null)
					{
						GameObject val2 = Object.Instantiate<GameObject>(val, ((Component)player).transform);
						val2.transform.localPosition = new Vector3(0f, 1.8f, 0f);
						Object.Destroy((Object)(object)val2, 3f);
						GameObject val3 = Object.Instantiate<GameObject>(val, ((Component)player).transform);
						val3.transform.localPosition = new Vector3(0.3f, 1.5f, 0f);
						Object.Destroy((Object)(object)val3, 3f);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] 힐 연출 호출 실패(무시): " + ex.Message));
			}
		}

		internal static string TryGetJobName(Player player)
		{
			if ((Object)(object)player == (Object)null || !IsInstalled)
			{
				return "";
			}
			try
			{
				if (!Chainloader.PluginInfos.TryGetValue("CaptainSkillTree.SkillTreeMod", out var value) || (Object)(object)value.Instance == (Object)null)
				{
					return "";
				}
				if (_getCurrentJob == null)
				{
					Assembly assembly = ((object)value.Instance).GetType().Assembly;
					_getCurrentJob = assembly.GetType("CaptainSkillTree.SkillTree.JobRestriction.JobTreeRules")?.GetMethod("GetCurrentJob", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Player) }, null);
					_jobDisplayNames = assembly.GetType("CaptainSkillTree.MMO_System.CaptainJobNameHud")?.GetField("JobDisplayNames", BindingFlags.Static | BindingFlags.NonPublic);
				}
				if (_getCurrentJob == null)
				{
					return "";
				}
				string text = _getCurrentJob.Invoke(null, new object[1] { player }) as string;
				if (string.IsNullOrEmpty(text))
				{
					return "";
				}
				if (_jobDisplayNames?.GetValue(null) is IDictionary<string, string> dictionary && dictionary.TryGetValue(text, out var value2))
				{
					return value2;
				}
				return text;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Rift] 직업명 조회 실패(무시): " + ex.Message));
				return "";
			}
		}

		private static MethodInfo ResolveDropMethod()
		{
			Resolve();
			return _dropMethod;
		}

		private static void Resolve()
		{
			if (!_resolved && Chainloader.PluginInfos.TryGetValue("CaptainSkillTree.SkillTreeMod", out var value) && !((Object)(object)value.Instance == (Object)null))
			{
				_resolved = true;
				Type type = ((object)value.Instance).GetType().Assembly.GetType("CaptainSkillTree.SkillTree.RiftCoinReward");
				_dropMethod = type?.GetMethod("TryDrop", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
				{
					typeof(Vector3),
					typeof(string),
					typeof(long)
				}, null);
				_activeProperty = type?.GetProperty("IsDropActive", BindingFlags.Static | BindingFlags.Public);
				if (_dropMethod == null)
				{
					Plugin.Log.LogInfo((object)"[Rift] CaptainSkillTree에 스킬포인트 코인 API가 없음(구버전) — 코인 드랍 스킵");
				}
			}
		}
	}
}
namespace Rift.Gateway
{
	internal class RiftGatewayColorCycle : MonoBehaviour
	{
		private sealed class ParticleState
		{
			internal ParticleSystem System;

			internal Particle[] Buffer;

			internal bool RecolorParticles = true;
		}

		private sealed class RendererState
		{
			internal Renderer Renderer;

			internal MaterialPropertyBlock Block = new MaterialPropertyBlock();

			internal readonly List<string> Properties = new List<string>();

			internal readonly List<float> Alphas = new List<float>();
		}

		private static readonly float[] PaletteHues = new float[7] { 0.14f, 0.07f, 0f, 0.33f, 0.5f, 0.62f, 0.75f };

		private const int FirstColorIndex = 0;

		private const int SecondColorIndex = 5;

		private const float MinHueDistance = 0.2f;

		private const float MaxHue = 0.78f;

		private const float TransitionSeconds = 3f;

		private const float TransitionJitter = 0.3f;

		private const float HueWobble = 0.05f;

		private const float WobbleSpeed = 2.3f;

		private const float BaseSaturation = 0.9f;

		private const float SaturationFlutter = 0.12f;

		private const float MinBrightness = 0.72f;

		private const float FlickerSpeed = 11f;

		private const float GlitchMinInterval = 1.2f;

		private const float GlitchMaxInterval = 3.5f;

		private const float GlitchMinDuration = 0.12f;

		private const float GlitchMaxDuration = 0.26f;

		private const float GlitchMinHueShift = 0.12f;

		private const float GlitchMaxHueShift = 0.3f;

		private static readonly string[] TintProperties = new string[5] { "_Color", "_TintColor", "_BaseColor", "_MainColor", "_EmissionColor" };

		private readonly List<ParticleState> _particles = new List<ParticleState>();

		private readonly List<RendererState> _renderers = new List<RendererState>();

		private readonly List<Light> _lights = new List<Light>();

		private float _fromHue;

		private float _toHue;

		private float _transitionStart;

		private float _transitionDuration;

		private float _nextGlitchTime;

		private float _glitchStart = -1f;

		private float _glitchDuration;

		private float _glitchShift;

		private float _seedA;

		private float _seedB;

		private const float ActiveDistance = 80f;

		private void Start()
		{
			_seedA = Random.Range(0f, 100f);
			_seedB = Random.Range(0f, 100f);
			_fromHue = PaletteHues[0];
			_toHue = PaletteHues[5];
			BeginTransition(_fromHue, _toHue);
			_nextGlitchTime = Time.time + Random.Range(1.2f, 3.5f);
			Collect();
			Plugin.Log.LogInfo((object)$"[Rift] 게이트웨이 색상 순환 시작: 파티클={_particles.Count} 렌더러(틴트)={_renderers.Count} 라이트={_lights.Count}");
		}

		private void Collect()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			_lights.AddRange(((Component)this).GetComponentsInChildren<Light>(true));
			Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer renderer in componentsInChildren)
			{
				RendererState rendererState = BuildRendererState(renderer);
				if (rendererState != null)
				{
					_renderers.Add(rendererState);
				}
			}
			ParticleSystem[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val in componentsInChildren2)
			{
				ParticleState particleState = new ParticleState();
				particleState.System = val;
				MainModule main = val.main;
				particleState.Buffer = (Particle[])(object)new Particle[Mathf.Max(1, ((MainModule)(ref main)).maxParticles)];
				ParticleState particleState2 = particleState;
				ParticleSystemRenderer psr = ((Component)val).GetComponent<ParticleSystemRenderer>();
				if ((Object)(object)psr != (Object)null && _renderers.Exists((RendererState r) => (Object)(object)r.Renderer == (Object)(object)psr))
				{
					particleState2.RecolorParticles = false;
				}
				StripLifetimeColor(val);
				_particles.Add(particleState2);
			}
		}

		private static RendererState BuildRendererState(Renderer renderer)
		{
			//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)
			//IL_0061: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			RendererState rendererState = null;
			Material[] sharedMaterials = renderer.sharedMaterials;
			foreach (Material val in sharedMaterials)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string[] tintProperties = TintProperties;
				foreach (string text in tintProperties)
				{
					if (!val.HasProperty(text))
					{
						continue;
					}
					Color color = val.GetColor(text);
					bool flag = color.r > 0.9f && color.g > 0.9f && color.b > 0.9f;
					bool flag2 = Mathf.Max(color.r, Mathf.Max(color.g, color.b)) < 0.1f;
					if (!(flag || flag2))
					{
						if (rendererState == null)
						{
							rendererState = new RendererState
							{
								Renderer = renderer
							};
						}
						if (!rendererState.Properties.Contains(text))
						{
							rendererState.Properties.Add(text);
							rendererState.Alphas.Add(color.a);
						}
					}
				}
			}
			return rendererState;
		}

		private static void StripLifetimeColor(ParticleSystem system)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected I4, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			ColorOverLifetimeModule colorOverLifetime = system.colorOverLifetime;
			if (((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled)
			{
				MinMaxGradient color = ((ColorOverLifetimeModule)(ref colorOverLifetime)).color;
				Gradient val = null;
				ParticleSystemGradientMode mode = ((MinMaxGradient)(ref color)).mode;
				ParticleSystemGradientMode val2 = mode;
				switch ((int)val2)
				{
				case 1:
					val = ((MinMaxGradient)(ref color)).gradient;
					break;
				case 3:
					val = ((MinMaxGradient)(ref color)).gradientMax;
					break;
				case 0:
					((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(new Color(1f, 1f, 1f, ((MinMaxGrad