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 FindTomb v1.0.8
FindTomb.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Splatform; using UnityEngine; using UnityEngine.UI; [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 FindTomb { [BepInPlugin("captain.FindTomb", "Find Tomb", "1.0.8")] public class Plugin : BaseUnityPlugin { public static Plugin Instance; public static ConfigEntry<bool> ModEnabled; public static ConfigEntry<int> MaxTrackedGraves; public static ConfigEntry<bool> ShowMinimapPins; public static ConfigEntry<bool> ShowDirectionVFX; public static ConfigEntry<KeyboardShortcut> CancelTrackingKey; public static ConfigEntry<KeyboardShortcut> CycleNextGraveKey; public static ManualLogSource Log { get; private set; } private void Awake() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable this mod"); MaxTrackedGraves = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxTrackedGraves", 5, "Number of recent graves to track and color (1-5)"); ShowMinimapPins = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowMinimapPins", true, "Color-code recent grave pins on the map"); ShowDirectionVFX = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowDirectionVFX", true, "Show a compass VFX pointing to your oldest unrecovered grave"); bool flag = IsKoreanLanguage(); CancelTrackingKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "CancelTrackingKey", new KeyboardShortcut((KeyCode)120, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), flag ? "다음 죽음 전까지 무덤 방향 표시를 숨깁니다" : "Hides the grave direction indicator until your next death"); CycleNextGraveKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "CycleNextGraveKey", new KeyboardShortcut((KeyCode)46, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), flag ? "무덤 방향 표시를 다음 무덤으로 전환합니다" : "Points the direction indicator at the next grave"); if (ModEnabled.Value) { Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); ((MonoBehaviour)this).InvokeRepeating("ReconcileTick", 2f, 2f); DebugCommands.Register(); Log.LogMessage((object)"[FindTomb] FindTomb 1.0.7 Loaded!"); } } private void ReconcileTick() { if (ModEnabled.Value && ShowMinimapPins.Value) { MinimapPinReconciler.Reconcile(); } } private static bool IsKoreanLanguage() { return PlayerPrefs.GetString("language", "English") == "Korean"; } } public static class DebugCommands { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; public static ConsoleEvent <>9__0_1; public static ConsoleEvent <>9__0_2; public static ConsoleEvent <>9__0_3; internal void <Register>b__0_0(ConsoleEventArgs args) { Terminal context = args.Context; if ((Object)(object)context == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return; } string text = ((args.Length >= 2) ? args[1].ToLowerInvariant() : ""); int num = 0; foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } string name = ((Object)prefab).name; if (text.Length == 0 || name.ToLowerInvariant().Contains(text)) { context.AddString(name); num++; if (num >= 80) { context.AddString("[FindTomb] ...80개 이상, 더 구체적인 키워드로 다시 검색"); break; } } } context.AddString($"[FindTomb] {num}개 발견 (keyword='{text}')"); } internal void <Register>b__0_1(ConsoleEventArgs args) { //IL_009b: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) Terminal context = args.Context; Player localPlayer = Player.m_localPlayer; if ((Object)(object)context == (Object)null || (Object)(object)localPlayer == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return; } if (args.Length < 2) { context.AddString("[FindTomb] 사용법: findtomb_previewvfx <prefabName>"); return; } GameObject prefab = ZNetScene.instance.GetPrefab(args[1]); if ((Object)(object)prefab == (Object)null) { context.AddString("[FindTomb] 프리팹을 찾을 수 없음: " + args[1]); return; } Vector3 val = ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward * 2f + Vector3.up * 1.5f; GameObject val2 = Object.Instantiate<GameObject>(prefab, val, Quaternion.LookRotation(((Component)localPlayer).transform.forward)); Object.Destroy((Object)(object)val2, 5f); context.AddString("[FindTomb] 미리보기 생성: " + args[1]); } internal void <Register>b__0_2(ConsoleEventArgs args) { Terminal context = args.Context; if ((Object)(object)context == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return; } if (args.Length < 2) { context.AddString("[FindTomb] 사용법: findtomb_dumpcomponents <prefabName>"); return; } GameObject prefab = ZNetScene.instance.GetPrefab(args[1]); if ((Object)(object)prefab == (Object)null) { context.AddString("[FindTomb] 프리팹을 찾을 수 없음: " + args[1]); return; } Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { context.AddString("[FindTomb] 이름: " + component.m_name + " -> " + Localization.instance.Localize(component.m_name)); } Transform[] componentsInChildren = prefab.GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { Component[] components = ((Component)val).GetComponents<Component>(); string text = string.Empty; Component[] array = components; foreach (Component val2 in array) { if ((Object)(object)val2 != (Object)null) { text = text + ((object)val2).GetType().Name + ", "; } } context.AddString("[FindTomb] " + ((Object)val).name + ": " + text); } StationExtension componentInChildren = prefab.GetComponentInChildren<StationExtension>(true); if ((Object)(object)componentInChildren != (Object)null) { string text2 = (((Object)(object)componentInChildren.m_connectionPrefab != (Object)null) ? ((Object)componentInChildren.m_connectionPrefab).name : "null"); context.AddString("[FindTomb] StationExtension 발견: m_connectionPrefab=" + text2); } else { context.AddString("[FindTomb] StationExtension 컴포넌트 없음"); } } internal void <Register>b__0_3(ConsoleEventArgs args) { //IL_00df: 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_0098: 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) Terminal context = args.Context; if ((Object)(object)context == (Object)null) { return; } IReadOnlyList<TombRecord> current = TombTrackerManager.Current; context.AddString($"[FindTomb] 추적 중인 무덤 {current.Count}개"); TombStone[] array = Object.FindObjectsOfType<TombStone>(); for (int i = 0; i < current.Count; i++) { TombRecord tombRecord = current[i]; TombStone val = null; TombStone[] array2 = array; foreach (TombStone val2 in array2) { if ((Object)(object)val2.m_nview != (Object)null && val2.m_nview.IsValid() && val2.m_nview.GetZDO().m_uid == tombRecord.ZdoId) { val = val2; break; } } if ((Object)(object)val == (Object)null) { context.AddString($"[FindTomb] [{i}] {tombRecord.ZdoId} - 씬에서 TombStone을 못 찾음(로드 안 된 구역이거나 이미 파괴됨)"); continue; } bool flag = val.m_nview.IsOwner(); bool flag2 = (Object)(object)val.m_container != (Object)null && val.m_container.IsInUse(); int num = (((Object)(object)val.m_container != (Object)null) ? val.m_container.GetInventory().NrOfItems() : (-1)); context.AddString($"[FindTomb] [{i}] {tombRecord.ZdoId} - IsOwner={flag}, IsInUse={flag2}, NrOfItems={num}"); } } } public static void Register() { //IL_0034: 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_002a: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_00a6: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { Terminal context = args.Context; if (!((Object)(object)context == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null)) { string text = ((args.Length >= 2) ? args[1].ToLowerInvariant() : ""); int num = 0; foreach (GameObject prefab2 in ZNetScene.instance.m_prefabs) { if (!((Object)(object)prefab2 == (Object)null)) { string name = ((Object)prefab2).name; if (text.Length == 0 || name.ToLowerInvariant().Contains(text)) { context.AddString(name); num++; if (num >= 80) { context.AddString("[FindTomb] ...80개 이상, 더 구체적인 키워드로 다시 검색"); break; } } } } context.AddString($"[FindTomb] {num}개 발견 (keyword='{text}')"); } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("findtomb_dumpprefabs", "[keyword] - FindTomb: ZNetScene 프리팹 중 이름에 keyword가 포함된 항목을 나열", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>c.<>9__0_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { //IL_009b: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) Terminal context = args.Context; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)context == (Object)null) && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null)) { if (args.Length < 2) { context.AddString("[FindTomb] 사용법: findtomb_previewvfx <prefabName>"); } else { GameObject prefab = ZNetScene.instance.GetPrefab(args[1]); if ((Object)(object)prefab == (Object)null) { context.AddString("[FindTomb] 프리팹을 찾을 수 없음: " + args[1]); } else { Vector3 val5 = ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward * 2f + Vector3.up * 1.5f; GameObject val6 = Object.Instantiate<GameObject>(prefab, val5, Quaternion.LookRotation(((Component)localPlayer).transform.forward)); Object.Destroy((Object)(object)val6, 5f); context.AddString("[FindTomb] 미리보기 생성: " + args[1]); } } } }; <>c.<>9__0_1 = val2; obj2 = (object)val2; } new ConsoleCommand("findtomb_previewvfx", "[prefabName] - FindTomb: 지정한 프리팹을 플레이어 앞에 5초간 생성해 미리보기", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj3 = <>c.<>9__0_2; if (obj3 == null) { ConsoleEvent val3 = delegate(ConsoleEventArgs args) { Terminal context = args.Context; if (!((Object)(object)context == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null)) { if (args.Length < 2) { context.AddString("[FindTomb] 사용법: findtomb_dumpcomponents <prefabName>"); } else { GameObject prefab = ZNetScene.instance.GetPrefab(args[1]); if ((Object)(object)prefab == (Object)null) { context.AddString("[FindTomb] 프리팹을 찾을 수 없음: " + args[1]); } else { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { context.AddString("[FindTomb] 이름: " + component.m_name + " -> " + Localization.instance.Localize(component.m_name)); } Transform[] componentsInChildren = prefab.GetComponentsInChildren<Transform>(true); foreach (Transform val5 in componentsInChildren) { Component[] components = ((Component)val5).GetComponents<Component>(); string text = string.Empty; Component[] array = components; foreach (Component val6 in array) { if ((Object)(object)val6 != (Object)null) { text = text + ((object)val6).GetType().Name + ", "; } } context.AddString("[FindTomb] " + ((Object)val5).name + ": " + text); } StationExtension componentInChildren = prefab.GetComponentInChildren<StationExtension>(true); if ((Object)(object)componentInChildren != (Object)null) { string text2 = (((Object)(object)componentInChildren.m_connectionPrefab != (Object)null) ? ((Object)componentInChildren.m_connectionPrefab).name : "null"); context.AddString("[FindTomb] StationExtension 발견: m_connectionPrefab=" + text2); } else { context.AddString("[FindTomb] StationExtension 컴포넌트 없음"); } } } } }; <>c.<>9__0_2 = val3; obj3 = (object)val3; } new ConsoleCommand("findtomb_dumpcomponents", "[prefabName] - FindTomb: 지정한 프리팹의 루트+자식 컴포넌트 목록을 출력", (ConsoleEvent)obj3, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj4 = <>c.<>9__0_3; if (obj4 == null) { ConsoleEvent val4 = delegate(ConsoleEventArgs args) { //IL_00df: 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_0098: 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) Terminal context = args.Context; if (!((Object)(object)context == (Object)null)) { IReadOnlyList<TombRecord> current = TombTrackerManager.Current; context.AddString($"[FindTomb] 추적 중인 무덤 {current.Count}개"); TombStone[] array = Object.FindObjectsOfType<TombStone>(); for (int i = 0; i < current.Count; i++) { TombRecord tombRecord = current[i]; TombStone val5 = null; TombStone[] array2 = array; foreach (TombStone val6 in array2) { if ((Object)(object)val6.m_nview != (Object)null && val6.m_nview.IsValid() && val6.m_nview.GetZDO().m_uid == tombRecord.ZdoId) { val5 = val6; break; } } if ((Object)(object)val5 == (Object)null) { context.AddString($"[FindTomb] [{i}] {tombRecord.ZdoId} - 씬에서 TombStone을 못 찾음(로드 안 된 구역이거나 이미 파괴됨)"); } else { bool flag = val5.m_nview.IsOwner(); bool flag2 = (Object)(object)val5.m_container != (Object)null && val5.m_container.IsInUse(); int num = (((Object)(object)val5.m_container != (Object)null) ? val5.m_container.GetInventory().NrOfItems() : (-1)); context.AddString($"[FindTomb] [{i}] {tombRecord.ZdoId} - IsOwner={flag}, IsInUse={flag2}, NrOfItems={num}"); } } } }; <>c.<>9__0_3 = val4; obj4 = (object)val4; } new ConsoleCommand("findtomb_status", "FindTomb: 추적 중인 무덤 목록과 각 TombStone의 소유권/컨테이너 상태를 출력", (ConsoleEvent)obj4, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } public class GraveDirectionVFX : MonoBehaviour { private static readonly Vector3 AnchorOffset = new Vector3(0f, 1.7f, 0.3f); private const float MinVfxLength = 1f; private const float MaxVfxLength = 8f; private const float DistanceToLengthDivisor = 5f; private const string SourceStationPieceName = "piece_workbench_ext1"; private static GameObject _cachedConnectionPrefab; private static bool _resolveFailed; private GameObject _vfxInstance; private void OnDestroy() { DestroyVfxInstance(); } private void Update() { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_0088: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList<TombRecord> current = TombTrackerManager.Current; HandleHotkeys(current.Count); if (!Plugin.ModEnabled.Value || !Plugin.ShowDirectionVFX.Value || GraveTrackingState.IsCancelled) { DestroyVfxInstance(); return; } int num = GraveTrackingState.ResolveIndex(current.Count); if (num < 0) { DestroyVfxInstance(); return; } Vector3 position = current[num].Position; Vector3 val = ((Component)this).transform.TransformPoint(AnchorOffset); Vector3 val2 = position - val; val2.y = 0f; float magnitude = ((Vector3)(ref val2)).magnitude; if (!(magnitude < 0.1f)) { EnsureVfxInstance(); if (!((Object)(object)_vfxInstance == (Object)null)) { float num2 = Mathf.Clamp(magnitude / 5f, 1f, 8f); _vfxInstance.transform.position = val; _vfxInstance.transform.rotation = Quaternion.LookRotation(val2 / magnitude); _vfxInstance.transform.localScale = new Vector3(1f, 1f, num2); } } } private static void HandleHotkeys(int graveCount) { //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_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) if (graveCount != 0) { KeyboardShortcut value = Plugin.CancelTrackingKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { GraveTrackingState.Cancel(); } value = Plugin.CycleNextGraveKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { GraveTrackingState.CycleNext(graveCount); } } } private void EnsureVfxInstance() { if (!((Object)(object)_vfxInstance != (Object)null)) { GameObject val = ResolveConnectionVfxPrefab(); if (!((Object)(object)val == (Object)null)) { _vfxInstance = Object.Instantiate<GameObject>(val); } } } public static void ResetPrefabCache() { _cachedConnectionPrefab = null; _resolveFailed = false; } private static GameObject ResolveConnectionVfxPrefab() { if ((Object)(object)_cachedConnectionPrefab != (Object)null) { return _cachedConnectionPrefab; } if (_resolveFailed || (Object)(object)ZNetScene.instance == (Object)null) { return null; } GameObject prefab = ZNetScene.instance.GetPrefab("piece_workbench_ext1"); StationExtension val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<StationExtension>() : null); if ((Object)(object)val == (Object)null || (Object)(object)val.m_connectionPrefab == (Object)null) { Plugin.Log.LogWarning((object)"[FindTomb] 'piece_workbench_ext1'에서 연결 VFX 프리팹을 찾지 못함."); _resolveFailed = true; return null; } _cachedConnectionPrefab = val.m_connectionPrefab; return _cachedConnectionPrefab; } private void DestroyVfxInstance() { if ((Object)(object)_vfxInstance != (Object)null) { Object.Destroy((Object)(object)_vfxInstance); _vfxInstance = null; } } } public static class GraveTrackingState { private static bool _cancelled; private static int _manualIndex = -1; public static bool IsCancelled => _cancelled; public static void Cancel() { _cancelled = true; } public static void CycleNext(int graveCount) { if (graveCount > 0) { _cancelled = false; int num = ResolveIndex(graveCount); _manualIndex = (num - 1 + graveCount) % graveCount; } } public static int ResolveIndex(int graveCount) { if (graveCount <= 0) { return -1; } if (_manualIndex < 0 || _manualIndex >= graveCount) { return graveCount - 1; } return _manualIndex; } public static int ResolveRank(int graveCount) { return TombTier.DeathOrderRank(ResolveIndex(graveCount), graveCount); } public static void ResetOnNewDeath() { _cancelled = false; _manualIndex = -1; } } public static class MinimapPinReconciler { private const float MatchToleranceXZ = 2f; private const float FallbackTimeoutSeconds = 8f; private const float NumberLabelFontSize = 22f; private static readonly Vector2 NumberLabelSize = new Vector2(28f, 28f); private static readonly Vector2 NumberLabelOffset = new Vector2(0f, 2f); private static readonly Dictionary<ZDOID, PinData> _linked = new Dictionary<ZDOID, PinData>(); private static readonly Dictionary<ZDOID, float> _unlinkedSince = new Dictionary<ZDOID, float>(); private static readonly Dictionary<ZDOID, GameObject> _numberLabels = new Dictionary<ZDOID, GameObject>(); private static bool _subscribed; private static Font _numberLabelFont; private static void EnsureSubscribed() { if (!_subscribed) { TombTrackerManager.OnGraveListChanged += PruneStaleLinks; _subscribed = true; } } public static void TryLinkFromAddPin(Vector3 pos, PinData pinData) { //IL_0020: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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) EnsureSubscribed(); IReadOnlyList<TombRecord> current = TombTrackerManager.Current; for (int i = 0; i < current.Count; i++) { TombRecord tombRecord = current[i]; if (!_linked.ContainsKey(tombRecord.ZdoId) && IsCloseXZ(tombRecord.Position, pos)) { _linked[tombRecord.ZdoId] = pinData; _unlinkedSince.Remove(tombRecord.ZdoId); break; } } } public static void ResetForNewSession() { _linked.Clear(); _unlinkedSince.Clear(); foreach (KeyValuePair<ZDOID, GameObject> numberLabel in _numberLabels) { if ((Object)(object)numberLabel.Value != (Object)null) { Object.Destroy((Object)(object)numberLabel.Value); } } _numberLabels.Clear(); } public static void Reconcile() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_020d: 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) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) EnsureSubscribed(); if ((Object)(object)Minimap.instance == (Object)null) { return; } IReadOnlyList<TombRecord> current = TombTrackerManager.Current; List<ZDOID> list = null; for (int i = 0; i < current.Count; i++) { TombRecord tombRecord = current[i]; if (_linked.TryGetValue(tombRecord.ZdoId, out var value)) { if (value != null && Minimap.instance.m_pins.Contains(value)) { continue; } _linked.Remove(tombRecord.ZdoId); } PinData val = FindNearbyUnlinkedDeathPin(tombRecord.Position); float value2; if (val != null) { _linked[tombRecord.ZdoId] = val; _unlinkedSince.Remove(tombRecord.ZdoId); } else if (!_unlinkedSince.TryGetValue(tombRecord.ZdoId, out value2)) { _unlinkedSince[tombRecord.ZdoId] = Time.time; } else { if (!(Time.time - value2 >= 8f)) { continue; } if (ZDOMan.instance != null && ZDOMan.instance.GetZDO(tombRecord.ZdoId) == null) { if (list == null) { list = new List<ZDOID>(); } list.Add(tombRecord.ZdoId); _unlinkedSince.Remove(tombRecord.ZdoId); Plugin.Log.LogMessage((object)$"[FindTomb] ZDO가 더 이상 존재하지 않음(이미 회수됨) - 추적 해제: {tombRecord.ZdoId}"); } else { PinData value3 = Minimap.instance.AddPin(tombRecord.Position, (PinType)4, "", true, false, 0L, default(PlatformUserID)); _linked[tombRecord.ZdoId] = value3; _unlinkedSince.Remove(tombRecord.ZdoId); } } } if (list != null) { for (int j = 0; j < list.Count; j++) { TombTrackerManager.RemoveByZdoId(list[j]); } } } public static void ApplyTierColors() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList<TombRecord> current = TombTrackerManager.Current; for (int i = 0; i < current.Count; i++) { ZDOID zdoId = current[i].ZdoId; if (_linked.TryGetValue(zdoId, out var value) && value != null && (Object)(object)value.m_iconElement != (Object)null) { ((Graphic)value.m_iconElement).color = TombTier.GetColor(i); ApplyNumberLabel(zdoId, value, TombTier.DeathOrderRank(i, current.Count)); } } } private static void ApplyNumberLabel(ZDOID id, PinData pin, int rank) { //IL_0019: 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 (!((Object)(object)pin.m_uiElement == (Object)null)) { if (!_numberLabels.TryGetValue(id, out var value) || (Object)(object)value == (Object)null || (Object)(object)value.transform.parent != (Object)(object)pin.m_uiElement) { value = CreateNumberLabel(pin.m_uiElement); _numberLabels[id] = value; } Text component = value.GetComponent<Text>(); if ((Object)(object)component != (Object)null) { component.text = rank.ToString(); } } } private static Font GetNumberLabelFont() { if ((Object)(object)_numberLabelFont != (Object)null) { return _numberLabelFont; } _numberLabelFont = Font.CreateDynamicFontFromOSFont("Arial", 22); if ((Object)(object)_numberLabelFont == (Object)null) { _numberLabelFont = Resources.GetBuiltinResource<Font>("Arial.ttf"); } return _numberLabelFont; } private static GameObject CreateNumberLabel(RectTransform parent) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("FindTombPinNumber", new Type[4] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Text), typeof(Outline) }); RectTransform component = val.GetComponent<RectTransform>(); ((Transform)component).SetParent((Transform)(object)parent, false); component.anchorMin = new Vector2(0.5f, 1f); component.anchorMax = new Vector2(0.5f, 1f); component.pivot = new Vector2(0.5f, 0f); component.anchoredPosition = NumberLabelOffset; component.sizeDelta = NumberLabelSize; Text component2 = val.GetComponent<Text>(); component2.font = GetNumberLabelFont(); component2.fontSize = 22; component2.fontStyle = (FontStyle)1; ((Graphic)component2).color = Color.white; component2.alignment = (TextAnchor)4; component2.verticalOverflow = (VerticalWrapMode)1; component2.horizontalOverflow = (HorizontalWrapMode)1; ((Graphic)component2).raycastTarget = false; Outline component3 = val.GetComponent<Outline>(); ((Shadow)component3).effectColor = Color.black; ((Shadow)component3).effectDistance = new Vector2(1.2f, -1.2f); return val; } private static PinData FindNearbyUnlinkedDeathPin(Vector3 pos) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_003b: 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) List<PinData> pins = Minimap.instance.m_pins; for (int i = 0; i < pins.Count; i++) { PinData val = pins[i]; if ((int)val.m_type == 4 && !IsLinkedToOther(val) && IsCloseXZ(pos, val.m_pos)) { return val; } } return null; } private static bool IsLinkedToOther(PinData pin) { foreach (KeyValuePair<ZDOID, PinData> item in _linked) { if (item.Value == pin) { return true; } } return false; } private static bool IsCloseXZ(Vector3 a, Vector3 b) { //IL_0001: 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_000f: 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) float num = a.x - b.x; float num2 = a.z - b.z; return num * num + num2 * num2 <= 4f; } private static void PruneStaleLinks() { //IL_0035: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: 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) IReadOnlyList<TombRecord> current = TombTrackerManager.Current; List<ZDOID> list = new List<ZDOID>(); foreach (KeyValuePair<ZDOID, PinData> item in _linked) { bool flag = false; for (int i = 0; i < current.Count; i++) { if (current[i].ZdoId == item.Key) { flag = true; break; } } if (!flag) { list.Add(item.Key); } } foreach (ZDOID item2 in list) { _linked.Remove(item2); _unlinkedSince.Remove(item2); if (_numberLabels.TryGetValue(item2, out var value)) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } _numberLabels.Remove(item2); } } } } public struct TombRecord { public ZDOID ZdoId; public Vector3 Position; public long DeathTimeTicks; public TombRecord(ZDOID zdoId, Vector3 position, long deathTimeTicks) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) ZdoId = zdoId; Position = position; DeathTimeTicks = deathTimeTicks; } } public static class TombTier { public static readonly Color[] Colors = (Color[])(object)new Color[5] { new Color(1f, 0.231f, 0.188f), new Color(1f, 0.498f, 0.769f), new Color(1f, 0.584f, 0f), new Color(1f, 0.839f, 0.039f), new Color(1f, 1f, 1f) }; public static Color GetColor(int tierIndex) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0030: Unknown result type (might be due to invalid IL or missing references) if (tierIndex < 0 || tierIndex >= Colors.Length) { return Color.white; } return Colors[tierIndex]; } public static int DeathOrderRank(int index, int count) { if (index < 0 || count <= 0 || index >= count) { return 0; } return count - index; } } public static class TombTrackerManager { public const int MaxGraves = 5; private static readonly List<TombRecord> _records = new List<TombRecord>(); private static long _loadedWorldUID = long.MinValue; private static bool _hasLoadedWorld = false; public static IReadOnlyList<TombRecord> Current { get { EnsureLoadedForCurrentWorld(); return _records; } } public static event Action OnGraveListChanged; public static void RegisterDeath(ZDOID zdoId, Vector3 position, long deathTimeTicks) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_0037: Unknown result type (might be due to invalid IL or missing references) EnsureLoadedForCurrentWorld(); _records.RemoveAll((TombRecord r) => r.ZdoId == zdoId); _records.Insert(0, new TombRecord(zdoId, position, deathTimeTicks)); while (_records.Count > 5) { _records.RemoveAt(_records.Count - 1); } Save(); GraveTrackingState.ResetOnNewDeath(); TombTrackerManager.OnGraveListChanged?.Invoke(); } public static bool RemoveByZdoId(ZDOID zdoId) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) EnsureLoadedForCurrentWorld(); int num = _records.RemoveAll((TombRecord r) => r.ZdoId == zdoId); if (num <= 0) { return false; } Save(); TombTrackerManager.OnGraveListChanged?.Invoke(); return true; } public static int IndexOf(ZDOID zdoId) { //IL_0017: 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) EnsureLoadedForCurrentWorld(); for (int i = 0; i < _records.Count; i++) { if (_records[i].ZdoId == zdoId) { return i; } } return -1; } private static void EnsureLoadedForCurrentWorld() { if (WorldContext.TryGetWorldUID(out var worldUID) && (!_hasLoadedWorld || worldUID != _loadedWorldUID)) { _records.Clear(); Load(worldUID); _loadedWorldUID = worldUID; _hasLoadedWorld = true; TombTrackerManager.OnGraveListChanged?.Invoke(); } } private static void Load(long worldUID) { //IL_00f3: 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) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } string saveKey = WorldContext.GetSaveKey(worldUID); if (!localPlayer.m_customData.TryGetValue(saveKey, out var value) || string.IsNullOrEmpty(value)) { return; } string[] array = value.Split(';'); string[] array2 = array; foreach (string text in array2) { if (!string.IsNullOrEmpty(text)) { string[] array3 = text.Split(','); if (array3.Length == 5 && WorldContext.TryParseZdoId(array3[0], out var id) && float.TryParse(array3[1], out var result) && float.TryParse(array3[2], out var result2) && float.TryParse(array3[3], out var result3) && long.TryParse(array3[4], out var result4)) { _records.Add(new TombRecord(id, new Vector3(result, result2, result3), result4)); } } } if (_records.Count > 5) { _records.RemoveRange(5, _records.Count - 5); } } private static void Save() { //IL_008c: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !_hasLoadedWorld) { return; } string saveKey = WorldContext.GetSaveKey(_loadedWorldUID); if (_records.Count == 0) { localPlayer.m_customData.Remove(saveKey); return; } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < _records.Count; i++) { TombRecord tombRecord = _records[i]; if (i > 0) { stringBuilder.Append(';'); } stringBuilder.Append(WorldContext.SerializeZdoId(tombRecord.ZdoId)).Append(',').Append(tombRecord.Position.x) .Append(',') .Append(tombRecord.Position.y) .Append(',') .Append(tombRecord.Position.z) .Append(',') .Append(tombRecord.DeathTimeTicks); } localPlayer.m_customData[saveKey] = stringBuilder.ToString(); } } public static class WorldContext { public static bool TryGetWorldUID(out long worldUID) { worldUID = 0L; if ((Object)(object)ZNet.instance == (Object)null) { return false; } World world = ZNet.m_world; if (world == null) { return false; } worldUID = world.m_uid; return true; } public static string GetSaveKey(long worldUID) { return "FindTomb.W" + worldUID; } public static string SerializeZdoId(ZDOID id) { return ((ZDOID)(ref id)).UserID + ":" + ((ZDOID)(ref id)).ID; } public static bool TryParseZdoId(string text, out ZDOID id) { //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_0075: 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) id = ZDOID.None; if (string.IsNullOrEmpty(text)) { return false; } int num = text.IndexOf(':'); if (num < 0) { return false; } if (!long.TryParse(text.Substring(0, num), out var result)) { return false; } if (!uint.TryParse(text.Substring(num + 1), out var result2)) { return false; } id = new ZDOID(result, result2); return true; } } } namespace FindTomb.Patches { [HarmonyPatch(typeof(Minimap))] internal static class MinimapPatches { [HarmonyPatch("AddPin")] [HarmonyPostfix] private static void AddPin_Postfix(Vector3 pos, PinType type, PinData __result) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (Plugin.ModEnabled.Value && Plugin.ShowMinimapPins.Value && (int)type == 4) { MinimapPinReconciler.TryLinkFromAddPin(pos, __result); } } [HarmonyPatch("UpdatePins")] [HarmonyPostfix] private static void UpdatePins_Postfix() { if (Plugin.ModEnabled.Value && Plugin.ShowMinimapPins.Value) { MinimapPinReconciler.ApplyTierColors(); } } } [HarmonyPatch(typeof(Player))] internal static class PlayerPatches { [HarmonyPatch("SetLocalPlayer")] [HarmonyPostfix] private static void SetLocalPlayer_Postfix(Player __instance) { GraveDirectionVFX.ResetPrefabCache(); MinimapPinReconciler.ResetForNewSession(); if ((Object)(object)((Component)__instance).GetComponent<GraveDirectionVFX>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<GraveDirectionVFX>(); } } } [HarmonyPatch(typeof(TombStone))] internal static class TombStonePatches { [HarmonyPatch("Setup")] [HarmonyPostfix] private static void Setup_Postfix(TombStone __instance, long ownerUID) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_0097: Unknown result type (might be due to invalid IL or missing references) if (Plugin.ModEnabled.Value) { ZNetView nview = __instance.m_nview; if (!((Object)(object)nview == (Object)null) && nview.IsValid()) { ZDOID uid = nview.GetZDO().m_uid; long deathTimeTicks = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTime().Ticks : 0); TombTrackerManager.RegisterDeath(uid, ((Component)__instance).transform.position, deathTimeTicks); Plugin.Log.LogMessage((object)$"[FindTomb] Grave registered: {uid} at {((Component)__instance).transform.position}"); } } } [HarmonyPatch("UpdateDespawn")] [HarmonyPrefix] private static void UpdateDespawn_Prefix(TombStone __instance) { //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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if (Plugin.ModEnabled.Value && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid() && __instance.m_nview.IsOwner() && !((Object)(object)__instance.m_container == (Object)null) && !__instance.m_container.IsInUse() && __instance.m_container.GetInventory().NrOfItems() <= 0) { ZDOID uid = __instance.m_nview.GetZDO().m_uid; if (TombTrackerManager.RemoveByZdoId(uid)) { Plugin.Log.LogMessage((object)$"[FindTomb] Grave emptied and removed: {uid}"); } } } } }