Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Rift v0.2.3
Rift.dll
Decompiled 6 hours ago
The result has been truncated due to the large size, download it to view full contents!
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