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.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using Unity.Collections; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: InternalsVisibleTo("RavenMap.Tests")] [assembly: AssemblyCompany("RavenMap")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.7.7.0")] [assembly: AssemblyInformationalVersion("1.7.7")] [assembly: AssemblyProduct("RavenMap")] [assembly: AssemblyTitle("RavenMap")] [assembly: AssemblyVersion("1.7.7.0")] namespace DragonMotion.RavenMap; internal static class RavenCommands { private const string CommandName = "ravenmap"; private static readonly FieldInfo TerminalCommandsField = AccessTools.Field(typeof(Terminal), "commands"); private static ConsoleCommand _command; private static bool _active; internal static void Initialize() { //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) //IL_003d: Expected O, but got Unknown //IL_003d: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown if (_command != null) { _active = true; return; } _command = new ConsoleCommand("ravenmap", string.Empty, new ConsoleEvent(Run), false, true, true, false, false, new ConsoleOptionsFetcher(GetOptions), false, true, true); _active = true; RefreshLocalization(); } internal static void RefreshLocalization(string language = null) { if (_command != null) { _command.Description = (IsRussian(language) ? "Сброс общих автоматических отметок RavenMap" : "Reset RavenMap shared automatic pins"); } } internal static void Shutdown() { _active = false; if (_command != null) { if (TerminalCommandsField?.GetValue(null) is Dictionary dictionary && dictionary.TryGetValue("ravenmap", out var value) && value == _command) { dictionary.Remove("ravenmap"); } _command = null; } } private static void Run(ConsoleEventArgs args) { if (!_active) { return; } bool flag = IsRussian(); if (args == null || args.Length != 3 || !string.Equals(args[1], "resetpins", StringComparison.OrdinalIgnoreCase) || !string.Equals(args[2], "confirm", StringComparison.OrdinalIgnoreCase)) { if (args != null) { Terminal context = args.Context; if (context != null) { context.AddString(flag ? "Использование: ravenmap resetpins confirm" : "Usage: ravenmap resetpins confirm"); } } } else if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { Terminal context2 = args.Context; if (context2 != null) { context2.AddString(flag ? "Сбрасывать общие автоматические отметки может только хост или администратор сервера." : "Only the host or a server administrator can reset shared automatic pins."); } } else { bool flag2 = RavenRuntime.RequestAutomaticPinReset(); Terminal context3 = args.Context; if (context3 != null) { context3.AddString((!flag2) ? (flag ? "Не удалось сбросить автоматические отметки: мир или сетевой сеанс RavenMap ещё не готов." : "Automatic pins could not be reset because the RavenMap world/network session is not ready.") : (flag ? "Общие автоматические отметки сброшены. Загруженные подходящие объекты будут обнаружены повторно." : "Shared automatic pins were reset. Loaded eligible objects will be discovered again.")); } } } private static List GetOptions() { return new List { "resetpins" }; } private static bool IsRussian(string language = null) { try { object obj = language; if (obj == null) { Localization instance = Localization.instance; obj = ((instance != null) ? instance.GetSelectedLanguage() : null); } return ConfigText.IsRussian((string)obj); } catch { return false; } } } internal static class GameAccess { private static FieldRef _explored; private static FieldRef _exploredOthers; private static FieldRef _fogTexture; private static FieldRef> _pins; private static FieldRef _pinUpdateRequired; private static FieldRef _mineRockHitAreas; private static FieldRef _mineRock5MeshRenderer; private static Func _mineRock5HitAreas; private static Func _mineRock5HitAreaHealth; private static bool _initialized; internal static bool TryInitialize(out string error) { if (_initialized) { error = string.Empty; return true; } try { _explored = AccessTools.FieldRefAccess("m_explored"); _exploredOthers = AccessTools.FieldRefAccess("m_exploredOthers"); _fogTexture = AccessTools.FieldRefAccess("m_fogTexture"); _pins = AccessTools.FieldRefAccess>("m_pins"); _pinUpdateRequired = AccessTools.FieldRefAccess("m_pinUpdateRequired"); _mineRockHitAreas = AccessTools.FieldRefAccess("m_hitAreas"); _mineRock5MeshRenderer = AccessTools.FieldRefAccess("m_meshRenderer"); FieldInfo fieldInfo = AccessTools.Field(typeof(MineRock5), "m_hitAreas"); if (fieldInfo == null) { throw new MissingFieldException(typeof(MineRock5).FullName, "m_hitAreas"); } _mineRock5HitAreas = BuildObjectFieldGetter(fieldInfo); Type type = fieldInfo.FieldType.GetGenericArguments()[0]; FieldInfo fieldInfo2 = AccessTools.Field(type, "m_health"); if (fieldInfo2 == null || fieldInfo2.FieldType != typeof(float)) { throw new MissingFieldException(type.FullName, "m_health"); } _mineRock5HitAreaHealth = BuildFloatFieldGetter(fieldInfo2); if (_explored == null || _exploredOthers == null || _fogTexture == null || _pins == null || _pinUpdateRequired == null || _mineRockHitAreas == null || _mineRock5MeshRenderer == null || _mineRock5HitAreas == null || _mineRock5HitAreaHealth == null) { throw new MissingFieldException("One or more required Minimap accessors could not be created."); } _initialized = true; error = string.Empty; return true; } catch (Exception ex) { _explored = null; _exploredOthers = null; _fogTexture = null; _pins = null; _pinUpdateRequired = null; _mineRockHitAreas = null; _mineRock5MeshRenderer = null; _mineRock5HitAreas = null; _mineRock5HitAreaHealth = null; _initialized = false; error = ex.GetType().Name + ": " + ex.Message; return false; } } internal static bool[] GetExplored(Minimap map) { if (!((Object)(object)map != (Object)null) || _explored == null) { return null; } return _explored.Invoke(map); } internal static bool[] GetExploredOthers(Minimap map) { if (!((Object)(object)map != (Object)null) || _exploredOthers == null) { return null; } return _exploredOthers.Invoke(map); } internal static Texture2D GetFogTexture(Minimap map) { if (!((Object)(object)map != (Object)null) || _fogTexture == null) { return null; } return _fogTexture.Invoke(map); } internal static List GetPins(Minimap map) { if (!((Object)(object)map != (Object)null) || _pins == null) { return null; } return _pins.Invoke(map); } internal static void MarkPinsDirty(Minimap map) { if (!((Object)(object)map == (Object)null) && _pinUpdateRequired != null) { _pinUpdateRequired.Invoke(map) = true; } } internal static int GetMineRockHitAreaCount(MineRock rock) { if (rock == null || _mineRockHitAreas == null) { return 0; } Collider[] obj = _mineRockHitAreas.Invoke(rock); if (obj == null) { return 0; } return obj.Length; } internal static int GetMineRock5HitAreaCount(MineRock5 rock) { if (rock == null || _mineRock5HitAreas == null) { return 0; } if (!(_mineRock5HitAreas(rock) is ICollection collection)) { return 0; } return collection.Count; } internal static bool TryMeasureMineRock5HitAreas(MineRock5 rock, float maximumHealth, out float remaining, out int totalParts, out int remainingParts) { remaining = 0f; totalParts = 0; remainingParts = 0; if (rock == null || maximumHealth <= 0f || _mineRock5HitAreas == null || _mineRock5HitAreaHealth == null || !(_mineRock5HitAreas(rock) is IList { Count: not 0 } list)) { return false; } totalParts = list.Count; for (int i = 0; i < list.Count; i++) { object obj = list[i]; if (obj != null) { float num = Mathf.Clamp(_mineRock5HitAreaHealth(obj), 0f, maximumHealth); remaining += num; if (num > 0f) { remainingParts++; } } } return true; } internal static MeshRenderer GetMineRock5CombinedRenderer(MineRock5 rock) { if (rock != null && _mineRock5MeshRenderer != null) { return _mineRock5MeshRenderer.Invoke(rock); } return null; } internal static bool TryGetMapState(Minimap map, out bool[] explored, out Texture2D fogTexture, out int textureSize) { explored = GetExplored(map); fogTexture = GetFogTexture(map); textureSize = (((Object)(object)map != (Object)null) ? map.m_textureSize : 0); if (explored != null && (Object)(object)fogTexture != (Object)null && textureSize > 0) { return explored.Length == textureSize * textureSize; } return false; } internal static bool ExploreRed(bool[] explored, Texture2D fogTexture, int size, int x, int y) { //IL_0035: 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_004b: Unknown result type (might be due to invalid IL or missing references) if (explored == null || (Object)(object)fogTexture == (Object)null || size <= 0 || explored.Length != size * size || (uint)x >= (uint)size || (uint)y >= (uint)size) { return false; } int num = y * size + x; if (explored[num]) { return false; } Color pixel = fogTexture.GetPixel(x, y); pixel.r = 0f; fogTexture.SetPixel(x, y, pixel); explored[num] = true; return true; } private static Func BuildObjectFieldGetter(FieldInfo field) { DynamicMethod dynamicMethod = new DynamicMethod("RavenMap_Get_" + typeof(T).Name + "_" + field.Name, typeof(object), new Type[1] { typeof(T) }, typeof(GameAccess), skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); if (field.FieldType.IsValueType) { iLGenerator.Emit(OpCodes.Box, field.FieldType); } iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func BuildFloatFieldGetter(FieldInfo field) { DynamicMethod dynamicMethod = new DynamicMethod("RavenMap_Get_" + field.DeclaringType.Name + "_" + field.Name, typeof(float), new Type[1] { typeof(object) }, typeof(GameAccess), skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, field.DeclaringType); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } } internal static class ConfigText { private static readonly Dictionary Russian = new Dictionary(StringComparer.Ordinal) { ["01 - Interface"] = "01 — Интерфейс", ["02 - Sharing"] = "02 — Общая карта", ["03 - Discovery"] = "03 — Обнаружение", ["04 - Resources"] = "04 — Ресурсы", ["04.1 - Pickables"] = "04.1 — Собираемые ресурсы", ["05 - Dungeons"] = "05 — Подземелья", ["06 - Markers"] = "06 — Метки", ["07 - Deduplication"] = "07 — Дедупликация", ["08 - Shimmer"] = "08 — Подсветка", ["08.1 - Pulse"] = "08.1 — Пульсация", ["08.2 - Sweep"] = "08.2 — Переливание", ["08.3 - X-ray"] = "08.3 — Рентген", ["09 - Performance"] = "09 — Производительность", ["10 - Diagnostics"] = "10 — Диагностика", ["Enabled"] = "Включено", ["Automatic pin names"] = "Названия автометок", ["Portal names"] = "Названия порталов", ["Pin icon size"] = "Размер значков", ["Filter scroll speed"] = "Скорость прокрутки", ["Shared fog"] = "Общий туман войны", ["Shared automatic pins"] = "Общие автометки", ["Resource radius"] = "Радиус ресурсов", ["Dungeon radius"] = "Радиус подземелий", ["Silver discovery"] = "Обнаружение серебра", ["Underground resources"] = "Подземные ресурсы", ["Discovery radius"] = "Радиус обнаружения", ["Cross out after harvest"] = "Зачёркивать после сбора", ["Merge distance"] = "Дистанция слияния", ["Remove after depletion"] = "Удаление после выработки", ["Progress update step"] = "Шаг обновления прогресса", ["Progress update interval"] = "Интервал обновления прогресса", ["Source prefab allow list"] = "Разрешённые префабы источников", ["Source prefab block list"] = "Запрещённые префабы источников", ["Dropped item block list"] = "Запрещённые выпадающие предметы", ["Dungeon prefab allow list"] = "Разрешённые префабы подземелий", ["Defeated enemies required"] = "Требуемый процент врагов", ["Inspected chests required"] = "Требуемый процент сундуков", ["Minimum observed chests"] = "Минимум найденных сундуков", ["Dungeon inventory settle delay"] = "Задержка учёта подземелья", ["Enemy respawn mode"] = "Режим респауна врагов", ["Reopen on respawn"] = "Возвращать при респауне", ["Manual dungeon toggle"] = "Ручная зачистка подземелья", ["Automatic portal pins"] = "Автометки порталов", ["Track ships"] = "Отслеживать корабли", ["Track carts"] = "Отслеживать повозки", ["Vehicle update interval"] = "Интервал обновления транспорта", ["Vehicle move threshold"] = "Порог движения транспорта", ["Resource merge distance"] = "Дистанция слияния ресурсов", ["Dungeon merge distance"] = "Дистанция слияния подземелий", ["Portal merge distance"] = "Дистанция слияния порталов", ["Animation"] = "Режим анимации", ["Pickable shimmer"] = "Подсветка собираемых ресурсов", ["Pulse color"] = "Цвет пульсации", ["Pulse interval"] = "Интервал пульсации", ["Pulse duration"] = "Длительность пульсации", ["Pulse intensity"] = "Яркость пульсации", ["Sweep color"] = "Цвет переливания", ["Sweep interval"] = "Интервал переливания", ["Sweep speed"] = "Скорость переливания", ["Sweep maximum duration"] = "Максимальная длительность переливания", ["Sweep intensity"] = "Яркость переливания", ["Radius"] = "Радиус", ["Sweep width"] = "Ширина волны", ["Sweep softness"] = "Мягкость волны", ["X-ray through terrain"] = "X-ray сквозь землю", ["X-ray toggle key"] = "Клавиша X-ray", ["X-ray color"] = "Цвет X-ray", ["X-ray intensity"] = "Яркость X-ray", ["X-ray radius"] = "Радиус X-ray", ["X-ray renderer budget"] = "Лимит рендереров X-ray", ["X-ray resource draw budget"] = "Лимит отрисовки ресурсов X-ray", ["Renderer budget"] = "Лимит рендереров", ["Save debounce"] = "Задержка сохранения", ["Fog pixels per packet"] = "Пикселей тумана в пакете", ["Fog merge cells per frame"] = "Ячеек тумана за кадр", ["Peer event limit"] = "Лимит событий игрока", ["Pin adds per frame"] = "Добавлений меток за кадр", ["Overlap counters"] = "Счётчики наложений", ["Overlap distance"] = "Дистанция наложения", ["State diagnostics on map"] = "Диагностика состояния на карте", ["Detailed logging"] = "Подробный журнал", ["Enable RavenMap. Requires a restart."] = "Включает RavenMap. Требуется перезапуск.", ["Show names beside automatic pins. Local setting."] = "Показывает названия рядом с автометками. Локальная настройка.", ["Show portal names independently. Local setting."] = "Показывает названия порталов независимо от других меток. Локальная настройка.", ["Local automatic-pin size multiplier."] = "Локальный множитель размера автометок.", ["Map-filter wheel speed in UI pixels per step."] = "Скорость колеса в окне фильтров, в пикселях за шаг.", ["Merge explored fog into the shared server map."] = "Объединяет разведанный туман войны на общей карте сервера.", ["Share automatic pins with every player."] = "Делится автометками со всеми игроками.", ["Discovery radius for loaded resources; unloaded zones are never scanned."] = "Радиус обнаружения загруженных ресурсов; незагруженные зоны не сканируются.", ["Discovery radius for loaded dungeons."] = "Радиус обнаружения загруженных подземелий.", ["WishboneOnly is vanilla-like; Radius is automatic; Disabled never pins silver."] = "«Только с дужкой» работает как в ваниле; «По радиусу» — автоматически; «Выключено» — не отмечать серебро.", ["Discover non-silver underground resources automatically instead of on detection or mining."] = "Автоматически обнаруживает подземные ресурсы, кроме серебра, не дожидаясь поиска или добычи.", ["Server policy: track naturally spawned renewable and one-shot berries, mushrooms, plants and other Pickable objects."] = "Серверное правило: отслеживает естественно появившиеся возобновляемые и одноразовые ягоды, грибы, растения и другие собираемые объекты.", ["Server discovery radius for loaded pickable plants; unloaded zones are never scanned."] = "Серверный радиус обнаружения загруженных собираемых растений; незагруженные зоны не сканируются.", ["Server policy: cross out a renewable pickable after harvest and restore it when the game respawns it."] = "Серверное правило: зачёркивает возобновляемый объект после сбора и снимает зачёркивание, когда игра восстановит его.", ["Server merge distance for equivalent pickable pins."] = "Серверная дистанция слияния одинаковых отметок собираемых объектов.", ["Remove a vein pin after this share of its original amount is depleted."] = "Удаляет метку жилы после выработки указанной доли исходного объёма.", ["Extra depletion required before another progress update."] = "Дополнительная выработка до следующего обновления прогресса.", ["Minimum interval between ordinary updates for one resource."] = "Минимальный интервал между обычными обновлениями одного ресурса.", ["Semicolon-separated source prefabs; SourcePrefab=ItemPrefab overrides inferred drops."] = "Префабы источников через точку с запятой; SourcePrefab=ItemPrefab переопределяет определённый предмет.", ["Semicolon-separated prefabs never treated as resources."] = "Префабы через точку с запятой, которые никогда не считаются ресурсами.", ["Ignore deposits whose inferred drops are only these item keys."] = "Игнорирует залежи, из которых определяются только перечисленные предметы.", ["Semicolon-separated location prefabs always treated as clearable dungeons."] = "Префабы локаций через точку с запятой, всегда считающиеся зачищаемыми подземельями.", ["Defeated share of observed enemies required before crossing out a dungeon."] = "Доля побеждённых обнаруженных врагов для зачёркивания подземелья.", ["Observed-chest share required before crossing out a dungeon."] = "Доля осмотренных обнаруженных сундуков для зачёркивания подземелья.", ["Minimum observed chests required for automatic clearing."] = "Минимум обнаруженных сундуков для автоматической отметки о зачистке.", ["Quiet period with no newly observed enemies or chests before the loaded dungeon inventory is considered complete."] = "Пауза без новых врагов или сундуков, после которой учёт загруженного подземелья считается завершённым.", ["Auto follows observed spawners; Enabled forces reopening; Disabled keeps cleared state."] = "«Авто» учитывает найденные спавнеры; «Включено» всегда возвращает метку; «Выключено» сохраняет зачистку.", ["Remove crossed-out state when a respawn-capable dungeon gets a live enemy."] = "Снимает зачёркивание, когда в подземелье с респауном появляется живой враг.", ["Hold this key and left-click a RavenMap dungeon icon to share a forced cleared/active state. Set None to disable."] = "Зажмите эту клавишу и щёлкните ЛКМ по значку подземелья RavenMap, чтобы принудительно и для всех переключить состояние зачистки. Значение None отключает функцию.", ["Pin portals automatically and keep their tag current."] = "Автоматически отмечает порталы и обновляет их название.", ["Track vanilla and modded Ship components."] = "Отслеживает ванильные и модифицированные компоненты Ship.", ["Track vanilla and modded Vagon components."] = "Отслеживает ванильные и модифицированные компоненты Vagon.", ["Position-report interval for loaded vehicles."] = "Интервал отправки позиции загруженного транспорта.", ["Movement required before reporting a new vehicle position."] = "Минимальное движение до отправки новой позиции транспорта.", ["Server merge distance for equivalent resource pins."] = "Серверная дистанция слияния одинаковых меток ресурсов.", ["Server merge distance for equivalent dungeon pins."] = "Серверная дистанция слияния одинаковых меток подземелий.", ["Server merge distance for equivalent portal pins."] = "Серверная дистанция слияния одинаковых меток порталов.", ["Periodically highlight nearby visible resources and enabled Pickables without material instances."] = "Периодически подсвечивает ближайшие видимые ресурсы и включённые природные собираемые объекты без создания копий материалов.", ["Sweep travels across highlighted geometry; Pulse brightens the whole object."] = "«Переливание» проходит волной по подсвечиваемой геометрии; «Пульсация» плавно подсвечивает весь объект.", ["Apply the same Pulse or Sweep highlight to nearby loaded natural Pickables. Local setting."] = "Применяет ту же пульсацию или переливание к ближайшим загруженным природным собираемым ресурсам. Локальная настройка.", ["Color used by the whole-object pulse."] = "Цвет пульсации, подсвечивающей весь объект.", ["Delay between pulse effects."] = "Пауза между пульсациями.", ["Duration of one smooth pulse."] = "Длительность одной плавной пульсации.", ["Tint and HDR glow strength of the pulse."] = "Сила оттенка и HDR-свечения пульсации.", ["Color of the soft wave travelling across highlighted geometry."] = "Цвет мягкой волны, проходящей по подсвечиваемой геометрии.", ["Delay between sweep effects."] = "Пауза между переливаниями.", ["World-space speed of the travelling wave."] = "Скорость движения волны в метрах игрового мира в секунду.", ["Safety limit for one sweep; very large geometry still completes its exit."] = "Предельная длительность одного переливания; на очень большой геометрии волна всё равно полностью выходит за дальний край.", ["Tint and HDR glow strength of the travelling wave."] = "Сила оттенка и HDR-свечения движущейся волны.", ["Only loaded resources and enabled Pickables inside this radius may shimmer."] = "Переливаются только загруженные ресурсы и включённые собираемые объекты в этом радиусе.", ["Relative width of the soft wave; the maximum covers almost the complete highlighted object."] = "Относительная ширина мягкой волны; максимальное значение покрывает почти весь подсвечиваемый объект.", ["Softness of the moving wave; higher values remove the flat center and spread the fade across the whole effect."] = "Мягкость движущейся волны; большие значения убирают плоский центр и растягивают затухание на весь эффект.", ["Enable local X-ray rendering. Its hotkey only changes temporary visibility while this setting is enabled."] = "Включает локальный X-ray. Горячая клавиша меняет только временную видимость, пока эта настройка включена.", ["Toggle local X-ray visibility during gameplay. Works only when XrayEnabled is on; set None to disable."] = "Переключает локальную видимость X-ray во время игры. Работает только при включённом XrayEnabled; значение None отключает клавишу.", ["Color used for vein geometry visible through terrain."] = "Цвет геометрии жилы, видимой сквозь землю.", ["HDR brightness of X-ray vein geometry."] = "HDR-яркость геометрии жилы в режиме X-ray.", ["Only already discovered loaded veins inside this local radius appear in X-ray."] = "В X-ray видны только уже обнаруженные и загруженные жилы в пределах этого локального радиуса.", ["Total renderer budget for the current X-ray selection."] = "Общий лимит рендереров в текущей выборке X-ray.", ["Hard resource draw-command limit for modded meshes with many submeshes."] = "Жёсткий лимит команд отрисовки ресурсов для модифицированных мешей с большим числом сабмешей.", ["Hard total renderer limit for one complete shimmer batch."] = "Жёсткий общий лимит рендереров для одного полного цикла подсветки.", ["Idle time after the last state change before saving; continuous changes are flushed periodically."] = "Время ожидания после последнего изменения; при непрерывных изменениях сохранение всё равно выполняется периодически.", ["Hard fog-delta packet limit."] = "Жёсткий лимит изменений тумана в одном пакете.", ["Shared-fog cells examined per frame; lower values reduce spikes."] = "Ячейки общего тумана, обрабатываемые за кадр; меньшее значение снижает скачки нагрузки.", ["Server event-rate guard per peer."] = "Серверный лимит частоты событий для одного игрока.", ["Frame budget for restoring or enabling automatic pins."] = "Кадровый лимит восстановления или включения автометок.", ["Show local P/S counters for overlapping canonical pins and sources."] = "Показывает локальные счётчики P/S для наложившихся меток и источников.", ["World-space grouping distance for overlap counters."] = "Дистанция группировки счётчиков наложения в игровом мире.", ["Show local resource measurements and dungeon clearing blockers beside RavenMap pins. Local setting."] = "Показывает рядом с отметками RavenMap локальные измерения ресурсов и причины, мешающие зачистке подземелья. Локальная настройка.", ["Log classification, deduplication and network details."] = "Записывает подробности классификации, дедупликации и сети." }; internal static bool IsRussian(string language) { return string.Equals(language, "Russian", StringComparison.OrdinalIgnoreCase); } internal static string Localize(string english, bool russian) { if (!russian || string.IsNullOrEmpty(english)) { return english ?? string.Empty; } if (!Russian.TryGetValue(english, out var value)) { return english; } return value; } internal static bool HasRussian(string english) { if (!string.IsNullOrEmpty(english)) { return Russian.ContainsKey(english); } return false; } internal unsafe static string EnumLabel(object value, bool russian) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_0111: Expected I4, but got Unknown if (value is SilverDiscoveryMode silverDiscoveryMode) { if (!russian) { if (silverDiscoveryMode != SilverDiscoveryMode.WishboneOnly) { return silverDiscoveryMode.ToString(); } return "Wishbone only"; } switch (silverDiscoveryMode) { case SilverDiscoveryMode.WishboneOnly: return "Только с дужкой"; case SilverDiscoveryMode.Radius: return "По радиусу"; case SilverDiscoveryMode.Disabled: return "Выключено"; } } if (value is DungeonRespawnMode dungeonRespawnMode) { if (!russian) { return dungeonRespawnMode.ToString(); } switch (dungeonRespawnMode) { case DungeonRespawnMode.Auto: return "Авто"; case DungeonRespawnMode.Enabled: return "Включено"; case DungeonRespawnMode.Disabled: return "Выключено"; } } if (value is ShimmerAnimationMode shimmerAnimationMode) { if (!russian) { return shimmerAnimationMode.ToString(); } switch (shimmerAnimationMode) { case ShimmerAnimationMode.Sweep: return "Переливание"; case ShimmerAnimationMode.Pulse: return "Пульсация"; } } if (value is KeyCode val) { if (!russian) { return ((object)(*(KeyCode*)(&val))/*cast due to .constrained prefix*/).ToString(); } if ((int)val != 0) { return (val - 303) switch { 5 => "Левый Alt", 4 => "Правый Alt", 3 => "Левый Ctrl", 2 => "Правый Ctrl", 1 => "Левый Shift", 0 => "Правый Shift", _ => ((object)(*(KeyCode*)(&val))/*cast due to .constrained prefix*/).ToString(), }; } return "Отключено"; } return null; } } internal sealed class ConfigurationManagerAttributes { public string Category { get; set; } public string DispName { get; set; } public string Description { get; set; } public bool? IsAdvanced { get; set; } public int? Order { get; set; } public bool? Browsable { get; set; } internal string EnglishCategory { get; set; } internal string EnglishDispName { get; set; } internal string EnglishDescription { get; set; } internal bool HasCompleteRussianTranslation { get { if (ConfigText.HasRussian(EnglishCategory) && ConfigText.HasRussian(EnglishDispName)) { return ConfigText.HasRussian(EnglishDescription); } return false; } } internal bool ApplyLanguage(string language) { bool russian = ConfigText.IsRussian(language); string text = ConfigText.Localize(EnglishCategory, russian); string text2 = ConfigText.Localize(EnglishDispName, russian); string text3 = ConfigText.Localize(EnglishDescription, russian); bool result = Category != text || DispName != text2 || Description != text3; Category = text; DispName = text2; Description = text3; return result; } } internal static class ConfigurationManagerIntegration { private const string PluginGuid = "_shudnal.ConfigurationManager"; private const string DrawerTypeName = "ConfigurationManager.SettingFieldDrawer"; private static bool _russian; private static bool _refreshFailureReported; private static PropertyInfo _guiContentTextProperty; internal static void SetLanguage(string language) { _russian = ConfigText.IsRussian(language); } internal static string GetEnumLabel(object value) { return ConfigText.EnumLabel(value, _russian); } internal static bool TryInstallEnumLocalization(Harmony harmony) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown if (harmony == null) { return false; } try { Type type = AccessTools.TypeByName("ConfigurationManager.SettingFieldDrawer"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "ObjectToGuiContent", new Type[1] { typeof(object) }, (Type[])null)); MethodInfo methodInfo2 = AccessTools.Method(typeof(ConfigurationManagerIntegration), "EnumGuiContentPostfix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { return false; } _guiContentTextProperty = methodInfo.ReturnType.GetProperty("text", BindingFlags.Instance | BindingFlags.Public); if (_guiContentTextProperty == null || !_guiContentTextProperty.CanWrite) { return false; } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } catch (Exception ex) { ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("Configuration Manager enum localization was unavailable: " + ex.Message)); } return false; } } internal static void RefreshIfInstalled() { try { Type type = AccessTools.TypeByName("ConfigurationManager.SettingFieldDrawer"); if (type != null) { AccessTools.Method(type, "ClearCache", (Type[])null, (Type[])null)?.Invoke(null, null); } if (Chainloader.PluginInfos.TryGetValue("_shudnal.ConfigurationManager", out var value) && !((Object)(object)value.Instance == (Object)null)) { AccessTools.Method(((object)value.Instance).GetType(), "BuildSettingList", (Type[])null, (Type[])null)?.Invoke(value.Instance, null); _refreshFailureReported = false; } } catch (Exception ex) { if (!_refreshFailureReported) { _refreshFailureReported = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("Configuration Manager could not refresh localized RavenMap labels: " + ex.Message)); } } } } private static void EnumGuiContentPostfix(object x, object __result) { string enumLabel = GetEnumLabel(x); if (!string.IsNullOrEmpty(enumLabel) && __result != null && _guiContentTextProperty != null) { _guiContentTextProperty.SetValue(__result, enumLabel, null); } } } internal sealed class ModConfig { internal const string LegacyResourcePrefabAllowList = "MineRock_Copper;MineRock_Tin;mine_rock_iron;silvervein;MineRock_Obsidian;MineRock_Meteorite;Leviathan;giant_brain;softtissue_mineable;blackmarble_1;blackmarble_2;blackmarble_3;blackmarble_4;blackmarble_head_big01;blackmarble_head_big02;blackmarble_head01;blackmarble_head02;blackmarble_out_1;blackmarble_out_2;blackmarble_out_3;blackmarble_out_4;blackmarble_tip;MineRock_Lava;MineRock_Lava_big;coal_rock1_bal;coal_rock_nomoss_bal;MineRock_Coal_bal;MineRock_CoalSnow_bal;gold_Rock_bal;MineRock_Blackmetal_bal;MineRock_Borax_bal;MineRock_Cobalt_bal;MineRock_DarkIron_bal;MineRock_Lead_bal;MineRock_Zinc_bal;MineRock_Nickel_bal;rock_nickel_bal;rock_nickel_nomoss_bal;MineRock_Copper_bal;MineRock_IronNew_bal;MineRock_IronSnow_bal;MineRock_Guck_bal;rock_silver_small_bal;rock_silver_small_frac_bal;ClayDeposit_bal;ChitinDeposit_bal;bloodshard_deposit_bal;MineRock_MeteoriteNew_bal;Pickable_Clay_bal;Pickable_GuckSack_bal;Pickable_MeteoriteNew_bal;Pickable_MagmaStone_bal;Pickable_TinNew_bal;Pickable_MountainCaveCrystal_bal;deposit_jotunfinger_bal"; internal const string DefaultResourcePrefabAllowList = "MineRock_Copper;rock4_copper;MineRock_Tin;mine_rock_iron;silvervein;MineRock_Obsidian;MineRock_Meteorite;Leviathan;giant_brain;softtissue_mineable;blackmarble_1;blackmarble_2;blackmarble_3;blackmarble_4;blackmarble_head_big01;blackmarble_head_big02;blackmarble_head01;blackmarble_head02;blackmarble_out_1;blackmarble_out_2;blackmarble_out_3;blackmarble_out_4;blackmarble_tip;MineRock_Lava;MineRock_Lava_big;coal_rock1_bal;coal_rock_nomoss_bal;MineRock_Coal_bal;MineRock_CoalSnow_bal;gold_Rock_bal;MineRock_Blackmetal_bal;MineRock_Borax_bal;MineRock_Cobalt_bal;MineRock_DarkIron_bal;MineRock_Lead_bal;MineRock_Zinc_bal;MineRock_Nickel_bal;rock_nickel_bal;rock_nickel_nomoss_bal;MineRock_Copper_bal;MineRock_IronNew_bal;MineRock_IronSnow_bal;MineRock_Guck_bal;rock_silver_small_bal;ClayDeposit_bal;ChitinDeposit_bal;MineRock_MeteoriteNew_bal;deposit_jotunfinger_bal"; internal ConfigEntry Enabled; internal ConfigEntry ShowPinNames; internal ConfigEntry ShowPortalNames; internal ConfigEntry PinIconScale; internal ConfigEntry FilterScrollSensitivity; internal ConfigEntry ShareFog; internal ConfigEntry SharePins; internal ConfigEntry ResourceDiscoveryRadius; internal ConfigEntry DungeonDiscoveryRadius; internal ConfigEntry SilverMode; internal ConfigEntry AutoPinUndergroundResources; internal ConfigEntry TrackPickables; internal ConfigEntry PickableDiscoveryRadius; internal ConfigEntry CrossOutRespawningPickables; internal ConfigEntry ResourceRemovalPercent; internal ConfigEntry ResourceProgressStepPercent; internal ConfigEntry ResourceProgressMinInterval; internal ConfigEntry ResourcePrefabAllowList; internal ConfigEntry ResourcePrefabBlockList; internal ConfigEntry ResourceItemBlockList; internal ConfigEntry DungeonPrefabAllowList; internal ConfigEntry RequiredDefeatedEnemiesPercent; internal ConfigEntry DungeonChestInspectionPercent; internal ConfigEntry DungeonMinimumObservedChests; internal ConfigEntry DungeonCensusSettleSeconds; internal ConfigEntry DungeonRespawn; internal ConfigEntry ReopenDungeonOnRespawn; internal ConfigEntry ManualDungeonToggleModifier; internal ConfigEntry AutoPinPortals; internal ConfigEntry TrackShips; internal ConfigEntry TrackCarts; internal ConfigEntry VehicleUpdateInterval; internal ConfigEntry VehicleMinimumMoveDistance; internal ConfigEntry ResourceDedupeDistance; internal ConfigEntry PickableDedupeDistance; internal ConfigEntry DungeonDedupeDistance; internal ConfigEntry PortalDedupeDistance; internal ConfigEntry ShimmerEnabled; internal ConfigEntry ShimmerMode; internal ConfigEntry HighlightPickables; internal ConfigEntry PulseColor; internal ConfigEntry PulseInterval; internal ConfigEntry PulseDuration; internal ConfigEntry PulseIntensity; internal ConfigEntry SweepColor; internal ConfigEntry SweepInterval; internal ConfigEntry SweepSpeed; internal ConfigEntry SweepMaximumDuration; internal ConfigEntry SweepIntensity; internal ConfigEntry ShimmerRadius; internal ConfigEntry SweepWaveWidth; internal ConfigEntry SweepSoftness; internal ConfigEntry XrayEnabled; internal ConfigEntry XrayToggleKey; internal ConfigEntry XrayColor; internal ConfigEntry XrayIntensity; internal ConfigEntry XrayRadius; internal ConfigEntry XrayRendererBudget; internal ConfigEntry XrayDrawCommandBudget; internal ConfigEntry ShimmerRendererBudget; internal ConfigEntry SaveDebounceSeconds; internal ConfigEntry MaxFogDeltaPixels; internal ConfigEntry FogMergeCellsPerFrame; internal ConfigEntry MaxNetworkEventsPerTenSeconds; internal ConfigEntry MaxPinAddsPerFrame; internal ConfigEntry ShowPinOverlapDiagnostics; internal ConfigEntry PinOverlapDiagnosticDistance; internal ConfigEntry ShowStateDiagnostics; internal ConfigEntry DetailedLogging; private const string InterfaceCategory = "01 - Interface"; private const string SharingCategory = "02 - Sharing"; private const string DiscoveryCategory = "03 - Discovery"; private const string ResourcesCategory = "04 - Resources"; private const string PickablesCategory = "04.1 - Pickables"; private const string DungeonsCategory = "05 - Dungeons"; private const string MarkersCategory = "06 - Markers"; private const string DeduplicationCategory = "07 - Deduplication"; private const string ShimmerCategory = "08 - Shimmer"; private const string PulseCategory = "08.1 - Pulse"; private const string SweepCategory = "08.2 - Sweep"; private const string XrayCategory = "08.3 - X-ray"; private const string PerformanceCategory = "09 - Performance"; private const string DiagnosticsCategory = "10 - Diagnostics"; private const int VisualSettingsVersion = 1; private static readonly FieldInfo[] ConfigEntryFields = (from field in typeof(ModConfig).GetFields(BindingFlags.Instance | BindingFlags.NonPublic) where typeof(ConfigEntryBase).IsAssignableFrom(field.FieldType) select field).ToArray(); private static readonly FieldInfo ConfigDescriptionTextField = typeof(ConfigDescription).GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); private static bool _canRewriteConfigDescription = ConfigDescriptionTextField != null; internal bool AnyResourceVisualEnabled { get { if (!ShimmerEnabled.Value) { return XrayEnabled.Value; } return true; } } private static ConfigDescription Describe(string description, string category, string displayName, int order, AcceptableValueBase acceptableValues = null, bool advanced = false) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes { EnglishCategory = category, EnglishDispName = displayName, EnglishDescription = description, Order = order, IsAdvanced = advanced }; configurationManagerAttributes.ApplyLanguage("English"); return new ConfigDescription(configurationManagerAttributes.Description, acceptableValues, new object[1] { configurationManagerAttributes }); } internal static ModConfig Bind(ConfigFile file, string language = "English") { if (file == null) { throw new ArgumentNullException("file"); } bool saveOnConfigSet = file.SaveOnConfigSet; file.SaveOnConfigSet = false; try { ModConfig result = BindCore(file, language); if (saveOnConfigSet) { file.Save(); } return result; } finally { file.SaveOnConfigSet = saveOnConfigSet; } } private static ModConfig BindCore(ConfigFile file, string language) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_099f: Unknown result type (might be due to invalid IL or missing references) //IL_0ab5: Unknown result type (might be due to invalid IL or missing references) //IL_0d43: Unknown result type (might be due to invalid IL or missing references) //IL_10f8: Unknown result type (might be due to invalid IL or missing references) //IL_1148: Unknown result type (might be due to invalid IL or missing references) int num = ((!HasPersistedLegacyVisualSettings(file)) ? 1 : 0); ConfigEntry val = file.Bind("00 - Internal", "VisualSettingsVersion", num, new ConfigDescription("Internal RavenMap visual-settings migration version.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Browsable = false, IsAdvanced = true, Order = int.MinValue } })); ModConfig modConfig = new ModConfig { Enabled = file.Bind("01 - General", "Enabled", true, Describe("Enable RavenMap. Requires a restart.", "01 - Interface", "Enabled", 1000)), ShowPinNames = file.Bind("01 - General", "ShowAutomaticPinNames", false, Describe("Show names beside automatic pins. Local setting.", "01 - Interface", "Automatic pin names", 990)), ShowPortalNames = file.Bind("01 - General", "ShowPortalNames", true, Describe("Show portal names independently. Local setting.", "01 - Interface", "Portal names", 980)), PinIconScale = file.Bind("01 - General", "AutomaticPinIconScale", 0.7f, Describe("Local automatic-pin size multiplier.", "01 - Interface", "Pin icon size", 970, (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 3f))), FilterScrollSensitivity = file.Bind("01 - General", "FilterScrollSpeed", 360f, Describe("Map-filter wheel speed in UI pixels per step.", "01 - Interface", "Filter scroll speed", 960, (AcceptableValueBase)(object)new AcceptableValueRange(40f, 1200f))), ShareFog = file.Bind("02 - Multiplayer", "ShareFog", true, Describe("Merge explored fog into the shared server map.", "02 - Sharing", "Shared fog", 900)), SharePins = file.Bind("02 - Multiplayer", "ShareAutomaticPins", true, Describe("Share automatic pins with every player.", "02 - Sharing", "Shared automatic pins", 890)), ResourceDiscoveryRadius = file.Bind("03 - Discovery", "ResourceRadius", 30f, Describe("Discovery radius for loaded resources; unloaded zones are never scanned.", "03 - Discovery", "Resource radius", 800, (AcceptableValueBase)(object)new AcceptableValueRange(5f, 128f))), DungeonDiscoveryRadius = file.Bind("03 - Discovery", "DungeonRadius", 30f, Describe("Discovery radius for loaded dungeons.", "03 - Discovery", "Dungeon radius", 790, (AcceptableValueBase)(object)new AcceptableValueRange(10f, 256f))), SilverMode = file.Bind("03 - Discovery", "SilverDiscovery", SilverDiscoveryMode.WishboneOnly, Describe("WishboneOnly is vanilla-like; Radius is automatic; Disabled never pins silver.", "03 - Discovery", "Silver discovery", 780)), AutoPinUndergroundResources = file.Bind("03 - Discovery", "AutoPinUndergroundResources", false, Describe("Discover non-silver underground resources automatically instead of on detection or mining.", "03 - Discovery", "Underground resources", 770)), ResourceRemovalPercent = file.Bind("04 - Resources", "RemoveAfterDepletedPercent", 50f, Describe("Remove a vein pin after this share of its original amount is depleted.", "04 - Resources", "Remove after depletion", 700, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f))), ResourceProgressStepPercent = file.Bind("04 - Resources", "ProgressUpdateStepPercent", 2f, Describe("Extra depletion required before another progress update.", "04 - Resources", "Progress update step", 690, (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 20f), advanced: true)), ResourceProgressMinInterval = file.Bind("04 - Resources", "ProgressUpdateMinIntervalSeconds", 0.25f, Describe("Minimum interval between ordinary updates for one resource.", "04 - Resources", "Progress update interval", 680, (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f), advanced: true)), ResourcePrefabAllowList = file.Bind("04 - Resources", "PrefabAllowList", "MineRock_Copper;rock4_copper;MineRock_Tin;mine_rock_iron;silvervein;MineRock_Obsidian;MineRock_Meteorite;Leviathan;giant_brain;softtissue_mineable;blackmarble_1;blackmarble_2;blackmarble_3;blackmarble_4;blackmarble_head_big01;blackmarble_head_big02;blackmarble_head01;blackmarble_head02;blackmarble_out_1;blackmarble_out_2;blackmarble_out_3;blackmarble_out_4;blackmarble_tip;MineRock_Lava;MineRock_Lava_big;coal_rock1_bal;coal_rock_nomoss_bal;MineRock_Coal_bal;MineRock_CoalSnow_bal;gold_Rock_bal;MineRock_Blackmetal_bal;MineRock_Borax_bal;MineRock_Cobalt_bal;MineRock_DarkIron_bal;MineRock_Lead_bal;MineRock_Zinc_bal;MineRock_Nickel_bal;rock_nickel_bal;rock_nickel_nomoss_bal;MineRock_Copper_bal;MineRock_IronNew_bal;MineRock_IronSnow_bal;MineRock_Guck_bal;rock_silver_small_bal;ClayDeposit_bal;ChitinDeposit_bal;MineRock_MeteoriteNew_bal;deposit_jotunfinger_bal", Describe("Semicolon-separated source prefabs; SourcePrefab=ItemPrefab overrides inferred drops.", "04 - Resources", "Source prefab allow list", 670, null, advanced: true)), ResourcePrefabBlockList = file.Bind("04 - Resources", "PrefabBlockList", "rock1_mountain;rock2_mountain;rock3_mountain", Describe("Semicolon-separated prefabs never treated as resources.", "04 - Resources", "Source prefab block list", 660, null, advanced: true)), ResourceItemBlockList = file.Bind("04 - Resources", "DroppedItemBlockList", "$item_stone;$item_wood;$item_roundlog", Describe("Ignore deposits whose inferred drops are only these item keys.", "04 - Resources", "Dropped item block list", 650, null, advanced: true)), TrackPickables = file.Bind("03 - Discovery", "TrackRespawningPickables", true, Describe("Server policy: track naturally spawned renewable and one-shot berries, mushrooms, plants and other Pickable objects.", "04.1 - Pickables", "Enabled", 700)), PickableDiscoveryRadius = file.Bind("03 - Discovery", "PickableRadius", 30f, Describe("Server discovery radius for loaded pickable plants; unloaded zones are never scanned.", "04.1 - Pickables", "Discovery radius", 690, (AcceptableValueBase)(object)new AcceptableValueRange(5f, 128f))), CrossOutRespawningPickables = file.Bind("04.1 - Pickables", "CrossOutRespawningPickables", true, Describe("Server policy: cross out a renewable pickable after harvest and restore it when the game respawns it.", "04.1 - Pickables", "Cross out after harvest", 680)), DungeonPrefabAllowList = file.Bind("05 - Dungeons", "PrefabAllowList", "Crypt2;Crypt3;Crypt4;SunkenCrypt4;MountainCave02;Mistlands_DvergrTownEntrance1;Mistlands_DvergrTownEntrance2;Mistlands_DvergrTownEntrance3;BFD_Exterior;CD_Exterior1", Describe("Semicolon-separated location prefabs always treated as clearable dungeons.", "05 - Dungeons", "Dungeon prefab allow list", 620, null, advanced: true)), RequiredDefeatedEnemiesPercent = file.Bind("05 - Dungeons", "RequiredDefeatedEnemiesPercent", 60f, Describe("Defeated share of observed enemies required before crossing out a dungeon.", "05 - Dungeons", "Defeated enemies required", 610, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f))), DungeonChestInspectionPercent = file.Bind("05 - Dungeons", "RequiredInspectedChestsPercent", 60f, Describe("Observed-chest share required before crossing out a dungeon.", "05 - Dungeons", "Inspected chests required", 590, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f))), DungeonMinimumObservedChests = file.Bind("05 - Dungeons", "MinimumObservedChests", 0, Describe("Minimum observed chests required for automatic clearing.", "05 - Dungeons", "Minimum observed chests", 580, (AcceptableValueBase)(object)new AcceptableValueRange(0, 100))), DungeonCensusSettleSeconds = file.Bind("05 - Dungeons", "CensusSettleSeconds", 1.25f, Describe("Quiet period with no newly observed enemies or chests before the loaded dungeon inventory is considered complete.", "05 - Dungeons", "Dungeon inventory settle delay", 570, (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 5f), advanced: true)), DungeonRespawn = file.Bind("05 - Dungeons", "EnemyRespawnMode", DungeonRespawnMode.Auto, Describe("Auto follows observed spawners; Enabled forces reopening; Disabled keeps cleared state.", "05 - Dungeons", "Enemy respawn mode", 560)), ReopenDungeonOnRespawn = file.Bind("05 - Dungeons", "ReopenWhenEnemiesRespawn", true, Describe("Remove crossed-out state when a respawn-capable dungeon gets a live enemy.", "05 - Dungeons", "Reopen on respawn", 550)), ManualDungeonToggleModifier = file.Bind("05 - Dungeons", "ManualToggleModifier", (KeyCode)308, Describe("Hold this key and left-click a RavenMap dungeon icon to share a forced cleared/active state. Set None to disable.", "05 - Dungeons", "Manual dungeon toggle", 540)), AutoPinPortals = file.Bind("06 - Portals and vehicles", "AutoPinPortals", true, Describe("Pin portals automatically and keep their tag current.", "06 - Markers", "Automatic portal pins", 500)), TrackShips = file.Bind("06 - Portals and vehicles", "TrackShips", true, Describe("Track vanilla and modded Ship components.", "06 - Markers", "Track ships", 490)), TrackCarts = file.Bind("06 - Portals and vehicles", "TrackCarts", true, Describe("Track vanilla and modded Vagon components.", "06 - Markers", "Track carts", 480)), VehicleUpdateInterval = file.Bind("06 - Portals and vehicles", "VehicleUpdateIntervalSeconds", 2f, Describe("Position-report interval for loaded vehicles.", "06 - Markers", "Vehicle update interval", 470, (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 30f), advanced: true)), VehicleMinimumMoveDistance = file.Bind("06 - Portals and vehicles", "VehicleMinimumMoveDistance", 2f, Describe("Movement required before reporting a new vehicle position.", "06 - Markers", "Vehicle move threshold", 460, (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 25f), advanced: true)), ResourceDedupeDistance = file.Bind("07 - Deduplication", "ResourceDistance", 4f, Describe("Server merge distance for equivalent resource pins.", "07 - Deduplication", "Resource merge distance", 400, (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 20f))), PickableDedupeDistance = file.Bind("07 - Deduplication", "PickableDistance", 4f, Describe("Server merge distance for equivalent pickable pins.", "04.1 - Pickables", "Merge distance", 670, (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 20f))), DungeonDedupeDistance = file.Bind("07 - Deduplication", "DungeonDistance", 12f, Describe("Server merge distance for equivalent dungeon pins.", "07 - Deduplication", "Dungeon merge distance", 390, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f))), PortalDedupeDistance = file.Bind("07 - Deduplication", "PortalDistance", 2f, Describe("Server merge distance for equivalent portal pins.", "07 - Deduplication", "Portal merge distance", 380, (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 10f))), ShimmerEnabled = file.Bind("08 - Resource shimmer", "Enabled", true, Describe("Periodically highlight nearby visible resources and enabled Pickables without material instances.", "08 - Shimmer", "Enabled", 320)), ShimmerMode = file.Bind("08 - Resource shimmer", "AnimationMode", ShimmerAnimationMode.Sweep, Describe("Sweep travels across highlighted geometry; Pulse brightens the whole object.", "08 - Shimmer", "Animation", 310)), HighlightPickables = file.Bind("08 - Resource shimmer", "HighlightPickables", false, Describe("Apply the same Pulse or Sweep highlight to nearby loaded natural Pickables. Local setting.", "08 - Shimmer", "Pickable shimmer", 300)), PulseColor = file.Bind("08 - Resource shimmer", "Color", new Color(1f, 1f, 1f, 0.2f), Describe("Color used by the whole-object pulse.", "08.1 - Pulse", "Pulse color", 300)), PulseInterval = file.Bind("08 - Resource shimmer", "IntervalSeconds", 1f, Describe("Delay between pulse effects.", "08.1 - Pulse", "Pulse interval", 290, (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 30f))), PulseDuration = file.Bind("08 - Resource shimmer", "DurationSeconds", 1f, Describe("Duration of one smooth pulse.", "08.1 - Pulse", "Pulse duration", 280, (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 5f))), PulseIntensity = file.Bind("08 - Resource shimmer", "Intensity", 2f, Describe("Tint and HDR glow strength of the pulse.", "08.1 - Pulse", "Pulse intensity", 270, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f))), SweepColor = file.Bind("08 - Resource shimmer", "SweepColor", new Color(1f, 1f, 1f, 0.2f), Describe("Color of the soft wave travelling across highlighted geometry.", "08.2 - Sweep", "Sweep color", 300)), SweepInterval = file.Bind("08 - Resource shimmer", "SweepIntervalSeconds", 1f, Describe("Delay between sweep effects.", "08.2 - Sweep", "Sweep interval", 290, (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 30f))), SweepSpeed = file.Bind("08 - Resource shimmer", "SweepSpeedMetersPerSecond", 5f, Describe("World-space speed of the travelling wave.", "08.2 - Sweep", "Sweep speed", 280, (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 30f))), SweepMaximumDuration = file.Bind("08 - Resource shimmer", "SweepMaximumDurationSeconds", 3f, Describe("Safety limit for one sweep; very large geometry still completes its exit.", "08.2 - Sweep", "Sweep maximum duration", 270, (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 30f))), SweepIntensity = file.Bind("08 - Resource shimmer", "SweepIntensity", 3f, Describe("Tint and HDR glow strength of the travelling wave.", "08.2 - Sweep", "Sweep intensity", 260, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f))), ShimmerRadius = file.Bind("08 - Resource shimmer", "Radius", 20f, Describe("Only loaded resources and enabled Pickables inside this radius may shimmer.", "08 - Shimmer", "Radius", 260, (AcceptableValueBase)(object)new AcceptableValueRange(5f, 96f))), SweepWaveWidth = file.Bind("08 - Resource shimmer", "WaveWidth", 1.5f, Describe("Relative width of the soft wave; the maximum covers almost the complete highlighted object.", "08.2 - Sweep", "Sweep width", 250, (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f))), SweepSoftness = file.Bind("08 - Resource shimmer", "SweepSoftness", 1f, Describe("Softness of the moving wave; higher values remove the flat center and spread the fade across the whole effect.", "08.2 - Sweep", "Sweep softness", 240, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f))), XrayEnabled = file.Bind("08 - Resource shimmer", "XrayEnabled", false, Describe("Enable local X-ray rendering. Its hotkey only changes temporary visibility while this setting is enabled.", "08.3 - X-ray", "X-ray through terrain", 240)), XrayToggleKey = file.Bind("08 - Resource shimmer", "XrayToggleKey", (KeyCode)285, Describe("Toggle local X-ray visibility during gameplay. Works only when XrayEnabled is on; set None to disable.", "08.3 - X-ray", "X-ray toggle key", 235)), XrayColor = file.Bind("08 - Resource shimmer", "XrayColor", new Color(1f, 1f, 0f, 0.050980393f), Describe("Color used for vein geometry visible through terrain.", "08.3 - X-ray", "X-ray color", 230)), XrayIntensity = file.Bind("08 - Resource shimmer", "XrayIntensity", 1f, Describe("HDR brightness of X-ray vein geometry.", "08.3 - X-ray", "X-ray intensity", 220, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f))), XrayRadius = file.Bind("08 - Resource shimmer", "XrayRadius", 10f, Describe("Only already discovered loaded veins inside this local radius appear in X-ray.", "08.3 - X-ray", "X-ray radius", 210, (AcceptableValueBase)(object)new AcceptableValueRange(5f, 96f))), XrayRendererBudget = file.Bind("08 - Resource shimmer", "XrayMaxRenderers", 256, Describe("Total renderer budget for the current X-ray selection.", "08.3 - X-ray", "X-ray renderer budget", 200, (AcceptableValueBase)(object)new AcceptableValueRange(16, 512), advanced: true)), XrayDrawCommandBudget = file.Bind("08 - Resource shimmer", "XrayMaxDrawCommands", 1024, Describe("Hard resource draw-command limit for modded meshes with many submeshes.", "08.3 - X-ray", "X-ray resource draw budget", 190, (AcceptableValueBase)(object)new AcceptableValueRange(64, 2048), advanced: true)), ShimmerRendererBudget = file.Bind("08 - Resource shimmer", "MaxRenderersPerPulse", 256, Describe("Hard total renderer limit for one complete shimmer batch.", "08 - Shimmer", "Renderer budget", 200, (AcceptableValueBase)(object)new AcceptableValueRange(1, 256), advanced: true)), SaveDebounceSeconds = file.Bind("09 - Performance", "PersistenceDebounceSeconds", 10f, Describe("Idle time after the last state change before saving; continuous changes are flushed periodically.", "09 - Performance", "Save debounce", 200, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 120f), advanced: true)), MaxFogDeltaPixels = file.Bind("09 - Performance", "MaxFogPixelsPerPacket", 2048, Describe("Hard fog-delta packet limit.", "09 - Performance", "Fog pixels per packet", 190, (AcceptableValueBase)(object)new AcceptableValueRange(64, 8192), advanced: true)), FogMergeCellsPerFrame = file.Bind("09 - Performance", "FogMergeCellsPerFrame", 8192, Describe("Shared-fog cells examined per frame; lower values reduce spikes.", "09 - Performance", "Fog merge cells per frame", 180, (AcceptableValueBase)(object)new AcceptableValueRange(4096, 262144), advanced: true)), MaxNetworkEventsPerTenSeconds = file.Bind("09 - Performance", "MaxPeerEventsPerTenSeconds", 500, Describe("Server event-rate guard per peer.", "09 - Performance", "Peer event limit", 170, (AcceptableValueBase)(object)new AcceptableValueRange(200, 5000), advanced: true)), MaxPinAddsPerFrame = file.Bind("09 - Performance", "MaxPinAddsPerFrame", 96, Describe("Frame budget for restoring or enabling automatic pins.", "09 - Performance", "Pin adds per frame", 160, (AcceptableValueBase)(object)new AcceptableValueRange(8, 512), advanced: true)), ShowPinOverlapDiagnostics = file.Bind("10 - Diagnostics", "ShowPinOverlapCounters", false, Describe("Show local P/S counters for overlapping canonical pins and sources.", "10 - Diagnostics", "Overlap counters", 100)), PinOverlapDiagnosticDistance = file.Bind("10 - Diagnostics", "PinOverlapDistance", 1.5f, Describe("World-space grouping distance for overlap counters.", "10 - Diagnostics", "Overlap distance", 90, (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), advanced: true)), ShowStateDiagnostics = file.Bind("10 - Diagnostics", "ShowStateOnMap", false, Describe("Show local resource measurements and dungeon clearing blockers beside RavenMap pins. Local setting.", "10 - Diagnostics", "State diagnostics on map", 80)), DetailedLogging = file.Bind("10 - Diagnostics", "DetailedLogging", false, Describe("Log classification, deduplication and network details.", "10 - Diagnostics", "Detailed logging", 70, null, advanced: true)) }; if (val.Value < 1) { if (modConfig.ShimmerMode.Value == ShimmerAnimationMode.Sweep) { modConfig.SweepColor.Value = modConfig.PulseColor.Value; modConfig.SweepInterval.Value = modConfig.PulseInterval.Value; modConfig.SweepIntensity.Value = modConfig.PulseIntensity.Value; modConfig.PulseColor.Value = new Color(1f, 1f, 1f, 0.2f); modConfig.PulseInterval.Value = 1f; modConfig.PulseDuration.Value = 1f; modConfig.PulseIntensity.Value = 2f; } val.Value = 1; } if (string.Equals(modConfig.ResourcePrefabAllowList.Value, "MineRock_Copper;MineRock_Tin;mine_rock_iron;silvervein;MineRock_Obsidian;MineRock_Meteorite;Leviathan;giant_brain;softtissue_mineable;blackmarble_1;blackmarble_2;blackmarble_3;blackmarble_4;blackmarble_head_big01;blackmarble_head_big02;blackmarble_head01;blackmarble_head02;blackmarble_out_1;blackmarble_out_2;blackmarble_out_3;blackmarble_out_4;blackmarble_tip;MineRock_Lava;MineRock_Lava_big;coal_rock1_bal;coal_rock_nomoss_bal;MineRock_Coal_bal;MineRock_CoalSnow_bal;gold_Rock_bal;MineRock_Blackmetal_bal;MineRock_Borax_bal;MineRock_Cobalt_bal;MineRock_DarkIron_bal;MineRock_Lead_bal;MineRock_Zinc_bal;MineRock_Nickel_bal;rock_nickel_bal;rock_nickel_nomoss_bal;MineRock_Copper_bal;MineRock_IronNew_bal;MineRock_IronSnow_bal;MineRock_Guck_bal;rock_silver_small_bal;rock_silver_small_frac_bal;ClayDeposit_bal;ChitinDeposit_bal;bloodshard_deposit_bal;MineRock_MeteoriteNew_bal;Pickable_Clay_bal;Pickable_GuckSack_bal;Pickable_MeteoriteNew_bal;Pickable_MagmaStone_bal;Pickable_TinNew_bal;Pickable_MountainCaveCrystal_bal;deposit_jotunfinger_bal", StringComparison.Ordinal)) { modConfig.ResourcePrefabAllowList.Value = "MineRock_Copper;rock4_copper;MineRock_Tin;mine_rock_iron;silvervein;MineRock_Obsidian;MineRock_Meteorite;Leviathan;giant_brain;softtissue_mineable;blackmarble_1;blackmarble_2;blackmarble_3;blackmarble_4;blackmarble_head_big01;blackmarble_head_big02;blackmarble_head01;blackmarble_head02;blackmarble_out_1;blackmarble_out_2;blackmarble_out_3;blackmarble_out_4;blackmarble_tip;MineRock_Lava;MineRock_Lava_big;coal_rock1_bal;coal_rock_nomoss_bal;MineRock_Coal_bal;MineRock_CoalSnow_bal;gold_Rock_bal;MineRock_Blackmetal_bal;MineRock_Borax_bal;MineRock_Cobalt_bal;MineRock_DarkIron_bal;MineRock_Lead_bal;MineRock_Zinc_bal;MineRock_Nickel_bal;rock_nickel_bal;rock_nickel_nomoss_bal;MineRock_Copper_bal;MineRock_IronNew_bal;MineRock_IronSnow_bal;MineRock_Guck_bal;rock_silver_small_bal;ClayDeposit_bal;ChitinDeposit_bal;MineRock_MeteoriteNew_bal;deposit_jotunfinger_bal"; } if (modConfig.PulseIntensity.Value < 1f) { modConfig.PulseIntensity.Value = 1f; } if (modConfig.SweepIntensity.Value < 1f) { modConfig.SweepIntensity.Value = 1f; } if (modConfig.XrayIntensity.Value < 1f) { modConfig.XrayIntensity.Value = 1f; } if (modConfig.ShimmerRendererBudget.Value == 48) { modConfig.ShimmerRendererBudget.Value = 256; } if (Mathf.Approximately(modConfig.FilterScrollSensitivity.Value, 28f) || Mathf.Approximately(modConfig.FilterScrollSensitivity.Value, 120f)) { modConfig.FilterScrollSensitivity.Value = 360f; } if (modConfig.MaxNetworkEventsPerTenSeconds.Value < 200) { modConfig.MaxNetworkEventsPerTenSeconds.Value = 200; } if (modConfig.FogMergeCellsPerFrame.Value == 32768) { modConfig.FogMergeCellsPerFrame.Value = 8192; } modConfig.ApplyLocalization(language); return modConfig; } private static bool HasPersistedLegacyVisualSettings(ConfigFile file) { string text = ((file != null) ? file.ConfigFilePath : null); if (string.IsNullOrEmpty(text) || !File.Exists(text)) { return false; } try { bool flag = false; foreach (string item in File.ReadLines(text)) { string text2 = item.Trim(); if (text2.Length == 0 || text2[0] == '#') { continue; } if (text2[0] == '[' && text2[text2.Length - 1] == ']') { flag = string.Equals(text2.Substring(1, text2.Length - 2).Trim(), "08 - Resource shimmer", StringComparison.OrdinalIgnoreCase); } else { if (!flag) { continue; } int num = text2.IndexOf('='); if (num > 0) { string a = text2.Substring(0, num).Trim(); if (string.Equals(a, "AnimationMode", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "Color", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "IntervalSeconds", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "DurationSeconds", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "Intensity", StringComparison.OrdinalIgnoreCase)) { return true; } } } } } catch (IOException) { return true; } catch (UnauthorizedAccessException) { return true; } return false; } internal bool ApplyLocalization(string language) { bool flag = false; FieldInfo[] configEntryFields = ConfigEntryFields; for (int i = 0; i < configEntryFields.Length; i++) { object? value = configEntryFields[i].GetValue(this); ConfigEntryBase val = (ConfigEntryBase)((value is ConfigEntryBase) ? value : null); if (val == null || val.Description == null) { continue; } ConfigurationManagerAttributes configurationManagerAttributes = val.Description.Tags?.OfType().FirstOrDefault(); if (configurationManagerAttributes == null) { continue; } flag |= configurationManagerAttributes.ApplyLanguage(language); if (_canRewriteConfigDescription) { try { ConfigDescriptionTextField.SetValue(val.Description, configurationManagerAttributes.Description); } catch { _canRewriteConfigDescription = false; } } } return flag; } internal Color GetShimmerColor(ShimmerAnimationMode mode) { //IL_0016: 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) if (mode != ShimmerAnimationMode.Pulse) { return SweepColor.Value; } return PulseColor.Value; } internal Color GetXrayColor() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return XrayColor.Value; } } internal static class StableZdoIdentity { private const string TokenKey = "dragonmotion.ravenmap.source.v1"; private const string SourcePrefix = "stable:"; private const int TokenLength = 32; private static readonly Dictionary TokenOwners = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary SourcesByZdo = new Dictionary(); internal static void Reset() { TokenOwners.Clear(); SourcesByZdo.Clear(); } internal static bool IsStableSource(string sourceId) { string token; return TryGetToken(sourceId, out token); } internal static bool TryGetToken(string sourceId, out string token) { token = string.Empty; if (string.IsNullOrEmpty(sourceId) || !sourceId.StartsWith("stable:", StringComparison.Ordinal) || sourceId.Length != "stable:".Length + 32) { return false; } string text = sourceId.Substring("stable:".Length); if (!IsValidToken(text)) { return false; } token = text; return true; } internal static string PinId(PinCategory category, string sourceId) { byte b = (byte)category; return b + ":" + sourceId; } internal static bool TryGetExistingSource(ZDO zdo, out string sourceId) { //IL_0012: 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_00aa: 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_004c: Unknown result type (might be due to invalid IL or missing references) sourceId = string.Empty; if (zdo == null) { return false; } if (SourcesByZdo.TryGetValue(zdo.m_uid, out var value) && IsStableSource(value)) { TryGetToken(value, out var token); if (string.Equals(zdo.GetString("dragonmotion.ravenmap.source.v1", string.Empty), token, StringComparison.Ordinal) && TryBind(token, zdo.m_uid, rejectCollision: false, out var _)) { sourceId = value; return true; } Forget(zdo.m_uid); } string token3 = zdo.GetString("dragonmotion.ravenmap.source.v1", string.Empty); if (!IsValidToken(token3) || !TryBind(token3, zdo.m_uid, rejectCollision: false, out token3)) { return false; } sourceId = "stable:" + token3; SourcesByZdo[zdo.m_uid] = sourceId; return true; } internal static bool TryAssignSource(ZDO zdo, string sourceId) { //IL_0054: 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) if (zdo == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !TryGetToken(sourceId, out var token)) { return false; } if (TryGetExistingSource(zdo, out var sourceId2)) { return string.Equals(sourceId2, sourceId, StringComparison.Ordinal); } if (!string.IsNullOrEmpty(zdo.GetString("dragonmotion.ravenmap.source.v1", string.Empty)) || !TryBind(token, zdo.m_uid, rejectCollision: true, out var _)) { return false; } zdo.Set("dragonmotion.ravenmap.source.v1", token); SourcesByZdo[zdo.m_uid] = sourceId; return true; } internal static bool TryGetOrCreateSource(ZDO zdo, out string sourceId) { //IL_0045: 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) if (TryGetExistingSource(zdo, out sourceId)) { return true; } sourceId = string.Empty; if (zdo == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return false; } string token; do { token = Guid.NewGuid().ToString("N"); } while (!TryBind(token, zdo.m_uid, rejectCollision: true, out token)); zdo.Set("dragonmotion.ravenmap.source.v1", token); sourceId = "stable:" + token; SourcesByZdo[zdo.m_uid] = sourceId; return true; } internal static bool TryResolveSource(string sourceId, out ZDO zdo) { //IL_002a: 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) zdo = null; if (!TryGetToken(sourceId, out var token) || !TokenOwners.TryGetValue(token, out var value)) { return false; } ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(value) : null); if (val == null || !string.Equals(val.GetString("dragonmotion.ravenmap.source.v1", string.Empty), token, StringComparison.Ordinal)) { SourcesByZdo.Remove(value); TokenOwners.Remove(token); return false; } zdo = val; return true; } internal static void Forget(ZDOID id) { //IL_0005: 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_0035: 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) if (SourcesByZdo.TryGetValue(id, out var value)) { SourcesByZdo.Remove(id); if (TryGetToken(value, out var token) && TokenOwners.TryGetValue(token, out var value2) && value2 == id) { TokenOwners.Remove(token); } } } private static bool TryBind(string requested, ZDOID id, bool rejectCollision, out string token) { //IL_0049: 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_001f: 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) token = requested; if (!IsValidToken(token)) { return false; } if (TokenOwners.TryGetValue(token, out var value) && value != id) { ZDOMan instance = ZDOMan.instance; if (((instance != null) ? instance.GetZDO(value) : null) != null || rejectCollision) { return false; } } TokenOwners[token] = id; return true; } private static bool IsValidToken(string token) { if (string.IsNullOrEmpty(token) || token.Length != 32) { return false; } foreach (char c in token) { if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) { return false; } } return true; } } internal enum PinCategory : byte { Resource = 1, Dungeon, Portal, Ship, Cart, Pickable } internal enum PinStatus : byte { Active, Depleted, Cleared, Destroyed } internal enum SilverDiscoveryMode { WishboneOnly, Radius, Disabled } internal enum DungeonRespawnMode { Auto, Enabled, Disabled } internal enum ShimmerAnimationMode { Sweep, Pulse } internal enum DungeonEventType : byte { RegisterEnemy = 1, EnemyKilled, RegisterChest, ChestInspected, RespawnCapable, RoomCount, GenerationReset, EnemyResolved, ChestResolved, DungeonEntered, CensusSettled, ManualSetCleared } internal sealed class PinRecord { internal string Id = string.Empty; internal string SourceId = string.Empty; internal PinCategory Category; internal PinStatus Status; internal string Prefab = string.Empty; internal string DisplayName = string.Empty; internal string ResourceType = string.Empty; internal bool Respawns; internal int SourceCount = 1; internal Biome Biome; internal Vector3 Position; internal float InitialAmount; internal float RemainingAmount; internal long Revision; internal long UpdatedUtcTicks; internal bool IsVisibleState { get { if (Status != PinStatus.Destroyed) { return Status != PinStatus.Depleted; } return false; } } internal PinRecord Clone() { return (PinRecord)MemberwiseClone(); } } internal sealed class FilterCatalogEntry { internal PinCategory Category { get; } internal Biome Biome { get; } internal string Prefab { get; } internal string DisplayName { get; } internal string ResourceType { get; } internal FilterCatalogEntry(PinCategory category, Biome biome, string prefab, string displayName, string resourceType) { //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) Category = category; Biome = biome; Prefab = prefab ?? string.Empty; DisplayName = displayName ?? string.Empty; ResourceType = resourceType ?? string.Empty; } } internal sealed class DungeonProgress { internal readonly HashSet Enemies = new HashSet(StringComparer.Ordinal); internal readonly HashSet KilledEnemies = new HashSet(StringComparer.Ordinal); internal readonly HashSet ResolvedEnemies = new HashSet(StringComparer.Ordinal); internal readonly HashSet Chests = new HashSet(StringComparer.Ordinal); internal readonly HashSet InspectedChests = new HashSet(StringComparer.Ordinal); internal readonly HashSet ResolvedChests = new HashSet(StringComparer.Ordinal); internal readonly HashSet RespawnSources = new HashSet(StringComparer.Ordinal); internal string GenerationToken = string.Empty; internal bool RespawnCapable; internal bool Entered; internal bool CensusSettled; internal bool Overflowed; internal int ManualOverride; internal int RoomCount; internal long Revision; internal int AliveEnemyCount { get { int num = 0; foreach (string enemy in Enemies) { if (!KilledEnemies.Contains(enemy) && !ResolvedEnemies.Contains(enemy)) { num++; } } return num; } } internal int DefeatedEnemyCount { get { int num = 0; foreach (string enemy in Enemies) { if (KilledEnemies.Contains(enemy) || ResolvedEnemies.Contains(enemy)) { num++; } } return num; } } internal int InspectedOrResolvedChestCount { get { int num = 0; foreach (string chest in Chests) { if (InspectedChests.Contains(chest) || ResolvedChests.Contains(chest)) { num++; } } return num; } } internal float DefeatedFraction { get { if (Enemies.Count != 0) { return (float)DefeatedEnemyCount / (float)Enemies.Count; } return 1f; } } internal float InspectedOrResolvedFraction { get { if (Chests.Count != 0) { return (float)InspectedOrResolvedChestCount / (float)Chests.Count; } return 1f; } } } internal static class RavenIds { internal unsafe static string ForZdo(PinCategory category, ZDOID id) { //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) byte b = (byte)category; string text = b.ToString(); ZDOID val = id; return text + ":zdo:" + ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString(); } internal static string ForPosition(PinCategory category, string prefab, Vector3 position, float cellSize = 1f) { //IL_000c: 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) float num = Mathf.Max(0.25f, cellSize); int num2 = Mathf.RoundToInt(position.x / num); int num3 = Mathf.RoundToInt(position.z / num); string[] array = new string[7]; byte b = (byte)category; array[0] = b.ToString(); array[1] = ":pos:"; array[2] = Normalize(prefab); array[3] = ":"; array[4] = num2.ToString(); array[5] = ":"; array[6] = num3.ToString(); return string.Concat(array); } internal static string Normalize(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } return value.Replace("(Clone)", string.Empty).Replace(" ", string.Empty).Replace("_", string.Empty) .Trim() .ToLowerInvariant(); } } internal sealed class DiscoveryService { private sealed class Candidate { internal string SourceId; internal GameObject Root; internal int RootInstanceId; internal ZNetView View; internal PrefabDescriptor Descriptor; internal PinCategory Category; internal Vector3 Position; internal long Cell; internal bool InSpatialIndex; internal bool Eligible = true; internal ResourceMath.ResourceProbe ResourceProbe; internal bool HasResourceMeasurement; internal ResourceMath.Measurement ResourceMeasurement; internal float LastSentInitial = -1f; internal float LastSentRemaining = -1f; internal float LastResourceReportTime = -999f; internal Vector3 LastSentPosition = new Vector3(float.PositiveInfinity, 0f, 0f); internal string LastSentName = string.Empty; internal long FirstObservationSequence; internal float FirstObservedAt; } internal sealed class ResourceDiagnosticSnapshot { internal string RequestedSourceId; internal string LocalSourceId; internal string StableSourceId; internal string Prefab; internal string ResourceType; internal ResourceMath.ProbeKind ProbeKind; internal bool Loaded; internal bool Eligible; internal bool Discovered; internal bool IsShell; internal bool ShellHandoffPending; internal bool RootActive; internal bool ViewActive; internal bool ZdoValid; internal bool Measured; internal float Initial; internal float Remaining; internal float DepletedPercent; internal int TotalParts; internal int RemainingParts; internal float LastSentInitial; internal float LastSentRemaining; } private sealed class PendingShellHandoff { internal string SourceId; internal string ResourceType; internal string ExpectedReplacementPrefab; internal Vector3 Position; internal long StartedAfterSequence; internal float StartedAt; internal float Deadline; internal bool ReplacementObserved; internal readonly HashSet ExistingReplacementSources = new HashSet(StringComparer.Ordinal); } private const float SpatialCellSize = 32f; private const float ShellHandoffRadius = 3f; private const float ShellPreDestroyGraceSeconds = 0.5f; private const float ShellPreDestroyPositionRadius = 0.75f; private readonly RavenMapPlugin _plugin; private readonly ModConfig _config; private readonly Action _submitPin; private readonly Func _isKnownResource; private readonly Action> _publishFilterCatalog; private readonly PrefabClassifier _classifier; private readonly DungeonTracker _dungeons; private readonly ShimmerService _shimmer; private readonly Dictionary _loaded = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _viewSources = new Dictionary(); private readonly Dictionary _rootSources = new Dictionary(); private readonly Dictionary> _resourceSpatial = new Dictionary>(); private readonly Dictionary> _pickableSpatial = new Dictionary>(); private readonly Dictionary> _dungeonSpatial = new Dictionary>(); private readonly Dictionary _vehicles = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _portals = new Dictionary(StringComparer.Ordinal); private readonly HashSet _discovered = new HashSet(StringComparer.Ordinal); private readonly HashSet _repairedPersistentSources = new HashSet(StringComparer.Ordinal); private readonly Dictionary _pendingShellHandoffs = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _prefabResourceProbes = new Dictionary(); private readonly HashSet _resourceVisualRefreshCandidates = new HashSet(); private ZNetScene _scene; private Coroutine _reportRoutine; private Coroutine _shellHandoffRoutine; private bool _reportFailureLogged; private bool _knownResourceLookupFailureLogged; private bool _pinSubmissionFailureLogged; private bool _contentCatalogReady; private bool _destructiveContentCatalogReady; private bool _contentAvailabilityFailureLogged; private long _candidateSequence; internal bool CanPruneMissingContent => _destructiveContentCatalogReady; internal DiscoveryService(RavenMapPlugin plugin, ModConfig config, Action submitPin, Action submitDungeonEvent, Func isKnownResource, Action dungeonDiagnosticChanged, ShimmerService shimmer, Action> publishFilterCatalog) { _plugin = plugin ?? throw new ArgumentNullException("plugin"); _config = config ?? throw new ArgumentNullException("config"); _submitPin = submitPin ?? throw new ArgumentNullException("submitPin"); _isKnownResource = isKnownResource ?? throw new ArgumentNullException("isKnownResource"); _publishFilterCatalog = publishFilterCatalog; _classifier = new PrefabClassifier(config); _dungeons = new DungeonTracker(_plugin, config, _classifier, submitDungeonEvent ?? throw new ArgumentNullException("submitDungeonEvent"), dungeonDiagnosticChanged ?? throw new ArgumentNullException("dungeonDiagnosticChanged")); _shimmer = shimmer ?? throw new ArgumentNullException("shimmer"); } internal void OnSceneAwake(ZNetScene scene) { _contentCatalogReady = false; _destructiveContentCatalogReady = false; _scene = scene; _prefabResourceProbes.Clear(); _classifier.Rebuild(scene); _publishFilterCatalog?.Invoke(_classifier.FilterCatalog); _shimmer.RefreshConfiguration(); RestartReporter(); } internal void RebuildCatalog() { _classifier.RefreshWorldCatalog(_scene ?? ZNetScene.instance); _contentCatalogReady = true; _destructiveContentCatalogReady = _classifier.HasCompleteContentPresenceCatalog(); _publishFilterCatalog?.Invoke(_classifier.FilterCatalog); } internal ContentAvailability GetContentAvailability(PinRecord pin) { if (!_contentCatalogReady) { return ContentAvailability.Unknown; } try { return _classifier.GetContentAvailability(pin); } catch (Exception ex) { if (!_contentAvailabilityFailureLogged) { _contentAvailabilityFailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("RavenMap could not evaluate one local content registration; the record will remain dormant until the catalog is rebuilt. " + ex.GetType().Name + ": " + ex.Message)); } } return ContentAvailability.Unknown; } } internal bool ValidatePersistedContentPresence(PinRecord pin) { if (!_destructiveContentCatalogReady || GetContentAvailability(pin) != ContentAvailability.Missing) { return true; } return !IsStrongMissingContentSource(pin); } internal static bool IsStrongMissingContentSource(PinRecord pin) { if (pin == null) { return false; } if ((pin.Category == PinCategory.Resource || pin.Category == PinCategory.Pickable) && StableZdoIdentity.IsStableSource(pin.SourceId)) { return true; } if (pin.Category != PinCategory.Dungeon || !PinRecordLookup.TryParseDungeonSource(pin.SourceId, out var semantic, out var _)) { return false; } return string.Equals(semantic, RavenIds.Normalize(pin.Prefab), StringComparison.Ordinal); } internal PinRecord TryRepairPersistedSource(PinRecord persisted) { //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) if (persisted == null || persisted.Category == PinCategory.Dungeon || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null) { return null; } bool num = ServerWorldState.IsLegacyZdoSource(persisted.SourceId); bool flag = StableZdoIdentity.IsStableSource(persisted.SourceId); if (!num && !flag) { return null; } if (flag && _repairedPersistentSources.Contains(persisted.SourceId)) { return null; } string b = RavenIds.Normalize(persisted.ResourceType); if (flag && StableZdoIdentity.TryResolveSource(persisted.SourceId, out var zdo)) { PinRecord pinRecord = persisted.Clone(); if (!NormalizeSubmittedPin(zdo, pinRecord) || pinRecord.Category != persisted.Category || ((persisted.Category == PinCategory.Resource || persisted.Category == PinCategory.Pickable) && !string.Equals(RavenIds.Normalize(pinRecord.ResourceType), b, StringComparison.Ordinal))) { return null; } return FinalizeRepairedPin(persisted, pinRecord, persisted.SourceId); } float num2 = ((persisted.Category == PinCategory.Resource || persisted.Category == PinCategory.Pickable) ? 0.35f : ((persisted.Category == PinCategory.Portal) ? 0.75f : (flag ? 0.75f : 8f))); int num3 = ((persisted.Category == PinCategory.Ship || persisted.Category == PinCategory.Cart) ? 1 : 0); List list = new List(); ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(persisted.Position), num3, num3, list, (List)null); ZDO val = null; PinRecord pinRecord2 = null; float num4 = float.MaxValue; int num5 = 0; string b2 = RavenIds.Normalize(persisted.Prefab); float num6 = num2 * num2; for (int i = 0; i < list.Count; i++) { ZDO val2 = list[i]; GameObject val3 = ((val2 != null) ? ZNetScene.instance.GetPrefab(val2.GetPrefab()) : null); if ((Object)(object)val3 == (Object)null || !string.Equals(RavenIds.Normalize(Utils.GetPrefabName(val3)), b2, StringComparison.Ordinal)) { continue; } Vector3 val4 = val2.GetPosition() - persisted.Position; if (persisted.Category == PinCategory.Ship || persisted.Category == PinCategory.Cart) { val4.y = 0f; } float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude; if (sqrMagnitude > num6) { continue; } PinRecord pinRecord3 = persisted.Clone(); if (NormalizeSubmittedPin(val2, pinRecord3) && pinRecord3.Category == persisted.Category && ((persisted.Category != PinCategory.Resource && persisted.Category != PinCategory.Pickable) || string.Equals(RavenIds.Normalize(pinRecord3.ResourceType), b, StringComparison.Ordinal))) { num5++; if (sqrMagnitude + 0.0001f < num4) { val = val2; pinRecord2 = pinRecord3; num4 = sqrMagnitude; } } } if (val == null || pinRecord2 == null || num5 != 1) { return null; } if (!StableZdoIdentity.TryGetExistingSource(val, out var sourceId)) { if (flag) { if (!StableZdoIdentity.TryAssignSource(val, persisted.SourceId)) { return null; } sourceId = persisted.SourceId; } else if (!StableZdoIdentity.TryGetOrCreateSource(val, out sourceId)) { return null; } } return FinalizeRepairedPin(persisted, pinRecord2, sourceId); } internal bool ValidatePersistedPinMetadata(PinRecord pin) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (pin == null) { return false; } if (pin.Category != PinCategory.Pickable) { return true; } if (IsInteriorPickable(pin.Category, pin.Position)) { return false; } ZNetScene instance = ZNetScene.instance; string text = CleanPrefabName(pin.Prefab); if (ResourceCatalog.IsRejectedPersistedPickable(pin.Category, text)) { return false; } if ((Object)(object)instance == (Object)null || text.Length == 0) { return true; } GameObject prefab = instance.GetPrefab(text); if ((Object)(object)prefab == (Object)null || !string.Equals(RavenIds.Normalize(Utils.GetPrefabName(prefab)), RavenIds.Normalize(text), StringComparison.Ordinal)) { return true; } PrefabDescriptor prefabDescriptor = _classifier.Describe(prefab, StringExtensionMethods.GetStableHashCode(text)); if (prefabDescriptor.Kind != DiscoveryKind.Pickable || !string.Equals(RavenIds.Normalize(prefabDescriptor.ResourceType), RavenIds.Normalize(pin.ResourceType), StringComparison.Ordinal)) { return false; } pin.Prefab = prefabDescriptor.PrefabName; pin.DisplayName = prefabDescriptor.DisplayName; pin.ResourceType = prefabDescriptor.ResourceType; pin.Respawns = prefabDescriptor.IsRespawningPickable; if (!pin.Respawns) { return pin.Status == PinStatus.Active; } return true; } private PinRecord FinalizeRepairedPin(PinRecord persisted, PinRecord normalized, string stableSource) { MergeRepairedResourceProgress(persisted, normalized); normalized.SourceId = stableSource; normalized.Id = StableZdoIdentity.PinId(normalized.Category, stableSource); normalized.SourceCount = 1; _repairedPersistentSources.Add(stableSource); return normalized; } internal static void MergeRepairedResourceProgress(PinRecord persisted, PinRecord normalized) { if (persisted != null && normalized != null && persisted.Category == PinCategory.Resource && !(persisted.InitialAmount <= 0f)) { bool flag = normalized.InitialAmount > 0f; float num = Mathf.Max(0f, normalized.RemainingAmount); normalized.InitialAmount = persisted.InitialAmount; normalized.RemainingAmount = (flag ? Mathf.Min(persisted.RemainingAmount, num) : persisted.RemainingAmount); normalized.Status = persisted.Status; normalized.Respawns = persisted.Respawns; } } internal bool NormalizeSubmittedPin(ZDO zdo, PinRecord pin) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || pin == null || (Object)(object)ZNetScene.instance == (Object)null) { return false; } int prefab = zdo.GetPrefab(); GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab); if ((Object)(object)prefab2 == (Object)null) { return false; } PrefabDescriptor prefabDescriptor = _classifier.Describe(prefab2, prefab); PinCategory pinCategory = ToCategory(prefabDescriptor.Kind); if (pinCategory == (PinCategory)0 || pinCategory == PinCategory.Dungeon || pinCategory != pin.Category) { return false; } Vector3 position = zdo.GetPosition(); ZNetView val = ((pinCategory == PinCategory.Pickable) ? ZNetScene.instance.FindInstance(zdo) : null); if ((pinCategory == PinCategory.Portal && !_config.AutoPinPortals.Value) || (pinCategory == PinCategory.Ship && !_config.TrackShips.Value) || (pinCategory == PinCategory.Cart && !_config.TrackCarts.Value) || (pinCategory == PinCategory.Pickable && !RavenNetwork.TrackPickables) || IsInteriorPickable(pinCategory, position, (val != null) ? ((Component)val).gameObject : null) || ((pinCategory == PinCategory.Resource || pinCategory == PinCategory.Pickable) && _classifier.IsPlayerCreatedResource(prefab2, zdo))) { return false; } float initial = 0f; float remaining = 0f; if (pinCategory == PinCategory.Resource) { if (prefabDescriptor.IsResourceShell) { initial = 0f; remaining = 0f; } else { string key = SourceFor(zdo.m_uid); if (_loaded.TryGetValue(key, out var value) && value.Category == PinCategory.Resource && TryMeasureCandidate(value, preferLiveMineRock5: false, out var measurement)) { initial = measurement.Initial; remaining = measurement.Remaining; } else { if (!_prefabResourceProbes.TryGetValue(prefab, out var value2) || (Object)(object)value2?.Root != (Object)(object)prefab2) { value2 = ResourceMath.CreateProbe(prefab2); _prefabResourceProbes[prefab] = value2; } if (!ResourceMath.TryMeasurePrefab(value2, zdo, out initial, out remaining) && !_classifier.IsExplicitResource(prefabDescriptor.PrefabName)) { return false; } } } } string displayName = prefabDescriptor.DisplayName; switch (pinCategory) { case PinCategory.Portal: { string text2 = zdo.GetString("tag", string.Empty); if (!string.IsNullOrWhiteSpace(text2)) { displayName = text2; } break; } case PinCategory.Ship: { string text = zdo.GetString("ShipName", string.Empty); if (!string.IsNullOrWhiteSpace(text)) { displayName = text; } break; } } pin.Id = RavenIds.ForZdo(pinCategory, zdo.m_uid); pin.SourceId = SourceFor(zdo.m_uid); PinStatus status = PinStatus.Active; bool flag = false; if (pinCategory == PinCategory.Pickable) { Pickable val2 = prefab2.GetComponent() ?? prefab2.GetComponentInChildren(true); if ((Object)(object)val2 == (Object)null) { return false; } flag = prefabDescriptor.IsRespawningPickable; Pickable val3 = (((Object)(object)val != (Object)null) ? (((Component)val).GetComponent() ?? ((Component)val).GetComponentInChildren(true)) : null); status = ((((Object)(object)val3 != (Object)null) ? val3.GetPicked() : zdo.GetBool(ZDOVars.s_picked, val2.m_defaultPicked)) ? (flag ? PinStatus.Cleared : PinStatus.Destroyed) : PinStatus.Active); } pin.Status = status; pin.Prefab = prefabDescriptor.PrefabName; pin.DisplayName = displayName; pin.ResourceType = prefabDescriptor.ResourceType; pin.Respawns = pinCategory == PinCategory.Pickable && flag; pin.SourceCount = 1; pin.Position = position; pin.Biome = ResolveBiome(pin.Position); pin.InitialAmount = initial; pin.RemainingAmount = remaining; pin.Revision = 0L; pin.UpdatedUtcTicks = DateTime.UtcNow.Ticks; if (pinCategory == PinCategory.Resource && !prefabDescriptor.IsResourceShell && initial > 0f) { ObserveShellReplacement(pin.ResourceType, prefabDescriptor.PrefabName, pin.SourceId, pin.Position); } return true; } internal bool ValidateRemoteResourceDiscovery(ZDO zdo, PinRecord pin, Vector3 peerPosition) { //IL_00ea: 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) if (zdo == null || pin == null || pin.Category != PinCategory.Resource || (Object)(object)ZNetScene.instance == (Object)null) { return false; } GameObject prefab = ZNetScene.instance.GetPrefab(zdo.GetPrefab()); if ((Object)(object)prefab == (Object)null) { return false; } PrefabDescriptor prefabDescriptor = _classifier.Describe(prefab, zdo.GetPrefab()); if (prefabDescriptor.Kind != DiscoveryKind.Resource) { return false; } bool flag; if (prefabDescriptor.IsSilver) { if (RavenNetwork.SilverMode == SilverDiscoveryMode.Disabled) { return false; } flag = RavenNetwork.SilverMode == SilverDiscoveryMode.WishboneOnly; } else { flag = prefabDescriptor.RequiresFinder && !RavenNetwork.AutoPinUndergroundResources; } if (!flag) { return true; } float num = 8f; Beacon val = prefab.GetComponent() ?? prefab.GetComponentInChildren(true); if ((Object)(object)val != (Object)null && !float.IsNaN(val.m_range) && !float.IsInfinity(val.m_range)) { num = Mathf.Clamp(val.m_range + 4f, 8f, 128f); } return DistanceXZSquared(peerPosition, zdo.GetPosition()) <= num * num; } internal bool ReconcileLoadedPin(ZDO zdo, PinRecord pin) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || pin == null || (Object)(object)ZNetScene.instance == (Object)null) { return true; } GameObject prefab = ZNetScene.instance.GetPrefab(zdo.GetPrefab()); if ((Object)(object)prefab == (Object)null) { return true; } PinCategory pinCategory = ToCategory(_classifier.Describe(prefab, zdo.GetPrefab()).Kind); if (pinCategory != 0 && pinCategory == pin.Category) { Vector3 position = zdo.GetPosition(); ZNetView obj = ZNetScene.instance.FindInstance(zdo); if (!IsInteriorPickable(pinCategory, position, (obj != null) ? ((Component)obj).gameObject : null)) { NormalizeSubmittedPin(zdo, pin); return true; } } return false; } internal bool NormalizeDungeonPin(LocationInstance instance, PinRecord pin) { //IL_0000: 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_0084: 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_008f: 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_009a: 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_00a8: 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_00b3: 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) string locationPrefabName = GetLocationPrefabName(instance.m_location); if (pin == null || locationPrefabName.Length == 0 || !_classifier.TryGetDungeonDescriptor(locationPrefabName, out var descriptor)) { return false; } if (descriptor.Kind != DiscoveryKind.Dungeon || pin.Category != PinCategory.Dungeon) { return false; } pin.Id = pin.SourceId; pin.Status = PinStatus.Active; pin.Prefab = descriptor.PrefabName; pin.DisplayName = descriptor.DisplayName; pin.ResourceType = descriptor.ResourceType; pin.Respawns = false; pin.SourceCount = 1; pin.Position = instance.m_position; pin.Biome = ResolveBiome(instance.m_position); if ((int)pin.Biome == 0) { pin.Biome = FirstBiome(instance.m_location.m_biome); } pin.InitialAmount = 0f; pin.RemainingAmount = 0f; pin.Revision = 0L; pin.UpdatedUtcTicks = DateTime.UtcNow.Ticks; return true; } internal void ResubmitLoaded() { foreach (Candidate value in _loaded.Values) { if (value.Eligible && ((_discovered.Contains(value.SourceId) && (value.Category == PinCategory.Resource || value.Category == PinCategory.Pickable || value.Category == PinCategory.Dungeon)) || IsAutoCategoryEnabled(value.Category))) { SubmitCandidate(value); if (value.Category == PinCategory.Dungeon) { _dungeons.OnDungeonDiscovered(value.SourceId); } } } } internal void ResetForRediscovery() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) _dungeons.ResetForRediscovery(); _discovered.Clear(); _repairedPersistentSources.Clear(); if (_shellHandoffRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_shellHandoffRoutine); _shellHandoffRoutine = null; } _pendingShellHandoffs.Clear(); foreach (Candidate value in _loaded.Values) { value.LastSentInitial = -1f; value.LastSentRemaining = -1f; value.LastResourceReportTime = -999f; value.LastSentPosition = new Vector3(float.PositiveInfinity, 0f, 0f); value.LastSentName = string.Empty; if (value.Category == PinCategory.Resource) { _shimmer.Unregister(value.SourceId); } } foreach (Candidate value2 in _loaded.Values) { if (!value2.Eligible || (Object)(object)value2.Root == (Object)null) { continue; } if (IsAutoCategoryEnabled(value2.Category)) { Discover(value2, force: true); } else if (value2.Category == PinCategory.Resource || value2.Category == PinCategory.Pickable || value2.Category == PinCategory.Dungeon) { float radius = DiscoveryRadius(value2.Category); if (IsNearAnyPlayer(value2.Position, radius) && (value2.Category != PinCategory.Resource || CanDiscoverResourceByRadius(value2.Descriptor))) { Discover(value2); } } } } internal void RefreshKnownResourceVisuals() { if (!_config.AnyResourceVisualEnabled) { return; } foreach (Candidate value in _loaded.Values) { if (value.Eligible && value.Category == PinCategory.Resource && (Object)(object)value.Root != (Object)null) { RefreshResourceVisual(value); } } } internal void RefreshKnownResourceVisual(PinRecord previous, PinRecord current) { if (!_config.AnyResourceVisualEnabled) { return; } _resourceVisualRefreshCandidates.Clear(); try { AddResourceVisualCandidates(previous, _resourceVisualRefreshCandidates); AddResourceVisualCandidates(current, _resourceVisualRefreshCandidates); foreach (Candidate resourceVisualRefreshCandidate in _resourceVisualRefreshCandidates) { RefreshResourceVisual(resourceVisualRefreshCandidate); } } finally { _resourceVisualRefreshCandidates.Clear(); } } private void AddResourceVisualCandidates(PinRecord record, HashSet destination) { //IL_0043: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) if (record == null || record.Category != PinCategory.Resource || destination == null) { return; } string text = PinRecordLookup.ResourceSemantic(record.ResourceType, record.Prefab); if (text.Length == 0) { return; } if (_loaded.TryGetValue(record.SourceId, out var value) && IsMatchingLoadedResource(value, text, record.Position, requireDistance: false, 0f)) { destination.Add(value); } if (StableZdoIdentity.IsStableSource(record.SourceId) && StableZdoIdentity.TryResolveSource(record.SourceId, out var zdo) && _loaded.TryGetValue(SourceFor(zdo.m_uid), out var value2) && IsMatchingLoadedResource(value2, text, record.Position, requireDistance: false, 0f)) { destination.Add(value2); } float num = Mathf.Max(0.1f, RavenNetwork.ResourceDedupeDistance); float radiusSquared = num * num; int num2 = Mathf.FloorToInt((record.Position.x - num) / 32f); int num3 = Mathf.FloorToInt((record.Position.x + num) / 32f); int num4 = Mathf.FloorToInt((record.Position.z - num) / 32f); int num5 = Mathf.FloorToInt((record.Position.z + num) / 32f); for (int i = num2; i <= num3; i++) { for (int j = num4; j <= num5; j++) { if (!_resourceSpatial.TryGetValue(CellKey(i, j), out var value3)) { continue; } for (int k = 0; k < value3.Count; k++) { Candidate candidate = value3[k]; if (IsMatchingLoadedResource(candidate, text, record.Position, requireDistance: true, radiusSquared)) { destination.Add(candidate); } } } } } private static bool IsMatchingLoadedResource(Candidate candidate, string semantic, Vector3 position, bool requireDistance, float radiusSquared) { //IL_0054: 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) if (candidate == null || !candidate.Eligible || (Object)(object)candidate.Root == (Object)null || candidate.Category != PinCategory.Resource || candidate.Descriptor == null || !string.Equals(PinRecordLookup.ResourceSemantic(candidate.Descriptor.ResourceType, candidate.Descriptor.PrefabName), semantic, StringComparison.Ordinal)) { return false; } if (requireDistance) { return DistanceXZSquared(candidate.Position, position) <= radiusSquared; } return true; } internal void RefreshConfiguration(string section, string key) { //IL_03d7: Unknown result type (might be due to invalid IL or missing references) bool num = string.IsNullOrEmpty(section); if (num || (section == "03 - Discovery" && key == "SilverDiscovery")) { goto IL_0074; } if (section == "04 - Resources") { switch (key) { case "PrefabAllowList": case "PrefabBlockList": case "DroppedItemBlockList": goto IL_0074; } } int num2 = ((section == "05 - Dungeons" && key == "PrefabAllowList") ? 1 : 0); goto IL_0075; IL_0074: num2 = 1; goto IL_0075; IL_00fe: int num3 = 1; goto IL_00ff; IL_00ff: bool flag = (byte)num3 != 0; bool flag2 = flag || (section == "08 - Resource shimmer" && key == "AnimationMode"); bool flag3 = num || section == "06 - Portals and vehicles"; bool flag4; if (flag4) { _classifier.Rebuild(_scene ?? ZNetScene.instance); _destructiveContentCatalogReady = _contentCatalogReady && _classifier.HasCompleteContentPresenceCatalog(); _publishFilterCatalog?.Invoke(_classifier.FilterCatalog); foreach (Candidate value in _loaded.Values) { if ((Object)(object)value.Root == (Object)null) { value.Eligible = false; continue; } ZNetView view = value.View; ZDO val = ((view != null) ? view.GetZDO() : null); PrefabDescriptor prefabDescriptor = _classifier.Describe(value.Root, (val != null) ? val.GetPrefab() : 0, val); value.Eligible = prefabDescriptor.Kind != DiscoveryKind.None && ToCategory(prefabDescriptor.Kind) == value.Category; if (value.Eligible) { value.Descriptor = prefabDescriptor; } else { _shimmer.Unregister(value.SourceId); } } } bool flag5; if (flag5) { _dungeons.RefreshConfiguration(); } if (flag2) { _shimmer.RefreshConfiguration(); } bool flag6; if (flag4 || flag6) { RefreshPickableSpatialMembership(); } if (flag3) { RestartReporter(); } if (_config.AnyResourceVisualEnabled && (flag4 || flag)) { foreach (Candidate value2 in _loaded.Values) { if (value2.Eligible && value2.Category == PinCategory.Resource) { RefreshResourceVisual(value2); } else if (value2.Eligible && value2.Category == PinCategory.Pickable) { RefreshPickableVisual(value2); } } } if (!(flag4 || flag6 || flag5 || flag3)) { return; } foreach (Candidate value3 in _loaded.Values) { if (value3.Eligible && IsAutoCategoryEnabled(value3.Category)) { Discover(value3, force: true); } if (flag5 && value3.Eligible && value3.Category == PinCategory.Dungeon && _discovered.Contains(value3.SourceId)) { _dungeons.OnDungeonDiscovered(value3.SourceId); } } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { DiscoverNear(((Component)localPlayer).transform.position); } return; IL_0075: flag4 = (byte)num2 != 0; flag5 = num || section == "05 - Dungeons"; flag6 = num || section == "03 - Discovery"; if (num) { goto IL_00fe; } if (section == "08 - Resource shimmer") { switch (key) { case "Enabled": case "HighlightPickables": case "XrayEnabled": goto IL_00fe; } } num3 = ((section == "03 - Discovery" && (key == "SilverDiscovery" || key == "AutoPinUndergroundResources")) ? 1 : 0); goto IL_00ff; } internal void ObserveNetworkObject(ZDO zdo, GameObject root) { if (!((Object)(object)root == (Object)null)) { Observe(root, zdo, null); } } internal void ObserveRelevantObject(GameObject gameObject) { if (!((Object)(object)gameObject == (Object)null)) { ZNetView val = FindView(gameObject); Observe(((Object)(object)val != (Object)null) ? ((Component)val).gameObject : gameObject, (val != null) ? val.GetZDO() : null, val); } } internal void ObserveDungeonObject(GameObject gameObject) { _dungeons.ObserveNetworkObject(gameObject); } internal void ObserveLocation(Location location) { //IL_0046: 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) if ((Object)(object)location == (Object)null) { return; } ZNetView val = FindView(((Component)location).gameObject); GameObject root = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : ((Component)location).gameObject); string text = CleanPrefabName(Utils.GetPrefabName(((Component)location).gameObject)); if (TryResolveCanonicalLocation(text, ((Component)location).transform.position, out var authoritativePosition)) { PrefabDescriptor prefabDescriptor = _classifier.DescribeDungeonLocation(location, text); if (prefabDescriptor.Kind == DiscoveryKind.Dungeon) { RegisterCandidate(root, val, (val != null) ? val.GetZDO() : null, prefabDescriptor, authoritativePosition); _dungeons.ObserveNetworkObject(((Component)location).gameObject); } } } internal void DiscoverNear(Vector3 playerPosition) { //IL_0001: 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_001b: Unknown result type (might be due to invalid IL or missing references) DiscoverCategoryNear(playerPosition, PinCategory.Resource, RavenNetwork.ResourceDiscoveryRadius, _resourceSpatial); if (RavenNetwork.TrackPickables) { DiscoverCategoryNear(playerPosition, PinCategory.Pickable, RavenNetwork.PickableDiscoveryRadius, _pickableSpatial); } DiscoverCategoryNear(playerPosition, PinCategory.Dungeon, RavenNetwork.DungeonDiscoveryRadius, _dungeonSpatial); } private void DiscoverCategoryNear(Vector3 playerPosition, PinCategory category, float radius, Dictionary> spatial) { //IL_001a: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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) if (radius <= 0f || spatial == null || spatial.Count == 0) { return; } float num = radius * radius; int num2 = Mathf.FloorToInt((playerPosition.x - radius) / 32f); int num3 = Mathf.FloorToInt((playerPosition.x + radius) / 32f); int num4 = Mathf.FloorToInt((playerPosition.z - radius) / 32f); int num5 = Mathf.FloorToInt((playerPosition.z + radius) / 32f); for (int i = num2; i <= num3; i++) { for (int j = num4; j <= num5; j++) { if (!spatial.TryGetValue(CellKey(i, j), out var value)) { continue; } for (int num6 = value.Count - 1; num6 >= 0; num6--) { Candidate candidate = value[num6]; if ((Object)(object)candidate.Root == (Object)null) { RemoveLoaded(candidate.SourceId); } else if (candidate.Eligible && candidate.Category == category && !(DistanceXZSquared(playerPosition, candidate.Position) > num) && (candidate.Category != PinCategory.Resource || CanDiscoverResourceByRadius(candidate.Descriptor))) { Discover(candidate); } } } } } internal void ReportResourceProgress(GameObject gameObject) { Candidate candidate = ResolveOrObserve(gameObject); if (candidate == null || !candidate.Eligible || candidate.Category != PinCategory.Resource || (candidate.Descriptor.IsSilver && RavenNetwork.SilverMode == SilverDiscoveryMode.Disabled)) { return; } bool flag = _discovered.Add(candidate.SourceId); if (candidate.Descriptor.IsResourceShell) { if (flag) { SubmitCandidate(candidate); _shimmer.Register(candidate.SourceId, candidate.Root, mayShimmer: true, allowXray: true); } return; } ResourceMath.Measurement measurement; bool flag2 = TryMeasureCandidate(candidate, preferLiveMineRock5: true, out measurement); float num = (flag2 ? measurement.Initial : 0f); float num2 = (flag2 ? measurement.Remaining : 0f); float unscaledTime = Time.unscaledTime; bool flag3 = flag2 && num2 <= 0f; bool flag4 = flag2 && CrossedRemovalThreshold(candidate, num, num2); bool flag5 = unscaledTime - candidate.LastResourceReportTime >= _config.ResourceProgressMinInterval.Value; bool flag6 = flag2 && ProgressDeltaPercent(candidate, num, num2) >= _config.ResourceProgressStepPercent.Value; bool flag7 = flag || flag3 || flag4 || !flag2 || (flag5 && flag6); if (flag7) { SubmitCandidate(candidate, flag2, num, num2); } LogResourceMeasurement(candidate, flag2, measurement, (!flag7) ? "below-step" : (flag3 ? "terminal-hit" : (flag4 ? "threshold" : (flag ? "first-hit" : "progress")))); if (flag) { _shimmer.Register(candidate.SourceId, candidate.Root, mayShimmer: true, allowXray: true); } } internal bool TryGetResourceDiagnostic(string sourceId, out ResourceDiagnosticSnapshot snapshot) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) snapshot = null; if (string.IsNullOrWhiteSpace(sourceId)) { return false; } Candidate value = null; if (!_loaded.TryGetValue(sourceId, out value) && StableZdoIdentity.TryResolveSource(sourceId, out var zdo)) { _loaded.TryGetValue(SourceFor(zdo.m_uid), out value); } if (value == null || value.Category != PinCategory.Resource) { if (_pendingShellHandoffs.TryGetValue(sourceId, out var value2)) { snapshot = new ResourceDiagnosticSnapshot { RequestedSourceId = sourceId, StableSourceId = sourceId, ResourceType = value2.ResourceType, IsShell = true, ShellHandoffPending = true }; return true; } return false; } ZNetView view = value.View; ZDO val = ((view != null) ? view.GetZDO() : null); string sourceId2 = string.Empty; if (val != null) { StableZdoIdentity.TryGetExistingSource(val, out sourceId2); } ResourceMath.Measurement measurement; bool flag = value.HasResourceMeasurement || TryMeasureCandidate(value, preferLiveMineRock5: false, out measurement); ResourceMath.Measurement resourceMeasurement = value.ResourceMeasurement; string key = ((sourceId2.Length != 0) ? sourceId2 : value.SourceId); snapshot = new ResourceDiagnosticSnapshot { RequestedSourceId = sourceId, LocalSourceId = value.SourceId, StableSourceId = sourceId2, Prefab = (value.Descriptor?.PrefabName ?? string.Empty), ResourceType = (value.Descriptor?.ResourceType ?? string.Empty), ProbeKind = (flag ? resourceMeasurement.Kind : ResourceMath.ProbeKind.None), Loaded = ((Object)(object)value.Root != (Object)null), Eligible = value.Eligible, Discovered = _discovered.Contains(value.SourceId), IsShell = (value.Descriptor?.IsResourceShell ?? false), ShellHandoffPending = _pendingShellHandoffs.ContainsKey(key), RootActive = ((Object)(object)value.Root != (Object)null && value.Root.activeInHierarchy), ViewActive = ((Object)(object)value.View != (Object)null && ((Behaviour)value.View).isActiveAndEnabled), ZdoValid = (val != null), Measured = flag, Initial = (flag ? resourceMeasurement.Initial : 0f), Remaining = (flag ? resourceMeasurement.Remaining : 0f), DepletedPercent = (flag ? resourceMeasurement.DepletedPercent : 0f), TotalParts = (flag ? resourceMeasurement.TotalParts : 0), RemainingParts = (flag ? resourceMeasurement.RemainingParts : 0), LastSentInitial = value.LastSentInitial, LastSentRemaining = value.LastSentRemaining }; return true; } internal bool TryGetDungeonDiagnostic(PinRecord canonical, out DungeonDiagnosticSnapshot snapshot) { return _dungeons.TryGetDiagnostic(canonical, out snapshot); } internal void ReportPickableProgress(GameObject gameObject, bool picked) { Candidate candidate = ResolveOrObserve(gameObject); if (candidate != null && candidate.Eligible && candidate.Category == PinCategory.Pickable) { RefreshPickableVisual(candidate); if (RavenNetwork.TrackPickables && CanReportPickableState((Object)(object)candidate.View == (Object)null || candidate.View.IsOwner(), (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) && (picked || _discovered.Contains(candidate.SourceId) || IsKnownAuthoritativePickable(candidate))) { _discovered.Add(candidate.SourceId); SubmitCandidate(candidate); } } } internal static bool CanReportPickableState(bool viewIsOwner, bool isServer) { return viewIsOwner || isServer; } private static bool IsKnownAuthoritativePickable(Candidate candidate) { object obj; if (candidate == null) { obj = null; } else { ZNetView view = candidate.View; obj = ((view != null) ? view.GetZDO() : null); } ZDO val = (ZDO)obj; if (val != null && StableZdoIdentity.TryGetExistingSource(val, out var sourceId) && RavenNetwork.TryGetAuthoritativeSource(sourceId, out var observation)) { if (observation == null) { return false; } return observation.Category == PinCategory.Pickable; } return false; } internal void OnFinderDetected(Beacon beacon) { if (!((Object)(object)beacon == (Object)null)) { Candidate candidate = ResolveOrObserve(((Component)beacon).gameObject); if (candidate != null && candidate.Category == PinCategory.Resource && (!candidate.Descriptor.IsSilver || RavenNetwork.SilverMode != SilverDiscoveryMode.Disabled) && (candidate.Descriptor.IsSilver || candidate.Descriptor.RequiresFinder)) { Discover(candidate); } } } internal void OnPortalTagChanged(TeleportWorld portal) { if (_config.AutoPinPortals.Value) { Candidate candidate = ResolveOrObserve((portal != null) ? ((Component)portal).gameObject : null); if (candidate != null && candidate.Eligible && candidate.Category == PinCategory.Portal) { RefreshDescriptor(candidate); SubmitCandidate(candidate); } } } internal void OnCharacterDied(Character character) { _dungeons.OnCharacterDied(character); } internal void OnContainerInspected(Container container) { _dungeons.OnContainerInspected(container); } internal void OnDungeonGenerated(DungeonGenerator generator) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) Location val = (((Object)(object)generator != (Object)null) ? Location.GetLocation(((Component)generator).transform.position, true) : null); if ((Object)(object)val != (Object)null) { ObserveLocation(val); } _dungeons.OnDungeonGenerated(generator); } internal void OnDungeonGenerating(DungeonGenerator generator, int seed, SpawnMode mode) { //IL_0012: 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) Location val = (((Object)(object)generator != (Object)null) ? Location.GetLocation(((Component)generator).transform.position, true) : null); if ((Object)(object)val != (Object)null) { ObserveLocation(val); } _dungeons.OnDungeonGenerating(generator, seed, mode); } internal void OnDungeonLoading(DungeonGenerator generator) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) Location val = (((Object)(object)generator != (Object)null) ? Location.GetLocation(((Component)generator).transform.position, true) : null); if ((Object)(object)val != (Object)null) { ObserveLocation(val); } _dungeons.OnDungeonLoading(generator); } internal void OnPlayerTeleportStarted(Vector3 sourcePosition, Vector3 targetPosition) { //IL_0006: 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) _dungeons.OnPlayerTeleportStarted(sourcePosition, targetPosition); } internal void OnReferencePositionSent(Vector3 referencePosition) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) _dungeons.OnReferencePositionSent(referencePosition); } internal void OnDungeonGeneratorDestroyed(DungeonGenerator generator) { _dungeons.OnGeneratorDestroyed(generator); } internal void OnObjectDestroying(GameObject gameObject) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) ZNetView val = FindView(gameObject); if ((Object)(object)val == (Object)null || val.GetZDO() == null) { return; } string text = SourceFor(val.GetZDO().m_uid); if (_loaded.TryGetValue(text, out var value) && value.Eligible && value.Category == PinCategory.Resource && !value.Descriptor.IsResourceShell && IsKnownResourceObservation(value)) { ResourceMath.Measurement measurement; bool flag = TryMeasureCandidate(value, preferLiveMineRock5: false, out measurement); float num = Mathf.Max(flag ? measurement.Initial : 0f, value.LastSentInitial); if (num > 0f) { ResourceMath.Measurement measurement2 = new ResourceMath.Measurement(flag ? measurement.Kind : ResourceMath.ProbeKind.None, num, 0f, (!flag) ? 1 : measurement.TotalParts, 0); SubmitCandidate(value, hasMeasurement: true, num); LogResourceMeasurement(value, measured: true, measurement2, "destroy-terminal"); } } RemoveLoaded(text); } internal void OnViewReset(ZNetView view) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)view == (Object)null)) { ZDO zDO = view.GetZDO(); if (zDO != null) { _dungeons.OnSubjectUnloaded(zDO.m_uid); StableZdoIdentity.Forget(zDO.m_uid); } if (_viewSources.TryGetValue(((Object)view).GetInstanceID(), out var value)) { RemoveLoaded(value); _discovered.Remove(value); } } } internal void OnLocationDestroying(Location location) { if (!((Object)(object)location == (Object)null)) { string value = null; ZNetView val = FindView(((Component)location).gameObject); if ((Object)(object)val != (Object)null) { _viewSources.TryGetValue(((Object)val).GetInstanceID(), out value); } if (string.IsNullOrEmpty(value)) { _rootSources.TryGetValue(((Object)((Component)location).gameObject).GetInstanceID(), out value); } if (!string.IsNullOrEmpty(value)) { RemoveLoaded(value); _discovered.Remove(value); } } } internal bool OnZdoDestroyed(ZDOID id, string authoritativeSource) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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_005d: 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_00be: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) string text = SourceFor(id); string resourceType = string.Empty; string text2 = string.Empty; Vector3 position = Vector3.zero; if (_loaded.TryGetValue(text, out var value) && value.Category == PinCategory.Resource && value.Descriptor.IsResourceShell) { resourceType = value.Descriptor.ResourceType; text2 = value.Descriptor.ResourceReplacementPrefab; position = value.Position; } PinRecord observation = null; int num; if (StableZdoIdentity.IsStableSource(authoritativeSource) && RavenNetwork.TryGetAuthoritativeSource(authoritativeSource, out observation)) { num = (IsAuthoritativeShell(observation) ? 1 : 0); if (num != 0) { resourceType = observation.ResourceType; text2 = ResolveExpectedShellReplacement(observation.Prefab, text2); position = observation.Position; } } else { num = 0; } RemoveLoaded(text); _discovered.Remove(text); _dungeons.OnSubjectDestroyed(id); if (num != 0 && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { BeginShellHandoff(authoritativeSource, resourceType, text2, position); } return (byte)num != 0; } private static bool IsAuthoritativeShell(PinRecord record) { if (record != null && record.Category == PinCategory.Resource) { if (!ResourceCatalog.IsKnownShell(record.Prefab)) { if (!record.Respawns) { return record.InitialAmount <= 0f; } return false; } return true; } return false; } private string ResolveExpectedShellReplacement(string shellPrefab, string fallback) { if (ResourceCatalog.TryGet(shellPrefab, out var identity) && identity.IsShell && !string.IsNullOrWhiteSpace(identity.ReplacementPrefab)) { return identity.ReplacementPrefab; } GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(shellPrefab) : null); if ((Object)(object)val != (Object)null) { PrefabDescriptor prefabDescriptor = _classifier.Describe(val, StringExtensionMethods.GetStableHashCode(shellPrefab)); if (prefabDescriptor.IsResourceShell && !string.IsNullOrWhiteSpace(prefabDescriptor.ResourceReplacementPrefab)) { return prefabDescriptor.ResourceReplacementPrefab; } } return fallback ?? string.Empty; } private void BeginShellHandoff(string source, string resourceType, string expectedReplacementPrefab, Vector3 position) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(source)) { float unscaledTime = Time.unscaledTime; PendingShellHandoff pendingShellHandoff = new PendingShellHandoff { SourceId = source, ResourceType = (resourceType ?? string.Empty), ExpectedReplacementPrefab = (expectedReplacementPrefab ?? string.Empty), Position = position, StartedAfterSequence = _candidateSequence, StartedAt = unscaledTime, Deadline = unscaledTime + 3f }; CaptureExistingShellReplacements(pendingShellHandoff); _pendingShellHandoffs[source] = pendingShellHandoff; if (_shellHandoffRoutine == null) { _shellHandoffRoutine = ((MonoBehaviour)_plugin).StartCoroutine(ProcessShellHandoffs()); } TrySubmitLoadedShellReplacement(pendingShellHandoff); } } private bool ObserveShellReplacement(string resourceType, string replacementPrefab, string replacementSource, Vector3 position) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) PendingShellHandoff pendingShellHandoff = FindPendingShellReplacement(resourceType, replacementPrefab, replacementSource, position); if (pendingShellHandoff != null) { pendingShellHandoff.ReplacementObserved = true; return true; } return false; } private PendingShellHandoff FindPendingShellReplacement(string resourceType, string replacementPrefab, string replacementSource, Vector3 position) { //IL_0090: 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_00a0: Unknown result type (might be due to invalid IL or missing references) if (_pendingShellHandoffs.Count == 0 || string.IsNullOrWhiteSpace(resourceType) || string.IsNullOrWhiteSpace(replacementPrefab)) { return null; } string b = RavenIds.Normalize(resourceType); string b2 = RavenIds.Normalize(replacementPrefab); float num = 9f; PendingShellHandoff result = null; float num2 = float.MaxValue; foreach (PendingShellHandoff value in _pendingShellHandoffs.Values) { if (!value.ReplacementObserved && string.Equals(RavenIds.Normalize(value.ResourceType), b, StringComparison.Ordinal) && string.Equals(RavenIds.Normalize(value.ExpectedReplacementPrefab), b2, StringComparison.Ordinal) && IsFreshShellReplacement(value, replacementSource, position)) { float num3 = DistanceXZSquared(value.Position, position); if (num3 <= num && num3 < num2) { result = value; num2 = num3; } } } return result; } private void CaptureExistingShellReplacements(PendingShellHandoff pending) { //IL_008a: 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) if (pending == null || string.IsNullOrWhiteSpace(pending.ExpectedReplacementPrefab)) { return; } string b = RavenIds.Normalize(pending.ResourceType); string b2 = RavenIds.Normalize(pending.ExpectedReplacementPrefab); float num = 9f; foreach (Candidate value in _loaded.Values) { if (IsMineableShellReplacement(value) && string.Equals(RavenIds.Normalize(value.Descriptor.ResourceType), b, StringComparison.Ordinal) && string.Equals(RavenIds.Normalize(value.Descriptor.PrefabName), b2, StringComparison.Ordinal) && !(DistanceXZSquared(value.Position, pending.Position) > num)) { pending.ExistingReplacementSources.Add(value.SourceId); } } } private bool IsFreshShellReplacement(PendingShellHandoff pending, string replacementSource, Vector3 position) { //IL_0071: 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_0037: 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) if (pending == null || string.IsNullOrEmpty(replacementSource)) { return false; } if (!_loaded.TryGetValue(replacementSource, out var value)) { return IsFreshShellReplacementObservation(pending.ExistingReplacementSources.Contains(replacementSource), hasLoadedCandidate: false, 0L, pending.StartedAfterSequence, 0f, DistanceXZSquared(position, pending.Position)); } float ageBeforeStart = pending.StartedAt - value.FirstObservedAt; return IsFreshShellReplacementObservation(pending.ExistingReplacementSources.Contains(replacementSource), hasLoadedCandidate: true, value.FirstObservationSequence, pending.StartedAfterSequence, ageBeforeStart, DistanceXZSquared(position, pending.Position)); } internal static bool IsFreshShellReplacementObservation(bool sourceExistedAtStart, bool hasLoadedCandidate, long candidateSequence, long startedAfterSequence, float ageBeforeStart, float distanceXZSquared) { if (!hasLoadedCandidate) { return false; } if (!sourceExistedAtStart) { return candidateSequence > startedAfterSequence; } if (candidateSequence > startedAfterSequence) { return false; } float num = 0.5625f; if (ageBeforeStart >= 0f && ageBeforeStart <= 0.5f) { return distanceXZSquared <= num; } return false; } private void TrySubmitLoadedShellReplacement(PendingShellHandoff pending) { //IL_00a1: 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_00b5: Unknown result type (might be due to invalid IL or missing references) if (pending == null || string.IsNullOrWhiteSpace(pending.ExpectedReplacementPrefab)) { return; } Candidate candidate = null; float num = float.MaxValue; float num2 = 9f; string b = RavenIds.Normalize(pending.ResourceType); string b2 = RavenIds.Normalize(pending.ExpectedReplacementPrefab); foreach (Candidate value in _loaded.Values) { if (IsMineableShellReplacement(value) && string.Equals(RavenIds.Normalize(value.Descriptor.ResourceType), b, StringComparison.Ordinal) && string.Equals(RavenIds.Normalize(value.Descriptor.PrefabName), b2, StringComparison.Ordinal) && IsFreshShellReplacement(pending, value.SourceId, value.Position)) { float num3 = DistanceXZSquared(value.Position, pending.Position); if (num3 <= num2 && num3 < num) { candidate = value; num = num3; } } } if (candidate != null) { Discover(candidate, force: true); } } private void TrySubmitPendingShellReplacement(Candidate candidate) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && IsMineableShellReplacement(candidate) && FindPendingShellReplacement(candidate.Descriptor.ResourceType, candidate.Descriptor.PrefabName, candidate.SourceId, candidate.Position) != null) { Discover(candidate, force: true); } } private static bool IsMineableShellReplacement(Candidate candidate) { if (candidate != null && candidate.Eligible && candidate.Category == PinCategory.Resource && !candidate.Descriptor.IsResourceShell && (Object)(object)candidate.Root != (Object)null) { ZNetView view = candidate.View; return ((view != null) ? view.GetZDO() : null) != null; } return false; } private IEnumerator ProcessShellHandoffs() { WaitForSecondsRealtime wait = new WaitForSecondsRealtime(0.1f); List completed = new List(4); try { while (_pendingShellHandoffs.Count != 0) { yield return wait; completed.Clear(); float unscaledTime = Time.unscaledTime; foreach (KeyValuePair pendingShellHandoff in _pendingShellHandoffs) { if (pendingShellHandoff.Value.ReplacementObserved || unscaledTime >= pendingShellHandoff.Value.Deadline) { RavenNetwork.RemoveSourceAuthoritative(pendingShellHandoff.Value.SourceId); completed.Add(pendingShellHandoff.Key); } } for (int i = 0; i < completed.Count; i++) { _pendingShellHandoffs.Remove(completed[i]); } } } finally { _shellHandoffRoutine = null; } } internal void FlushPendingShellHandoffs() { if (_shellHandoffRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_shellHandoffRoutine); _shellHandoffRoutine = null; } if (_pendingShellHandoffs.Count == 0) { return; } List list = new List(_pendingShellHandoffs.Count); foreach (PendingShellHandoff value in _pendingShellHandoffs.Values) { if (StableZdoIdentity.IsStableSource(value.SourceId) && RavenNetwork.TryGetAuthoritativeSource(value.SourceId, out var observation) && IsAuthoritativeShell(observation)) { list.Add(value.SourceId); } } _pendingShellHandoffs.Clear(); for (int i = 0; i < list.Count; i++) { RavenNetwork.RemoveSourceAuthoritative(list[i]); } } internal void Clear() { StopReporter(); if (_shellHandoffRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_shellHandoffRoutine); _shellHandoffRoutine = null; } _pendingShellHandoffs.Clear(); _dungeons.Clear(); _shimmer.Clear(); _loaded.Clear(); _viewSources.Clear(); _rootSources.Clear(); _resourceSpatial.Clear(); _pickableSpatial.Clear(); _dungeonSpatial.Clear(); _vehicles.Clear(); _portals.Clear(); _discovered.Clear(); _repairedPersistentSources.Clear(); _prefabResourceProbes.Clear(); _resourceVisualRefreshCandidates.Clear(); _reportFailureLogged = false; _knownResourceLookupFailureLogged = false; _pinSubmissionFailureLogged = false; _contentCatalogReady = false; _destructiveContentCatalogReady = false; _contentAvailabilityFailureLogged = false; _candidateSequence = 0L; _scene = null; } private void Observe(GameObject root, ZDO zdo, ZNetView knownView) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0079: 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) ZNetView val = knownView ?? FindView(root); GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : root); Vector3 position = ((zdo != null) ? zdo.GetPosition() : val2.transform.position); if (!IsDuplicateRegistration(val2, val, zdo, position)) { int prefabHash = ((zdo != null) ? zdo.GetPrefab() : 0); PrefabDescriptor prefabDescriptor = _classifier.Describe(root, prefabHash, zdo); PinCategory category = ToCategory(prefabDescriptor.Kind); if (prefabDescriptor.Kind != DiscoveryKind.None && !IsInteriorPickable(category, position, val2)) { RegisterCandidate(val2, val, zdo, prefabDescriptor, position); } } } private bool IsDuplicateRegistration(GameObject root, ZNetView view, ZDO zdo, Vector3 position) { //IL_0079: 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_0080: 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_009a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)root == (Object)null) { return false; } string value = null; if ((Object)(object)view != (Object)null) { _viewSources.TryGetValue(((Object)view).GetInstanceID(), out value); } if (string.IsNullOrEmpty(value)) { _rootSources.TryGetValue(((Object)root).GetInstanceID(), out value); } if (!string.IsNullOrEmpty(value) && _loaded.TryGetValue(value, out var value2) && value2.Eligible && value2.Root == root && value2.View == view) { Vector3 val = value2.Position - position; if (!(((Vector3)(ref val)).sqrMagnitude > 0.0001f) && (zdo == null || string.Equals(value, SourceFor(zdo.m_uid), StringComparison.Ordinal))) { int instanceID = ((Object)root).GetInstanceID(); if (_rootSources.TryGetValue(instanceID, out var value3) && string.Equals(value3, value, StringComparison.Ordinal)) { if (!((Object)(object)view == (Object)null)) { if (_viewSources.TryGetValue(((Object)view).GetInstanceID(), out var value4)) { return string.Equals(value4, value, StringComparison.Ordinal); } return false; } return true; } return false; } } return false; } private Candidate RegisterCandidate(GameObject root, ZNetView view, ZDO zdo, PrefabDescriptor descriptor, Vector3 position) { //IL_0011: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) PinCategory pinCategory = ToCategory(descriptor.Kind); if (pinCategory == (PinCategory)0 || IsInteriorPickable(pinCategory, position, root)) { return null; } string text = ((pinCategory == PinCategory.Dungeon) ? RavenIds.ForPosition(PinCategory.Dungeon, descriptor.PrefabName, position) : ((zdo != null) ? SourceFor(zdo.m_uid) : RavenIds.ForPosition(pinCategory, descriptor.PrefabName, position, 0.5f))); if (_loaded.TryGetValue(text, out var value)) { if (IsUnchangedRegistration(value, root, view, descriptor, pinCategory, position)) { return value; } RemoveFromIndexes(value); value.Root = root; value.RootInstanceId = (((Object)(object)root != (Object)null) ? ((Object)root).GetInstanceID() : 0); value.View = view; value.Descriptor = descriptor; value.Category = pinCategory; value.Eligible = true; value.Position = position; bool flag = pinCategory == PinCategory.Resource && value.ResourceProbe != null && value.ResourceProbe.Root == root; value.ResourceProbe = ((pinCategory != PinCategory.Resource) ? null : (flag ? value.ResourceProbe : ResourceMath.CreateProbe(root))); if (!flag) { value.HasResourceMeasurement = false; value.ResourceMeasurement = default(ResourceMath.Measurement); } Index(value); if ((Object)(object)view != (Object)null) { _viewSources[((Object)view).GetInstanceID()] = text; } switch (pinCategory) { case PinCategory.Resource: { if (!descriptor.IsResourceShell && _discovered.Contains(text) && value.LastSentInitial <= 0f && TryMeasureCandidate(value, preferLiveMineRock5: false, out var measurement) && measurement.Initial > 0f) { SubmitCandidate(value, hasMeasurement: true, measurement.Initial, measurement.Remaining); } RefreshResourceVisual(value); TrySubmitPendingShellReplacement(value); TryDiscoverAtCurrentPlayer(value); break; } case PinCategory.Pickable: RefreshPickableVisual(value); TryDiscoverAtCurrentPlayer(value); break; case PinCategory.Dungeon: if (IsNearAnyPlayer(value.Position, RavenNetwork.DungeonDiscoveryRadius)) { Discover(value, force: true); } else { TryDiscoverAtCurrentPlayer(value); } break; default: if (IsAutoCategoryEnabled(pinCategory)) { Discover(value, force: true); } break; } return value; } Candidate candidate = new Candidate { SourceId = text, Root = root, RootInstanceId = (((Object)(object)root != (Object)null) ? ((Object)root).GetInstanceID() : 0), View = view, Descriptor = descriptor, Category = pinCategory, Position = position, FirstObservationSequence = ++_candidateSequence, FirstObservedAt = Time.unscaledTime, ResourceProbe = ((pinCategory == PinCategory.Resource) ? ResourceMath.CreateProbe(root) : null) }; if (zdo != null && pinCategory != PinCategory.Dungeon) { StableZdoIdentity.TryGetExistingSource(zdo, out var _); } _loaded.Add(text, candidate); if ((Object)(object)view != (Object)null) { _viewSources[((Object)view).GetInstanceID()] = text; } Index(candidate); switch (pinCategory) { case PinCategory.Resource: RefreshResourceVisual(candidate); TrySubmitPendingShellReplacement(candidate); TryDiscoverAtCurrentPlayer(candidate); break; case PinCategory.Pickable: RefreshPickableVisual(candidate); TryDiscoverAtCurrentPlayer(candidate); break; case PinCategory.Dungeon: if (IsNearAnyPlayer(candidate.Position, RavenNetwork.DungeonDiscoveryRadius)) { Discover(candidate, force: true); } else { TryDiscoverAtCurrentPlayer(candidate); } break; default: if (IsAutoCategoryEnabled(pinCategory)) { Discover(candidate, force: true); } break; } return candidate; } private bool IsUnchangedRegistration(Candidate candidate, GameObject root, ZNetView view, PrefabDescriptor descriptor, PinCategory category, Vector3 position) { //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_003e: 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) if (candidate != null && candidate.Eligible && candidate.Root == root && candidate.View == view && candidate.Category == category && EquivalentDescriptor(candidate.Descriptor, descriptor)) { Vector3 val = candidate.Position - position; if (!(((Vector3)(ref val)).sqrMagnitude > 0.0001f)) { if (candidate.RootInstanceId != 0 && (!_rootSources.TryGetValue(candidate.RootInstanceId, out var value) || !string.Equals(value, candidate.SourceId, StringComparison.Ordinal))) { return false; } if (!((Object)(object)view == (Object)null)) { if (_viewSources.TryGetValue(((Object)view).GetInstanceID(), out var value2)) { return string.Equals(value2, candidate.SourceId, StringComparison.Ordinal); } return false; } return true; } } return false; } private static bool EquivalentDescriptor(PrefabDescriptor left, PrefabDescriptor right) { if (left != right) { if (left != null && right != null && left.Kind == right.Kind && string.Equals(left.PrefabName, right.PrefabName, StringComparison.Ordinal) && string.Equals(left.DisplayName, right.DisplayName, StringComparison.Ordinal) && string.Equals(left.ResourceType, right.ResourceType, StringComparison.Ordinal) && left.IsSilver == right.IsSilver && left.IsRespawningPickable == right.IsRespawningPickable && left.IsResourceShell == right.IsResourceShell && left.IsDirectPickable == right.IsDirectPickable && string.Equals(left.ResourceReplacementPrefab, right.ResourceReplacementPrefab, StringComparison.Ordinal)) { return left.RequiresFinder == right.RequiresFinder; } return false; } return true; } private void Index(Candidate candidate) { if (candidate.RootInstanceId != 0) { _rootSources[candidate.RootInstanceId] = candidate.SourceId; } if (candidate.Category == PinCategory.Resource || candidate.Category == PinCategory.Pickable || candidate.Category == PinCategory.Dungeon) { if (candidate.Category != PinCategory.Pickable || RavenNetwork.TrackPickables) { AddToSpatialIndex(candidate); } } else if (candidate.Category == PinCategory.Portal) { _portals[candidate.SourceId] = candidate; } else if (candidate.Category == PinCategory.Ship || candidate.Category == PinCategory.Cart) { _vehicles[candidate.SourceId] = candidate; } } private void RemoveFromIndexes(Candidate candidate) { RemoveFromSpatialIndex(candidate); _vehicles.Remove(candidate.SourceId); _portals.Remove(candidate.SourceId); _shimmer.Unregister(candidate.SourceId); if (candidate.RootInstanceId != 0) { int rootInstanceId = candidate.RootInstanceId; if (_rootSources.TryGetValue(rootInstanceId, out var value) && string.Equals(value, candidate.SourceId, StringComparison.Ordinal)) { _rootSources.Remove(rootInstanceId); } candidate.RootInstanceId = 0; } if ((Object)(object)candidate.View != (Object)null) { _viewSources.Remove(((Object)candidate.View).GetInstanceID()); } } private void AddToSpatialIndex(Candidate candidate) { if (candidate == null || candidate.InSpatialIndex) { return; } Dictionary> dictionary = SpatialIndexFor(candidate.Category); if (dictionary != null) { int x = Mathf.FloorToInt(candidate.Position.x / 32f); int z = Mathf.FloorToInt(candidate.Position.z / 32f); candidate.Cell = CellKey(x, z); if (!dictionary.TryGetValue(candidate.Cell, out var value)) { value = new List(4); dictionary.Add(candidate.Cell, value); } value.Add(candidate); candidate.InSpatialIndex = true; } } private void RemoveFromSpatialIndex(Candidate candidate) { if (candidate == null || !candidate.InSpatialIndex) { return; } Dictionary> dictionary = SpatialIndexFor(candidate.Category); if (dictionary != null && dictionary.TryGetValue(candidate.Cell, out var value)) { value.Remove(candidate); if (value.Count == 0) { dictionary.Remove(candidate.Cell); } } candidate.InSpatialIndex = false; } private Dictionary> SpatialIndexFor(PinCategory category) { return category switch { PinCategory.Resource => _resourceSpatial, PinCategory.Pickable => _pickableSpatial, PinCategory.Dungeon => _dungeonSpatial, _ => null, }; } internal void RefreshNetworkPolicy() { RefreshPickableSpatialMembership(); } private void RefreshPickableSpatialMembership() { bool trackPickables = RavenNetwork.TrackPickables; foreach (Candidate value in _loaded.Values) { if (value.Category == PinCategory.Pickable) { if (trackPickables && value.Eligible && (Object)(object)value.Root != (Object)null) { AddToSpatialIndex(value); } else { RemoveFromSpatialIndex(value); } } } } private void RemoveLoaded(string source) { if (!string.IsNullOrEmpty(source) && _loaded.TryGetValue(source, out var value)) { RemoveFromIndexes(value); _loaded.Remove(source); } } private Candidate ResolveOrObserve(GameObject gameObject) { //IL_0031: 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) if ((Object)(object)gameObject == (Object)null) { return null; } ZNetView val = FindView(gameObject); ZDO val2 = ((val != null) ? val.GetZDO() : null); if ((Object)(object)val != (Object)null && val2 == null) { return null; } if (val2 != null) { string key = SourceFor(val2.m_uid); if (_loaded.TryGetValue(key, out var value)) { return value; } } ObserveRelevantObject(gameObject); if (val2 != null && _loaded.TryGetValue(SourceFor(val2.m_uid), out var value2)) { return value2; } GameObject val3 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : gameObject); if ((Object)(object)val3 != (Object)null && _rootSources.TryGetValue(((Object)val3).GetInstanceID(), out var value3) && _loaded.TryGetValue(value3, out var value4)) { return value4; } return null; } private void TryDiscoverAtCurrentPlayer(Candidate candidate) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { float num = DiscoveryRadius(candidate.Category); if (DistanceXZSquared(((Component)localPlayer).transform.position, candidate.Position) <= num * num && (candidate.Category != PinCategory.Resource || CanDiscoverResourceByRadius(candidate.Descriptor))) { Discover(candidate); } } } private void Discover(Candidate candidate, bool force = false) { if (candidate == null || !candidate.Eligible || (candidate.Category == PinCategory.Pickable && !RavenNetwork.TrackPickables)) { return; } bool flag = _discovered.Add(candidate.SourceId); if (force || flag) { SubmitCandidate(candidate); if (candidate.Category == PinCategory.Dungeon) { _dungeons.OnDungeonDiscovered(candidate.SourceId); } if (flag && candidate.Category == PinCategory.Resource) { _shimmer.Register(candidate.SourceId, candidate.Root, mayShimmer: true, allowXray: true); } } } private void SubmitCandidate(Candidate candidate, bool hasMeasurement = false, float measuredInitial = 0f, float measuredRemaining = 0f) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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) //IL_0094: 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_0099: Unknown result type (might be due to invalid IL or missing references) if (!_config.SharePins.Value || !candidate.Eligible || (Object)(object)candidate.Root == (Object)null || (candidate.Category == PinCategory.Pickable && !RavenNetwork.TrackPickables)) { return; } if (candidate.Category != PinCategory.Dungeon) { ZNetView view = candidate.View; Vector3? obj; if (view == null) { obj = null; } else { ZDO zDO = view.GetZDO(); obj = ((zDO != null) ? new Vector3?(zDO.GetPosition()) : ((Vector3?)null)); } candidate.Position = (Vector3)(((??)obj) ?? candidate.Root.transform.position); } if (IsInteriorPickable(candidate.Category, candidate.Position, candidate.Root)) { return; } RefreshDescriptor(candidate); PinRecord pinRecord = BuildRecord(candidate, hasMeasurement, measuredInitial, measuredRemaining); try { _submitPin(pinRecord); candidate.LastSentPosition = candidate.Position; candidate.LastSentName = pinRecord.DisplayName; if (candidate.Category == PinCategory.Resource && pinRecord.InitialAmount > 0f) { candidate.LastSentInitial = pinRecord.InitialAmount; candidate.LastSentRemaining = pinRecord.RemainingAmount; candidate.LastResourceReportTime = Time.unscaledTime; } } catch (Exception ex) { if (!_pinSubmissionFailureLogged) { _pinSubmissionFailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)($"Could not submit {candidate.Category} '{candidate.Descriptor.PrefabName}'; " + "further callback failures are suppressed for this session: " + ex.Message)); } } } } private PinRecord BuildRecord(Candidate candidate, bool hasMeasurement, float measuredInitial, float measuredRemaining) { //IL_00b5: 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_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) float initialAmount = (hasMeasurement ? measuredInitial : 0f); float remainingAmount = (hasMeasurement ? measuredRemaining : 0f); ResourceMath.Measurement measurement; if (candidate.Category == PinCategory.Resource && candidate.Descriptor.IsResourceShell) { initialAmount = 0f; remainingAmount = 0f; } else if (candidate.Category == PinCategory.Resource && !hasMeasurement && TryMeasureCandidate(candidate, preferLiveMineRock5: false, out measurement)) { initialAmount = measurement.Initial; remainingAmount = measurement.Remaining; } object obj; if (candidate.Category != PinCategory.Dungeon) { ZNetView view = candidate.View; obj = ((((view != null) ? view.GetZDO() : null) != null) ? RavenIds.ForZdo(candidate.Category, candidate.View.GetZDO().m_uid) : RavenIds.ForPosition(candidate.Category, candidate.Descriptor.PrefabName, candidate.Position, 0.5f)); } else { obj = candidate.SourceId; } string id = (string)obj; PinStatus status = PinStatus.Active; bool flag = candidate.Category == PinCategory.Pickable && candidate.Descriptor.IsRespawningPickable; if (candidate.Category == PinCategory.Pickable) { Pickable val = candidate.Root.GetComponent() ?? candidate.Root.GetComponentInChildren(true); status = (((Object)(object)val != (Object)null && val.GetPicked()) ? (flag ? PinStatus.Cleared : PinStatus.Destroyed) : PinStatus.Active); } return new PinRecord { Id = id, SourceId = candidate.SourceId, Category = candidate.Category, Status = status, Prefab = candidate.Descriptor.PrefabName, DisplayName = candidate.Descriptor.DisplayName, ResourceType = candidate.Descriptor.ResourceType, Respawns = flag, Biome = ResolveBiome(candidate.Position), Position = candidate.Position, InitialAmount = initialAmount, RemainingAmount = remainingAmount, UpdatedUtcTicks = DateTime.UtcNow.Ticks }; } internal static bool IsInteriorPickable(PinCategory category, Vector3 position, GameObject root = null) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (category != PinCategory.Pickable) { return false; } if (position.y > 3000f) { return true; } return PrefabClassifier.IsDungeonAlgorithm((root != null) ? (root.GetComponent() ?? root.GetComponentInParent()) : null); } private bool CrossedRemovalThreshold(Candidate candidate, float initial, float remaining) { if (initial <= 0f || candidate.LastSentInitial <= 0f) { return false; } float num = Mathf.Clamp(RavenNetwork.ResourceRemovalPercent, 1f, 100f); float num2 = 100f * (1f - Mathf.Clamp01(candidate.LastSentRemaining / candidate.LastSentInitial)); float num3 = 100f * (1f - Mathf.Clamp01(remaining / initial)); if (num2 < num) { return num3 >= num; } return false; } private static bool TryMeasureCandidate(Candidate candidate, bool preferLiveMineRock5, out ResourceMath.Measurement measurement) { measurement = default(ResourceMath.Measurement); if (candidate?.ResourceProbe == null || !ResourceMath.TryMeasureDetailed(candidate.ResourceProbe, preferLiveMineRock5, out measurement)) { if (candidate != null) { candidate.HasResourceMeasurement = false; candidate.ResourceMeasurement = default(ResourceMath.Measurement); } return false; } candidate.HasResourceMeasurement = true; candidate.ResourceMeasurement = measurement; return true; } private void RefreshResourceVisual(Candidate candidate) { if (candidate != null && candidate.Category == PinCategory.Resource && candidate.Eligible && !((Object)(object)candidate.Root == (Object)null)) { bool flag = IsKnownResourceObservation(candidate); bool mayShimmer = CanDiscoverResourceByRadius(candidate.Descriptor) || flag; if (!_shimmer.UpdatePermissions(candidate.SourceId, mayShimmer, flag)) { _shimmer.Register(candidate.SourceId, candidate.Root, mayShimmer, flag); } } } private void RefreshPickableVisual(Candidate candidate) { if (candidate != null && candidate.Category == PinCategory.Pickable && candidate.Eligible && !((Object)(object)candidate.Root == (Object)null)) { Pickable val = candidate.Root.GetComponent() ?? candidate.Root.GetComponentInChildren(true); bool mayShimmer = _config.HighlightPickables.Value && (Object)(object)val != (Object)null && !val.GetPicked(); if (!_shimmer.UpdatePermissions(candidate.SourceId, mayShimmer, allowXray: false, useSourceAlphaMask: true)) { _shimmer.Register(candidate.SourceId, candidate.Root, mayShimmer, allowXray: false, useSourceAlphaMask: true); } } } private bool IsKnownResourceObservation(Candidate candidate) { //IL_00ad: 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) if (candidate == null || candidate.Category != PinCategory.Resource || candidate.Descriptor == null) { return false; } if (_discovered.Contains(candidate.SourceId)) { return true; } ZNetView view = candidate.View; ZDO val = ((view != null) ? view.GetZDO() : null); string sourceId = string.Empty; if (val != null) { StableZdoIdentity.TryGetExistingSource(val, out sourceId); } if (sourceId.Length != 0 && RavenNetwork.TryGetAuthoritativeSource(sourceId, out var observation) && PinRecordLookup.IsKnownResource(observation, candidate.Descriptor.ResourceType, candidate.Descriptor.PrefabName, candidate.Position, requireDistance: false, 0f)) { return true; } try { return _isKnownResource(sourceId, candidate.Descriptor.ResourceType, candidate.Descriptor.PrefabName, candidate.Position); } catch (Exception ex) { if (!_knownResourceLookupFailureLogged) { _knownResourceLookupFailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("Could not restore known resource visuals from map state: " + ex.Message)); } } return false; } } private void LogResourceMeasurement(Candidate candidate, bool measured, ResourceMath.Measurement measurement, string reason) { if (!_config.DetailedLogging.Value || candidate == null) { return; } if (!measured) { ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogInfo((object)("Resource state [" + reason + "] source=" + candidate.SourceId + " prefab=" + candidate.Descriptor?.PrefabName + " measurement=unavailable")); } return; } ManualLogSource log2 = RavenMapPlugin.Log; if (log2 != null) { log2.LogInfo((object)("Resource state [" + reason + "] source=" + candidate.SourceId + " prefab=" + candidate.Descriptor?.PrefabName + " " + $"kind={measurement.Kind} health={measurement.Remaining:0.##}/{measurement.Initial:0.##} " + $"parts={measurement.RemainingParts}/{measurement.TotalParts} depleted={measurement.DepletedPercent:0.##}% " + $"last={candidate.LastSentRemaining:0.##}/{candidate.LastSentInitial:0.##}")); } } private static float ProgressDeltaPercent(Candidate candidate, float initial, float remaining) { if (initial <= 0f || candidate.LastSentInitial <= 0f) { return 100f; } float num = Mathf.Clamp01(candidate.LastSentRemaining / candidate.LastSentInitial); float num2 = Mathf.Clamp01(remaining / initial); return Mathf.Abs(num - num2) * 100f; } private void RefreshDescriptor(Candidate candidate) { if (!((Object)(object)candidate.Root == (Object)null)) { ZNetView view = candidate.View; ZDO val = ((view != null) ? view.GetZDO() : null); PrefabDescriptor prefabDescriptor = _classifier.Describe(candidate.Root, (val != null) ? val.GetPrefab() : 0, val); if (prefabDescriptor.Kind != DiscoveryKind.None) { candidate.Descriptor = prefabDescriptor; } } } private IEnumerator ReportMovingObjects() { WaitForSecondsRealtime wait = new WaitForSecondsRealtime(_config.VehicleUpdateInterval.Value); try { while (true) { yield return wait; try { ReportVehicles(); ReportPortalNames(); _reportFailureLogged = false; } catch (Exception ex) { if (!_reportFailureLogged) { ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("RavenMap moving-object reporter recovered from an error: " + ex.Message)); } _reportFailureLogged = true; } } } } finally { _reportRoutine = null; } } private void ReportVehicles() { //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) if (!_config.TrackShips.Value && !_config.TrackCarts.Value) { return; } float num = _config.VehicleMinimumMoveDistance.Value * _config.VehicleMinimumMoveDistance.Value; List list = null; foreach (KeyValuePair vehicle in _vehicles) { Candidate value = vehicle.Value; if (!value.Eligible || (value.Category == PinCategory.Ship && !_config.TrackShips.Value) || (value.Category == PinCategory.Cart && !_config.TrackCarts.Value)) { continue; } ZNetView view = value.View; ZDO val = ((view != null) ? view.GetZDO() : null); if ((Object)(object)value.Root == (Object)null || val == null) { if (list == null) { list = new List(); } list.Add(vehicle.Key); } else { if ((Object)(object)value.View != (Object)null && !value.View.IsOwner() && ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())) { continue; } Vector3 position = val.GetPosition(); string a = value.Descriptor.DisplayName; if (value.Category == PinCategory.Ship) { string text = val.GetString("ShipName", string.Empty); if (!string.IsNullOrEmpty(text)) { a = text; } } if (!(DistanceXZSquared(position, value.LastSentPosition) < num) || !string.Equals(a, value.LastSentName, StringComparison.Ordinal)) { value.Position = position; SubmitCandidate(value); } } } RemoveStale(list); } private void ReportPortalNames() { if (!_config.AutoPinPortals.Value) { return; } List list = null; foreach (KeyValuePair portal in _portals) { Candidate value = portal.Value; if (!value.Eligible) { continue; } ZNetView view = value.View; ZDO val = ((view != null) ? view.GetZDO() : null); if ((Object)(object)value.Root == (Object)null || val == null) { if (list == null) { list = new List(); } list.Add(portal.Key); continue; } string text = val.GetString("tag", string.Empty); if (string.IsNullOrEmpty(text)) { text = value.Descriptor.DisplayName; } if (!string.Equals(text, value.LastSentName, StringComparison.Ordinal)) { RefreshDescriptor(value); SubmitCandidate(value); } } RemoveStale(list); } private void RemoveStale(List stale) { if (stale != null) { for (int i = 0; i < stale.Count; i++) { RemoveLoaded(stale[i]); } } } private void RestartReporter() { StopReporter(); _reportFailureLogged = false; if (_config.AutoPinPortals.Value || _config.TrackShips.Value || _config.TrackCarts.Value) { _reportRoutine = ((MonoBehaviour)_plugin).StartCoroutine(ReportMovingObjects()); } } private void StopReporter() { if (_reportRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_reportRoutine); _reportRoutine = null; } } private static ZNetView FindView(GameObject gameObject) { object obj; if (!((Object)(object)gameObject == (Object)null)) { obj = gameObject.GetComponent(); if (obj == null) { return gameObject.GetComponentInParent(); } } else { obj = null; } return (ZNetView)obj; } private unsafe static string SourceFor(ZDOID id) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) ZDOID val = id; return "zdo:" + ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString(); } private static PinCategory ToCategory(DiscoveryKind kind) { return kind switch { DiscoveryKind.Resource => PinCategory.Resource, DiscoveryKind.Dungeon => PinCategory.Dungeon, DiscoveryKind.Portal => PinCategory.Portal, DiscoveryKind.Ship => PinCategory.Ship, DiscoveryKind.Cart => PinCategory.Cart, DiscoveryKind.Pickable => PinCategory.Pickable, _ => (PinCategory)0, }; } private static float DiscoveryRadius(PinCategory category) { return category switch { PinCategory.Resource => RavenNetwork.ResourceDiscoveryRadius, PinCategory.Pickable => RavenNetwork.PickableDiscoveryRadius, PinCategory.Dungeon => RavenNetwork.DungeonDiscoveryRadius, _ => 0f, }; } private bool IsAutoCategoryEnabled(PinCategory category) { if ((category != PinCategory.Portal || !_config.AutoPinPortals.Value) && (category != PinCategory.Ship || !_config.TrackShips.Value)) { if (category == PinCategory.Cart) { return _config.TrackCarts.Value; } return false; } return true; } private bool CanDiscoverResourceByRadius(PrefabDescriptor descriptor) { if (descriptor == null) { return false; } if (descriptor.IsSilver) { return RavenNetwork.SilverMode == SilverDiscoveryMode.Radius; } if (descriptor.RequiresFinder) { return RavenNetwork.AutoPinUndergroundResources; } return true; } private static bool IsNearAnyPlayer(Vector3 position, float radius) { //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_0068: 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) float num = radius * radius; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && DistanceXZSquared(((Component)localPlayer).transform.position, position) <= num) { return true; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer()) { return false; } foreach (ZNetPeer peer in instance.GetPeers()) { if (peer != null && peer.IsReady() && DistanceXZSquared(peer.m_refPos, position) <= num) { return true; } } return false; } private static bool TryResolveCanonicalLocation(string prefabName, Vector3 observedPosition, out Vector3 authoritativePosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //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_0039: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0077: 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_008a: Unknown result type (might be due to invalid IL or missing references) //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) authoritativePosition = default(Vector3); ZoneSystem instance = ZoneSystem.instance; string text = CleanPrefabName(prefabName); if ((Object)(object)instance == (Object)null || text.Length == 0) { return false; } Vector2i zone = ZoneSystem.GetZone(observedPosition); Vector2i key = default(Vector2i); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { ((Vector2i)(ref key))..ctor(zone.x + j, zone.y + i); if (instance.m_locationInstances.TryGetValue(key, out var value) && string.Equals(GetLocationPrefabName(value.m_location), text, StringComparison.OrdinalIgnoreCase) && !(DistanceXZSquared(value.m_position, observedPosition) > 16f)) { authoritativePosition = value.m_position; return true; } } } return false; } private static string GetLocationPrefabName(ZoneLocation location) { if (location == null) { return string.Empty; } string text = CleanPrefabName(location.m_prefabName); if (text.Length == 0) { return CleanPrefabName(location.m_prefab.Name); } return text; } private static Biome ResolveBiome(Vector3 position) { //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) if (WorldGenerator.instance == null) { return (Biome)0; } return WorldGenerator.instance.GetBiome(position); } private static Biome FirstBiome(Biome biomes) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Expected I4, but got Unknown int num = (int)biomes; if (num == 0) { return (Biome)0; } return (Biome)(num & -num); } private static long CellKey(int x, int z) { return ((long)x << 32) ^ (uint)z; } private static float DistanceXZSquared(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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; } private static string CleanPrefabName(string value) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } string text = value.Trim(); if (!text.EndsWith("(Clone)", StringComparison.Ordinal)) { return text; } return text.Substring(0, text.Length - "(Clone)".Length).TrimEnd(' ', '\t', '\r', '\n'); } } internal sealed class DungeonDiagnosticIndex { private sealed class Entry { internal string Id; internal string Semantic; internal Vector3 Position; internal long Cell; internal DungeonDiagnosticSnapshot Snapshot; } private const float CellSize = 32f; private readonly Dictionary _entries = new Dictionary(StringComparer.Ordinal); private readonly Dictionary> _spatial = new Dictionary>(); internal DungeonDiagnosticSnapshot GetOrCreate(string dungeonId, string prefab, Vector3 position) { //IL_001f: 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_004b: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: 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) if (string.IsNullOrEmpty(dungeonId)) { throw new ArgumentException("Dungeon diagnostic identity is required.", "dungeonId"); } string text = RavenIds.Normalize(prefab); long num = CellFor(position); if (!_entries.TryGetValue(dungeonId, out var value)) { value = new Entry { Id = dungeonId, Semantic = text, Position = position, Cell = num, Snapshot = new DungeonDiagnosticSnapshot { DungeonId = dungeonId } }; _entries.Add(dungeonId, value); Index(value); return value.Snapshot; } if (value.Cell != num || !string.Equals(value.Semantic, text, StringComparison.Ordinal)) { Unindex(value); value.Semantic = text; value.Position = position; value.Cell = num; Index(value); } else { value.Position = position; } return value.Snapshot; } internal bool TryGet(string dungeonId, out DungeonDiagnosticSnapshot snapshot) { snapshot = null; if (string.IsNullOrEmpty(dungeonId) || !_entries.TryGetValue(dungeonId, out var value)) { return false; } snapshot = value.Snapshot.Clone(); return true; } internal bool TryGet(PinRecord canonical, float dedupeDistance, out DungeonDiagnosticSnapshot snapshot) { //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) snapshot = null; if (canonical == null || canonical.Category != PinCategory.Dungeon) { return false; } if (TryGet(canonical.SourceId, out snapshot) || (!string.Equals(canonical.Id, canonical.SourceId, StringComparison.Ordinal) && TryGet(canonical.Id, out snapshot))) { return true; } string text = RavenIds.Normalize(canonical.Prefab); if (text.Length == 0) { return false; } float num = Mathf.Max(0.1f, dedupeDistance); float num2 = num * num; int num3 = Mathf.FloorToInt((canonical.Position.x - num) / 32f); int num4 = Mathf.FloorToInt((canonical.Position.x + num) / 32f); int num5 = Mathf.FloorToInt((canonical.Position.z - num) / 32f); int num6 = Mathf.FloorToInt((canonical.Position.z + num) / 32f); Entry entry = null; float num7 = num2; for (int i = num3; i <= num4; i++) { for (int j = num5; j <= num6; j++) { if (!_spatial.TryGetValue(CellKey(i, j), out var value)) { continue; } for (int k = 0; k < value.Count; k++) { if (_entries.TryGetValue(value[k], out var value2) && string.Equals(value2.Semantic, text, StringComparison.Ordinal)) { float num8 = DistanceXZSquared(value2.Position, canonical.Position); if (!(num8 > num2) && (entry == null || !(num8 > num7)) && (entry == null || !Mathf.Approximately(num8, num7) || string.CompareOrdinal(value2.Id, entry.Id) < 0)) { entry = value2; num7 = num8; } } } } } if (entry == null) { return false; } snapshot = entry.Snapshot.Clone(); return true; } internal bool Remove(string dungeonId) { if (string.IsNullOrEmpty(dungeonId) || !_entries.TryGetValue(dungeonId, out var value)) { return false; } Unindex(value); return _entries.Remove(dungeonId); } internal void Clear() { _entries.Clear(); _spatial.Clear(); } private void Index(Entry entry) { if (!_spatial.TryGetValue(entry.Cell, out var value)) { value = new List(2); _spatial.Add(entry.Cell, value); } value.Add(entry.Id); } private void Unindex(Entry entry) { if (_spatial.TryGetValue(entry.Cell, out var value)) { value.Remove(entry.Id); if (value.Count == 0) { _spatial.Remove(entry.Cell); } } } private static long CellFor(Vector3 position) { //IL_0000: 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) return CellKey(Mathf.FloorToInt(position.x / 32f), Mathf.FloorToInt(position.z / 32f)); } private static long CellKey(int x, int z) { return ((long)x << 32) ^ (uint)z; } private static float DistanceXZSquared(Vector3 left, Vector3 right) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = left.x - right.x; float num2 = left.z - right.z; return num * num + num2 * num2; } } internal enum DungeonSubjectKind : byte { Enemy = 1, Chest, RespawnSource } internal static class DungeonSubjectIdentity { private const float Quantization = 4f; internal static string ForObject(DungeonSubjectKind kind, GameObject gameObject, ZDO zdo) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((zdo != null) ? zdo.GetPosition() : (((Object)(object)gameObject != (Object)null) ? gameObject.transform.position : Vector3.zero)); int prefabHash = ((zdo != null) ? zdo.GetPrefab() : (((Object)(object)gameObject != (Object)null) ? StringExtensionMethods.GetStableHashCode(Utils.GetPrefabName(gameObject)) : 0)); return ForPosition(kind, prefabHash, position); } internal static string ForPosition(DungeonSubjectKind kind, int prefabHash, Vector3 position) { //IL_0007: 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_002b: Unknown result type (might be due to invalid IL or missing references) char c = Marker(kind); int num = Mathf.RoundToInt(position.x * 4f); int num2 = Mathf.RoundToInt(position.y * 4f); int num3 = Mathf.RoundToInt(position.z * 4f); string[] obj = new string[10] { "ds", c.ToString(), ":", null, null, null, null, null, null, null }; uint num4 = (uint)prefabHash; obj[3] = num4.ToString("X8", CultureInfo.InvariantCulture); obj[4] = ":"; obj[5] = num.ToString(CultureInfo.InvariantCulture); obj[6] = ":"; obj[7] = num2.ToString(CultureInfo.InvariantCulture); obj[8] = ":"; obj[9] = num3.ToString(CultureInfo.InvariantCulture); return string.Concat(obj); } internal static bool TryParse(string value, out DungeonSubjectKind kind, out int prefabHash, out Vector3 position) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) kind = (DungeonSubjectKind)0; prefabHash = 0; position = default(Vector3); if (string.IsNullOrEmpty(value) || value.Length > 160) { return false; } string[] array = value.Split(new char[1] { ':' }, StringSplitOptions.None); if (array.Length != 5 || array[0].Length != 3 || array[0][0] != 'd' || array[0][1] != 's' || !TryKind(array[0][2], out kind) || !uint.TryParse(array[1], NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) || !int.TryParse(array[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) || !int.TryParse(array[4], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result4)) { kind = (DungeonSubjectKind)0; return false; } if (Math.Abs((long)result2) > 100000 || Math.Abs((long)result3) > 100000 || Math.Abs((long)result4) > 100000) { kind = (DungeonSubjectKind)0; return false; } prefabHash = (int)result; position = new Vector3((float)result2 / 4f, (float)result3 / 4f, (float)result4 / 4f); return true; } private static char Marker(DungeonSubjectKind kind) { return kind switch { DungeonSubjectKind.Enemy => 'e', DungeonSubjectKind.Chest => 'c', DungeonSubjectKind.RespawnSource => 's', _ => throw new ArgumentOutOfRangeException("kind"), }; } private static bool TryKind(char marker, out DungeonSubjectKind kind) { switch (marker) { case 'e': kind = DungeonSubjectKind.Enemy; return true; case 'c': kind = DungeonSubjectKind.Chest; return true; case 's': kind = DungeonSubjectKind.RespawnSource; return true; default: kind = (DungeonSubjectKind)0; return false; } } } internal static class DungeonGenerationIdentity { internal const string EpochZdoKey = "dragonmotion.ravenmap.dungeon_epoch"; internal const string CllcRegenerationZdoKey = "cllc DungeonRegen"; private const ulong FnvOffset = 14695981039346656037uL; private const ulong FnvPrime = 1099511628211uL; internal static void PrepareAuthoritativeEpoch(DungeonGenerator generator, SpawnMode mode) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 if ((Object)(object)generator == (Object)null || (int)mode == 1 || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } ZDO zdo = GetZdo(((Component)generator).gameObject); if (zdo != null) { long num = Math.Max(0L, zdo.GetLong("dragonmotion.ravenmap.dungeon_epoch", 0L)); long ticks = ZNet.instance.GetTime().Ticks; if (ticks <= 0) { ticks = DateTime.UtcNow.Ticks; } long val = ((num >= 9223372036854775806L) ? 1 : (num + 1)); zdo.Set("dragonmotion.ravenmap.dungeon_epoch", Math.Max(val, ticks)); } } internal static string GetToken(DungeonGenerator generator, int fallbackSeed = 0) { ZDO val = (((Object)(object)generator != (Object)null) ? GetZdo(((Component)generator).gameObject) : null); if (val == null) { return "static:seed:" + fallbackSeed.ToString(CultureInfo.InvariantCulture); } long num = val.GetLong("dragonmotion.ravenmap.dungeon_epoch", 0L); if (num > 0) { return "epoch:" + num.ToString(CultureInfo.InvariantCulture); } long num2 = val.GetLong("cllc DungeonRegen", 0L); if (num2 > 0) { return "cllc:" + num2.ToString(CultureInfo.InvariantCulture); } byte[] array = default(byte[]); if (val.GetByteArray(ZDOVars.s_roomData, ref array) && array != null && array.Length >= 4) { return "rooms:" + Math.Max(0, BitConverter.ToInt32(array, 0)).ToString(CultureInfo.InvariantCulture) + ":" + Fnv1A64(array).ToString("X16", CultureInfo.InvariantCulture); } int num3 = Math.Max(0, val.GetInt(ZDOVars.s_rooms, 0)); return "static:" + ((object)Unsafe.As(ref val.m_uid)/*cast due to .constrained prefix*/).ToString() + ":" + num3.ToString(CultureInfo.InvariantCulture); } internal static int GetRoomCount(DungeonGenerator generator) { ZDO val = (((Object)(object)generator != (Object)null) ? GetZdo(((Component)generator).gameObject) : null); if (val == null) { return 0; } byte[] array = default(byte[]); if (val.GetByteArray(ZDOVars.s_roomData, ref array) && array != null && array.Length >= 4) { return Math.Max(0, BitConverter.ToInt32(array, 0)); } return Math.Max(0, val.GetInt(ZDOVars.s_rooms, 0)); } internal static ulong Fnv1A64(byte[] value) { ulong num = 14695981039346656037uL; if (value == null) { return num; } for (int i = 0; i < value.Length; i++) { num ^= value[i]; num *= 1099511628211L; } return num; } internal static bool IsLegacyGeneratorToken(string token) { if (!string.IsNullOrEmpty(token)) { return token.StartsWith("generator:", StringComparison.Ordinal); } return false; } internal static bool IsRoomFingerprintToken(string token) { if (!string.IsNullOrEmpty(token)) { return token.StartsWith("rooms:", StringComparison.Ordinal); } return false; } private static ZDO GetZdo(GameObject gameObject) { ZNetView val = (((Object)(object)gameObject != (Object)null) ? (gameObject.GetComponent() ?? gameObject.GetComponentInParent()) : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetZDO(); } } internal sealed class DungeonDiagnosticSnapshot { internal string DungeonId = string.Empty; internal string Prefab = string.Empty; internal string GenerationToken = string.Empty; internal string BlockerCode = "not-observed"; internal bool CensusPending; internal bool CensusSettled; internal bool AreaReady; internal bool ChestStateReady; internal bool PlayerInside; internal bool Entered; internal int ReadinessAttempts; internal int EnemiesTotal; internal int EnemiesAlive; internal int EnemiesDefeated; internal int EnemiesKilled; internal int EnemiesResolved; internal int EnemiesInactive; internal int EnemiesMissing; internal int ChestsTotal; internal int ChestsPresent; internal int ChestsReady; internal int ChestsNonEmpty; internal int ChestsEmpty; internal int ChestsUnresolved; internal int ChestsInspected; internal int ChestsResolved; internal int ChestsInactive; internal int ChestsMissing; internal string EntryStageCode = "not-observed"; internal int EntrySignalsSent; internal DungeonDiagnosticSnapshot Clone() { return (DungeonDiagnosticSnapshot)MemberwiseClone(); } } internal sealed class DungeonTracker { private sealed class DungeonContext { internal readonly string Id; internal readonly string PrefabName; internal readonly Vector3 Position; internal readonly bool IsInterior; internal DungeonContext(string id, string prefabName, Vector3 position, bool isInterior) { //IL_0015: 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) Id = id; PrefabName = prefabName; Position = position; IsInterior = isInterior; } } private sealed class DungeonObservationState { internal readonly HashSet RegisteredEnemies = new HashSet(StringComparer.Ordinal); internal readonly HashSet KilledEnemies = new HashSet(StringComparer.Ordinal); internal readonly HashSet ResolvedEnemies = new HashSet(StringComparer.Ordinal); internal readonly Dictionary> EnemyCharacters = new Dictionary>(StringComparer.Ordinal); internal readonly HashSet RegisteredChests = new HashSet(StringComparer.Ordinal); internal readonly HashSet InspectedChests = new HashSet(StringComparer.Ordinal); internal readonly HashSet ResolvedChests = new HashSet(StringComparer.Ordinal); internal readonly Dictionary> ChestContainers = new Dictionary>(StringComparer.Ordinal); internal readonly HashSet ObservedRespawnSubjects = new HashSet(StringComparer.Ordinal); internal readonly Dictionary RespawnSignals = new Dictionary(StringComparer.Ordinal); internal readonly Dictionary LastEnemyZdo = new Dictionary(StringComparer.Ordinal); internal readonly HashSet RememberedSubjects = new HashSet(StringComparer.Ordinal); internal readonly HashSet SubjectZdos = new HashSet(); internal string ReplayedGenerationToken = string.Empty; internal int SubmittedRoomCount; internal bool Entered; } private sealed class SubjectObservation { internal readonly string SubjectId; internal readonly DungeonContext Context; internal readonly DungeonSubjectKind Kind; internal readonly Vector3 Position; internal float UnloadExpiresAt; internal SubjectObservation(string subjectId, DungeonContext context, DungeonSubjectKind kind, Vector3 position) { //IL_001c: 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) SubjectId = subjectId; Context = context; Kind = kind; Position = position; } } private sealed class CensusState { internal readonly DungeonContext Context; internal Vector3 ObservationPosition; internal float Deadline; internal int ReadinessAttempts; internal int FailureAttempts; internal bool FailureLogged; internal int Revision; internal CensusState(DungeonContext context) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) Context = context; ObservationPosition = context.Position; } } private struct EnemyCensus { internal int Alive; internal int Dead; internal int Inactive; internal int Missing; } private struct ChestCensus { internal int Present; internal int Ready; internal int NonEmpty; internal int Empty; internal int Unresolved; internal int Inactive; internal int Missing; } private const string CllcPluginGuid = "org.bepinex.plugins.creaturelevelcontrol"; private const string CllcCreatureSection = "2 - Creatures"; private const string CllcLootSection = "3 - Loot"; private const string CllcDungeonCreatureKey = "Time until creatures in dungeons respawn in minutes (0 means disabled, 30 is one ingame day)"; private const string CllcCampCreatureKey = "Time until creatures in camps respawn in minutes (0 means disabled, 30 is one ingame day)"; private const string CllcDungeonLootKey = "Time until items in dungeons respawn in minutes (0 means disabled, 30 is one ingame day)"; private const int CensusReadinessAttempts = 8; private const float CensusReadinessRetrySeconds = 0.75f; private const float CensusFailureRetryInitialSeconds = 0.5f; private const float CensusFailureRetryMaximumSeconds = 5f; private const int CensusFailureLimit = 6; private const float DestroyedZdoCorrelationSeconds = 2f; private const float DungeonArrivalProbeSeconds = 0.1f; private const float DungeonArrivalTimeoutSeconds = 75f; private const float DungeonEntryMaximumHorizontalDistance = 512f; private const float DungeonArrivalMaximumHorizontalError = 16f; private const float DungeonArrivalMaximumVerticalError = 128f; private const int SynchronizedEntrySignalCount = 2; private static FieldRef _containerLoading; private static FieldRef _containerLastRevision; private static bool _containerAccessProbed; private readonly RavenMapPlugin _plugin; private readonly ModConfig _config; private readonly Action _submit; private readonly Action _diagnosticChanged; private readonly PrefabClassifier _classifier; private readonly Dictionary _contextsBySubject = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _generationTokens = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _generators = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _observations = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _subjectsByZdo = new Dictionary(); private readonly Dictionary _pendingSubjectUnloads = new Dictionary(); private readonly List _expiredSubjectUnloadIds = new List(); private readonly Dictionary _dirtyCensus = new Dictionary(StringComparer.Ordinal); private readonly DungeonDiagnosticIndex _diagnostics = new DungeonDiagnosticIndex(); private ConfigEntry _cllcDungeonCreatureRespawn; private ConfigEntry _cllcCampCreatureRespawn; private ConfigEntry _cllcDungeonLootRespawn; private bool _cllcUnavailable; private float _nextCllcProbeTime; private Coroutine _censusRoutine; private Coroutine _subjectUnloadRoutine; private Coroutine _entryConfirmationRoutine; private DungeonContext _pendingEntryContext; private int _pendingEntryAttempt; private int _pendingEntrySignalsRemaining; private bool _pendingEntryArrivalObserved; private bool _lastReferenceWasInterior; private bool _diagnosticCallbackFailureLogged; private bool _areaReadyFailureLogged; private bool _submitFailureLogged; internal DungeonTracker(RavenMapPlugin plugin, ModConfig config, PrefabClassifier classifier, Action submit, Action diagnosticChanged) { _plugin = plugin ?? throw new ArgumentNullException("plugin"); _config = config ?? throw new ArgumentNullException("config"); _classifier = classifier ?? throw new ArgumentNullException("classifier"); _submit = submit ?? throw new ArgumentNullException("submit"); _diagnosticChanged = diagnosticChanged ?? throw new ArgumentNullException("diagnosticChanged"); TryResolveCllcConfig(); } internal void ObserveNetworkObject(GameObject gameObject) { //IL_01d9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gameObject == (Object)null || !TryResolveDungeon(gameObject, out var context)) { return; } bool flag = false; Character component = gameObject.GetComponent(); if ((Object)(object)component != (Object)null && IsPotentialDungeonEnemy(component)) { ZDO zdo = TryGetZdo(((Component)component).gameObject); string subjectId = DungeonSubjectIdentity.ForObject(DungeonSubjectKind.Enemy, ((Component)component).gameObject, zdo); RememberSubject(subjectId, context, zdo, DungeonSubjectKind.Enemy); RememberEnemyCharacter(context, subjectId, component); if (IsTrackableEnemy(component)) { bool flag2 = component.GetHealth() <= 0f; RegisterEnemy(context, subjectId, zdo, !flag2); if (flag2) { KillEnemy(context, subjectId); } } flag = true; } Container component2 = gameObject.GetComponent(); if ((Object)(object)component2 != (Object)null && IsTrackableChest(component2)) { ZDO zdo2 = TryGetContainerZdo(component2); string subjectId2 = DungeonSubjectIdentity.ForObject(DungeonSubjectKind.Chest, ((Component)component2).gameObject, zdo2); RememberSubject(subjectId2, context, zdo2, DungeonSubjectKind.Chest); RegisterChest(context, subjectId2); RememberChestContainer(context, subjectId2, component2); flag = true; } CreatureSpawner component3 = gameObject.GetComponent(); if ((Object)(object)component3 != (Object)null) { ZDO zdo3 = TryGetZdo(gameObject); string text = DungeonSubjectIdentity.ForObject(DungeonSubjectKind.RespawnSource, gameObject, zdo3); RememberSubject(text, context, zdo3, DungeonSubjectKind.RespawnSource); int minutes = EffectiveRespawnMinutes(context, Mathf.CeilToInt(Mathf.Max(0f, component3.m_respawnTimeMinuts))); SignalRespawn(context, text, minutes); flag = true; } SpawnArea component4 = gameObject.GetComponent(); if ((Object)(object)component4 != (Object)null) { ZDO zdo4 = TryGetZdo(gameObject); string text2 = DungeonSubjectIdentity.ForObject(DungeonSubjectKind.RespawnSource, gameObject, zdo4); RememberSubject(text2, context, zdo4, DungeonSubjectKind.RespawnSource); int observedMinutes = Mathf.Max(1, Mathf.CeilToInt(Mathf.Max(0f, component4.m_spawnIntervalSec) / 60f)); SignalRespawn(context, text2, EffectiveRespawnMinutes(context, observedMinutes)); flag = true; } DungeonGenerator component5 = gameObject.GetComponent(); if ((Object)(object)component5 != (Object)null) { OnDungeonGenerated(component5); flag = true; } if (flag) { MarkCensusDirty(context, gameObject.transform.position); } } internal void OnCharacterDied(Character character) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)character == (Object)null) && IsTrackableEnemy(character)) { ZDO zdo = TryGetZdo(((Component)character).gameObject); string subjectId = DungeonSubjectIdentity.ForObject(DungeonSubjectKind.Enemy, ((Component)character).gameObject, zdo); if (TryGetRememberedContext(subjectId, out var context) || TryResolveDungeon(((Component)character).gameObject, out context)) { RememberSubject(subjectId, context, zdo, DungeonSubjectKind.Enemy); RememberEnemyCharacter(context, subjectId, character); RegisterEnemy(context, subjectId, zdo, liveObservation: false); KillEnemy(context, subjectId); MarkCensusDirty(context, ((Component)character).transform.position); } } } internal void OnContainerInspected(Container container) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)container == (Object)null || !IsTrackableChest(container)) { return; } ZDO zdo = TryGetContainerZdo(container); string text = DungeonSubjectIdentity.ForObject(DungeonSubjectKind.Chest, ((Component)container).gameObject, zdo); if (TryGetRememberedContext(text, out var context) || TryResolveDungeon(((Component)container).gameObject, out context)) { RememberSubject(text, context, zdo, DungeonSubjectKind.Chest); RegisterChest(context, text); RememberChestContainer(context, text, container); DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); if (orCreateObservation.InspectedChests.Contains(text)) { ForgetSubjectContext(context, text); } else if (TryAddBoundedSubject(orCreateObservation.InspectedChests, text)) { Submit(context.Id, DungeonEventType.ChestInspected, text, 0); ForgetSubjectContext(context, text); } MarkCensusDirty(context, ((Component)container).transform.position); } } internal void OnDungeonGenerated(DungeonGenerator generator) { ObserveGeneration(generator, ((Object)(object)generator != (Object)null) ? generator.m_generatedSeed : 0); } internal void OnDungeonGenerating(DungeonGenerator generator, int seed, SpawnMode mode) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) DungeonGenerationIdentity.PrepareAuthoritativeEpoch(generator, mode); ObserveGeneration(generator, seed); } internal void OnDungeonLoading(DungeonGenerator generator) { ObserveGeneration(generator, 0); } internal void OnPlayerTeleportStarted(Vector3 sourcePosition, Vector3 targetPosition) { //IL_0000: 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_001f: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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) if (!Character.InInterior(targetPosition)) { CancelPendingEntry("left-interior"); return; } DungeonContext context = null; if ((Character.InInterior(sourcePosition) || !TryResolveDungeon(sourcePosition, out context) || !IsReferencePositionForDungeon(targetPosition, context.Position)) && !TryResolveDungeon(targetPosition, out context)) { CancelPendingEntry("target-unresolved"); return; } CancelPendingEntry(null); _pendingEntryContext = context; _pendingEntryAttempt = ((_pendingEntryAttempt == int.MaxValue) ? 1 : (_pendingEntryAttempt + 1)); _pendingEntrySignalsRemaining = 2; _pendingEntryArrivalObserved = false; SetEntryDiagnostic(context, "teleport-started", resetSignals: true); int pendingEntryAttempt = _pendingEntryAttempt; _entryConfirmationRoutine = ((MonoBehaviour)_plugin).StartCoroutine(ConfirmDungeonArrival(context, targetPosition, pendingEntryAttempt)); } internal void OnReferencePositionSent(Vector3 referencePosition) { //IL_0000: 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_008c: 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_0054: Unknown result type (might be due to invalid IL or missing references) bool flag = referencePosition.y > 3000f; Player localPlayer = Player.m_localPlayer; bool flag2 = flag && ((Object)(object)localPlayer == (Object)null || !((Character)localPlayer).IsTeleporting()); bool flag3 = IsExteriorToInteriorEdge(_lastReferenceWasInterior, flag2); _lastReferenceWasInterior = flag2; DungeonContext context = _pendingEntryContext; if (context == null) { if (!flag3 || !TryResolveDungeon(referencePosition, out context)) { return; } _pendingEntryContext = context; _pendingEntrySignalsRemaining = 2; _pendingEntryArrivalObserved = true; SetEntryDiagnostic(context, "interior-refpos-recovered", resetSignals: true); } if (!CanConfirmPendingEntry(_pendingEntryArrivalObserved, referencePosition, context.Position)) { if (_pendingEntryArrivalObserved && !flag) { CancelPendingEntry("left-before-sync"); } return; } _pendingEntryArrivalObserved = true; ConfirmEntry(context, referencePosition, "refpos-sent"); if (--_pendingEntrySignalsRemaining <= 0) { CompletePendingEntry(context); } } internal void OnDungeonDiscovered(string dungeonId) { if (!string.IsNullOrEmpty(dungeonId)) { if (_generators.TryGetValue(dungeonId, out var value) && (Object)(object)value != (Object)null) { ObserveGeneration(value, value.m_generatedSeed, forceReplay: true); } else { ReplayDungeon(dungeonId); } } } private void ObserveGeneration(DungeonGenerator generator, int seed, bool forceReplay = false) { //IL_013c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)generator == (Object)null || !TryResolveDungeon(((Component)generator).gameObject, out var context)) { return; } _generators[context.Id] = generator; string token = DungeonGenerationIdentity.GetToken(generator, seed); string value; bool flag = _generationTokens.TryGetValue(context.Id, out value); bool flag2 = !flag || !string.Equals(value, token, StringComparison.Ordinal); if (flag2 || forceReplay) { if (!Submit(context.Id, DungeonEventType.GenerationReset, token, 0)) { return; } bool flag3 = flag2 && flag && DungeonGenerationIdentity.IsLegacyGeneratorToken(value) && DungeonGenerationIdentity.IsRoomFingerprintToken(token); if (flag2 && flag && !flag3) { ResetObservedSubjects(context.Id); } } _generationTokens[context.Id] = token; DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); int roomCount = DungeonGenerationIdentity.GetRoomCount(generator); if (roomCount > 0 && (forceReplay || orCreateObservation.SubmittedRoomCount != roomCount) && Submit(context.Id, DungeonEventType.RoomCount, token, roomCount)) { orCreateObservation.SubmittedRoomCount = roomCount; } if (forceReplay || !string.Equals(orCreateObservation.ReplayedGenerationToken, token, StringComparison.Ordinal)) { ReplayDungeon(context.Id); orCreateObservation.ReplayedGenerationToken = token; } SignalRespawn(context, "cfg:cllc", EffectiveRespawnMinutes(context, 0)); MarkCensusDirty(context, ((Component)generator).transform.position); } internal void Clear() { ClearObservedState(clearGenerators: true); } internal void ResetForRediscovery() { ClearObservedState(clearGenerators: false); } internal bool TryGetDiagnostic(PinRecord canonical, out DungeonDiagnosticSnapshot snapshot) { return _diagnostics.TryGet(canonical, RavenNetwork.DungeonDedupeDistance, out snapshot); } private void ClearObservedState(bool clearGenerators) { if (_censusRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_censusRoutine); _censusRoutine = null; } if (_subjectUnloadRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_subjectUnloadRoutine); _subjectUnloadRoutine = null; } if (_entryConfirmationRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_entryConfirmationRoutine); _entryConfirmationRoutine = null; } _pendingEntryContext = null; _pendingEntrySignalsRemaining = 0; _pendingEntryArrivalObserved = false; _lastReferenceWasInterior = false; _contextsBySubject.Clear(); _generationTokens.Clear(); if (clearGenerators) { _generators.Clear(); } else { string[] array = (from pair in _generators where (Object)(object)pair.Value == (Object)null select pair.Key).ToArray(); for (int num = 0; num < array.Length; num++) { _generators.Remove(array[num]); } } _observations.Clear(); _subjectsByZdo.Clear(); _pendingSubjectUnloads.Clear(); _expiredSubjectUnloadIds.Clear(); _dirtyCensus.Clear(); _diagnostics.Clear(); _diagnosticCallbackFailureLogged = false; _areaReadyFailureLogged = false; _submitFailureLogged = false; } internal void RefreshConfiguration() { _classifier.RefreshRuleSets(); } internal void OnSubjectUnloaded(ZDOID id) { //IL_0006: 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_003b: Unknown result type (might be due to invalid IL or missing references) if (_subjectsByZdo.TryGetValue(id, out var value)) { ForgetLoadedSubjectReferences(value); _subjectsByZdo.Remove(id); value.UnloadExpiresAt = Time.unscaledTime + 2f; _pendingSubjectUnloads[id] = value; if (_subjectUnloadRoutine == null) { _subjectUnloadRoutine = ((MonoBehaviour)_plugin).StartCoroutine(ExpireSubjectUnloads()); } } } internal void OnSubjectDestroyed(ZDOID id) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_005a: 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_0124: Unknown result type (might be due to invalid IL or missing references) if (!_subjectsByZdo.TryGetValue(id, out var value) && !_pendingSubjectUnloads.TryGetValue(id, out value)) { return; } _subjectsByZdo.Remove(id); _pendingSubjectUnloads.Remove(id); ForgetLoadedSubjectReferences(value); DungeonObservationState orCreateObservation = GetOrCreateObservation(value.Context.Id); orCreateObservation.SubjectZdos.Remove(id); switch (value.Kind) { case DungeonSubjectKind.Enemy: if (!orCreateObservation.KilledEnemies.Contains(value.SubjectId) && TryAddBoundedSubject(orCreateObservation.ResolvedEnemies, value.SubjectId)) { Submit(value.Context.Id, DungeonEventType.EnemyResolved, value.SubjectId, 0); } break; case DungeonSubjectKind.Chest: if (!orCreateObservation.InspectedChests.Contains(value.SubjectId) && TryAddBoundedSubject(orCreateObservation.ResolvedChests, value.SubjectId)) { Submit(value.Context.Id, DungeonEventType.ChestResolved, value.SubjectId, 0); } break; case DungeonSubjectKind.RespawnSource: SignalRespawn(value.Context, value.SubjectId, 0); break; } MarkCensusDirty(value.Context, value.Position); } private void ForgetLoadedSubjectReferences(SubjectObservation subject) { ForgetSubjectContext(subject.Context, subject.SubjectId); if (_observations.TryGetValue(subject.Context.Id, out var value)) { if (subject.Kind == DungeonSubjectKind.Chest) { value.ChestContainers.Remove(subject.SubjectId); } else if (subject.Kind == DungeonSubjectKind.Enemy) { value.EnemyCharacters.Remove(subject.SubjectId); } } } private IEnumerator ExpireSubjectUnloads() { try { while (_pendingSubjectUnloads.Count > 0) { _expiredSubjectUnloadIds.Clear(); float unscaledTime = Time.unscaledTime; float num = float.PositiveInfinity; foreach (KeyValuePair pendingSubjectUnload in _pendingSubjectUnloads) { float unloadExpiresAt = pendingSubjectUnload.Value.UnloadExpiresAt; if (unloadExpiresAt <= unscaledTime) { _expiredSubjectUnloadIds.Add(pendingSubjectUnload.Key); } else if (unloadExpiresAt < num) { num = unloadExpiresAt; } } for (int i = 0; i < _expiredSubjectUnloadIds.Count; i++) { ZDOID val = _expiredSubjectUnloadIds[i]; if (_pendingSubjectUnloads.TryGetValue(val, out var value) && !(value.UnloadExpiresAt > unscaledTime)) { if (_observations.TryGetValue(value.Context.Id, out var value2)) { value2.SubjectZdos.Remove(val); } _pendingSubjectUnloads.Remove(val); } } if (_pendingSubjectUnloads.Count > 0) { float num2 = (float.IsPositiveInfinity(num) ? 2f : (num - Time.unscaledTime)); yield return (object)new WaitForSecondsRealtime(Mathf.Clamp(num2, 0.05f, 2f)); } } } finally { DungeonTracker dungeonTracker = this; dungeonTracker._expiredSubjectUnloadIds.Clear(); dungeonTracker._subjectUnloadRoutine = null; } } internal void OnGeneratorDestroyed(DungeonGenerator generator) { if ((Object)(object)generator == (Object)null) { return; } List list = new List(); foreach (KeyValuePair generator2 in _generators) { if ((Object)(object)generator2.Value == (Object)(object)generator) { list.Add(generator2.Key); } } for (int i = 0; i < list.Count; i++) { _generators.Remove(list[i]); } } private void RegisterEnemy(DungeonContext context, string subjectId, ZDO zdo, bool liveObservation) { //IL_0062: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_009c: Unknown result type (might be due to invalid IL or missing references) DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); bool flag = orCreateObservation.RegisteredEnemies.Contains(subjectId); if (flag || TryAddBoundedSubject(orCreateObservation.RegisteredEnemies, subjectId)) { bool flag2 = liveObservation && (orCreateObservation.KilledEnemies.Remove(subjectId) | orCreateObservation.ResolvedEnemies.Remove(subjectId)); bool flag3 = zdo != null; ZDOID val = (ZDOID)(flag3 ? zdo.m_uid : default(ZDOID)); ZDOID value; bool flag4 = liveObservation && flag && flag3 && orCreateObservation.LastEnemyZdo.TryGetValue(subjectId, out value) && !((ZDOID)(ref value)).Equals(val); if (flag3) { orCreateObservation.LastEnemyZdo[subjectId] = val; } if (!flag) { Submit(context.Id, DungeonEventType.RegisterEnemy, subjectId, liveObservation ? 2 : 0); } else if (flag4 || flag2) { Submit(context.Id, DungeonEventType.RegisterEnemy, subjectId, 1); } } } private void KillEnemy(DungeonContext context, string subjectId) { DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); if (orCreateObservation.KilledEnemies.Contains(subjectId)) { ForgetSubjectContext(context, subjectId); } else if (TryAddBoundedSubject(orCreateObservation.KilledEnemies, subjectId)) { Submit(context.Id, DungeonEventType.EnemyKilled, subjectId, 0); ForgetSubjectContext(context, subjectId); } } private void ResolveEnemy(DungeonContext context, string subjectId) { DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); if (!orCreateObservation.KilledEnemies.Contains(subjectId) && !orCreateObservation.ResolvedEnemies.Contains(subjectId) && TryAddBoundedSubject(orCreateObservation.ResolvedEnemies, subjectId)) { Submit(context.Id, DungeonEventType.EnemyResolved, subjectId, 0); } } private void ResolveChest(DungeonContext context, string subjectId) { DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); if (!orCreateObservation.InspectedChests.Contains(subjectId) && !orCreateObservation.ResolvedChests.Contains(subjectId) && TryAddBoundedSubject(orCreateObservation.ResolvedChests, subjectId)) { Submit(context.Id, DungeonEventType.ChestResolved, subjectId, 0); } } private void RegisterChest(DungeonContext context, string subjectId) { DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); if (!orCreateObservation.RegisteredChests.Contains(subjectId) && TryAddBoundedSubject(orCreateObservation.RegisteredChests, subjectId)) { Submit(context.Id, DungeonEventType.RegisterChest, subjectId, 0); } } private void RememberChestContainer(DungeonContext context, string subjectId, Container container) { if (context != null && !string.IsNullOrEmpty(subjectId) && !((Object)(object)container == (Object)null)) { DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); if (orCreateObservation.ChestContainers.ContainsKey(subjectId) || orCreateObservation.ChestContainers.Count < 256) { orCreateObservation.ChestContainers[subjectId] = new WeakReference(container); } } } private void RememberEnemyCharacter(DungeonContext context, string subjectId, Character character) { if (context != null && !string.IsNullOrEmpty(subjectId) && !((Object)(object)character == (Object)null)) { DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); if (orCreateObservation.EnemyCharacters.ContainsKey(subjectId) || orCreateObservation.EnemyCharacters.Count < 256) { orCreateObservation.EnemyCharacters[subjectId] = new WeakReference(character); } } } private void ResolveKnownEnemyStates(DungeonContext context, bool canResolveAbsent, ref EnemyCensus census) { if (!_observations.TryGetValue(context.Id, out var value)) { return; } List list = null; foreach (KeyValuePair> enemyCharacter in value.EnemyCharacters) { string key = enemyCharacter.Key; bool flag = value.RegisteredEnemies.Contains(key); if (!enemyCharacter.Value.TryGetTarget(out var target) || (Object)(object)target == (Object)null) { census.Missing++; if (canResolveAbsent && flag) { ResolveEnemy(context, key); } ForgetSubjectContext(context, key); if (list == null) { list = new List(); } list.Add(key); } else if (target.GetHealth() <= 0f) { census.Dead++; if (flag) { KillEnemy(context, key); } } else if (!((Behaviour)target).isActiveAndEnabled || !((Component)target).gameObject.activeInHierarchy || !IsTrackableEnemy(target)) { census.Inactive++; if (canResolveAbsent && flag) { ResolveEnemy(context, key); } } else { census.Alive++; RegisterEnemy(context, key, TryGetZdo(((Component)target).gameObject), liveObservation: true); } } if (list != null) { for (int i = 0; i < list.Count; i++) { value.EnemyCharacters.Remove(list[i]); } } } private bool ResolveKnownChestStates(DungeonContext context, bool canResolveAbsent, ref ChestCensus census) { if (!_observations.TryGetValue(context.Id, out var value)) { return true; } bool result = true; List list = null; foreach (KeyValuePair> chestContainer in value.ChestContainers) { if (!chestContainer.Value.TryGetTarget(out var target) || (Object)(object)target == (Object)null) { census.Missing++; if (canResolveAbsent) { ResolveChest(context, chestContainer.Key); } else { result = false; } ForgetSubjectContext(context, chestContainer.Key); if (list == null) { list = new List(); } list.Add(chestContainer.Key); continue; } if (!((Behaviour)target).isActiveAndEnabled || !((Component)target).gameObject.activeInHierarchy) { census.Inactive++; if (canResolveAbsent) { ResolveChest(context, chestContainer.Key); } else { result = false; } continue; } census.Present++; Inventory inventory = target.GetInventory(); if (inventory == null || !IsContainerInventoryReady(target)) { result = false; continue; } census.Ready++; if (inventory.NrOfItems() != 0) { census.NonEmpty++; if (!value.InspectedChests.Contains(chestContainer.Key) && !value.ResolvedChests.Contains(chestContainer.Key)) { census.Unresolved++; } } else { census.Empty++; ResolveChest(context, chestContainer.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { value.ChestContainers.Remove(list[i]); } } return result; } private static bool IsContainerInventoryReady(Container container) { if (!_containerAccessProbed) { _containerAccessProbed = true; try { _containerLoading = AccessTools.FieldRefAccess("m_loading"); _containerLastRevision = AccessTools.FieldRefAccess("m_lastRevision"); } catch (Exception ex) { ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("Could not create cached Container inventory-state accessors: " + ex.Message)); } } } if ((Object)(object)container == (Object)null || _containerLoading == null || _containerLastRevision == null) { return false; } try { return !_containerLoading.Invoke(container) && _containerLastRevision.Invoke(container) != uint.MaxValue; } catch (Exception ex2) { _containerLoading = null; _containerLastRevision = null; ManualLogSource log2 = RavenMapPlugin.Log; if (log2 != null) { log2.LogWarning((object)("Could not read loaded Container inventory state: " + ex2.Message)); } return false; } } private void SignalRespawn(DungeonContext context, string sourceId, int minutes) { string text = (string.IsNullOrEmpty(sourceId) ? "respawn" : sourceId); DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); bool flag = orCreateObservation.ObservedRespawnSubjects.Contains(text); if (!flag && !TryAddBoundedSubject(orCreateObservation.ObservedRespawnSubjects, text)) { return; } bool flag2 = !flag; int value; if (minutes <= 0) { if (orCreateObservation.RespawnSignals.Remove(text) || flag2) { Submit(context.Id, DungeonEventType.RespawnCapable, text, 0); } } else if ((!orCreateObservation.RespawnSignals.TryGetValue(text, out value) || value != minutes) && Submit(context.Id, DungeonEventType.RespawnCapable, text, minutes)) { orCreateObservation.RespawnSignals[text] = minutes; } } private int EffectiveRespawnMinutes(DungeonContext context, int observedMinutes) { TryResolveCllcConfig(); int val = ((!context.IsInterior) ? GetConfigValue(_cllcCampCreatureRespawn) : Math.Max(GetConfigValue(_cllcDungeonCreatureRespawn), GetConfigValue(_cllcDungeonLootRespawn))); return Math.Max(observedMinutes, val); } private void TryResolveCllcConfig() { if (_cllcUnavailable || _cllcDungeonCreatureRespawn != null || Time.realtimeSinceStartup < _nextCllcProbeTime) { return; } if (!Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.creaturelevelcontrol", out var value)) { _nextCllcProbeTime = Time.realtimeSinceStartup + 2f; return; } if ((Object)(object)value.Instance == (Object)null) { _nextCllcProbeTime = Time.realtimeSinceStartup + 2f; return; } ConfigFile config = value.Instance.Config; config.TryGetEntry("2 - Creatures", "Time until creatures in dungeons respawn in minutes (0 means disabled, 30 is one ingame day)", ref _cllcDungeonCreatureRespawn); config.TryGetEntry("2 - Creatures", "Time until creatures in camps respawn in minutes (0 means disabled, 30 is one ingame day)", ref _cllcCampCreatureRespawn); config.TryGetEntry("3 - Loot", "Time until items in dungeons respawn in minutes (0 means disabled, 30 is one ingame day)", ref _cllcDungeonLootRespawn); if (_cllcDungeonCreatureRespawn == null && _cllcCampCreatureRespawn == null && _cllcDungeonLootRespawn == null) { _cllcUnavailable = true; } } private bool TryResolveDungeon(GameObject gameObject, out DungeonContext context) { //IL_002e: 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_00ad: 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_00dc: Unknown result type (might be due to invalid IL or missing references) context = null; if ((Object)(object)gameObject == (Object)null) { return false; } Location val = gameObject.GetComponent() ?? gameObject.GetComponentInParent(); if ((Object)(object)val == (Object)null) { val = Location.GetLocation(gameObject.transform.position, true); } DungeonGenerator val2 = gameObject.GetComponent() ?? gameObject.GetComponentInParent(); if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null) { val = Location.GetZoneLocation(((Component)val2).transform.position); } if ((Object)(object)val == (Object)null) { return false; } bool flag = PrefabClassifier.IsDungeonStructure(val.m_hasInterior, PrefabClassifier.IsDungeonAlgorithm(val.m_generator), PrefabClassifier.IsDungeonAlgorithm(val2)); if (!TryResolveCanonicalDungeon(val, flag, out var descriptor, out var exteriorPosition)) { return false; } string id = RavenIds.ForPosition(PinCategory.Dungeon, descriptor.PrefabName, exteriorPosition); bool isInterior = flag || Character.InInterior(gameObject.transform.position); context = new DungeonContext(id, descriptor.PrefabName, exteriorPosition, isInterior); return true; } private bool TryResolveDungeon(Vector3 position, out DungeonContext context) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) context = null; Location location = Location.GetLocation(position, true); if ((Object)(object)location != (Object)null) { return TryResolveDungeon(((Component)location).gameObject, out context); } return false; } private bool TryResolveCanonicalDungeon(Location location, bool structuralDungeon, out PrefabDescriptor descriptor, out Vector3 exteriorPosition) { //IL_0009: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_007e: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: 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_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) descriptor = PrefabDescriptor.None; exteriorPosition = default(Vector3); ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)location == (Object)null || (Object)(object)instance == (Object)null) { return false; } Vector3 position = ((Component)location).transform.position; string b = CleanPrefabName(Utils.GetPrefabName(((Component)location).gameObject)); Vector2i zone = ZoneSystem.GetZone(position); LocationInstance val = default(LocationInstance); string suppliedName = string.Empty; PrefabDescriptor prefabDescriptor = null; float num = float.MaxValue; bool flag = false; bool flag2 = false; Vector2i key = default(Vector2i); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { ((Vector2i)(ref key))..ctor(zone.x + j, zone.y + i); if (!instance.m_locationInstances.TryGetValue(key, out var value)) { continue; } string locationPrefabName = GetLocationPrefabName(value.m_location); if (locationPrefabName.Length != 0) { bool flag3 = string.Equals(locationPrefabName, b, StringComparison.OrdinalIgnoreCase); PrefabDescriptor descriptor2; bool flag4 = _classifier.TryGetDungeonDescriptor(locationPrefabName, out descriptor2); bool flag5 = _classifier.IsExplicitDungeon(locationPrefabName); float num2 = DistanceXZSquared(value.m_position, position); if (!(num2 > 4096f) && (flag3 || flag4 || flag5) && (!(flag2 && flag) || flag3) && (!flag2 || flag != flag3 || !(num2 >= num)) && (structuralDungeon || flag4 || flag5)) { val = value; suppliedName = locationPrefabName; prefabDescriptor = (flag4 ? descriptor2 : null); num = num2; flag = flag3; flag2 = true; } } } } if (!flag2) { return false; } descriptor = prefabDescriptor ?? _classifier.DescribeDungeonLocation(location, suppliedName); if (descriptor.Kind != DiscoveryKind.Dungeon) { descriptor = PrefabDescriptor.None; return false; } exteriorPosition = val.m_position; return true; } private static string GetLocationPrefabName(ZoneLocation location) { if (location == null) { return string.Empty; } string text = CleanPrefabName(location.m_prefabName); if (text.Length == 0) { return CleanPrefabName(location.m_prefab.Name); } return text; } private static float DistanceXZSquared(Vector3 left, Vector3 right) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = left.x - right.x; float num2 = left.z - right.z; return num * num + num2 * num2; } private bool TryGetRememberedContext(string subjectId, out DungeonContext context) { context = null; if (!string.IsNullOrEmpty(subjectId)) { return _contextsBySubject.TryGetValue(subjectId, out context); } return false; } private void ForgetSubjectContext(DungeonContext context, string subjectId) { if (context != null && !string.IsNullOrEmpty(subjectId)) { if (_contextsBySubject.TryGetValue(subjectId, out var value) && string.Equals(value.Id, context.Id, StringComparison.Ordinal)) { _contextsBySubject.Remove(subjectId); } if (_observations.TryGetValue(context.Id, out var value2)) { value2.RememberedSubjects.Remove(subjectId); } } } private void RememberSubject(string subjectId, DungeonContext context, ZDO zdo, DungeonSubjectKind kind) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00fe: 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) //IL_0144: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) if (context == null || string.IsNullOrEmpty(subjectId)) { return; } DungeonObservationState orCreateObservation = GetOrCreateObservation(context.Id); if (kind switch { DungeonSubjectKind.Enemy => (orCreateObservation.EnemyCharacters.ContainsKey(subjectId) || orCreateObservation.EnemyCharacters.Count < 256) ? 1 : 0, DungeonSubjectKind.Chest => (orCreateObservation.ChestContainers.ContainsKey(subjectId) || orCreateObservation.ChestContainers.Count < 256) ? 1 : 0, _ => (orCreateObservation.ObservedRespawnSubjects.Contains(subjectId) || orCreateObservation.ObservedRespawnSubjects.Count < 256) ? 1 : 0, } == 0) { return; } _contextsBySubject[subjectId] = context; orCreateObservation.RememberedSubjects.Add(subjectId); if (zdo != null) { ZDOID uid = zdo.m_uid; if (_pendingSubjectUnloads.TryGetValue(uid, out var value) && _observations.TryGetValue(value.Context.Id, out var value2)) { value2.SubjectZdos.Remove(uid); } if (_subjectsByZdo.TryGetValue(uid, out var value3) && _observations.TryGetValue(value3.Context.Id, out var value4)) { value4.SubjectZdos.Remove(uid); } _pendingSubjectUnloads.Remove(uid); orCreateObservation.SubjectZdos.Add(uid); _subjectsByZdo[uid] = new SubjectObservation(subjectId, context, kind, zdo.GetPosition()); } } private static bool IsPotentialDungeonEnemy(Character character) { //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_0019: 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_001f: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Invalid comparison between Unknown and I4 if (character.IsPlayer() || character.IsTamed()) { return false; } Faction faction = character.GetFaction(); if ((int)faction != 0 && (int)faction != 11 && (int)faction != 12) { return (int)faction != 1; } return false; } private static bool IsTrackableEnemy(Character character) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if (!IsPotentialDungeonEnemy(character)) { return false; } if ((int)character.GetFaction() != 10) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { return BaseAI.IsEnemy((Character)(object)localPlayer, character); } BaseAI baseAI = character.GetBaseAI(); if ((Object)(object)baseAI != (Object)null) { return baseAI.IsAggravated(); } return false; } private static bool IsTrackableChest(Container container) { if ((Object)(object)container.m_wagon != (Object)null) { return false; } ZDO val = TryGetContainerZdo(container); if (val != null) { return val.GetLong(ZDOVars.s_creator, 0L) == 0; } return false; } private static ZDO TryGetContainerZdo(Container container) { if ((Object)(object)container.m_rootObjectOverride != (Object)null) { return container.m_rootObjectOverride.GetZDO(); } return TryGetZdo(((Component)container).gameObject); } private static ZDO TryGetZdo(GameObject gameObject) { ZNetView val = gameObject.GetComponent() ?? gameObject.GetComponentInParent(); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetZDO(); } private void ReplayDungeon(string dungeonId, bool replayEntry = true) { if (string.IsNullOrEmpty(dungeonId) || !_observations.TryGetValue(dungeonId, out var value)) { return; } ReplaySet(dungeonId, value.RegisteredEnemies, DungeonEventType.RegisterEnemy); ReplaySet(dungeonId, value.KilledEnemies, DungeonEventType.EnemyKilled); ReplaySet(dungeonId, value.ResolvedEnemies, DungeonEventType.EnemyResolved); ReplaySet(dungeonId, value.RegisteredChests, DungeonEventType.RegisterChest); ReplaySet(dungeonId, value.InspectedChests, DungeonEventType.ChestInspected); ReplaySet(dungeonId, value.ResolvedChests, DungeonEventType.ChestResolved); if (replayEntry && value.Entered) { Submit(dungeonId, DungeonEventType.DungeonEntered, string.Empty, 1); } foreach (KeyValuePair respawnSignal in value.RespawnSignals) { Submit(dungeonId, DungeonEventType.RespawnCapable, respawnSignal.Key, respawnSignal.Value); } } private void MarkCensusDirty(DungeonContext context, Vector3 observationPosition) { //IL_0053: 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) if (context != null) { float num = Mathf.Clamp(_config.DungeonCensusSettleSeconds.Value, 0.25f, 15f); if (!_dirtyCensus.TryGetValue(context.Id, out var value)) { value = new CensusState(context); _dirtyCensus.Add(context.Id, value); } value.ObservationPosition = observationPosition; value.Deadline = Time.unscaledTime + num; value.ReadinessAttempts = 0; value.Revision = ((value.Revision == int.MaxValue) ? 1 : (value.Revision + 1)); DungeonDiagnosticSnapshot orCreateDiagnostic = GetOrCreateDiagnostic(context); bool num2 = !orCreateDiagnostic.CensusPending || orCreateDiagnostic.CensusSettled || !string.Equals(orCreateDiagnostic.BlockerCode, "settling", StringComparison.Ordinal); orCreateDiagnostic.CensusPending = true; orCreateDiagnostic.CensusSettled = false; orCreateDiagnostic.BlockerCode = "settling"; if (num2) { NotifyDiagnosticChanged(context.Id); } if (_censusRoutine == null) { _censusRoutine = ((MonoBehaviour)_plugin).StartCoroutine(ProcessDirtyCensus()); } } } private IEnumerator ProcessDirtyCensus() { List scheduled = new List(); bool workerFailureLogged = false; try { while (_dirtyCensus.Count > 0) { float unscaledTime = Time.unscaledTime; float nextDelay = 5f; try { scheduled.Clear(); scheduled.AddRange(_dirtyCensus.Keys); for (int i = 0; i < scheduled.Count; i++) { string text = scheduled[i]; if (_dirtyCensus.TryGetValue(text, out var value)) { int revision = value.Revision; if (TryProcessCensusState(text, value, unscaledTime, ref nextDelay) && value.Revision == revision && _dirtyCensus.TryGetValue(text, out var value2) && value2 == value) { _dirtyCensus.Remove(text); } } } } catch (Exception ex) { nextDelay = 5f; if (!workerFailureLogged) { workerFailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("Dungeon state-check worker failed; retrying with bounded backoff: " + ex.Message)); } } } if (_dirtyCensus.Count > 0) { yield return (object)new WaitForSecondsRealtime(Mathf.Clamp(nextDelay, 0.05f, 5f)); } } } finally { _censusRoutine = null; } } private bool TryProcessCensusState(string dungeonId, CensusState state, float now, ref float nextDelay) { //IL_0030: 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) try { if (state.Deadline > now) { nextDelay = Mathf.Min(nextDelay, Mathf.Max(0.05f, state.Deadline - now)); return false; } bool flag = IsAreaReady(state.ObservationPosition) || IsAreaReady(state.Context.Position); bool flag2 = IsLocalPlayerInside(state.Context); bool canResolveAbsent = flag || (flag2 && state.ReadinessAttempts + 1 >= 8); EnemyCensus census = default(EnemyCensus); ChestCensus census2 = default(ChestCensus); ResolveKnownEnemyStates(state.Context, canResolveAbsent, ref census); bool flag3 = ResolveKnownChestStates(state.Context, canResolveAbsent, ref census2); state.FailureAttempts = 0; if (!flag || !flag3) { state.ReadinessAttempts++; if (!CanSettleCensus(flag, flag3, flag2, state.ReadinessAttempts, out var abandon)) { if (abandon) { UpdateDiagnostic(state, flag, flag3, flag2, census, census2, "readiness-abandoned", settled: false); return true; } UpdateDiagnostic(state, flag, flag3, flag2, census, census2, (!flag3) ? "chests-loading" : "area-not-ready", settled: false); state.Deadline = now + 0.75f; nextDelay = Mathf.Min(nextDelay, 0.75f); return false; } } SubmitConfirmedEntry(state.Context, flag2); ReplayDungeon(dungeonId, !flag2); int num = Math.Min(256, census.Alive); int num2 = Math.Min(256, census2.Unresolved); int value = (num & 0xFFFF) | ((num2 & 0xFFFF) << 16); bool flag4 = Submit(dungeonId, DungeonEventType.CensusSettled, string.Empty, value); string text = ((num > 0) ? "enemies-alive" : ((CountUnresolvedChests(state.Context.Id) > 0) ? "chests-unresolved" : "awaiting-server")); UpdateDiagnostic(state, flag, flag3, flag2, census, census2, flag4 ? text : "submit-failed", flag4); return true; } catch (Exception ex) { state.FailureAttempts = Math.Min(state.FailureAttempts + 1, 6); bool flag5 = CensusFailureIsTerminal(state.FailureAttempts); float num3 = CensusFailureRetryDelay(state.FailureAttempts); if (!flag5) { state.Deadline = now + num3; nextDelay = Mathf.Min(nextDelay, num3); } DungeonDiagnosticSnapshot orCreateDiagnostic = GetOrCreateDiagnostic(state.Context); bool num4 = !string.Equals(orCreateDiagnostic.BlockerCode, flag5 ? "census-error" : "census-pending", StringComparison.Ordinal) || orCreateDiagnostic.CensusPending != !flag5 || orCreateDiagnostic.CensusSettled || orCreateDiagnostic.ReadinessAttempts != state.ReadinessAttempts; orCreateDiagnostic.BlockerCode = (flag5 ? "census-error" : "census-pending"); orCreateDiagnostic.CensusPending = !flag5; orCreateDiagnostic.CensusSettled = false; orCreateDiagnostic.ReadinessAttempts = state.ReadinessAttempts; if (num4) { NotifyDiagnosticChanged(state.Context.Id); } if (!state.FailureLogged) { state.FailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("Dungeon state check for '" + dungeonId + "' failed; retrying up to " + 6 + " times with bounded backoff: " + ex.Message)); } } return flag5; } } internal static bool CensusFailureIsTerminal(int failureAttempts) { return failureAttempts >= 6; } internal static float CensusFailureRetryDelay(int failureAttempts) { int num = Math.Min(4, Math.Max(0, failureAttempts - 1)); return Math.Min(5f, 0.5f * (float)(1 << num)); } internal static bool CanSettleCensus(bool areaReady, bool chestStateReady, bool localPlayerInside, int readinessAttempts, out bool abandon) { abandon = false; if (areaReady && chestStateReady) { return true; } if (readinessAttempts < 8) { return false; } if (chestStateReady && localPlayerInside) { return true; } abandon = true; return false; } private bool IsAreaReady(Vector3 position) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) try { return (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZoneSystem.instance != (Object)null && ZNetScene.instance.IsAreaReady(position); } catch (Exception ex) { if (!_areaReadyFailureLogged) { _areaReadyFailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("Could not verify dungeon state-check readiness; further failures are suppressed for this world: " + ex.Message)); } } return false; } } internal static bool IsReferencePositionForDungeon(Vector3 referencePosition, Vector3 exteriorPosition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (referencePosition.y > 3000f) { return DistanceXZSquared(referencePosition, exteriorPosition) <= 262144f; } return false; } internal static bool IsExteriorToInteriorEdge(bool wasInterior, bool isStableInterior) { return !wasInterior && isStableInterior; } internal static bool CanConfirmPendingEntry(bool arrivalObserved, Vector3 referencePosition, Vector3 exteriorPosition) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (arrivalObserved) { return IsReferencePositionForDungeon(referencePosition, exteriorPosition); } return false; } internal static bool IsTeleportArrivalReady(bool playerExists, bool isTeleporting, Vector3 playerPosition, Vector3 targetPosition, Vector3 exteriorPosition) { //IL_0006: 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_0010: 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_001e: 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) if (playerExists && !isTeleporting && IsReferencePositionForDungeon(playerPosition, exteriorPosition) && DistanceXZSquared(playerPosition, targetPosition) <= 256f) { return Mathf.Abs(playerPosition.y - targetPosition.y) <= 128f; } return false; } private IEnumerator ConfirmDungeonArrival(DungeonContext context, Vector3 targetPosition, int attempt) { //IL_0015: 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) float deadline = Time.realtimeSinceStartup + 75f; WaitForSecondsRealtime delay = new WaitForSecondsRealtime(0.1f); try { while (attempt == _pendingEntryAttempt && _pendingEntryContext == context && Time.realtimeSinceStartup < deadline) { Player player = Player.m_localPlayer; if (IsTeleportArrivalReady((Object)(object)player != (Object)null, (Object)(object)player != (Object)null && ((Character)player).IsTeleporting(), (Vector3)(((Object)(object)player != (Object)null) ? ((Component)player).transform.position : default(Vector3)), targetPosition, context.Position)) { Vector3 position = ((Component)player).transform.position; _pendingEntryArrivalObserved = true; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { ConfirmEntry(context, position, "host-arrived"); yield return (object)new WaitForSecondsRealtime(0.25f); if (attempt == _pendingEntryAttempt && _pendingEntryContext == context && (Object)(object)player != (Object)null && IsTeleportArrivalReady(playerExists: true, ((Character)player).IsTeleporting(), ((Component)player).transform.position, targetPosition, context.Position)) { ConfirmEntry(context, ((Component)player).transform.position, "host-confirmed"); } CompletePendingEntry(context); } else { SetEntryDiagnostic(context, "arrived-awaiting-refpos"); } yield break; } yield return delay; } if (attempt == _pendingEntryAttempt && _pendingEntryContext == context) { SetEntryDiagnostic(context, "teleport-timeout"); _pendingEntryAttempt = ((_pendingEntryAttempt == int.MaxValue) ? 1 : (_pendingEntryAttempt + 1)); _pendingEntryContext = null; _pendingEntrySignalsRemaining = 0; _pendingEntryArrivalObserved = false; _entryConfirmationRoutine = null; } } finally { DungeonTracker dungeonTracker = this; if (attempt == dungeonTracker._pendingEntryAttempt) { dungeonTracker._entryConfirmationRoutine = null; } } } private void ConfirmEntry(DungeonContext context, Vector3 observationPosition, string stageCode) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) GetOrCreateObservation(context.Id).Entered = true; DungeonDiagnosticSnapshot orCreateDiagnostic = GetOrCreateDiagnostic(context); string text = stageCode ?? string.Empty; bool num = !orCreateDiagnostic.Entered || !string.Equals(orCreateDiagnostic.EntryStageCode, text, StringComparison.Ordinal) || orCreateDiagnostic.EntrySignalsSent < int.MaxValue; orCreateDiagnostic.Entered = true; orCreateDiagnostic.EntryStageCode = text; if (orCreateDiagnostic.EntrySignalsSent < int.MaxValue) { orCreateDiagnostic.EntrySignalsSent++; } if (num) { NotifyDiagnosticChanged(context.Id); } Submit(context.Id, DungeonEventType.DungeonEntered, string.Empty, 1); MarkCensusDirty(context, observationPosition); } private void CompletePendingEntry(DungeonContext context) { if (_pendingEntryContext == context) { _pendingEntryContext = null; _pendingEntrySignalsRemaining = 0; _pendingEntryArrivalObserved = false; } } private void CancelPendingEntry(string stageCode) { DungeonContext pendingEntryContext = _pendingEntryContext; _pendingEntryAttempt = ((_pendingEntryAttempt == int.MaxValue) ? 1 : (_pendingEntryAttempt + 1)); if (_entryConfirmationRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_entryConfirmationRoutine); _entryConfirmationRoutine = null; } _pendingEntryContext = null; _pendingEntrySignalsRemaining = 0; _pendingEntryArrivalObserved = false; if (pendingEntryContext != null && !string.IsNullOrEmpty(stageCode)) { SetEntryDiagnostic(pendingEntryContext, stageCode); } } private void SetEntryDiagnostic(DungeonContext context, string stageCode, bool resetSignals = false) { DungeonDiagnosticSnapshot orCreateDiagnostic = GetOrCreateDiagnostic(context); string text = stageCode ?? string.Empty; DungeonObservationState value; bool flag = _observations.TryGetValue(context.Id, out value) && value.Entered; bool num = !string.Equals(orCreateDiagnostic.EntryStageCode, text, StringComparison.Ordinal) || orCreateDiagnostic.Entered != flag || (resetSignals && orCreateDiagnostic.EntrySignalsSent != 0); orCreateDiagnostic.EntryStageCode = text; orCreateDiagnostic.Entered = flag; if (resetSignals) { orCreateDiagnostic.EntrySignalsSent = 0; } if (num) { NotifyDiagnosticChanged(context.Id); } } private void SubmitConfirmedEntry(DungeonContext context, bool localPlayerInside) { if (localPlayerInside && (_pendingEntryContext == null || !string.Equals(_pendingEntryContext.Id, context.Id, StringComparison.Ordinal) || !((Object)(object)ZNet.instance != (Object)null) || ZNet.instance.IsServer())) { GetOrCreateObservation(context.Id).Entered = true; Submit(context.Id, DungeonEventType.DungeonEntered, string.Empty, 1); } } private bool IsLocalPlayerInside(DungeonContext context) { //IL_0018: 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_0055: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (context == null || (Object)(object)localPlayer == (Object)null || !Character.InInterior(((Component)localPlayer).transform.position)) { return false; } if (TryResolveDungeon(((Component)localPlayer).gameObject, out var context2)) { return string.Equals(context2.Id, context.Id, StringComparison.Ordinal); } return IsReferencePositionForDungeon(((Component)localPlayer).transform.position, context.Position); } private DungeonObservationState GetOrCreateObservation(string dungeonId) { if (!_observations.TryGetValue(dungeonId, out var value)) { value = new DungeonObservationState(); _observations.Add(dungeonId, value); } return value; } private int CountUnresolvedChests(string dungeonId) { if (!_observations.TryGetValue(dungeonId, out var value)) { return 0; } int num = 0; foreach (string registeredChest in value.RegisteredChests) { if (!value.InspectedChests.Contains(registeredChest) && !value.ResolvedChests.Contains(registeredChest)) { num++; } } return num; } private DungeonDiagnosticSnapshot GetOrCreateDiagnostic(DungeonContext context) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) DungeonDiagnosticSnapshot orCreate = _diagnostics.GetOrCreate(context.Id, context.PrefabName, context.Position); orCreate.Prefab = context.PrefabName; orCreate.GenerationToken = (_generationTokens.TryGetValue(context.Id, out var value) ? value : string.Empty); return orCreate; } private void UpdateDiagnostic(CensusState state, bool areaReady, bool chestStateReady, bool playerInside, EnemyCensus enemies, ChestCensus chests, string blockerCode, bool settled) { DungeonDiagnosticSnapshot orCreateDiagnostic = GetOrCreateDiagnostic(state.Context); string text = blockerCode ?? string.Empty; bool flag = !settled && (string.Equals(blockerCode, "area-not-ready", StringComparison.Ordinal) || string.Equals(blockerCode, "chests-loading", StringComparison.Ordinal)); DungeonObservationState orCreateObservation = GetOrCreateObservation(state.Context.Id); bool entered = orCreateObservation.Entered; int count = orCreateObservation.RegisteredEnemies.Count; int count2 = orCreateObservation.KilledEnemies.Count; int count3 = orCreateObservation.ResolvedEnemies.Count; int num = Math.Min(count, count2 + count3); int count4 = orCreateObservation.RegisteredChests.Count; int num2 = CountUnresolvedChests(state.Context.Id); int count5 = orCreateObservation.InspectedChests.Count; int count6 = orCreateObservation.ResolvedChests.Count; bool num3 = !string.Equals(orCreateDiagnostic.BlockerCode, text, StringComparison.Ordinal) || orCreateDiagnostic.CensusPending != flag || orCreateDiagnostic.CensusSettled != settled || orCreateDiagnostic.AreaReady != areaReady || orCreateDiagnostic.ChestStateReady != chestStateReady || orCreateDiagnostic.PlayerInside != playerInside || orCreateDiagnostic.Entered != entered || orCreateDiagnostic.ReadinessAttempts != state.ReadinessAttempts || orCreateDiagnostic.EnemiesTotal != count || orCreateDiagnostic.EnemiesAlive != enemies.Alive || orCreateDiagnostic.EnemiesDefeated != num || orCreateDiagnostic.EnemiesKilled != count2 || orCreateDiagnostic.EnemiesResolved != count3 || orCreateDiagnostic.EnemiesInactive != enemies.Inactive || orCreateDiagnostic.EnemiesMissing != enemies.Missing || orCreateDiagnostic.ChestsTotal != count4 || orCreateDiagnostic.ChestsPresent != chests.Present || orCreateDiagnostic.ChestsReady != chests.Ready || orCreateDiagnostic.ChestsNonEmpty != chests.NonEmpty || orCreateDiagnostic.ChestsEmpty != chests.Empty || orCreateDiagnostic.ChestsUnresolved != num2 || orCreateDiagnostic.ChestsInspected != count5 || orCreateDiagnostic.ChestsResolved != count6 || orCreateDiagnostic.ChestsInactive != chests.Inactive || orCreateDiagnostic.ChestsMissing != chests.Missing; orCreateDiagnostic.BlockerCode = text; orCreateDiagnostic.CensusPending = flag; orCreateDiagnostic.CensusSettled = settled; orCreateDiagnostic.AreaReady = areaReady; orCreateDiagnostic.ChestStateReady = chestStateReady; orCreateDiagnostic.PlayerInside = playerInside; orCreateDiagnostic.Entered = entered; orCreateDiagnostic.ReadinessAttempts = state.ReadinessAttempts; orCreateDiagnostic.EnemiesTotal = count; orCreateDiagnostic.EnemiesAlive = enemies.Alive; orCreateDiagnostic.EnemiesDefeated = num; orCreateDiagnostic.EnemiesKilled = count2; orCreateDiagnostic.EnemiesResolved = count3; orCreateDiagnostic.EnemiesInactive = enemies.Inactive; orCreateDiagnostic.EnemiesMissing = enemies.Missing; orCreateDiagnostic.ChestsTotal = count4; orCreateDiagnostic.ChestsPresent = chests.Present; orCreateDiagnostic.ChestsReady = chests.Ready; orCreateDiagnostic.ChestsNonEmpty = chests.NonEmpty; orCreateDiagnostic.ChestsEmpty = chests.Empty; orCreateDiagnostic.ChestsUnresolved = num2; orCreateDiagnostic.ChestsInspected = count5; orCreateDiagnostic.ChestsResolved = count6; orCreateDiagnostic.ChestsInactive = chests.Inactive; orCreateDiagnostic.ChestsMissing = chests.Missing; if (num3) { NotifyDiagnosticChanged(state.Context.Id); } } private void NotifyDiagnosticChanged(string dungeonId) { if (string.IsNullOrEmpty(dungeonId)) { return; } try { _diagnosticChanged(dungeonId); } catch (Exception ex) { if (!_diagnosticCallbackFailureLogged) { _diagnosticCallbackFailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("Could not refresh a dungeon diagnostic label: " + ex.Message)); } } } } internal static bool TryAddBoundedSubject(HashSet values, string subjectId) { if (values.Contains(subjectId) || values.Count < 256) { return values.Add(subjectId); } return false; } private void ReplaySet(string dungeonId, HashSet values, DungeonEventType eventType) { foreach (string value in values) { Submit(dungeonId, eventType, value, 0); } } private void ResetObservedSubjects(string dungeonId) { //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_00a7: Unknown result type (might be due to invalid IL or missing references) _dirtyCensus.Remove(dungeonId); if (_observations.TryGetValue(dungeonId, out var value)) { foreach (string rememberedSubject in value.RememberedSubjects) { if (_contextsBySubject.TryGetValue(rememberedSubject, out var value2) && string.Equals(value2.Id, dungeonId, StringComparison.Ordinal)) { _contextsBySubject.Remove(rememberedSubject); } } foreach (ZDOID subjectZdo in value.SubjectZdos) { _subjectsByZdo.Remove(subjectZdo); _pendingSubjectUnloads.Remove(subjectZdo); } } _observations.Remove(dungeonId); _diagnostics.Remove(dungeonId); } private bool Submit(string dungeonId, DungeonEventType eventType, string subjectId, int value) { try { string value2; string arg = ((eventType == DungeonEventType.GenerationReset) ? (subjectId ?? string.Empty) : (_generationTokens.TryGetValue(dungeonId, out value2) ? value2 : string.Empty)); _submit(dungeonId, eventType, subjectId ?? string.Empty, value, arg); return true; } catch (Exception ex) { if (!_submitFailureLogged) { _submitFailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)($"Dungeon event {eventType} for '{dungeonId}' failed; further callback failures " + "are suppressed for this world: " + ex.Message)); } } return false; } } private static int GetConfigValue(ConfigEntry entry) { if (entry != null) { return Math.Max(0, entry.Value); } return 0; } private static string CleanPrefabName(string value) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } string text = value.Trim(); if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "(Clone)".Length).TrimEnd(' ', '\t', '\r', '\n'); } int num = text.LastIndexOf(" (", StringComparison.Ordinal); if (num >= 0 && text.EndsWith(")", StringComparison.Ordinal)) { bool flag = num + 2 < text.Length - 1; int num2 = num + 2; while (flag && num2 < text.Length - 1) { flag = char.IsDigit(text[num2]); num2++; } if (flag) { text = text.Substring(0, num); } } return text; } } internal static class PlayerCreatedResourceContext { private const string MarkerKey = "dragonmotion.ravenmap.playergrown.v1"; private static readonly int MarkerHash = StringExtensionMethods.GetStableHashCode("dragonmotion.ravenmap.playergrown.v1"); [ThreadStatic] private static int _placementDepth; [ThreadStatic] private static int _playerGrowthDepth; private static bool _markerFailureLogged; internal static bool IsCreationActive { get { if (_placementDepth <= 0) { return _playerGrowthDepth > 0; } return true; } } internal static void BeginPlacement() { if (_placementDepth < int.MaxValue) { _placementDepth++; } } internal static void EndPlacement() { if (_placementDepth > 0) { _placementDepth--; } } internal static bool BeginPlantGrowth(Plant plant) { try { ZNetView obj = (((Object)(object)plant != (Object)null) ? ((Component)plant).GetComponent() : null); ZDO val = ((obj != null) ? obj.GetZDO() : null); int num; if (val != null) { if (val.GetLong(ZDOVars.s_creator, 0L) == 0L) { num = (IsMarked(val) ? 1 : 0); if (num == 0) { goto IL_0058; } } else { num = 1; } if (_playerGrowthDepth < int.MaxValue) { _playerGrowthDepth++; } } else { num = 0; } goto IL_0058; IL_0058: return (byte)num != 0; } catch (Exception exception) { ReportFailure("read plant provenance", exception); return false; } } internal static void EndPlantGrowth(bool playerCreated) { if (playerCreated && _playerGrowthDepth > 0) { _playerGrowthDepth--; } } internal static void MarkPlantGrowthResult(GameObject result, bool playerCreated) { if (!playerCreated || (Object)(object)result == (Object)null) { return; } try { Pickable val = result.GetComponent() ?? result.GetComponentInChildren(true); if (!((Object)(object)val == (Object)null)) { ZNetView componentInParent = ((Component)val).GetComponentInParent(); ZDO val2 = ((componentInParent != null) ? componentInParent.GetZDO() : null); if (val2 != null && (componentInParent.IsOwner() || (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()))) { val2.Set(MarkerHash, true); } } } catch (Exception exception) { ReportFailure("write grown-Pickable provenance", exception); } } internal static bool IsMarked(ZDO zdo) { if (zdo == null) { return false; } try { return zdo.GetBool(MarkerHash, false); } catch (Exception exception) { ReportFailure("read grown-Pickable provenance", exception); return false; } } internal static void Reset() { _placementDepth = 0; _playerGrowthDepth = 0; _markerFailureLogged = false; } private static void ReportFailure(string operation, Exception exception) { if (_markerFailureLogged) { return; } _markerFailureLogged = true; try { ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("RavenMap could not " + operation + "; further provenance warnings are suppressed: " + exception.Message)); } } catch { } } } internal enum DiscoveryKind : byte { None, Resource, Dungeon, Portal, Ship, Cart, Pickable } internal enum ContentAvailability : byte { NotApplicable, Available, Missing, Unknown } internal sealed class PrefabDescriptor { internal static readonly PrefabDescriptor None = new PrefabDescriptor(DiscoveryKind.None, string.Empty, string.Empty, string.Empty, isSilver: false, isRespawningPickable: false); internal readonly DiscoveryKind Kind; internal readonly string PrefabName; internal readonly string DisplayName; internal readonly string ResourceType; internal readonly bool IsSilver; internal readonly bool IsRespawningPickable; internal readonly bool IsResourceShell; internal readonly bool IsDirectPickable; internal readonly string ResourceReplacementPrefab; internal readonly bool RequiresFinder; internal PrefabDescriptor(DiscoveryKind kind, string prefabName, string displayName, string resourceType, bool isSilver, bool isRespawningPickable, bool isResourceShell = false, bool isDirectPickable = false, string resourceReplacementPrefab = null, bool requiresFinder = false) { Kind = kind; PrefabName = prefabName ?? string.Empty; DisplayName = displayName ?? string.Empty; ResourceType = resourceType ?? string.Empty; IsSilver = isSilver; IsRespawningPickable = isRespawningPickable; IsResourceShell = isResourceShell; IsDirectPickable = isDirectPickable; ResourceReplacementPrefab = resourceReplacementPrefab ?? string.Empty; RequiresFinder = requiresFinder; } internal PrefabDescriptor WithDisplayName(string displayName) { if (string.IsNullOrWhiteSpace(displayName) || string.Equals(DisplayName, displayName, StringComparison.Ordinal)) { return this; } return new PrefabDescriptor(Kind, PrefabName, displayName, ResourceType, IsSilver, IsRespawningPickable, IsResourceShell, IsDirectPickable, ResourceReplacementPrefab, RequiresFinder); } } internal sealed class PrefabClassifier { private sealed class DropEvidence { internal GameObject Item; internal float Dominance; } private static readonly HashSet BuiltInDungeonPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase) { "Crypt2", "Crypt3", "Crypt4", "TrollCave02", "Hildir_crypt", "SunkenCrypt4", "MountainCave02", "Hildir_cave", "Hildir_plainsfortress", "Mistlands_DvergrTownEntrance1", "Mistlands_DvergrTownEntrance2", "Mistlands_DvergrBossEntrance1", "PlaceofMystery3", "MorgenHole1", "MorgenHole2", "MorgenHole3", "BFD_Exterior", "CD_Exterior1", "cd_exterior" }; private static readonly HashSet BuiltInBlockedItemNames = new HashSet(StringComparer.OrdinalIgnoreCase) { "Moss_bal", "$tag_moss_bal", "Moss" }; private static readonly HashSet BuiltInNonDungeonLocations = new HashSet(StringComparer.OrdinalIgnoreCase) { "AshlandRuins", "FortressRuins", "WoodFarm1", "WoodVillage1", "GoblinCamp2", "Mistlands_DvergrTownEntrance3", "MWL_MinddripHallow1" }; private static readonly int[] CatalogBiomeValues = new int[9] { 1, 8, 2, 4, 16, 512, 32, 256, 64 }; private readonly ModConfig _config; private Dictionary _prefabsByHash = new Dictionary(); private Dictionary _locationsByHash = new Dictionary(); private HashSet _locationProxyPrefabHashes = new HashSet(); private IReadOnlyList _filterCatalog = Array.Empty(); private HashSet _resourceAllow = new HashSet(StringComparer.OrdinalIgnoreCase); private Dictionary _resourceAliases = new Dictionary(StringComparer.OrdinalIgnoreCase); private HashSet _resourceBlock = new HashSet(StringComparer.OrdinalIgnoreCase); private HashSet _resourceItemBlock = new HashSet(StringComparer.OrdinalIgnoreCase); private HashSet _dungeonAllow = new HashSet(StringComparer.OrdinalIgnoreCase); private HashSet _enabledVegetationPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase); private HashSet _registeredObjectPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase); private HashSet _registeredLocationPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase); internal IReadOnlyList FilterCatalog => _filterCatalog; internal PrefabClassifier(ModConfig config) { _config = config ?? throw new ArgumentNullException("config"); RefreshRules(); } internal void Rebuild(ZNetScene scene) { RefreshRules(); Dictionary dictionary = new Dictionary(); HashSet hashSet = new HashSet(); HashSet locationProxyPrefabHashes = new HashSet(); HashSet hashSet2 = new HashSet(StringComparer.OrdinalIgnoreCase); ZoneSystem instance = ZoneSystem.instance; List list = (((Object)(object)scene != (Object)null) ? scene.GetPrefabNames() : null); _enabledVegetationPrefabs = BuildEnabledVegetationProvenance(instance); if ((Object)(object)scene != (Object)null) { if (scene.m_prefabs != null) { foreach (GameObject prefab2 in scene.m_prefabs) { AddPresenceName(hashSet2, prefab2); AddPrefab(prefab2, dictionary, hashSet, locationProxyPrefabHashes); } } if (list != null) { foreach (string item in list) { if (string.IsNullOrEmpty(item)) { continue; } int stableHashCode = StringExtensionMethods.GetStableHashCode(item); GameObject prefab = scene.GetPrefab(stableHashCode); if ((Object)(object)prefab == (Object)null) { dictionary[stableHashCode] = PrefabDescriptor.None; continue; } string text = CleanPrefabName(Utils.GetPrefabName(prefab)); if (text.Length != 0) { hashSet2.Add(text); } int instanceID = ((Object)prefab).GetInstanceID(); RememberLocationProxyHash(prefab, stableHashCode, locationProxyPrefabHashes); if (!hashSet.Add(instanceID)) { if (!dictionary.ContainsKey(stableHashCode)) { int stableHashCode2 = StringExtensionMethods.GetStableHashCode(CleanPrefabName(Utils.GetPrefabName(prefab))); if (dictionary.TryGetValue(stableHashCode2, out var value)) { dictionary[stableHashCode] = value; } } } else { string suppliedName = CleanPrefabName(Utils.GetPrefabName(prefab)); dictionary[stableHashCode] = ClassifyPrefab(prefab, suppliedName); } } } } if ((Object)(object)instance != (Object)null && instance.m_vegetation != null) { foreach (ZoneVegetation item2 in instance.m_vegetation) { if (item2 != null) { AddPresenceName(hashSet2, item2.m_prefab); AddPrefab(item2.m_prefab, dictionary, hashSet, locationProxyPrefabHashes); } } } Dictionary dictionary2 = BuildLocationCatalog(dictionary); foreach (KeyValuePair item3 in dictionary2) { if (!dictionary.TryGetValue(item3.Key, out var value2) || value2.Kind == DiscoveryKind.None) { dictionary[item3.Key] = item3.Value; } } _locationsByHash = dictionary2; _prefabsByHash = dictionary; _locationProxyPrefabHashes = locationProxyPrefabHashes; RefreshContentPresence(scene, instance, hashSet2, scanObjects: false); _filterCatalog = BuildFilterCatalog(instance, dictionary, dictionary2); } internal void RefreshWorldCatalog(ZNetScene scene) { if (_prefabsByHash.Count == 0) { Rebuild(scene); return; } Dictionary dictionary = new Dictionary(_prefabsByHash); HashSet locationProxyPrefabHashes = new HashSet(_locationProxyPrefabHashes); ZoneSystem instance = ZoneSystem.instance; Dictionary dictionary2 = new Dictionary(StringComparer.OrdinalIgnoreCase); HashSet hashSet = BuildEnabledVegetationProvenance(instance, dictionary2); HashSet hashSet2 = new HashSet(_enabledVegetationPrefabs, StringComparer.OrdinalIgnoreCase); hashSet2.SymmetricExceptWith(hashSet); _enabledVegetationPrefabs = hashSet; foreach (KeyValuePair item in dictionary2) { int stableHashCode = StringExtensionMethods.GetStableHashCode(item.Key); if (stableHashCode != 0) { dictionary[stableHashCode] = ClassifyPrefab(item.Value, item.Key); RememberLocationProxyHash(item.Value, stableHashCode, locationProxyPrefabHashes); } } foreach (string item2 in hashSet2) { if (!hashSet.Contains(item2)) { int stableHashCode2 = StringExtensionMethods.GetStableHashCode(item2); GameObject val = (((Object)(object)scene != (Object)null) ? scene.GetPrefab(stableHashCode2) : null); PrefabDescriptor value; if ((Object)(object)val != (Object)null) { dictionary[stableHashCode2] = ClassifyPrefab(val, item2); RememberLocationProxyHash(val, stableHashCode2, locationProxyPrefabHashes); } else if (dictionary.TryGetValue(stableHashCode2, out value) && value.Kind == DiscoveryKind.Pickable) { dictionary[stableHashCode2] = PrefabDescriptor.None; } } } Dictionary dictionary3 = BuildLocationCatalog(dictionary); foreach (KeyValuePair item3 in dictionary3) { if (!dictionary.TryGetValue(item3.Key, out var value2) || value2.Kind == DiscoveryKind.None) { dictionary[item3.Key] = item3.Value; } } _locationsByHash = dictionary3; _prefabsByHash = dictionary; _locationProxyPrefabHashes = locationProxyPrefabHashes; RefreshContentPresence(scene, instance); _filterCatalog = BuildFilterCatalog(instance, dictionary, dictionary3); } internal void RefreshRuleSets() { RefreshRules(); } internal ContentAvailability GetContentAvailability(PinRecord pin) { if (pin == null) { return ContentAvailability.Unknown; } if (pin.Category != PinCategory.Resource && pin.Category != PinCategory.Pickable && pin.Category != PinCategory.Dungeon) { return ContentAvailability.NotApplicable; } string text = CleanPrefabName(pin.Prefab); if (text.Length == 0 || text[0] == '$' || text[0] == '[') { return ContentAvailability.Unknown; } if (pin.Category == PinCategory.Dungeon) { if (_registeredLocationPrefabs.Contains(text)) { return ContentAvailability.Available; } int stableHashCode = StringExtensionMethods.GetStableHashCode(text); if (_registeredObjectPrefabs.Contains(text) && stableHashCode != 0 && _prefabsByHash.TryGetValue(stableHashCode, out var value) && value.Kind == DiscoveryKind.Dungeon && string.Equals(value.PrefabName, text, StringComparison.OrdinalIgnoreCase)) { return ContentAvailability.Available; } return ContentAvailability.Missing; } if (!_registeredObjectPrefabs.Contains(text)) { return ContentAvailability.Missing; } return ContentAvailability.Available; } internal bool HasCompleteContentPresenceCatalog() { if (_registeredObjectPrefabs.Contains("rock4_copper") && _registeredObjectPrefabs.Contains("Pickable_Mushroom")) { return _registeredLocationPrefabs.Contains("Crypt2"); } return false; } internal PrefabDescriptor Describe(GameObject prefabOrInstance, int prefabHash = 0) { return Describe(prefabOrInstance, prefabHash, null); } internal PrefabDescriptor Describe(GameObject prefabOrInstance, int prefabHash, ZDO knownZdo) { if ((Object)(object)prefabOrInstance == (Object)null) { return PrefabDescriptor.None; } PrefabDescriptor value = null; bool flag = prefabHash != 0 && _prefabsByHash.TryGetValue(prefabHash, out value); bool flag2 = prefabHash == 0 || !flag || _locationProxyPrefabHashes.Contains(prefabHash); if (flag && !flag2) { if (value.Kind == DiscoveryKind.None) { return value; } if (value.Kind == DiscoveryKind.Dungeon || value.Kind == DiscoveryKind.Cart) { return value; } } ZDO val = knownZdo ?? TryGetZdo(prefabOrInstance); if (prefabHash == 0 && val != null) { prefabHash = val.GetPrefab(); flag = prefabHash != 0 && _prefabsByHash.TryGetValue(prefabHash, out value); flag2 = prefabHash == 0 || !flag || _locationProxyPrefabHashes.Contains(prefabHash); } if (flag2 && val != null && (Object)(object)FindRootComponent(prefabOrInstance) != (Object)null) { int num = val.GetInt(ZDOVars.s_location, 0); if (num != 0 && _locationsByHash.TryGetValue(num, out var value2)) { return value2; } } if (!flag && prefabHash != 0) { flag = _prefabsByHash.TryGetValue(prefabHash, out value); } if (value == null) { string text = ResolvePrefabName(prefabOrInstance, val); value = ClassifyPrefab(prefabOrInstance, text); int num2 = ((prefabHash != 0) ? prefabHash : StringExtensionMethods.GetStableHashCode(text)); if (num2 != 0) { _prefabsByHash[num2] = value; if ((Object)(object)FindRootComponent(prefabOrInstance) != (Object)null) { _locationProxyPrefabHashes.Add(num2); } } } if (value.Kind == DiscoveryKind.None) { return value; } if ((value.Kind == DiscoveryKind.Resource || value.Kind == DiscoveryKind.Pickable) && IsPlayerCreatedResource(prefabOrInstance, val)) { return PrefabDescriptor.None; } if (val == null) { return value; } if (value.Kind == DiscoveryKind.Portal) { string text2 = val.GetString("tag", string.Empty); return value.WithDisplayName(string.IsNullOrWhiteSpace(text2) ? value.DisplayName : text2); } if (value.Kind == DiscoveryKind.Ship) { string text3 = val.GetString("ShipName", string.Empty); return value.WithDisplayName(string.IsNullOrWhiteSpace(text3) ? value.DisplayName : text3); } return value; } internal bool IsExplicitDungeon(string prefabName) { string item = CleanPrefabName(prefabName); if (!BuiltInNonDungeonLocations.Contains(item)) { if (!_dungeonAllow.Contains(item)) { return BuiltInDungeonPrefabs.Contains(item); } return true; } return false; } internal bool IsExplicitResource(string prefabName) { string text = CleanPrefabName(prefabName); ResourceCatalog.Identity identity; if (!_resourceAllow.Contains(text)) { return ResourceCatalog.TryGet(text, out identity); } return true; } internal bool TryGetDungeonDescriptor(string prefabName, out PrefabDescriptor descriptor) { descriptor = null; string text = CleanPrefabName(prefabName); if (text.Length != 0 && _locationsByHash.TryGetValue(StringExtensionMethods.GetStableHashCode(text), out descriptor)) { return descriptor.Kind == DiscoveryKind.Dungeon; } return false; } internal PrefabDescriptor DescribeDungeonLocation(Location location, string suppliedName) { if ((Object)(object)location == (Object)null) { return PrefabDescriptor.None; } string text = CleanPrefabName(suppliedName); if (text.Length == 0) { text = CleanPrefabName(Utils.GetPrefabName(((Component)location).gameObject)); } if (BuiltInNonDungeonLocations.Contains(text)) { return PrefabDescriptor.None; } if (!HasDungeonStructure(location) && !IsExplicitDungeon(text)) { return PrefabDescriptor.None; } string dungeonDisplayName = GetDungeonDisplayName(text, location.m_discoverLabel); PrefabDescriptor prefabDescriptor = new PrefabDescriptor(DiscoveryKind.Dungeon, text, dungeonDisplayName, GetDungeonFilterFamily(text), isSilver: false, isRespawningPickable: false); int stableHashCode = StringExtensionMethods.GetStableHashCode(text); if (stableHashCode != 0) { _locationsByHash[stableHashCode] = prefabDescriptor; _prefabsByHash[stableHashCode] = prefabDescriptor; } return prefabDescriptor; } private void AddPrefab(GameObject prefab, Dictionary target, HashSet seenObjects, HashSet locationProxyPrefabHashes) { if (!((Object)(object)prefab == (Object)null) && seenObjects.Add(((Object)prefab).GetInstanceID())) { string text = CleanPrefabName(Utils.GetPrefabName(prefab)); if (!string.IsNullOrEmpty(text)) { int stableHashCode = StringExtensionMethods.GetStableHashCode(text); target[stableHashCode] = ClassifyPrefab(prefab, text); RememberLocationProxyHash(prefab, stableHashCode, locationProxyPrefabHashes); } } } private static HashSet BuildEnabledVegetationProvenance(ZoneSystem zoneSystem, Dictionary prefabsByName = null) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (zoneSystem?.m_vegetation == null) { return hashSet; } foreach (ZoneVegetation item in zoneSystem.m_vegetation) { GameObject val = item?.m_prefab; if (item == null || !item.m_enable || (Object)(object)val == (Object)null) { continue; } string text = CleanPrefabName(Utils.GetPrefabName(val)); if (text.Length != 0) { hashSet.Add(text); if (prefabsByName != null && !prefabsByName.ContainsKey(text)) { prefabsByName.Add(text, val); } } } return hashSet; } private void RefreshContentPresence(ZNetScene scene, ZoneSystem zoneSystem, HashSet knownObjects = null, bool scanObjects = true) { HashSet hashSet = knownObjects ?? new HashSet(StringComparer.OrdinalIgnoreCase); HashSet hashSet2 = new HashSet(StringComparer.OrdinalIgnoreCase); if (scanObjects && scene?.m_prefabs != null) { foreach (GameObject prefab2 in scene.m_prefabs) { AddPresenceName(hashSet, prefab2); } } List list = ((scanObjects && (Object)(object)scene != (Object)null) ? scene.GetPrefabNames() : null); if (list != null) { foreach (string item in list) { string text = CleanPrefabName(item); if (text.Length != 0) { GameObject prefab = scene.GetPrefab(StringExtensionMethods.GetStableHashCode(text)); string text2 = (((Object)(object)prefab != (Object)null) ? CleanPrefabName(Utils.GetPrefabName(prefab)) : string.Empty); if (text2.Length != 0) { hashSet.Add(text2); } } } } if (scanObjects && zoneSystem?.m_vegetation != null) { foreach (ZoneVegetation item2 in zoneSystem.m_vegetation) { AddPresenceName(hashSet, item2?.m_prefab); } } if (zoneSystem?.m_locations != null) { foreach (ZoneLocation location in zoneSystem.m_locations) { string locationPrefabName = GetLocationPrefabName(location); if (locationPrefabName.Length != 0) { hashSet2.Add(locationPrefabName); } } } _registeredObjectPrefabs = hashSet; _registeredLocationPrefabs = hashSet2; } private static void AddPresenceName(HashSet names, GameObject prefab) { if (names != null && !((Object)(object)prefab == (Object)null)) { string text = CleanPrefabName(Utils.GetPrefabName(prefab)); if (text.Length != 0) { names.Add(text); } } } private static void RememberLocationProxyHash(GameObject prefab, int prefabHash, HashSet locationProxyPrefabHashes) { if (prefabHash != 0 && locationProxyPrefabHashes != null && (Object)(object)FindRootComponent(prefab) != (Object)null) { locationProxyPrefabHashes.Add(prefabHash); } } private Dictionary BuildLocationCatalog(Dictionary registeredPrefabs) { Dictionary dictionary = new Dictionary(); ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null || instance.m_locations == null) { return dictionary; } foreach (ZoneLocation location in instance.m_locations) { if (location == null || !location.m_enable) { continue; } string locationPrefabName = GetLocationPrefabName(location); if (!string.IsNullOrEmpty(locationPrefabName) && !BuiltInNonDungeonLocations.Contains(locationPrefabName)) { int stableHashCode = StringExtensionMethods.GetStableHashCode(locationPrefabName); PrefabDescriptor value = null; registeredPrefabs?.TryGetValue(stableHashCode, out value); if ((value != null && value.Kind == DiscoveryKind.Dungeon) || IsExplicitDungeon(locationPrefabName) || IsDungeonGroup(location.m_group)) { dictionary[stableHashCode] = ((value != null && value.Kind == DiscoveryKind.Dungeon) ? value : new PrefabDescriptor(DiscoveryKind.Dungeon, locationPrefabName, GetDungeonDisplayName(locationPrefabName), GetDungeonFilterFamily(locationPrefabName), isSilver: false, isRespawningPickable: false)); } } } return dictionary; } private static IReadOnlyList BuildFilterCatalog(ZoneSystem zoneSystem, Dictionary prefabs, Dictionary locations) { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)zoneSystem == (Object)null) { return Array.Empty(); } List list = new List(); HashSet seen = new HashSet(StringComparer.Ordinal); if (zoneSystem.m_vegetation != null) { foreach (ZoneVegetation item in zoneSystem.m_vegetation) { if (item != null && item.m_enable && !((Object)(object)item.m_prefab == (Object)null)) { string text = CleanPrefabName(Utils.GetPrefabName(item.m_prefab)); if (!string.IsNullOrEmpty(text) && prefabs.TryGetValue(StringExtensionMethods.GetStableHashCode(text), out var value) && (value.Kind == DiscoveryKind.Resource || value.Kind == DiscoveryKind.Pickable)) { AddFilterCatalogEntries(list, seen, (value.Kind != DiscoveryKind.Pickable) ? PinCategory.Resource : PinCategory.Pickable, item.m_biome, value); } } } } if (zoneSystem.m_locations != null) { foreach (ZoneLocation location in zoneSystem.m_locations) { if (location != null && location.m_enable) { string locationPrefabName = GetLocationPrefabName(location); if (!string.IsNullOrEmpty(locationPrefabName) && locations.TryGetValue(StringExtensionMethods.GetStableHashCode(locationPrefabName), out var value2)) { AddFilterCatalogEntries(list, seen, PinCategory.Dungeon, location.m_biome, value2); } } } } if (list.Count != 0) { return list.ToArray(); } return Array.Empty(); } private static void AddFilterCatalogEntries(List catalog, HashSet seen, PinCategory category, Biome biomeMask, PrefabDescriptor descriptor) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_003d: 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_0060: Expected I4, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) string value = ((!string.IsNullOrWhiteSpace(descriptor.ResourceType)) ? descriptor.ResourceType : descriptor.PrefabName); if (string.IsNullOrWhiteSpace(value)) { return; } string text = RavenIds.Normalize(value); for (int i = 0; i < CatalogBiomeValues.Length; i++) { Biome val = (Biome)CatalogBiomeValues[i]; if ((biomeMask & val) != 0) { string[] array = new string[5]; byte b = (byte)category; array[0] = b.ToString(); array[1] = ":"; array[2] = ((int)val).ToString(); array[3] = ":"; array[4] = text; string item = string.Concat(array); if (seen.Add(item)) { catalog.Add(new FilterCatalogEntry(category, val, descriptor.PrefabName, descriptor.DisplayName, descriptor.ResourceType)); } } } } private PrefabDescriptor ClassifyPrefab(GameObject gameObject, string suppliedName) { if ((Object)(object)gameObject == (Object)null) { return PrefabDescriptor.None; } string text = CleanPrefabName(suppliedName); if (string.IsNullOrEmpty(text)) { text = CleanPrefabName(Utils.GetPrefabName(gameObject)); } if ((Object)(object)FindRootComponent(gameObject) != (Object)null) { return new PrefabDescriptor(DiscoveryKind.Portal, text, DisplayToken("$piece_portal", "Portal"), string.Empty, isSilver: false, isRespawningPickable: false); } if ((Object)(object)FindRootComponent(gameObject) != (Object)null) { return new PrefabDescriptor(DiscoveryKind.Ship, text, DisplayToken((FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true))?.m_name, Prettify(text)), string.Empty, isSilver: false, isRespawningPickable: false); } Vagon val = FindRootComponent(gameObject); if ((Object)(object)val != (Object)null) { return new PrefabDescriptor(DiscoveryKind.Cart, text, DisplayToken(val.m_name, Prettify(text)), string.Empty, isSilver: false, isRespawningPickable: false); } Location component = gameObject.GetComponent(); if (!BuiltInNonDungeonLocations.Contains(text) && (IsExplicitDungeon(text) || ((Object)(object)component != (Object)null && HasDungeonStructure(component)))) { string dungeonDisplayName = GetDungeonDisplayName(text, component?.m_discoverLabel); return new PrefabDescriptor(DiscoveryKind.Dungeon, text, dungeonDisplayName, GetDungeonFilterFamily(text), isSilver: false, isRespawningPickable: false); } bool flag = _resourceAllow.Contains(text); if (_resourceBlock.Contains(text) || ResourceCatalog.IsRejectedSource(text)) { return PrefabDescriptor.None; } if (!flag && IsBuiltInNonResourcePrefab(text)) { return PrefabDescriptor.None; } MineRock val2 = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); MineRock5 val3 = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); Pickable val4 = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); Destructible val5 = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); DropOnDestroyed val6 = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); Beacon val7 = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); bool flag2 = (Object)(object)val2 != (Object)null || (Object)(object)val3 != (Object)null; bool flag3 = (Object)(object)val4 != (Object)null && !flag2; if (flag3 && !IsEligiblePickableSource(text, ((Object)(object)val4.m_itemPrefab != (Object)null) ? CleanPrefabName(Utils.GetPrefabName(val4.m_itemPrefab)) : string.Empty, _enabledVegetationPrefabs.Contains(text), (Object)(object)FindRootComponent(gameObject) != (Object)null || (Object)(object)FindRootComponent(gameObject) != (Object)null, (Object)(object)FindRootComponent(gameObject) != (Object)null, flag)) { return PrefabDescriptor.None; } bool flag4 = flag3; if (!(flag2 || flag4) && !((Object)(object)val5 != (Object)null) && !((Object)(object)val6 != (Object)null)) { return PrefabDescriptor.None; } DropTable val8 = (((Object)(object)val2 != (Object)null) ? val2.m_dropItems : (((Object)(object)val3 != (Object)null) ? val3.m_dropItems : (((Object)(object)val6 != (Object)null) ? val6.m_dropWhenDestroyed : null))); DropEvidence dropEvidence = new DropEvidence(); if (flag4 && (Object)(object)val4.m_itemPrefab != (Object)null && !IsBlockedItem(val4.m_itemPrefab)) { dropEvidence.Item = val4.m_itemPrefab; dropEvidence.Dominance = 1f; } if ((Object)(object)dropEvidence.Item == (Object)null && val8 != null) { dropEvidence = FindPrimaryDrop(val8); } if (ShouldRejectPieceCandidate(flag4, (Object)(object)FindRootComponent(gameObject) != (Object)null, flag)) { return PrefabDescriptor.None; } ResourceCatalog.Identity identity = null; string value; bool flag5 = _resourceAliases.TryGetValue(text, out value); bool flag6 = !flag5 && ResourceCatalog.TryGet(text, out identity); GameObject item = dropEvidence.Item; float dominance = dropEvidence.Dominance; string text2 = (flag5 ? value : (flag6 ? identity.ItemPrefab : (((Object)(object)item != (Object)null) ? CleanPrefabName(Utils.GetPrefabName(item)) : string.Empty))); bool isResourceShell = flag6 && identity.IsShell; string resourceReplacementPrefab = (flag6 ? identity.ReplacementPrefab : string.Empty); if (TryFindSpawnedDrop(gameObject, out var evidence, out var spawnedPrefab) && (Object)(object)evidence.Item != (Object)null) { string text3 = CleanPrefabName(Utils.GetPrefabName(evidence.Item)); if (!flag5 && !flag6 && IsMeaningfulMineableDrop(text, text3, evidence.Item, evidence.Dominance)) { item = evidence.Item; dominance = evidence.Dominance; text2 = text3; } if (string.Equals(RavenIds.Normalize(text3), RavenIds.Normalize(text2), StringComparison.Ordinal)) { isResourceShell = true; resourceReplacementPrefab = spawnedPrefab; } } if (string.IsNullOrWhiteSpace(text2)) { return PrefabDescriptor.None; } bool num = flag5 || flag6; bool flag7 = (Object)(object)item != (Object)null && IsMeaningfulMineableDrop(text, text2, item, dominance); if (!(num || flag4 || (flag && (Object)(object)item != (Object)null) || flag7)) { return PrefabDescriptor.None; } string itemDisplayName = GetItemDisplayName(ResolveItemPrefab(text2) ?? item, flag6 ? identity.DisplayToken : Prettify(text2)); bool isSilver = IsSilver(text, text2, itemDisplayName); return new PrefabDescriptor((!flag4) ? DiscoveryKind.Resource : DiscoveryKind.Pickable, text, itemDisplayName, text2, isSilver, flag4 && val4.m_respawnTimeMinutes > 0f, isResourceShell, flag4, resourceReplacementPrefab, (Object)(object)val7 != (Object)null); } internal static bool IsEligiblePickableSource(string sourcePrefab, string itemPrefab, bool isEnabledVegetation, bool hasCreatureRoot, bool hasItemDropRoot, bool explicitlyAllowed = false) { if (hasCreatureRoot || hasItemDropRoot) { return false; } string text = CleanPrefabName(sourcePrefab); string text2 = CleanPrefabName(itemPrefab); if (!isEnabledVegetation && !ResourceCatalog.IsBuiltInNaturalPickableSource(text) && !explicitlyAllowed) { return false; } if (ResourceCatalog.IsRejectedPickableSource(text) || ResourceCatalog.IsRejectedPickableSource(text2)) { return false; } if (!explicitlyAllowed && !ResourceCatalog.HasPickableFloraSignal(text)) { return ResourceCatalog.HasPickableFloraSignal(text2); } return true; } private DropEvidence FindPrimaryDrop(DropTable table) { //IL_002a: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_006d: Unknown result type (might be due to invalid IL or missing references) DropEvidence dropEvidence = new DropEvidence(); if (table == null || table.m_drops == null) { return dropEvidence; } Dictionary dictionary = new Dictionary(); foreach (DropData drop in table.m_drops) { if (!((Object)(object)drop.m_item == (Object)null)) { float num = Mathf.Max(0f, drop.m_weight); if (!(num <= 0f)) { dictionary.TryGetValue(drop.m_item, out var value); dictionary[drop.m_item] = value + num; } } } float num2 = 0f; float num3 = 0f; foreach (KeyValuePair item in dictionary) { num2 = Mathf.Max(num2, item.Value); if (!IsBlockedItem(item.Key) && item.Value > num3) { num3 = item.Value; dropEvidence.Item = item.Key; } } dropEvidence.Dominance = ((num2 > 0f) ? (num3 / num2) : 0f); return dropEvidence; } private bool TryFindSpawnedDrop(GameObject source, out DropEvidence evidence, out string spawnedPrefab) { evidence = new DropEvidence(); spawnedPrefab = string.Empty; if ((Object)(object)source == (Object)null) { return false; } HashSet hashSet = new HashSet(); GameObject val = source; for (int i = 0; i < 2; i++) { if (!((Object)(object)val != (Object)null)) { break; } if (!hashSet.Add(((Object)val).GetInstanceID())) { break; } Destructible val2 = FindRootComponent(val) ?? val.GetComponentInChildren(true); GameObject val3 = (((Object)(object)val2 != (Object)null) ? val2.m_spawnWhenDestroyed : null); if ((Object)(object)val3 == (Object)null || hashSet.Contains(((Object)val3).GetInstanceID())) { return false; } evidence = InspectDropEvidence(val3); if ((Object)(object)evidence.Item != (Object)null) { spawnedPrefab = CleanPrefabName(Utils.GetPrefabName(val3)); return true; } val = val3; } return false; } private DropEvidence InspectDropEvidence(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return new DropEvidence(); } MineRock val = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); MineRock5 val2 = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); DropOnDestroyed val3 = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); DropTable val4 = (((Object)(object)val != (Object)null) ? val.m_dropItems : (((Object)(object)val2 != (Object)null) ? val2.m_dropItems : (((Object)(object)val3 != (Object)null) ? val3.m_dropWhenDestroyed : null))); if (val4 != null) { return FindPrimaryDrop(val4); } Pickable val5 = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); if ((Object)(object)val5?.m_itemPrefab == (Object)null) { return new DropEvidence(); } return new DropEvidence { Item = (IsBlockedItem(val5.m_itemPrefab) ? null : val5.m_itemPrefab), Dominance = 1f }; } private bool IsMeaningfulMineableDrop(string sourcePrefab, string resourceType, GameObject itemPrefab, float dominance) { if ((Object)(object)itemPrefab == (Object)null || IsBlockedItem(itemPrefab) || dominance < 0.45f) { return false; } return SourceMatchesResource(sourcePrefab, resourceType); } internal static bool SourceMatchesResource(string sourcePrefab, string itemPrefab) { string text = ResourceStem(sourcePrefab); string text2 = ResourceStem(itemPrefab); if (text.Length >= 3 && text2.Length >= 3) { if (!string.Equals(text, text2, StringComparison.Ordinal) && text.IndexOf(text2, StringComparison.Ordinal) < 0) { return text2.IndexOf(text, StringComparison.Ordinal) >= 0; } return true; } return false; } private static string ResourceStem(string value) { string text = RavenIds.Normalize(value); string[] array = new string[12] { "minerock", "mine", "deposit", "vein", "rock", "ore", "frac", "nomoss", "small", "snow", "new", "pickable" }; for (int i = 0; i < array.Length; i++) { text = text.Replace(array[i], string.Empty); } if (text.EndsWith("bal", StringComparison.Ordinal) && text.Length > 3) { text = text.Substring(0, text.Length - 3); } return text; } private static GameObject ResolveItemPrefab(string itemPrefab) { string text = CleanPrefabName(itemPrefab); if (text.Length == 0) { return null; } GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(text) : null); if (!((Object)(object)val != (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null)) { return ZNetScene.instance.GetPrefab(text); } return val; } private static string GetItemDisplayName(GameObject itemPrefab, string fallback) { return DisplayToken((((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent() : null)?.m_itemData?.m_shared?.m_name, fallback); } private bool IsBlockedItem(GameObject itemPrefab) { if ((Object)(object)itemPrefab == (Object)null) { return false; } string text = CleanPrefabName(Utils.GetPrefabName(itemPrefab)); if (_resourceItemBlock.Contains(text) || IsBuiltInBlockedItem(text)) { return true; } ItemDrop component = itemPrefab.GetComponent(); if ((Object)(object)component != (Object)null && component.m_itemData != null && component.m_itemData.m_shared != null) { if (!_resourceItemBlock.Contains(component.m_itemData.m_shared.m_name)) { return IsBuiltInBlockedItem(component.m_itemData.m_shared.m_name); } return true; } return false; } internal static bool IsBuiltInBlockedItem(string itemName) { if (!string.IsNullOrWhiteSpace(itemName)) { return BuiltInBlockedItemNames.Contains(itemName.Trim()); } return false; } internal static bool IsBuiltInNonResourcePrefab(string prefabName) { if (string.IsNullOrWhiteSpace(prefabName)) { return false; } string text = CleanPrefabName(prefabName); if (!ResourceCatalog.IsRejectedSource(text) && text.IndexOf("stub", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("stump", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } internal static bool ShouldRejectPieceCandidate(bool directPickable, bool hasPiece, bool explicitlyAllowed) { if (!directPickable && hasPiece) { return !explicitlyAllowed; } return false; } internal bool IsPlayerCreatedResource(GameObject gameObject, ZDO zdo) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return false; } if (PlayerCreatedResourceContext.IsCreationActive || PlayerCreatedResourceContext.IsMarked(zdo)) { return true; } Pickable val = FindRootComponent(gameObject) ?? gameObject.GetComponentInChildren(true); if (zdo.GetLong(ZDOVars.s_creator, 0L) != 0L && ((Object)(object)FindRootComponent(gameObject) != (Object)null || (Object)(object)val != (Object)null)) { return true; } if ((Object)(object)val != (Object)null) { string sourcePrefab = CleanPrefabName(Utils.GetPrefabName(gameObject)); if (ResourceCatalog.IsBuiltInNaturalPickableSource(sourcePrefab) && !IsVerifiedNaturalPickableLocation(gameObject, zdo.GetPosition(), sourcePrefab)) { return true; } } return false; } private static bool IsVerifiedNaturalPickableLocation(GameObject gameObject, Vector3 position, string sourcePrefab) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) Location val = (((Object)(object)gameObject != (Object)null) ? gameObject.GetComponentInParent() : null); if ((Object)(object)val == (Object)null) { val = Location.GetLocation(position, false); } if ((Object)(object)val == (Object)null) { return false; } string locationPrefab = CleanPrefabName(Utils.GetPrefabName(((Component)val).gameObject)); return ResourceCatalog.IsAllowedNaturalPickableLocation(sourcePrefab, locationPrefab); } private void RefreshRules() { ParseResourceRules(_config.ResourcePrefabAllowList.Value, out _resourceAllow, out _resourceAliases); _resourceBlock = ParseList(_config.ResourcePrefabBlockList.Value); _resourceItemBlock = ParseList(_config.ResourceItemBlockList.Value); _dungeonAllow = ParseList(_config.DungeonPrefabAllowList.Value); } private static void ParseResourceRules(string value, out HashSet allow, out Dictionary aliases) { allow = new HashSet(StringComparer.OrdinalIgnoreCase); aliases = new Dictionary(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(value)) { return; } string[] array = value.Split(new char[2] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); int num = text.IndexOf('='); string text2 = CleanPrefabName((num >= 0) ? text.Substring(0, num) : text); if (text2.Length == 0) { continue; } allow.Add(text2); if (num >= 0 && num < text.Length - 1) { string text3 = CleanPrefabName(text.Substring(num + 1)); if (text3.Length != 0) { aliases[text2] = text3; } } } } private static HashSet ParseList(string value) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(value)) { return hashSet; } string[] array = value.Split(new char[2] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = CleanPrefabName(array[i].Trim()); if (!string.IsNullOrEmpty(text)) { hashSet.Add(text); } } return hashSet; } private static bool IsDungeonGroup(string group) { if (!string.IsNullOrWhiteSpace(group)) { if (!string.Equals(group.Trim(), "Dungeon", StringComparison.OrdinalIgnoreCase) && !string.Equals(group.Trim(), "Dungeons", StringComparison.OrdinalIgnoreCase)) { return group.Trim().StartsWith("Dungeon_", StringComparison.OrdinalIgnoreCase); } return true; } return false; } private static bool HasDungeonStructure(Location location) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 if ((Object)(object)location == (Object)null) { return false; } DungeonGenerator componentInChildren = ((Component)location).GetComponentInChildren(true); return IsDungeonStructure(location.m_hasInterior, IsDungeonAlgorithm(location.m_generator), (Object)(object)componentInChildren != (Object)null && (int)componentInChildren.m_algorithm == 0); } internal static bool IsDungeonStructure(bool hasInterior, bool hasAssignedDungeonAlgorithm, bool hasDescendantDungeonAlgorithm) { return hasInterior || hasAssignedDungeonAlgorithm || hasDescendantDungeonAlgorithm; } internal static bool IsDungeonAlgorithm(DungeonGenerator generator) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (generator != null) { return (int)generator.m_algorithm == 0; } return false; } private static string GetLocationPrefabName(ZoneLocation location) { if (location == null) { return string.Empty; } string text = CleanPrefabName(location.m_prefabName); if (text.Length == 0) { return CleanPrefabName(location.m_prefab.Name); } return text; } private static bool IsSilver(string prefabName, string resourceType, string displayName) { if (!Contains(prefabName, "silver") && !Contains(resourceType, "silverore")) { return Contains(displayName, "silver"); } return true; } private static bool Contains(string value, string fragment) { if (!string.IsNullOrEmpty(value)) { return value.IndexOf(fragment, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static string ResolvePrefabName(GameObject gameObject, ZDO zdo) { if (zdo != null && zdo.GetPrefab() != 0 && (Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(zdo.GetPrefab()); if ((Object)(object)prefab != (Object)null) { return CleanPrefabName(Utils.GetPrefabName(prefab)); } } Location val = FindRootComponent(gameObject); if ((Object)(object)val != (Object)null) { return CleanPrefabName(Utils.GetPrefabName(((Component)val).gameObject)); } return CleanPrefabName(Utils.GetPrefabName(gameObject)); } private static ZDO TryGetZdo(GameObject gameObject) { ZNetView val = gameObject.GetComponent() ?? gameObject.GetComponentInParent(); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetZDO(); } private static T FindRootComponent(GameObject gameObject) where T : Component { return gameObject.GetComponent() ?? gameObject.GetComponentInParent(); } private static string CleanPrefabName(string value) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } string text = value.Trim(); if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "(Clone)".Length).TrimEnd(' ', '\t', '\r', '\n'); } int num = text.LastIndexOf(" (", StringComparison.Ordinal); if (num >= 0 && text.EndsWith(")", StringComparison.Ordinal)) { bool flag = num + 2 < text.Length - 1; int num2 = num + 2; while (flag && num2 < text.Length - 1) { flag = char.IsDigit(text[num2]); num2++; } if (flag) { text = text.Substring(0, num); } } return text; } private static string Prettify(string prefabName) { string text = CleanPrefabName(prefabName); if (text.StartsWith("MWL_", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(4); } return text.Replace('_', ' ').Trim(); } internal static string GetDungeonDisplayName(string prefabName, string discoverLabel = null) { string text = RavenIds.Normalize(prefabName); if (text.Contains("bfdexterior")) { return "$ravenmap_location_underground_ruins"; } if (text.Contains("cdexterior")) { return "$ravenmap_location_forbidden_catacombs"; } switch (text) { case "hildircrypt": return "$hud_pin_hildir1"; case "hildircave": return "$hud_pin_hildir2"; case "hildirplainsfortress": return "$hud_pin_hildir3"; default: if (text.Contains("mistlandsdvergrbossentrance")) { return "$location_dvergrboss"; } if (text.Contains("mistlandsdvergrtownentrance") || text.Contains("infestedmine")) { return "$location_dvergrtown"; } if (text.Contains("placeofmystery3")) { return "$location_mausoleum"; } if (text.Contains("morgenhole")) { return "$location_morgenhole"; } if (text.Contains("sunkencrypt")) { return "$location_sunkencrypt"; } if (text.Contains("mountaincave") || text.Contains("frostcave")) { return "$location_mountaincave"; } if (text.Contains("trollcave")) { return "$location_forestcave"; } if (text.StartsWith("crypt", StringComparison.Ordinal) || text.Contains("forestcrypt") || text.Contains("burialchamber")) { return "$location_forestcrypt"; } if (text.Contains("catacomb")) { return "$ravenmap_location_catacombs"; } if (!string.IsNullOrWhiteSpace(discoverLabel)) { return DisplayToken(discoverLabel, HumanizeDungeonName(prefabName)); } return HumanizeDungeonName(prefabName); } } internal static string GetDungeonFilterFamily(string prefabName) { string text = RavenIds.Normalize(prefabName); if (text.Length == 0) { return string.Empty; } if (text.Contains("bfdexterior")) { return "undergroundruins"; } if (text.Contains("cdexterior")) { return "forbiddencatacombs"; } if (text == "hildircrypt") { return "smoulderingtomb"; } if (text.Contains("placeofmystery3") || text.Contains("mausoleum")) { return "mausoleum"; } if (text == "hildircave") { return "howlingcavern"; } if (text.Contains("mountaincave") || text.Contains("frostcave")) { return "frostcave"; } if (text == "hildirplainsfortress" || text.Contains("sealedtower")) { return "sealedtower"; } if (text.Contains("mistlandsdvergrbossentrance")) { return "infestedcitadel"; } if (text.Contains("mistlandsdvergrtownentrance") || text.Contains("infestedmine")) { return "infestedmine"; } if (text.Contains("morgenhole")) { return "morgen"; } if (text.Contains("sunkencrypt")) { return "sunkencrypt"; } if (text.Contains("trollcave")) { return "trollcave"; } if (text.StartsWith("crypt", StringComparison.Ordinal) || text.Contains("forestcrypt") || text.Contains("burialchamber")) { return "burialchamber"; } if (text.Contains("catacomb")) { return "catacombs"; } return string.Empty; } private static string HumanizeDungeonName(string prefabName) { string text = CleanPrefabName(prefabName); if (text.StartsWith("MWL_", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(4); } if (text.StartsWith("DG_", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(3); } StringBuilder stringBuilder = new StringBuilder(text.Length + 8); char c = '\0'; bool flag = false; foreach (char c2 in text) { if (c2 == '_' || c2 == '-' || char.IsWhiteSpace(c2)) { flag = stringBuilder.Length > 0; continue; } bool flag2 = stringBuilder.Length > 0 && ((char.IsUpper(c2) && char.IsLower(c)) || (char.IsDigit(c2) && char.IsLetter(c)) || (char.IsLetter(c2) && char.IsDigit(c))); if ((flag || flag2) && stringBuilder[stringBuilder.Length - 1] != ' ') { stringBuilder.Append(' '); } stringBuilder.Append(c2); c = c2; flag = false; } string text2 = stringBuilder.ToString().Trim(); if (text2.EndsWith(" bal", StringComparison.OrdinalIgnoreCase)) { text2 = text2.Substring(0, text2.Length - 4).TrimEnd(' ', '\t', '\r', '\n'); } if (!string.IsNullOrEmpty(text2)) { return text2; } return "$ravenmap_location_dungeon"; } private static string DisplayToken(string token, string fallback) { if (string.IsNullOrWhiteSpace(token)) { return fallback; } return token.Trim(); } } internal static class ResourceCatalog { internal sealed class Identity { internal string ItemPrefab { get; } internal string DisplayToken { get; } internal bool IsShell { get; } internal string ReplacementPrefab { get; } internal Identity(string itemPrefab, string displayToken, bool isShell = false, string replacementPrefab = null) { ItemPrefab = itemPrefab ?? string.Empty; DisplayToken = displayToken ?? string.Empty; IsShell = isShell; ReplacementPrefab = replacementPrefab ?? string.Empty; } } private static readonly Dictionary KnownSources = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["rock4_copper"] = Ore("CopperOre", "$item_copperore", shell: true, "rock4_copper_frac"), ["rock4_copper_frac"] = Ore("CopperOre", "$item_copperore"), ["MineRock_Copper"] = Ore("CopperOre", "$item_copperore"), ["MineRock_Tin"] = Ore("TinOre", "$item_tinore"), ["silvervein"] = Ore("SilverOre", "$item_silverore", shell: true, "silvervein_frac"), ["silvervein_frac"] = Ore("SilverOre", "$item_silverore"), ["rock3_silver"] = Ore("SilverOre", "$item_silverore", shell: true, "rock3_silver_frac"), ["rock3_silver_frac"] = Ore("SilverOre", "$item_silverore"), ["MineRock_Obsidian"] = Ore("Obsidian", "$item_obsidian"), ["Leviathan"] = Ore("Chitin", "$item_chitin"), ["giant_brain"] = Ore("Softtissue", "$item_softtissue"), ["softtissue_mineable"] = Ore("Softtissue", "$item_softtissue"), ["blackmarble_1"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_2"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_3"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_4"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_head_big01"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_head_big02"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_head01"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_head02"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_out_1"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_out_2"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_out_3"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_out_4"] = Ore("BlackMarble", "$item_blackmarble"), ["blackmarble_tip"] = Ore("BlackMarble", "$item_blackmarble"), ["rock_nickel_bal"] = Ore("NickelOre_bal", "$tag_nickelore_bal", shell: true, "rock_nickel_frac_bal"), ["rock_nickel_nomoss_bal"] = Ore("NickelOre_bal", "$tag_nickelore_bal", shell: true, "rock_nickel_frac_bal"), ["rock_nickel_frac_bal"] = Ore("NickelOre_bal", "$tag_nickelore_bal"), ["MineRock_Nickel_bal"] = Ore("NickelOre_bal", "$tag_nickelore_bal"), ["rock_silver_small_bal"] = Ore("SilverOre", "$item_silverore", shell: true, "rock_silver_small_frac_bal"), ["rock_silver_small_frac_bal"] = Ore("SilverOre", "$item_silverore"), ["coal_rock1_bal"] = Ore("Coal", "$item_coal", shell: true, "coal_rock1_frac_bal"), ["coal_rock1_frac_bal"] = Ore("Coal", "$item_coal"), ["coal_rock_nomoss_bal"] = Ore("Coal", "$item_coal", shell: true, "coal_rock_nomoss_frac_bal"), ["coal_rock_nomoss_frac_bal"] = Ore("Coal", "$item_coal"), ["MineRock_Coal_bal"] = Ore("Coal", "$item_coal"), ["MineRock_CoalSnow_bal"] = Ore("Coal", "$item_coal"), ["gold_Rock_bal"] = Ore("GoldOre_bal", "$tag_goldore_bal", shell: true, "gold_Rock_frac_bal"), ["gold_Rock_frac_bal"] = Ore("GoldOre_bal", "$tag_goldore_bal"), ["MineRock_Blackmetal_bal"] = Ore("BlackMetalOre_bal", "$tag_blackmetalore_bal"), ["MineRock_Borax_bal"] = Ore("BoraxCrystal_bal", "$tag_boraxcrystal_bal"), ["MineRock_Cobalt_bal"] = Ore("CobaltOre_bal", "$tag_cobaltore_bal"), ["MineRock_DarkIron_bal"] = Ore("DarkIron_bal", "$tag_darkiron_bal"), ["MineRock_Lead_bal"] = Ore("LeadOre_bal", "$tag_leadore_bal"), ["MineRock_Zinc_bal"] = Ore("ZincOre_bal", "$tag_zincore_bal"), ["MineRock_Copper_bal"] = Ore("CopperOre", "$item_copperore"), ["MineRock_IronNew_bal"] = Ore("IronOre", "$item_ironore"), ["MineRock_IronSnow_bal"] = Ore("IronOre", "$item_ironore"), ["MineRock_Guck_bal"] = Ore("Guck", "$item_guck"), ["ClayDeposit_bal"] = Ore("Clay_bal", "$tag_clay_bal"), ["ChitinDeposit_bal"] = Ore("Chitin", "$item_chitin"), ["MineRock_MeteoriteNew_bal"] = Ore("FlametalOre", "$tag_ifrytium_ore_bal"), ["deposit_jotunfinger_bal"] = Ore("JotunFinger_bal", "$tag_jotunfinger_bal") }; private static readonly HashSet BuiltInRejectedSources = new HashSet(StringComparer.OrdinalIgnoreCase) { "bloodshard_deposit_bal", "rock_nickel_nomoss_frac_bal" }; private static readonly HashSet BuiltInRejectedPickableSources = new HashSet(StringComparer.OrdinalIgnoreCase) { "Pickable_Stone", "Pickable_StoneRock", "Pickable_Flint", "Pickable_BogIronOre", "Pickable_Obsidian", "Pickable_MountainCaveObsidian", "Pickable_Clay_bal", "Pickable_TinNew_bal", "Pickable_MeteoriteNew_bal", "Pickable_MagmaStone_bal", "Pickable_GuckSack_bal", "Pickable_MountainCaveCrystal_bal", "Pickable_MeadowsMeatPile01_bal", "Pickable_MeadowsMeatPile02_bal", "Pickable_RottenVegetable_bal", "Pickable_Mushroom_Random_bal" }; private static readonly HashSet BuiltInNaturalPickableSources = new HashSet(StringComparer.OrdinalIgnoreCase) { "Pickable_Fiddlehead", "Pickable_Barley_Wild", "Pickable_Flax_Wild", "VineAsh" }; private static readonly Dictionary> BuiltInNaturalPickableLocations = new Dictionary>(StringComparer.OrdinalIgnoreCase) { ["Pickable_Fiddlehead"] = Locations("CharredRuins15"), ["Pickable_Barley_Wild"] = Locations("GoblinCamp2"), ["Pickable_Flax_Wild"] = Locations("GoblinCamp2"), ["VineAsh"] = Locations("CharredRuins1", "CharredRuins3") }; private static readonly string[] PickableFloraSignals = new string[47] { "berry", "bush", "mushroom", "shroom", "morel", "spore", "mycelium", "kelp", "weed", "wort", "cattail", "puff", "puffs", "cap", "plant", "herb", "flower", "lily", "lotus", "thistle", "vine", "seed", "seeds", "sage", "mint", "lavender", "yarrow", "nettle", "garlic", "cabbage", "carrot", "turnip", "onion", "barley", "flax", "fiddlehead", "dandelion", "vegetable", "leaf", "tree", "shrub", "apple", "potato", "straw", "acai", "lija", "plantain" }; private static readonly string[] PickableLootSignals = new string[41] { "ore", "rock", "stone", "flint", "clay", "crystal", "meat", "corpse", "loot", "pile", "rotten", "meteorite", "magma", "guck", "trophy", "hide", "pelt", "resin", "bloodbag", "gland", "eye", "tooth", "fang", "claw", "scale", "feather", "bone", "sinew", "egg", "core", "chain", "ooze", "entrails", "needle", "mandible", "carapace", "bile", "farm", "cultivated", "planted", "sapling" }; internal static bool TryGet(string sourcePrefab, out Identity identity) { identity = null; if (!string.IsNullOrWhiteSpace(sourcePrefab)) { return KnownSources.TryGetValue(sourcePrefab.Trim(), out identity); } return false; } internal static bool IsRejectedSource(string sourcePrefab) { if (!string.IsNullOrWhiteSpace(sourcePrefab)) { return BuiltInRejectedSources.Contains(sourcePrefab.Trim()); } return false; } internal static bool IsRejectedPickableSource(string sourcePrefab) { if (string.IsNullOrWhiteSpace(sourcePrefab)) { return false; } string text = sourcePrefab.Trim(); if (BuiltInRejectedPickableSources.Contains(text)) { return true; } return HasSemanticSignal(SplitSemanticWords(text), PickableLootSignals, allowSuffixMatch: false); } internal static bool IsBuiltInNaturalPickableSource(string sourcePrefab) { if (!string.IsNullOrWhiteSpace(sourcePrefab)) { return BuiltInNaturalPickableSources.Contains(sourcePrefab.Trim()); } return false; } internal static bool IsAllowedNaturalPickableLocation(string sourcePrefab, string locationPrefab) { if (!string.IsNullOrWhiteSpace(sourcePrefab) && !string.IsNullOrWhiteSpace(locationPrefab) && BuiltInNaturalPickableLocations.TryGetValue(sourcePrefab.Trim(), out var value)) { return value.Contains(locationPrefab.Trim()); } return false; } internal static bool HasPickableFloraSignal(string sourceOrItemPrefab) { if (!string.IsNullOrWhiteSpace(sourceOrItemPrefab)) { return HasSemanticSignal(SplitSemanticWords(sourceOrItemPrefab.Trim()), PickableFloraSignals, allowSuffixMatch: true); } return false; } internal static bool IsRejectedPersistedPickable(PinCategory category, string sourcePrefab) { if (category != PinCategory.Pickable && (category != PinCategory.Resource || string.IsNullOrWhiteSpace(sourcePrefab) || !sourcePrefab.Trim().StartsWith("Pickable_", StringComparison.OrdinalIgnoreCase))) { return false; } return IsRejectedPickableSource(sourcePrefab); } private static HashSet Locations(params string[] names) { return new HashSet(names ?? Array.Empty(), StringComparer.OrdinalIgnoreCase); } private static List SplitSemanticWords(string value) { List list = new List(); StringBuilder stringBuilder = new StringBuilder(value.Length); char c = '\0'; foreach (char c2 in value) { if (!char.IsLetterOrDigit(c2)) { FlushWord(list, stringBuilder); c = '\0'; continue; } if (stringBuilder.Length > 0 && ((char.IsUpper(c2) && char.IsLower(c)) || (char.IsDigit(c2) && char.IsLetter(c)) || (char.IsLetter(c2) && char.IsDigit(c)))) { FlushWord(list, stringBuilder); } stringBuilder.Append(char.ToLowerInvariant(c2)); c = c2; } FlushWord(list, stringBuilder); return list; } private static void FlushWord(List destination, StringBuilder word) { if (word.Length != 0) { string text = word.ToString(); word.Clear(); if (!string.Equals(text, "pickable", StringComparison.Ordinal) && !string.Equals(text, "bal", StringComparison.Ordinal)) { destination.Add(text); } } } private static bool HasSemanticSignal(List words, string[] signals, bool allowSuffixMatch) { for (int i = 0; i < words.Count; i++) { string text = words[i]; foreach (string text2 in signals) { if (string.Equals(text, text2, StringComparison.Ordinal) || (allowSuffixMatch && text.EndsWith(text2, StringComparison.Ordinal))) { return true; } } } return false; } internal static bool IsKnownShell(string sourcePrefab) { if (TryGet(sourcePrefab, out var identity)) { return identity.IsShell; } return false; } private static Identity Ore(string itemPrefab, string displayToken, bool shell = false, string replacementPrefab = null) { return new Identity(itemPrefab, displayToken, shell, replacementPrefab); } } internal static class ResourceMath { internal enum ProbeKind { None, MineRock, MineRock5, Destructible, Pickable } internal readonly struct Measurement { internal ProbeKind Kind { get; } internal float Initial { get; } internal float Remaining { get; } internal int TotalParts { get; } internal int RemainingParts { get; } internal float DepletedPercent { get { if (!(Initial > 0f)) { return 0f; } return 100f * (1f - Mathf.Clamp01(Remaining / Initial)); } } internal Measurement(ProbeKind kind, float initial, float remaining, int totalParts, int remainingParts) { Kind = kind; Initial = initial; Remaining = remaining; TotalParts = Math.Max(0, totalParts); RemainingParts = Math.Max(0, Math.Min(remainingParts, TotalParts)); } } internal sealed class ResourceProbe { internal readonly GameObject Root; internal readonly MineRock[] MineRocks; internal readonly int[] MineRockColliderCounts; internal readonly string[][] MineRockHealthKeys; internal readonly MineRock5[] MineRocks5; internal readonly int[] MineRock5ColliderCounts; internal readonly Destructible[] Destructibles; internal readonly Pickable[] Pickables; internal ResourceProbe(GameObject root) { Root = root; MineRocks = (((Object)(object)root != (Object)null) ? root.GetComponentsInChildren(true) : Array.Empty()); MineRockColliderCounts = new int[MineRocks.Length]; MineRockHealthKeys = new string[MineRocks.Length][]; for (int i = 0; i < MineRocks.Length; i++) { MineRock val = MineRocks[i]; int mineRockHitAreaCount = GameAccess.GetMineRockHitAreaCount(val); if (mineRockHitAreaCount > 0) { MineRockColliderCounts[i] = mineRockHitAreaCount; } else { GameObject val2 = (((Object)(object)val != (Object)null && (Object)(object)val.m_areaRoot != (Object)null) ? val.m_areaRoot : ((val != null) ? ((Component)val).gameObject : null)); MineRockColliderCounts[i] = (((Object)(object)val2 != (Object)null) ? val2.GetComponentsInChildren().Length : 0); } int num = MineRockColliderCounts[i]; string[] array = new string[num]; for (int j = 0; j < num; j++) { array[j] = "Health" + j; } MineRockHealthKeys[i] = array; } MineRocks5 = ((MineRocks.Length == 0 && (Object)(object)root != (Object)null) ? root.GetComponentsInChildren(true) : Array.Empty()); MineRock5ColliderCounts = new int[MineRocks5.Length]; for (int k = 0; k < MineRocks5.Length; k++) { MineRock5 val3 = MineRocks5[k]; int mineRock5HitAreaCount = GameAccess.GetMineRock5HitAreaCount(val3); MineRock5ColliderCounts[k] = ((mineRock5HitAreaCount > 0) ? mineRock5HitAreaCount : (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponentsInChildren().Length : 0)); } Destructibles = ((MineRocks.Length == 0 && MineRocks5.Length == 0 && (Object)(object)root != (Object)null) ? root.GetComponentsInChildren(true) : Array.Empty()); Pickables = ((MineRocks.Length == 0 && MineRocks5.Length == 0 && Destructibles.Length == 0 && (Object)(object)root != (Object)null) ? root.GetComponentsInChildren(true) : Array.Empty()); } } private delegate bool MeasureComponent(T component, out float initial, out float remaining); internal static ResourceProbe CreateProbe(GameObject root) { if (!((Object)(object)root == (Object)null)) { return new ResourceProbe(root); } return null; } internal static bool TryMeasureDetailed(ResourceProbe probe, bool preferLiveMineRock5, out Measurement measurement) { measurement = default(Measurement); if ((Object)(object)probe?.Root == (Object)null) { return false; } try { if (TryMeasureMineRocks(probe, null, out var initial, out var remaining, out var totalParts, out var remainingParts)) { measurement = new Measurement(ProbeKind.MineRock, initial, remaining, totalParts, remainingParts); return true; } if (TryMeasureMineRocks5(probe, null, preferLiveMineRock5, out initial, out remaining, out totalParts, out remainingParts)) { measurement = new Measurement(ProbeKind.MineRock5, initial, remaining, totalParts, remainingParts); return true; } if (TryMeasureMany(probe.Destructibles, TryMeasureDestructible, out initial, out remaining, out totalParts, out remainingParts)) { measurement = new Measurement(ProbeKind.Destructible, initial, remaining, totalParts, remainingParts); return true; } if (probe.Pickables.Length != 0) { initial = probe.Pickables.Length; remainingParts = 0; for (int i = 0; i < probe.Pickables.Length; i++) { if ((Object)(object)probe.Pickables[i] != (Object)null && !probe.Pickables[i].GetPicked()) { remainingParts++; } } remaining = remainingParts; measurement = new Measurement(ProbeKind.Pickable, initial, remaining, probe.Pickables.Length, remainingParts); return true; } } catch (Exception ex) { RavenMapPlugin instance = RavenMapPlugin.Instance; if (instance != null && instance.Settings.DetailedLogging.Value) { RavenMapPlugin.Log.LogWarning((object)("Cached resource measurement failed: " + ex.Message)); } } return false; } internal static bool TryMeasurePrefab(GameObject prefab, ZDO zdo, out float initial, out float remaining) { return TryMeasurePrefab(CreateProbe(prefab), zdo, out initial, out remaining); } internal static bool TryMeasurePrefab(ResourceProbe probe, ZDO zdo, out float initial, out float remaining) { initial = 0f; remaining = 0f; if ((Object)(object)probe?.Root == (Object)null || zdo == null) { return false; } try { if (probe.MineRocks.Length != 0 && TryMeasureMineRocks(probe, zdo, out initial, out remaining, out var totalParts, out var remainingParts)) { return true; } if (probe.MineRocks5.Length != 0 && TryMeasureMineRocks5(probe, zdo, preferLiveState: false, out initial, out remaining, out remainingParts, out totalParts)) { return true; } Destructible[] destructibles = probe.Destructibles; if (destructibles.Length != 0) { for (int i = 0; i < destructibles.Length; i++) { float num = ScaleMineHealth(destructibles[i].m_health); initial += num; remaining += Mathf.Clamp(zdo.GetFloat(ZDOVars.s_health, num), 0f, num); } if (initial > 0f) { return true; } } if ((Object)(object)((probe.Pickables.Length != 0) ? probe.Pickables[0] : null) != (Object)null) { initial = 1f; remaining = (zdo.GetBool(ZDOVars.s_picked, false) ? 0f : 1f); return true; } } catch (Exception ex) { RavenMapPlugin instance = RavenMapPlugin.Instance; if (instance != null && instance.Settings.DetailedLogging.Value) { RavenMapPlugin.Log.LogWarning((object)("Authoritative resource measurement failed: " + ex.Message)); } } return false; } private static bool TryMeasureMineRocks(ResourceProbe probe, ZDO authoritativeZdo, out float initial, out float remaining, out int totalParts, out int remainingParts) { initial = 0f; remaining = 0f; totalParts = 0; remainingParts = 0; for (int i = 0; i < probe.MineRocks.Length; i++) { MineRock val = probe.MineRocks[i]; int num = probe.MineRockColliderCounts[i]; if ((Object)(object)val == (Object)null || num <= 0) { continue; } ZDO val2 = authoritativeZdo; if (val2 == null) { ZNetView obj = ((Component)val).GetComponent() ?? ((Component)val).GetComponentInParent(); val2 = ((obj != null) ? obj.GetZDO() : null); } if (val2 == null) { continue; } float num2 = ScaleMineHealth(val.m_health); initial += num2 * (float)num; totalParts += num; string[] array = probe.MineRockHealthKeys[i]; for (int j = 0; j < num; j++) { float num3 = Mathf.Clamp(val2.GetFloat(array[j], num2), 0f, num2); remaining += num3; if (num3 > 0f) { remainingParts++; } } } return initial > 0f; } private static bool TryMeasureMany(T[] components, MeasureComponent measure, out float initial, out float remaining, out int totalParts, out int remainingParts) { initial = 0f; remaining = 0f; totalParts = 0; remainingParts = 0; bool flag = false; if (components == null) { return false; } for (int i = 0; i < components.Length; i++) { if (components[i] != null && measure(components[i], out var initial2, out var remaining2)) { initial += initial2; remaining += remaining2; totalParts++; if (remaining2 > 0f) { remainingParts++; } flag = true; } } if (flag) { return initial > 0f; } return false; } private static bool TryMeasureMineRocks5(ResourceProbe probe, ZDO authoritativeZdo, bool preferLiveState, out float initial, out float remaining, out int totalParts, out int remainingParts) { initial = 0f; remaining = 0f; totalParts = 0; remainingParts = 0; for (int i = 0; i < probe.MineRocks5.Length; i++) { MineRock5 val = probe.MineRocks5[i]; int num = probe.MineRock5ColliderCounts[i]; if ((Object)(object)val == (Object)null) { continue; } ZDO val2 = authoritativeZdo; if (val2 == null) { ZNetView obj = ((Component)val).GetComponent() ?? ((Component)val).GetComponentInParent(); val2 = ((obj != null) ? obj.GetZDO() : null); } if (val2 == null) { continue; } float num2 = ScaleMineHealth(val.m_health); float remaining2 = num2 * (float)num; int remainingParts2 = num; if (authoritativeZdo == null && preferLiveState && GameAccess.TryMeasureMineRock5HitAreas(val, num2, out var remaining3, out var totalParts2, out var remainingParts3)) { num = totalParts2; remaining2 = remaining3; remainingParts2 = remainingParts3; } else { string text = val2.GetString(ZDOVars.s_health, string.Empty); if (!string.IsNullOrEmpty(text)) { if (!TryReadMineRock5Health(text, num, num2, out remaining2, out remainingParts2, out var storedCount)) { return false; } if (num <= 0) { num = storedCount; } if (storedCount < num) { int num3 = num - storedCount; remaining2 += num2 * (float)num3; remainingParts2 += num3; } } } if (num > 0) { initial += num2 * (float)num; remaining += remaining2; totalParts += num; remainingParts += remainingParts2; } } return initial > 0f; } internal static bool TryReadMineRock5Health(string encoded, int capacity, float maximumHealth, out float remaining, out int remainingParts, out int storedCount) { remaining = 0f; remainingParts = 0; storedCount = 0; if (string.IsNullOrEmpty(encoded) || encoded.Length > 1000000 || maximumHealth <= 0f) { return false; } byte[] array; try { array = Convert.FromBase64String(encoded); } catch (FormatException) { return false; } if (array.Length < 4) { return false; } storedCount = array[0] | (array[1] << 8) | (array[2] << 16) | (array[3] << 24); if (storedCount < 0 || storedCount > 100000 || 4 + (long)storedCount * 4L > array.Length) { storedCount = 0; return false; } int num = ((capacity > 0) ? Math.Min(capacity, storedCount) : storedCount); for (int i = 0; i < num; i++) { float num2 = Mathf.Clamp(BitConverter.ToSingle(array, 4 + i * 4), 0f, maximumHealth); if (float.IsNaN(num2)) { remaining = 0f; remainingParts = 0; storedCount = 0; return false; } remaining += num2; if (num2 > 0f) { remainingParts++; } } return true; } private static bool TryMeasureDestructible(Destructible destructible, out float initial, out float remaining) { initial = ScaleMineHealth(destructible.m_health); remaining = initial; ZNetView obj = ((Component)destructible).GetComponent() ?? ((Component)destructible).GetComponentInParent(); ZDO val = ((obj != null) ? obj.GetZDO() : null); if (val != null) { remaining = Mathf.Clamp(val.GetFloat(ZDOVars.s_health, initial), 0f, initial); } return initial > 0f; } private static float ScaleMineHealth(float baseHealth) { if ((Object)(object)Game.instance == (Object)null) { return baseHealth; } return baseHealth + (float)Game.m_worldLevel * baseHealth * Game.instance.m_worldLevelMineHPMultiplier; } } internal enum SourceAlphaMode : byte { Opaque, Cutout, Fade, FadeCutout } internal sealed class ShimmerService { private sealed class ResourceVisual { internal GameObject Root; internal Renderer[] Renderers; internal MeshFilter[] MeshFilters; internal SourceAlphaBinding[][] SourceAlphaBindings; internal float DistanceSqr; internal bool Registered; internal bool MayShimmer; internal bool AllowXray; internal bool UseSourceAlphaMask; internal bool LodBindingsCached; internal Dictionary LodBindings; internal long LastSelectedGeneration; internal long RegistrationOrder; } private readonly struct LodBinding { internal readonly LODGroup Group; internal readonly LOD[] Levels; internal readonly int Level; internal LodBinding(LODGroup group, LOD[] levels, int level) { Group = group; Levels = levels; Level = level; } } private readonly struct RendererPart { internal readonly Renderer Renderer; internal readonly MeshFilter Filter; internal readonly Mesh Mesh; internal readonly Matrix4x4 LocalToWorldMatrix; internal readonly SourceAlphaBinding[] SourceAlphaBindings; internal RendererPart(Renderer renderer, MeshFilter filter, Mesh mesh, Matrix4x4 localToWorldMatrix, SourceAlphaBinding[] sourceAlphaBindings) { //IL_0016: 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) Renderer = renderer; Filter = filter; Mesh = mesh; LocalToWorldMatrix = localToWorldMatrix; SourceAlphaBindings = sourceAlphaBindings; } } private readonly struct TextureProperty { internal readonly int Texture; internal readonly int ScaleOffset; internal TextureProperty(string name) { Texture = Shader.PropertyToID(name); ScaleOffset = Shader.PropertyToID(name + "_ST"); } } private readonly struct SourceAlphaBinding { internal readonly Texture Texture; internal readonly Vector4 ScaleOffset; internal readonly float Cutoff; internal readonly float Multiplier; internal readonly float Cull; internal readonly SourceAlphaMode Mode; internal bool Enabled { get { if ((Object)(object)Texture != (Object)null) { return Mode != SourceAlphaMode.Opaque; } return false; } } internal SourceAlphaBinding(Texture texture, Vector4 scaleOffset, float cutoff, float multiplier, float cull, SourceAlphaMode mode) { //IL_0008: 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) Texture = texture; ScaleOffset = scaleOffset; Cutoff = cutoff; Multiplier = multiplier; Cull = cull; Mode = mode; } } private sealed class MaterialAlphaCacheEntry { internal Shader Shader; internal Texture MainTexture; internal int RenderQueue; internal SourceAlphaBinding[] Bindings; internal bool Matches(Material material) { if ((Object)(object)material != (Object)null && (Object)(object)material.shader == (Object)(object)Shader && (Object)(object)material.mainTexture == (Object)(object)MainTexture) { return material.renderQueue == RenderQueue; } return false; } } private sealed class MaterialReferenceComparer : IEqualityComparer { internal static readonly MaterialReferenceComparer Instance = new MaterialReferenceComparer(); public bool Equals(Material first, Material second) { return first == second; } public int GetHashCode(Material material) { if (material != null) { return RuntimeHelpers.GetHashCode(material); } return 0; } } private sealed class GeometryPart { internal ResourceVisual Owner; internal Renderer Renderer; internal MeshFilter Filter; internal Mesh Mesh; internal Matrix4x4 LocalToWorldMatrix; internal SourceAlphaBinding[] SourceAlphaBindings; internal float MinimumProjection; internal float MaximumProjection; } private sealed class SweepVein { internal Vector3 Axis; internal float MinimumProjection; internal float MaximumProjection; internal float WaveHalfWidth; internal float TravelDuration; internal bool TerminalFrameRendered; internal bool HasSourceAlphaMask; internal bool IsPickable; internal readonly List Parts = new List(32); } private const int MaxConcurrentResourceHighlights = 4; private const int InitialHighlightCapacity = 64; private const int MaxPlayerMaskDrawCommands = 256; private const int MaxSourceMaskedDrawCommands = 128; private const float ShimmerIdlePollSeconds = 0.2f; private const float XrayPollSeconds = 0.5f; private const float XraySafetyRefreshSeconds = 5f; private const float XrayMovementRefreshDistance = 2f; internal const float SweepPeakOpacity = 0.42f; private const float MinimumEffectDuration = 0.1f; private const CameraEvent XrayCameraEvent = (CameraEvent)18; private const string ShaderResource = "DragonMotion.RavenMap.Shaders.ravenmap_shaders"; private const string ShaderAsset = "Assets/Shaders/RavenMapResourceOverlay.shader"; private static readonly int ColorId = Shader.PropertyToID("_Color"); private static readonly int BaseColorId = Shader.PropertyToID("_BaseColor"); private static readonly int ModeId = Shader.PropertyToID("_Mode"); private static readonly int SurfaceId = Shader.PropertyToID("_Surface"); private static readonly int AlphaClipId = Shader.PropertyToID("_AlphaClip"); private static readonly int CutoffId = Shader.PropertyToID("_Cutoff"); private static readonly int AlphaCutoffId = Shader.PropertyToID("_AlphaCutoff"); private static readonly int CutoffThresholdId = Shader.PropertyToID("_CutoffThreshold"); private static readonly int AlphaClipThresholdId = Shader.PropertyToID("_AlphaClipThreshold"); private static readonly int SrcBlendId = Shader.PropertyToID("_SrcBlend"); private static readonly int DstBlendId = Shader.PropertyToID("_DstBlend"); private static readonly int ZWriteId = Shader.PropertyToID("_ZWrite"); private static readonly int CullId = Shader.PropertyToID("_Cull"); private static readonly int CullModeId = Shader.PropertyToID("_CullMode"); private static readonly int SweepColorId = Shader.PropertyToID("_SweepColor"); private static readonly int SweepGainId = Shader.PropertyToID("_SweepGain"); private static readonly int SweepOpacityId = Shader.PropertyToID("_SweepOpacity"); private static readonly int SweepAxisId = Shader.PropertyToID("_SweepAxis"); private static readonly int SweepCenterId = Shader.PropertyToID("_SweepCenter"); private static readonly int SweepHalfWidthId = Shader.PropertyToID("_SweepHalfWidth"); private static readonly int SweepSoftnessId = Shader.PropertyToID("_SweepSoftness"); private static readonly int SweepWholeVeinId = Shader.PropertyToID("_SweepWholeVein"); private static readonly int SweepZTestId = Shader.PropertyToID("_SweepZTest"); private static readonly int SourceAlphaTexId = Shader.PropertyToID("_SourceAlphaTex"); private static readonly int SourceAlphaTexStId = Shader.PropertyToID("_SourceAlphaTex_ST"); private static readonly int SourceAlphaEnabledId = Shader.PropertyToID("_SourceAlphaEnabled"); private static readonly int SourceAlphaClipId = Shader.PropertyToID("_SourceAlphaClip"); private static readonly int SourceAlphaBlendId = Shader.PropertyToID("_SourceAlphaBlend"); private static readonly int SourceAlphaCutoffId = Shader.PropertyToID("_SourceAlphaCutoff"); private static readonly int SourceAlphaMultiplierId = Shader.PropertyToID("_SourceAlphaMultiplier"); private static readonly int SourceCullId = Shader.PropertyToID("_SourceCull"); private static readonly int SweepStencilCompId = Shader.PropertyToID("_SweepStencilComp"); private static readonly int SweepStencilWriteMaskId = Shader.PropertyToID("_SweepStencilWriteMask"); private static readonly int XrayColorId = Shader.PropertyToID("_XRayColor"); private static readonly int XrayIntensityId = Shader.PropertyToID("_XRayIntensity"); private static readonly int XrayAlphaId = Shader.PropertyToID("_XRayAlpha"); private static readonly int XrayZTestId = Shader.PropertyToID("_XRayZTest"); private readonly RavenMapPlugin _plugin; private readonly ModConfig _config; private readonly Dictionary _resources = new Dictionary(); private readonly List _nearby = new List(64); private readonly List _staleIds = new List(16); private readonly List _rendererBuffer = new List(256); private readonly List _lodGroupBuffer = new List(4); private readonly List _axisSamples = new List(256); private readonly List _sweepVeins = new List(64); private readonly Stack _sweepVeinPool = new Stack(64); private readonly List _xrayParts = new List(256); private readonly HashSet _xrayOwners = new HashSet(); private readonly List _playerMaskRenderers = new List(32); private readonly List _sourceMaterialBuffer = new List(8); private readonly List _sourceBindingBuffer = new List(8); private readonly Dictionary _sourceAlphaBindingCache = new Dictionary(MaterialReferenceComparer.Instance); private readonly MaterialPropertyBlock _sourcePropertyBlock = new MaterialPropertyBlock(); private readonly Stack _geometryPartPool = new Stack(256); private readonly Dictionary _activeLods = new Dictionary(); private readonly Plane[] _shimmerFrustumPlanes = (Plane[])(object)new Plane[6]; private readonly ShimmerOverlayRenderer _overlay; private Coroutine _routine; private Coroutine _xrayRoutine; private Camera _renderCamera; private Camera _xrayCommandCamera; private CommandBuffer _xrayCommandBuffer; private Shader _geometryShader; private Material _geometryMaterial; private int _sweepPass = -1; private int _playerMaskPass = -1; private int _xrayPass = -1; private Player _playerMaskOwner; private Transform _playerMaskRoot; private bool _shaderUnavailable; private bool _shaderFailureLogged; private bool _renderFailureLogged; private bool _xrayVisible = true; private bool _xraySelectionDirty = true; private bool _xraySelectionValid; private bool _xrayCommandSettingsValid; private Vector3 _xraySelectionOrigin; private float _xraySelectionRadius; private float _xrayLastSelectionRefresh; private int _xraySelectionRendererBudget; private int _xraySelectionDrawBudget; private int _xrayCommandDrawBudget; private Color _xrayCommandColor; private float _xrayCommandIntensity; private bool _sweepActive; private ShimmerAnimationMode _geometryHighlightMode; private float _effectElapsed; private float _sweepOpacity; private Color _sweepColor; private float _sweepGain; private bool _sourceAlphaStateValid; private SourceAlphaBinding _appliedSourceAlphaBinding; private bool _sweepStencilPolicyValid; private bool _appliedPickableStencilPolicy; private long _shimmerSelectionGeneration; private long _registrationSequence; private static readonly TextureProperty[] SourceTextureProperties = new TextureProperty[6] { new TextureProperty("_MainTex"), new TextureProperty("_BaseMap"), new TextureProperty("_BaseColorMap"), new TextureProperty("_Albedo"), new TextureProperty("_AlbedoMap"), new TextureProperty("_AlbedoTex") }; private static readonly int[] SourceCutoffProperties = new int[4] { CutoffId, AlphaCutoffId, CutoffThresholdId, AlphaClipThresholdId }; private static readonly int[] SourceCullProperties = new int[2] { CullId, CullModeId }; private static readonly Comparison DistanceComparison = CompareByDistance; private static readonly Comparison ShimmerPriorityComparison = CompareBySelectionAgeThenDistance; internal ShimmerService(RavenMapPlugin plugin, ModConfig config) { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown _plugin = plugin; _config = config; _overlay = ((Component)plugin).gameObject.AddComponent(); _overlay.Owner = this; ((Behaviour)_overlay).enabled = false; } internal void Register(string id, GameObject root, bool mayShimmer, bool allowXray = false, bool useSourceAlphaMask = false) { if (IsHeadlessGraphics() || (!(_config.ShimmerEnabled.Value && mayShimmer) && !(_config.XrayEnabled.Value && allowXray)) || string.IsNullOrEmpty(id) || (Object)(object)root == (Object)null) { return; } if (_resources.TryGetValue(id, out var value)) { if ((Object)(object)value.Root == (Object)(object)root) { UpdatePermissions(id, mayShimmer, allowXray, useSourceAlphaMask); return; } InvalidateXraySelection(value); ReleaseVisual(value); } Renderer[] renderers = CaptureResourceRenderers(root); ResourceVisual value2 = new ResourceVisual { Root = root, Renderers = renderers, MeshFilters = CaptureMeshFilters(renderers), SourceAlphaBindings = CaptureSourceAlphaBindings(renderers, useSourceAlphaMask), Registered = true, MayShimmer = mayShimmer, AllowXray = allowXray, UseSourceAlphaMask = useSourceAlphaMask, RegistrationOrder = ++_registrationSequence }; _resources[id] = value2; if (allowXray) { _xraySelectionDirty = true; } } private static MeshFilter[] CaptureMeshFilters(Renderer[] renderers) { if (renderers == null || renderers.Length == 0) { return Array.Empty(); } MeshFilter[] array = (MeshFilter[])(object)new MeshFilter[renderers.Length]; for (int i = 0; i < renderers.Length; i++) { int num = i; Renderer obj = renderers[i]; MeshRenderer val = (MeshRenderer)(object)((obj is MeshRenderer) ? obj : null); array[num] = ((val != null) ? ((Component)val).GetComponent() : null); } return array; } private SourceAlphaBinding[][] CaptureSourceAlphaBindings(Renderer[] renderers, bool enabled) { if (!enabled || renderers == null || renderers.Length == 0) { return null; } SourceAlphaBinding[][] array = null; bool flag = false; for (int i = 0; i < renderers.Length; i++) { Renderer val = renderers[i]; if ((Object)(object)val == (Object)null) { continue; } _sourceMaterialBuffer.Clear(); val.GetSharedMaterials(_sourceMaterialBuffer); if (_sourceMaterialBuffer.Count == 0) { continue; } _sourceBindingBuffer.Clear(); bool flag2 = false; bool flag3 = val.HasPropertyBlock(); if (!flag3 && _sourceMaterialBuffer.Count == 1) { Material val2 = _sourceMaterialBuffer[0]; SourceAlphaBinding[] array2 = null; if ((Object)(object)val2 != (Object)null) { if (!_sourceAlphaBindingCache.TryGetValue(val2, out var value) || !value.Matches(val2)) { SourceAlphaBinding sourceAlphaBinding = CaptureSourceAlphaBinding(val2, null); MaterialAlphaCacheEntry materialAlphaCacheEntry = new MaterialAlphaCacheEntry(); materialAlphaCacheEntry.Shader = val2.shader; materialAlphaCacheEntry.MainTexture = val2.mainTexture; materialAlphaCacheEntry.RenderQueue = val2.renderQueue; materialAlphaCacheEntry.Bindings = ((!sourceAlphaBinding.Enabled) ? null : new SourceAlphaBinding[1] { sourceAlphaBinding }); value = materialAlphaCacheEntry; _sourceAlphaBindingCache[val2] = value; } array2 = value.Bindings; } if (array2 != null) { if (array == null) { array = new SourceAlphaBinding[renderers.Length][]; } array[i] = array2; flag = true; } continue; } for (int j = 0; j < _sourceMaterialBuffer.Count; j++) { _sourcePropertyBlock.Clear(); MaterialPropertyBlock overrides = null; if (flag3) { val.GetPropertyBlock(_sourcePropertyBlock, j); overrides = _sourcePropertyBlock; } SourceAlphaBinding item = CaptureSourceAlphaBinding(_sourceMaterialBuffer[j], overrides); _sourceBindingBuffer.Add(item); flag2 |= item.Enabled; } if (flag2) { if (array == null) { array = new SourceAlphaBinding[renderers.Length][]; } array[i] = _sourceBindingBuffer.ToArray(); flag = true; } } _sourceMaterialBuffer.Clear(); _sourceBindingBuffer.Clear(); _sourcePropertyBlock.Clear(); if (!flag) { return null; } return array; } private static SourceAlphaBinding CaptureSourceAlphaBinding(Material material, MaterialPropertyBlock overrides) { //IL_0108: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return default(SourceAlphaBinding); } SourceAlphaMode classifiedMode = ClassifySourceAlphaMode(material, overrides); string text = (((Object)(object)material.shader != (Object)null) ? ((Object)material.shader).name : string.Empty); classifiedMode = ResolvePickableSourceAlphaMode(classifiedMode, text, material.HasProperty(CutoffId)); if (classifiedMode == SourceAlphaMode.Opaque || !TryGetSourceAlphaTexture(material, overrides, out var texture, out var scaleOffset)) { return default(SourceAlphaBinding); } float cutoff = 0.5f; if (SourceAlphaClips(classifiedMode) && TryGetFirstFloat(material, overrides, SourceCutoffProperties, out var value)) { cutoff = Mathf.Clamp01(value); } float multiplier = 1f; if (TryGetColorAlpha(material, overrides, BaseColorId, out var alpha) || TryGetColorAlpha(material, overrides, ColorId, out alpha)) { multiplier = Mathf.Clamp01(alpha); } float cull = (string.Equals(text, "Custom/Grass", StringComparison.OrdinalIgnoreCase) ? 0f : 2f); if (TryGetFirstFloat(material, overrides, SourceCullProperties, out var value2)) { cull = Mathf.Clamp(Mathf.Round(value2), 0f, 2f); } return new SourceAlphaBinding(texture, scaleOffset, cutoff, multiplier, cull, classifiedMode); } internal static SourceAlphaMode ResolvePickableSourceAlphaMode(SourceAlphaMode classifiedMode, string shaderName, bool hasCutoffProperty) { if (classifiedMode != SourceAlphaMode.Opaque || !hasCutoffProperty) { return classifiedMode; } string a = shaderName ?? string.Empty; if (!string.Equals(a, "Custom/Vegetation", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "Balrond/Vegetation", StringComparison.OrdinalIgnoreCase)) { return SourceAlphaMode.Opaque; } return SourceAlphaMode.Cutout; } private static SourceAlphaMode ClassifySourceAlphaMode(Material material, MaterialPropertyBlock overrides) { float value; float value2; float value3; return ClassifySourceAlphaMode(material.IsKeywordEnabled("_ALPHATEST_ON") || material.IsKeywordEnabled("_ALPHACLIP_ON") || material.IsKeywordEnabled("_ALPHA_CLIP_ON"), material.IsKeywordEnabled("_ALPHABLEND_ON") || material.IsKeywordEnabled("_ALPHAPREMULTIPLY_ON") || material.IsKeywordEnabled("_SURFACE_TYPE_TRANSPARENT"), material.GetTag("RenderType", true, string.Empty), ((Object)(object)material.shader != (Object)null) ? ((Object)material.shader).name : string.Empty, hasStandardMode: TryGetFloat(material, overrides, ModeId, out value), alphaClipEnabled: TryGetFloat(material, overrides, AlphaClipId, out value2) && value2 > 0.5f, transparentSurface: TryGetFloat(material, overrides, SurfaceId, out value3) && value3 > 0.5f, transparentBlend: HasTransparentBlend(material, overrides), renderQueue: material.renderQueue, standardMode: value); } internal static SourceAlphaMode ClassifySourceAlphaMode(bool alphaTestKeyword, bool alphaBlendKeyword, string renderType, string shaderName, int renderQueue, bool hasStandardMode, float standardMode, bool alphaClipEnabled, bool transparentSurface, bool transparentBlend) { string text = renderType ?? string.Empty; string a = shaderName ?? string.Empty; bool flag = alphaTestKeyword || alphaClipEnabled || text.IndexOf("Cutout", StringComparison.OrdinalIgnoreCase) >= 0 || (renderQueue >= 2450 && renderQueue < 3000) || string.Equals(a, "Custom/Grass", StringComparison.OrdinalIgnoreCase); bool flag2 = alphaBlendKeyword || transparentSurface || transparentBlend || (text.IndexOf("Transparent", StringComparison.OrdinalIgnoreCase) >= 0 && text.IndexOf("Cutout", StringComparison.OrdinalIgnoreCase) < 0) || renderQueue >= 3000; if (hasStandardMode) { int num = Mathf.RoundToInt(standardMode); flag = flag || num == 1; flag2 = flag2 || ((num == 2 || num == 3) && (alphaBlendKeyword || transparentSurface || transparentBlend || renderQueue >= 3000)); } if (flag && flag2) { return SourceAlphaMode.FadeCutout; } if (flag) { return SourceAlphaMode.Cutout; } if (!flag2) { return SourceAlphaMode.Opaque; } return SourceAlphaMode.Fade; } private static bool HasTransparentBlend(Material material, MaterialPropertyBlock overrides) { if (!TryGetFloat(material, overrides, SrcBlendId, out var value) || !TryGetFloat(material, overrides, DstBlendId, out var value2)) { return false; } if (Mathf.RoundToInt(value) == 1 && Mathf.RoundToInt(value2) == 0) { return false; } if (TryGetFloat(material, overrides, ZWriteId, out var value3)) { return value3 < 0.5f; } return true; } private static bool TryGetSourceAlphaTexture(Material material, MaterialPropertyBlock overrides, out Texture texture, out Vector4 scaleOffset) { //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Invalid comparison between Unknown and I4 //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_0070: Invalid comparison between Unknown and I4 //IL_0083: 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_0088: 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_008d: 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_00b4: 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_00c2: 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_00d0: 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) //IL_00de: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < SourceTextureProperties.Length; i++) { TextureProperty textureProperty = SourceTextureProperties[i]; bool flag = overrides != null && overrides.HasTexture(textureProperty.Texture); bool flag2 = material.HasTexture(textureProperty.Texture); if (flag || flag2) { texture = (flag ? overrides.GetTexture(textureProperty.Texture) : material.GetTexture(textureProperty.Texture)); if (!((Object)(object)texture == (Object)null) && (int)texture.dimension == 2) { Vector2 val = (flag2 ? material.GetTextureScale(textureProperty.Texture) : Vector2.one); Vector2 val2 = (flag2 ? material.GetTextureOffset(textureProperty.Texture) : Vector2.zero); scaleOffset = (Vector4)((overrides != null && overrides.HasVector(textureProperty.ScaleOffset)) ? overrides.GetVector(textureProperty.ScaleOffset) : new Vector4(val.x, val.y, val2.x, val2.y)); return true; } } } texture = material.mainTexture; if ((Object)(object)texture != (Object)null && (int)texture.dimension == 2) { Vector2 mainTextureScale = material.mainTextureScale; Vector2 mainTextureOffset = material.mainTextureOffset; scaleOffset = new Vector4(mainTextureScale.x, mainTextureScale.y, mainTextureOffset.x, mainTextureOffset.y); return true; } texture = null; scaleOffset = new Vector4(1f, 1f, 0f, 0f); return false; } private static bool TryGetFirstFloat(Material material, MaterialPropertyBlock overrides, int[] properties, out float value) { for (int i = 0; i < properties.Length; i++) { if (TryGetFloat(material, overrides, properties[i], out value)) { return true; } } value = 0f; return false; } private static bool TryGetFloat(Material material, MaterialPropertyBlock overrides, int property, out float value) { if (overrides != null && overrides.HasFloat(property)) { value = overrides.GetFloat(property); return true; } if ((Object)(object)material != (Object)null && material.HasProperty(property)) { value = material.GetFloat(property); return true; } value = 0f; return false; } private static bool TryGetColorAlpha(Material material, MaterialPropertyBlock overrides, int property, out float alpha) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (overrides != null && overrides.HasColor(property)) { alpha = overrides.GetColor(property).a; return true; } if ((Object)(object)material != (Object)null && material.HasProperty(property)) { alpha = material.GetColor(property).a; return true; } alpha = 1f; return false; } private static bool SourceAlphaClips(SourceAlphaMode mode) { if (mode != SourceAlphaMode.Cutout) { return mode == SourceAlphaMode.FadeCutout; } return true; } private static bool SourceAlphaBlends(SourceAlphaMode mode) { if (mode != SourceAlphaMode.Fade) { return mode == SourceAlphaMode.FadeCutout; } return true; } private static Renderer[] CaptureResourceRenderers(GameObject root) { MineRock5[] componentsInChildren = root.GetComponentsInChildren(true); if (componentsInChildren.Length != 0) { List list = new List(componentsInChildren.Length * 3); HashSet hashSet = new HashSet(); for (int i = 0; i < componentsInChildren.Length; i++) { MeshRenderer mineRock5CombinedRenderer = GameAccess.GetMineRock5CombinedRenderer(componentsInChildren[i]); if ((Object)(object)mineRock5CombinedRenderer == (Object)null) { return root.GetComponentsInChildren(true); } if (hashSet.Add(((Object)mineRock5CombinedRenderer).GetInstanceID())) { list.Add((Renderer)(object)mineRock5CombinedRenderer); } LODGroup componentInParent = ((Component)componentsInChildren[i]).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { continue; } LOD[] lODs = componentInParent.GetLODs(); for (int j = 1; j < lODs.Length; j++) { Renderer[] renderers = lODs[j].renderers; if (renderers == null) { continue; } foreach (Renderer val in renderers) { if ((Object)(object)val != (Object)null && hashSet.Add(((Object)val).GetInstanceID())) { list.Add(val); } } } } return list.ToArray(); } return root.GetComponentsInChildren(true); } internal bool UpdatePermissions(string id, bool mayShimmer, bool allowXray, bool useSourceAlphaMask = false) { if (string.IsNullOrEmpty(id) || !_resources.TryGetValue(id, out var value)) { return false; } if ((Object)(object)value.Root == (Object)null) { _resources.Remove(id); InvalidateXraySelection(value); ReleaseVisual(value); return false; } bool flag = value.AllowXray != allowXray; bool flag2 = value.UseSourceAlphaMask != useSourceAlphaMask; value.Registered = true; value.MayShimmer = mayShimmer; value.AllowXray = allowXray; value.UseSourceAlphaMask = useSourceAlphaMask; if (!(_config.ShimmerEnabled.Value && mayShimmer) && !(_config.XrayEnabled.Value && allowXray)) { _resources.Remove(id); InvalidateXraySelection(value); ReleaseVisual(value); return true; } if (flag) { _xraySelectionDirty = true; InvalidateXraySelection(value); } if (flag2) { value.SourceAlphaBindings = CaptureSourceAlphaBindings(value.Renderers, useSourceAlphaMask); } return true; } internal void Unregister(string id) { if (!string.IsNullOrEmpty(id) && _resources.TryGetValue(id, out var value)) { _resources.Remove(id); if (value.AllowXray) { _xraySelectionDirty = true; } InvalidateXraySelection(value); ReleaseVisual(value); } } internal void RefreshConfiguration() { Stop(); if (IsHeadlessGraphics()) { ReleaseAllVisuals(); DestroyGeometryAssets(); return; } if (_config.ShimmerEnabled.Value) { _routine = ((MonoBehaviour)_plugin).StartCoroutine(EffectLoop()); } StartXrayIfVisible(); if (!_config.AnyResourceVisualEnabled) { ReleaseAllVisuals(); DestroyGeometryAssets(); } } internal void Clear() { Stop(); ReleaseAllVisuals(); _nearby.Clear(); _shimmerSelectionGeneration = 0L; _registrationSequence = 0L; DestroyGeometryAssets(); } private void Stop() { if (_routine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_routine); _routine = null; } StopXrayOnly(); RestoreActive(); _nearby.Clear(); _rendererBuffer.Clear(); _axisSamples.Clear(); _activeLods.Clear(); _renderCamera = null; } internal bool TryToggleXrayVisibility(out bool visible) { visible = false; if (!_config.XrayEnabled.Value || IsHeadlessGraphics() || _shaderUnavailable) { return false; } _xrayVisible = !_xrayVisible; if (_xrayVisible) { StartXrayIfVisible(); } else { StopXrayOnly(); } visible = _xrayVisible; return true; } private void StartXrayIfVisible() { if (_xrayRoutine == null && _xrayVisible && _config.XrayEnabled.Value && !_shaderUnavailable && !IsHeadlessGraphics()) { _xrayRoutine = ((MonoBehaviour)_plugin).StartCoroutine(XrayLoop()); } } private void StopXrayOnly() { if (_xrayRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_xrayRoutine); _xrayRoutine = null; } ReleaseXraySelection(); ClearPlayerMaskCache(); } private static bool IsHeadlessGraphics() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType != 4) { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsDedicated(); } return false; } return true; } private IEnumerator EffectLoop() { WaitForSecondsRealtime idlePoll = new WaitForSecondsRealtime(0.2f); bool skipConfiguredGap = true; try { while (_config.ShimmerEnabled.Value) { Player player = Player.m_localPlayer; if ((Object)(object)player == (Object)null || ((Character)player).IsDead()) { yield return idlePoll; continue; } if (!skipConfiguredGap) { ShimmerAnimationMode value = _config.ShimmerMode.Value; float configuredGap = Mathf.Max(0.5f, (value == ShimmerAnimationMode.Pulse) ? _config.PulseInterval.Value : _config.SweepInterval.Value); float waitStarted = Time.unscaledTime; while (_config.ShimmerEnabled.Value) { player = Player.m_localPlayer; if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || Time.unscaledTime - waitStarted >= configuredGap) { break; } yield return idlePoll; } if ((Object)(object)player == (Object)null || ((Character)player).IsDead()) { yield return idlePoll; continue; } } skipConfiguredGap = false; ShimmerAnimationMode mode = _config.ShimmerMode.Value; if (!EnsureGeometryMaterial()) { yield return idlePoll; continue; } UpdateRenderCamera(); Vector3 position = ((Component)player).transform.position; CollectNearby(position, _config.ShimmerRadius.Value, forXray: false); PrepareCompleteVeins(); if (_sweepVeins.Count == 0) { continue; } float duration = ((mode == ShimmerAnimationMode.Pulse) ? Mathf.Max(0.1f, _config.PulseDuration.Value) : MaximumPreparedSweepDuration()); SnapshotEffectStyle(mode); float started = Time.unscaledTime; while (_config.ShimmerEnabled.Value && (mode != ShimmerAnimationMode.Sweep || !_shaderUnavailable)) { float waitStarted = Mathf.Min(Mathf.Max(0f, Time.unscaledTime - started), duration); ApplyEffectFrame(waitStarted, duration, mode); yield return null; if (waitStarted >= duration) { break; } player = Player.m_localPlayer; if ((Object)(object)player == (Object)null || ((Character)player).IsDead()) { break; } } RestoreActive(); } } finally { ShimmerService shimmerService = this; shimmerService.RestoreActive(); shimmerService._routine = null; } } private IEnumerator XrayLoop() { WaitForSecondsRealtime wait = new WaitForSecondsRealtime(0.5f); try { while (_xrayVisible && _config.XrayEnabled.Value && !_shaderUnavailable) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { if (_xraySelectionValid || _xrayParts.Count > 0) { ClearXraySelectionInPlace(); InvalidateXrayCache(); } } else { UpdateRenderCamera(); if (!EnsureGeometryMaterial()) { break; } Vector3 position = ((Component)localPlayer).transform.position; float unscaledTime = Time.unscaledTime; if (ShouldRefreshXraySelection(position, unscaledTime)) { CollectNearby(position, _config.XrayRadius.Value, forXray: true); PrepareXray(position, unscaledTime); } else if (HaveXrayCommandSettingsChanged()) { RebuildXrayCommandBuffer(); } } yield return wait; } } finally { ShimmerService shimmerService = this; shimmerService.ReleaseXraySelection(); shimmerService._xrayRoutine = null; } } private void UpdateRenderCamera() { GameCamera instance = GameCamera.instance; Camera val = (((Object)(object)instance != (Object)null) ? ((Component)instance).GetComponent() : Camera.main); if (!((Object)(object)val == (Object)(object)_renderCamera)) { ReleaseXraySelection(); _renderCamera = val; } } private void CollectNearby(Vector3 playerPosition, float radius, bool forXray) { //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_0088: 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_0098: 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) _nearby.Clear(); float num = radius * radius; _staleIds.Clear(); foreach (KeyValuePair resource in _resources) { ResourceVisual value = resource.Value; if ((Object)(object)value.Root == (Object)null) { _staleIds.Add(resource.Key); } else if (!(forXray ? (!value.AllowXray) : (!value.MayShimmer))) { Vector3 position = value.Root.transform.position; float num2 = playerPosition.x - position.x; float num3 = playerPosition.z - position.z; value.DistanceSqr = num2 * num2 + num3 * num3; if (value.DistanceSqr <= num) { _nearby.Add(value); } } } for (int i = 0; i < _staleIds.Count; i++) { string key = _staleIds[i]; if (_resources.TryGetValue(key, out var value2)) { InvalidateXraySelection(value2); ReleaseVisual(value2); } _resources.Remove(key); } _staleIds.Clear(); _nearby.Sort(forXray ? DistanceComparison : ShimmerPriorityComparison); } private static int CompareByDistance(ResourceVisual first, ResourceVisual second) { int num = first.DistanceSqr.CompareTo(second.DistanceSqr); if (num == 0) { return first.RegistrationOrder.CompareTo(second.RegistrationOrder); } return num; } private static int CompareBySelectionAgeThenDistance(ResourceVisual first, ResourceVisual second) { return CompareSelectionPriority(first.LastSelectedGeneration, first.DistanceSqr, first.RegistrationOrder, second.LastSelectedGeneration, second.DistanceSqr, second.RegistrationOrder); } internal static int CompareSelectionPriority(long firstGeneration, float firstDistanceSqr, long firstRegistrationOrder, long secondGeneration, float secondDistanceSqr, long secondRegistrationOrder) { int num = firstGeneration.CompareTo(secondGeneration); if (num != 0) { return num; } int num2 = firstDistanceSqr.CompareTo(secondDistanceSqr); if (num2 == 0) { return firstRegistrationOrder.CompareTo(secondRegistrationOrder); } return num2; } private long NextShimmerSelectionGeneration() { if (_shimmerSelectionGeneration == long.MaxValue) { foreach (ResourceVisual value in _resources.Values) { value.LastSelectedGeneration = 0L; } _shimmerSelectionGeneration = 0L; } return ++_shimmerSelectionGeneration; } private bool ShouldRefreshXraySelection(Vector3 playerPosition, float now) { //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) float value = _config.XrayRadius.Value; int num = Mathf.Max(1, _config.XrayRendererBudget.Value); int num2 = Mathf.Max(1, _config.XrayDrawCommandBudget.Value); if (_xraySelectionDirty || !_xraySelectionValid || !Mathf.Approximately(_xraySelectionRadius, value) || _xraySelectionRendererBudget != num || _xraySelectionDrawBudget != num2 || now - _xrayLastSelectionRefresh >= 5f) { return true; } if (ExceedsHorizontalRefreshDistance(_xraySelectionOrigin, playerPosition, 2f)) { return true; } return HasXrayLodOrRendererChanged(); } internal static bool ExceedsHorizontalRefreshDistance(Vector3 origin, Vector3 current, float distance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = current.x - origin.x; float num2 = current.z - origin.z; float num3 = Mathf.Max(0f, distance); return num * num + num2 * num2 >= num3 * num3; } private bool HasXrayLodOrRendererChanged() { _activeLods.Clear(); for (int i = 0; i < _xrayParts.Count; i++) { GeometryPart geometryPart = _xrayParts[i]; if (geometryPart.Owner == null || !IsRendererAtActiveLod(geometryPart.Owner, geometryPart.Renderer) || !TryGetCachedStaticMesh(geometryPart.Renderer, geometryPart.Filter, out var mesh) || (Object)(object)mesh != (Object)(object)geometryPart.Mesh) { return true; } } return false; } private bool HaveXrayCommandSettingsChanged() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (_xrayCommandSettingsValid && !(_xrayCommandColor != _config.GetXrayColor()) && Mathf.Approximately(_xrayCommandIntensity, Mathf.Clamp(_config.XrayIntensity.Value, 1f, 10f))) { return _xrayCommandDrawBudget != Mathf.Max(1, _config.XrayDrawCommandBudget.Value); } return true; } private void PrepareXray(Vector3 playerPosition, float now) { //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if (_shaderUnavailable) { return; } if ((Object)(object)_renderCamera == (Object)null) { ClearXraySelectionInPlace(); } else { if (!EnsureGeometryMaterial()) { return; } ClearXraySelectionInPlace(); int num = Mathf.Max(1, _config.XrayRendererBudget.Value); int num2 = num; int num3 = Mathf.Max(1, _config.XrayDrawCommandBudget.Value); int num4 = num3; _activeLods.Clear(); for (int i = 0; i < _nearby.Count; i++) { if (num2 <= 0) { break; } if (num4 <= 0) { break; } ResourceVisual resourceVisual = _nearby[i]; CollectActiveMeshRenderers(resourceVisual); int count = _rendererBuffer.Count; int num5 = XrayDrawCommandCost(_rendererBuffer); if (count != 0 && count <= num2 && num5 > 0 && num5 <= num4) { for (int j = 0; j < _rendererBuffer.Count; j++) { RendererPart rendererPart = _rendererBuffer[j]; _xrayParts.Add(AcquireGeometryPart(resourceVisual, rendererPart.Renderer, rendererPart.Filter, rendererPart.Mesh, rendererPart.LocalToWorldMatrix, null)); _xrayOwners.Add(resourceVisual); } num2 -= count; num4 -= num5; } } _xraySelectionOrigin = playerPosition; _xraySelectionRadius = _config.XrayRadius.Value; _xraySelectionRendererBudget = num; _xraySelectionDrawBudget = num3; _xrayLastSelectionRefresh = now; _xraySelectionDirty = false; _xraySelectionValid = true; RebuildXrayCommandBuffer(); } } private static int XrayDrawCommandCost(List renderers) { int num = 0; for (int i = 0; i < renderers.Count; i++) { Mesh mesh = renderers[i].Mesh; if ((Object)(object)mesh != (Object)null) { num += mesh.subMeshCount; } } return num; } private void PrepareCompleteVeins() { int num = Mathf.Max(1, _config.ShimmerRendererBudget.Value); int num2 = Mathf.Clamp(_config.ShimmerRendererBudget.Value, 1, 128); int num3 = 0; long lastSelectedGeneration = NextShimmerSelectionGeneration(); _activeLods.Clear(); if (!CaptureShimmerFrustum()) { return; } for (int i = 0; i < _nearby.Count; i++) { if (num <= 0) { break; } ResourceVisual resourceVisual = _nearby[i]; bool useSourceAlphaMask = resourceVisual.UseSourceAlphaMask; CollectActiveMeshRenderers(resourceVisual); int count = _rendererBuffer.Count; if (count == 0 || !HasRendererInCurrentFrustum(_rendererBuffer)) { continue; } int num4 = EstimateSourceMaskedDrawCommands(_rendererBuffer); if (CanAdmitHighlightCandidate(useSourceAlphaMask, count, num4, num, num2, num3) && PrepareSweepVein(resourceVisual)) { num -= count; num2 -= num4; resourceVisual.LastSelectedGeneration = lastSelectedGeneration; if (!useSourceAlphaMask) { num3++; } } } } internal static bool CanAdmitHighlightCandidate(bool pickable, int rendererCount, int maskedDrawCommands, int rendererBudget, int maskedDrawBudget, int preparedResources) { if (rendererCount <= 0 || maskedDrawCommands < 0 || rendererCount > rendererBudget || maskedDrawCommands > maskedDrawBudget) { return false; } if (!pickable) { return preparedResources < 4; } return true; } private bool CaptureShimmerFrustum() { if ((Object)(object)_renderCamera == (Object)null) { return false; } GeometryUtility.CalculateFrustumPlanes(_renderCamera, _shimmerFrustumPlanes); return true; } private static int EstimateSourceMaskedDrawCommands(List renderers) { bool flag = false; for (int i = 0; i < renderers.Count; i++) { if (HasEnabledSourceAlphaBinding(renderers[i].SourceAlphaBindings)) { flag = true; break; } } if (!flag) { return 0; } int num = 0; for (int j = 0; j < renderers.Count; j++) { RendererPart rendererPart = renderers[j]; SourceAlphaBinding[] sourceAlphaBindings = rendererPart.SourceAlphaBindings; if (sourceAlphaBindings == null || sourceAlphaBindings.Length <= 1) { num++; continue; } Mesh mesh = rendererPart.Mesh; num += (((Object)(object)mesh != (Object)null) ? mesh.subMeshCount : 0); if (num > 128) { return num; } } return num; } private float MaximumPreparedSweepDuration() { float num = 0.1f; for (int i = 0; i < _sweepVeins.Count; i++) { num = Mathf.Max(num, _sweepVeins[i].TravelDuration); } return num; } private bool PrepareSweepVein(ResourceVisual visual) { //IL_0002: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0077: 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_00b9: 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_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) Bounds completeBounds = default(Bounds); bool hasBounds = false; _axisSamples.Clear(); for (int i = 0; i < _rendererBuffer.Count; i++) { RendererPart rendererPart = _rendererBuffer[i]; AddTransformedBoundsSamples(rendererPart.Mesh.bounds, rendererPart.LocalToWorldMatrix, _axisSamples, ref completeBounds, ref hasBounds); } if (!hasBounds) { return false; } Vector3 axis = SelectSweepAxis(visual.Root, completeBounds, _axisSamples); GetProjectionRange(_axisSamples, axis, out var minimum, out var maximum); if (maximum - minimum <= 0.001f) { return false; } SweepVein sweepVein = ((_sweepVeinPool.Count > 0) ? _sweepVeinPool.Pop() : new SweepVein()); sweepVein.Axis = axis; sweepVein.MinimumProjection = minimum; sweepVein.MaximumProjection = maximum; float sweepLength = maximum - minimum; sweepVein.WaveHalfWidth = SweepBandHalfWidth(sweepLength, _config.SweepWaveWidth.Value); sweepVein.TravelDuration = SweepTravelDuration(SweepTravelDistance(sweepLength, sweepVein.WaveHalfWidth), _config.SweepSpeed.Value, _config.SweepMaximumDuration.Value); sweepVein.IsPickable = visual.UseSourceAlphaMask; for (int j = 0; j < _rendererBuffer.Count; j++) { RendererPart rendererPart2 = _rendererBuffer[j]; GeometryPart geometryPart = AcquireGeometryPart(visual, rendererPart2.Renderer, rendererPart2.Filter, rendererPart2.Mesh, rendererPart2.LocalToWorldMatrix, rendererPart2.SourceAlphaBindings); GetTransformedProjectionRange(rendererPart2.Mesh.bounds, rendererPart2.LocalToWorldMatrix, axis, out geometryPart.MinimumProjection, out geometryPart.MaximumProjection); sweepVein.Parts.Add(geometryPart); sweepVein.HasSourceAlphaMask |= HasEnabledSourceAlphaBinding(geometryPart.SourceAlphaBindings); } if (sweepVein.Parts.Count == 0) { RecycleSweepVein(sweepVein); return false; } _sweepVeins.Add(sweepVein); return true; } private GeometryPart AcquireGeometryPart(ResourceVisual visual, Renderer renderer, MeshFilter filter, Mesh mesh, Matrix4x4 localToWorldMatrix, SourceAlphaBinding[] sourceAlphaBindings) { //IL_003e: 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) GeometryPart obj = ((_geometryPartPool.Count > 0) ? _geometryPartPool.Pop() : new GeometryPart()); obj.Owner = visual; obj.Renderer = renderer; obj.Filter = filter; obj.Mesh = mesh; obj.LocalToWorldMatrix = localToWorldMatrix; obj.SourceAlphaBindings = sourceAlphaBindings; return obj; } private static bool HasEnabledSourceAlphaBinding(SourceAlphaBinding[] bindings) { if (bindings == null) { return false; } for (int i = 0; i < bindings.Length; i++) { if (bindings[i].Enabled) { return true; } } return false; } private static Vector3 SelectSweepAxis(GameObject root, Bounds bounds, IReadOnlyList rendererCenters) { //IL_0016: 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_001b: 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_0083: 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_00a6: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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) //IL_0067: 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) Vector3 best = (((Object)(object)root != (Object)null) ? root.transform.right : Vector3.right); float bestSpan = -1f; if ((Object)(object)root != (Object)null) { ConsiderAxis(root.transform.right, ((Bounds)(ref bounds)).extents, ref best, ref bestSpan); ConsiderAxis(root.transform.up, ((Bounds)(ref bounds)).extents, ref best, ref bestSpan); ConsiderAxis(root.transform.forward, ((Bounds)(ref bounds)).extents, ref best, ref bestSpan); } ConsiderAxis(Vector3.right, ((Bounds)(ref bounds)).extents, ref best, ref bestSpan); ConsiderAxis(Vector3.up, ((Bounds)(ref bounds)).extents, ref best, ref bestSpan); ConsiderAxis(Vector3.forward, ((Bounds)(ref bounds)).extents, ref best, ref bestSpan); return DominantAxis(rendererCenters, best); } internal static Vector3 DominantAxis(IReadOnlyList points, Vector3 fallback) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_0029: 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_0030: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0062: 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_009c: 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) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_00bd: 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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0174: 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_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: 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_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((((Vector3)(ref fallback)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref fallback)).normalized : Vector3.right); if (points == null || points.Count < 2) { return val; } Vector3 val2 = Vector3.zero; for (int i = 0; i < points.Count; i++) { val2 += points[i]; } val2 /= (float)points.Count; float num = 0f; float num2 = 0f; float num3 = 0f; float num4 = 0f; float num5 = 0f; float num6 = 0f; for (int j = 0; j < points.Count; j++) { Vector3 val3 = points[j] - val2; num += val3.x * val3.x; num2 += val3.x * val3.y; num3 += val3.x * val3.z; num4 += val3.y * val3.y; num5 += val3.y * val3.z; num6 += val3.z * val3.z; } float num7 = num + num4 + num6; if (num7 < 0.0001f) { return val; } Vector3 val4 = val + new Vector3(0.173f, 0.271f, 0.419f); Vector3 val5 = ((Vector3)(ref val4)).normalized; for (int k = 0; k < 8; k++) { Vector3 val6 = MultiplySymmetric(val5, num, num2, num3, num4, num5, num6); if (((Vector3)(ref val6)).sqrMagnitude < 1E-07f) { return val; } val5 = ((Vector3)(ref val6)).normalized; } if (Vector3.Dot(val5, MultiplySymmetric(val5, num, num2, num3, num4, num5, num6)) / num7 < 0.55f) { return val; } if (Vector3.Dot(val5, val) < 0f) { val5 = -val5; } return val5; } private static Vector3 MultiplySymmetric(Vector3 value, float xx, float xy, float xz, float yy, float yz, float zz) { //IL_0001: 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_0012: 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_0024: 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_0037: 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_004a: 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) return new Vector3(xx * value.x + xy * value.y + xz * value.z, xy * value.x + yy * value.y + yz * value.z, xz * value.x + yz * value.y + zz * value.z); } private static void ConsiderAxis(Vector3 candidate, Vector3 extents, ref Vector3 best, ref float bestSpan) { //IL_0016: 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_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) if (!(((Vector3)(ref candidate)).sqrMagnitude < 0.0001f)) { ((Vector3)(ref candidate)).Normalize(); float num = ProjectedExtent(extents, candidate); if (num > bestSpan) { best = candidate; bestSpan = num; } } } private static float ProjectedExtent(Vector3 extents, Vector3 direction) { //IL_0000: 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_0012: 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_0025: 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) return Mathf.Abs(direction.x) * extents.x + Mathf.Abs(direction.y) * extents.y + Mathf.Abs(direction.z) * extents.z; } internal static void AddTransformedBoundsSamples(Bounds localBounds, Matrix4x4 localToWorld, List samples, ref Bounds completeBounds, ref bool hasBounds) { //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_000a: 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_0017: 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_001d: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0067: 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_008f: 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_0079: 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) Vector3 center = ((Bounds)(ref localBounds)).center; Vector3 extents = ((Bounds)(ref localBounds)).extents; for (int i = 0; i < 8; i++) { Vector3 val = center + new Vector3(((i & 1) == 0) ? (0f - extents.x) : extents.x, ((i & 2) == 0) ? (0f - extents.y) : extents.y, ((i & 4) == 0) ? (0f - extents.z) : extents.z); Vector3 val2 = ((Matrix4x4)(ref localToWorld)).MultiplyPoint3x4(val); samples.Add(val2); if (!hasBounds) { completeBounds = new Bounds(val2, Vector3.zero); hasBounds = true; } else { ((Bounds)(ref completeBounds)).Encapsulate(val2); } } } internal static void GetProjectionRange(List samples, Vector3 axis, out float minimum, out float maximum) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) minimum = float.PositiveInfinity; maximum = float.NegativeInfinity; for (int i = 0; i < samples.Count; i++) { float num = Vector3.Dot(samples[i], axis); minimum = Mathf.Min(minimum, num); maximum = Mathf.Max(maximum, num); } } internal static void GetTransformedProjectionRange(Bounds localBounds, Matrix4x4 localToWorld, Vector3 axis, out float minimum, out float maximum) { //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) //IL_001e: 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_0031: 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_0045: 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_0059: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_006d: 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_0073: Unknown result type (might be due to invalid IL or missing references) minimum = float.PositiveInfinity; maximum = float.NegativeInfinity; Vector3 center = ((Bounds)(ref localBounds)).center; Vector3 extents = ((Bounds)(ref localBounds)).extents; for (int i = 0; i < 8; i++) { Vector3 val = center + new Vector3(((i & 1) == 0) ? (0f - extents.x) : extents.x, ((i & 2) == 0) ? (0f - extents.y) : extents.y, ((i & 4) == 0) ? (0f - extents.z) : extents.z); float num = Vector3.Dot(((Matrix4x4)(ref localToWorld)).MultiplyPoint3x4(val), axis); minimum = Mathf.Min(minimum, num); maximum = Mathf.Max(maximum, num); } } internal static bool ProjectionRangesOverlap(float firstMinimum, float firstMaximum, float secondMinimum, float secondMaximum) { if (firstMaximum >= secondMinimum) { return secondMaximum >= firstMinimum; } return false; } private void EnsureLodBindings(ResourceVisual visual) { if (visual.LodBindingsCached) { return; } visual.LodBindingsCached = true; _lodGroupBuffer.Clear(); visual.Root.GetComponentsInChildren(true, _lodGroupBuffer); if (_lodGroupBuffer.Count == 0) { return; } visual.LodBindings = new Dictionary(); for (int i = 0; i < _lodGroupBuffer.Count; i++) { LODGroup val = _lodGroupBuffer[i]; if ((Object)(object)val == (Object)null) { continue; } LOD[] lODs = val.GetLODs(); for (int j = 0; j < lODs.Length; j++) { Renderer[] renderers = lODs[j].renderers; if (renderers == null) { continue; } foreach (Renderer val2 in renderers) { if ((Object)(object)val2 != (Object)null) { visual.LodBindings[((Object)val2).GetInstanceID()] = new LodBinding(val, lODs, j); } } } } _lodGroupBuffer.Clear(); } private void CollectActiveMeshRenderers(ResourceVisual visual) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) _rendererBuffer.Clear(); EnsureLodBindings(visual); Renderer[] renderers = visual.Renderers; MeshFilter[] meshFilters = visual.MeshFilters; if (renderers == null || meshFilters == null) { return; } int num = Mathf.Min(renderers.Length, meshFilters.Length); for (int i = 0; i < num; i++) { Renderer val = renderers[i]; if (IsRendererAtActiveLod(visual, val) && TryGetCachedStaticMesh(val, meshFilters[i], out var mesh)) { SourceAlphaBinding[] sourceAlphaBindings = ((visual.SourceAlphaBindings != null && i < visual.SourceAlphaBindings.Length) ? visual.SourceAlphaBindings[i] : null); _rendererBuffer.Add(new RendererPart(val, meshFilters[i], mesh, val.localToWorldMatrix, sourceAlphaBindings)); } } } private bool IsRendererAtActiveLod(ResourceVisual visual, Renderer renderer) { if (!IsRendererDrawable(renderer)) { return false; } if (visual.LodBindings == null || !visual.LodBindings.TryGetValue(((Object)renderer).GetInstanceID(), out var value) || (Object)(object)value.Group == (Object)null || !value.Group.enabled || (Object)(object)_renderCamera == (Object)null) { return true; } if (!_activeLods.TryGetValue(value.Group, out var value2)) { value2 = CalculateActiveLod(value.Group, value.Levels, _renderCamera); _activeLods[value.Group] = value2; } return value.Level == value2; } internal static int CalculateActiveLod(LODGroup group, IReadOnlyList levels, Camera camera) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0038: 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_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_007d: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)group == (Object)null || (Object)(object)camera == (Object)null) { return 0; } if (levels == null || levels.Count == 0) { return 0; } Vector3 lossyScale = ((Component)group).transform.lossyScale; float num = Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Max(Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z))); float num2 = Mathf.Max(0.001f, group.size * num); Vector3 val = ((Component)group).transform.TransformPoint(group.localReferencePoint); float num3; if (camera.orthographic) { num3 = num2 / Mathf.Max(0.001f, camera.orthographicSize * 2f); } else { float num4 = Vector3.Distance(((Component)camera).transform.position, val); float num5 = 2f * Mathf.Max(0.001f, num4) * Mathf.Tan(camera.fieldOfView * 0.5f * (MathF.PI / 180f)); num3 = num2 / Mathf.Max(0.001f, num5); } num3 *= Mathf.Max(0.01f, QualitySettings.lodBias); for (int i = 0; i < levels.Count; i++) { if (num3 >= levels[i].screenRelativeTransitionHeight) { return i; } } return -1; } private bool HasRendererInCurrentFrustum(List renderers) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_renderCamera == (Object)null) { return false; } int cullingMask = _renderCamera.cullingMask; for (int i = 0; i < renderers.Count; i++) { Renderer renderer = renderers[i].Renderer; if ((Object)(object)renderer != (Object)null && (cullingMask & (1 << ((Component)renderer).gameObject.layer)) != 0 && GeometryUtility.TestPlanesAABB(_shimmerFrustumPlanes, renderer.bounds)) { return true; } } return false; } private static bool IsRendererDrawable(Renderer renderer) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if ((Object)(object)renderer != (Object)null && renderer.enabled && !renderer.forceRenderingOff && (int)renderer.shadowCastingMode != 3) { return ((Component)renderer).gameObject.activeInHierarchy; } return false; } private static bool TryGetCachedStaticMesh(Renderer renderer, MeshFilter filter, out Mesh mesh) { mesh = null; if (!(renderer is MeshRenderer) || !IsRendererDrawable(renderer)) { return false; } mesh = (((Object)(object)filter != (Object)null) ? filter.sharedMesh : null); return (Object)(object)mesh != (Object)null; } private void SnapshotEffectStyle(ShimmerAnimationMode mode) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) _sweepColor = _config.GetShimmerColor(mode); float intensity = ((mode == ShimmerAnimationMode.Pulse) ? _config.PulseIntensity.Value : _config.SweepIntensity.Value); _sweepGain = HighlightGain(intensity); } private void ApplyEffectFrame(float elapsed, float duration, ShimmerAnimationMode mode) { float num = PulseEnvelope(Mathf.Clamp01(elapsed / Mathf.Max(0.1f, duration))); bool flag = !_shaderUnavailable && _sweepVeins.Count > 0; if (_sweepActive != flag) { _sweepActive = flag; ((Behaviour)_overlay).enabled = flag; } _geometryHighlightMode = mode; _effectElapsed = Mathf.Max(0f, elapsed); _sweepOpacity = 0.42f * ((mode == ShimmerAnimationMode.Pulse) ? num : 1f); } internal static float PulseEnvelope(float progress) { return 0.5f - 0.5f * Mathf.Cos(Mathf.Clamp01(progress) * MathF.PI * 2f); } internal static float SweepTravelDuration(float travelDistance, float speedMetersPerSecond, float maximumDuration) { float num = Mathf.Max(0f, travelDistance); float num2 = Mathf.Max(0.1f, speedMetersPerSecond); float num3 = Mathf.Max(0.1f, maximumDuration); return Mathf.Min(Mathf.Max(0.1f, num / num2), num3); } internal static float HighlightGain(float intensity) { return 1f + 0.25f * Mathf.Clamp(intensity, 1f, 10f); } internal static float SweepVisualWidth(float configuredWidth) { return Mathf.Clamp(configuredWidth * 0.24f, 0.015f, 0.48f); } internal static float SweepBandHalfWidth(float sweepLength, float configuredWidth) { return Mathf.Max(0.1f, Mathf.Max(0f, sweepLength) * SweepVisualWidth(configuredWidth)); } internal static float SweepTravelDistance(float sweepLength, float halfWidth) { return Mathf.Max(0f, sweepLength) + Mathf.Max(0f, halfWidth) * 2f; } internal static float SweepWorldCenter(float minimumProjection, float maximumProjection, float halfWidth, float progress) { float num = Mathf.Max(0f, halfWidth); return Mathf.Lerp(minimumProjection - num, maximumProjection + num, Mathf.Clamp01(progress)); } internal static bool TryGetSweepFrame(float elapsed, float duration, bool terminalFrameRendered, out float progress, out bool terminalFrame) { float num = Mathf.Max(0.1f, duration); float num2 = Mathf.Max(0f, elapsed); if (num2 < num) { progress = Mathf.Clamp01(num2 / num); terminalFrame = false; return true; } progress = 1f; terminalFrame = !terminalFrameRendered; return terminalFrame; } internal void RenderGeometryOverlay(Camera camera) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0157: 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_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0170: 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_0183: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)camera == (Object)null || (Object)(object)camera != (Object)(object)_renderCamera || !_sweepActive || !EnsureGeometryMaterial()) { return; } try { _geometryMaterial.SetColor(SweepColorId, _sweepColor); _geometryMaterial.SetFloat(SweepGainId, _sweepGain); _geometryMaterial.SetFloat(SweepOpacityId, _sweepOpacity); _geometryMaterial.SetFloat(SweepSoftnessId, Mathf.Clamp01(_config.SweepSoftness.Value)); _geometryMaterial.SetFloat(SweepZTestId, 4f); bool flag = _geometryHighlightMode == ShimmerAnimationMode.Pulse; _geometryMaterial.SetFloat(SweepWholeVeinId, flag ? 1f : 0f); int drawBudget = Mathf.Clamp(_config.ShimmerRendererBudget.Value, 1, 128); for (int i = 0; i < _sweepVeins.Count; i++) { SweepVein sweepVein = _sweepVeins[i]; float progress = 0f; bool terminalFrame = false; if (!flag && !TryGetSweepFrame(_effectElapsed, sweepVein.TravelDuration, sweepVein.TerminalFrameRendered, out progress, out terminalFrame)) { continue; } if (!flag && terminalFrame) { sweepVein.TerminalFrameRendered = true; } float num = sweepVein.MaximumProjection - sweepVein.MinimumProjection; if (num <= 0.001f) { continue; } Vector3 axis = sweepVein.Axis; _geometryMaterial.SetVector(SweepAxisId, new Vector4(axis.x, axis.y, axis.z, 0f)); float num2 = (flag ? Mathf.Max(0.1f, num) : sweepVein.WaveHalfWidth); float num3 = (flag ? ((sweepVein.MinimumProjection + sweepVein.MaximumProjection) * 0.5f) : SweepWorldCenter(sweepVein.MinimumProjection, sweepVein.MaximumProjection, num2, progress)); _geometryMaterial.SetFloat(SweepCenterId, num3); _geometryMaterial.SetFloat(SweepHalfWidthId, num2); ApplySweepStencilPolicy(sweepVein.IsPickable); if (sweepVein.HasSourceAlphaMask) { if (!DrawSourceMaskedGeometryParts(sweepVein.Parts, flag, num3 - num2, num3 + num2, ref drawBudget)) { DisableGeometryAfterRenderFailure("Unity could not activate the source-masked Sweep shader pass"); break; } continue; } ApplySourceAlphaBinding(default(SourceAlphaBinding)); if (!_geometryMaterial.SetPass(_sweepPass)) { DisableGeometryAfterRenderFailure("Unity could not activate the Sweep shader pass"); break; } DrawGeometryParts(sweepVein.Parts, flag, num3 - num2, num3 + num2); } } catch (Exception ex) { DisableGeometryAfterRenderFailure(ex.GetType().Name + " - " + ex.Message); } } private void RebuildXrayCommandBuffer() { //IL_005c: 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_0071: Expected O, but got Unknown //IL_00a3: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) if (_shaderUnavailable || (Object)(object)_renderCamera == (Object)null) { ReleaseXraySelection(); return; } if (_xrayParts.Count == 0) { ClearXrayCommands(release: false); SnapshotXrayCommandSettings(); return; } try { if (_xrayCommandBuffer == null || (Object)(object)_xrayCommandCamera != (Object)(object)_renderCamera) { ClearXrayCommands(release: true); _xrayCommandBuffer = new CommandBuffer { name = "RavenMap discovered-resource X-ray" }; _xrayCommandCamera = _renderCamera; _xrayCommandCamera.AddCommandBuffer((CameraEvent)18, _xrayCommandBuffer); } else { _xrayCommandBuffer.Clear(); } Color xrayColor = _config.GetXrayColor(); float num = Mathf.Clamp(_config.XrayIntensity.Value, 1f, 10f); int num2 = Mathf.Max(1, _config.XrayDrawCommandBudget.Value); _geometryMaterial.SetColor(XrayColorId, xrayColor); _geometryMaterial.SetFloat(XrayIntensityId, num); _geometryMaterial.SetFloat(XrayAlphaId, Mathf.Lerp(0.18f, 0.62f, (num - 1f) / 9f)); _geometryMaterial.SetFloat(XrayZTestId, 5f); AppendLocalPlayerMaskCommands(); int num3 = 0; for (int i = 0; i < _xrayParts.Count; i++) { if (num3 >= num2) { break; } GeometryPart geometryPart = _xrayParts[i]; if (!TryGetRenderableMesh(geometryPart, out var mesh)) { continue; } int subMeshCount = mesh.subMeshCount; for (int j = 0; j < subMeshCount; j++) { if (num3 >= num2) { break; } _xrayCommandBuffer.DrawMesh(mesh, geometryPart.LocalToWorldMatrix, _geometryMaterial, j, _xrayPass); num3++; } } if (num3 == 0) { ClearXrayCommands(release: false); } SnapshotXrayCommandSettings(); } catch (Exception ex) { DisableGeometryAfterRenderFailure(ex.GetType().Name + " - " + ex.Message); } } private void SnapshotXrayCommandSettings() { //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) _xrayCommandColor = _config.GetXrayColor(); _xrayCommandIntensity = Mathf.Clamp(_config.XrayIntensity.Value, 1f, 10f); _xrayCommandDrawBudget = Mathf.Max(1, _config.XrayDrawCommandBudget.Value); _xrayCommandSettingsValid = true; } private void AppendLocalPlayerMaskCommands() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { ClearPlayerMaskCache(); return; } if ((Object)(object)_playerMaskOwner != (Object)(object)localPlayer || (Object)(object)_playerMaskRoot == (Object)null) { _playerMaskOwner = localPlayer; _playerMaskRoot = ((Component)localPlayer).transform.Find("Visual") ?? ((Component)localPlayer).transform; } if ((Object)(object)_playerMaskRoot == (Object)null) { return; } _playerMaskRenderers.Clear(); ((Component)_playerMaskRoot).GetComponentsInChildren(false, _playerMaskRenderers); int num = 0; try { for (int i = 0; i < _playerMaskRenderers.Count; i++) { if (num >= 256) { break; } Renderer val = _playerMaskRenderers[i]; if (!IsRendererDrawable(val) || !val.isVisible || (_renderCamera.cullingMask & (1 << ((Component)val).gameObject.layer)) == 0) { continue; } int num2 = PlayerMaskSubMeshCount(val); for (int j = 0; j < num2; j++) { if (num >= 256) { break; } _xrayCommandBuffer.DrawRenderer(val, _geometryMaterial, j, _playerMaskPass); num++; } } } finally { _playerMaskRenderers.Clear(); } } private static int PlayerMaskSubMeshCount(Renderer renderer) { Mesh val = null; SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (val2 != null) { val = val2.sharedMesh; } else { MeshRenderer val3 = (MeshRenderer)(object)((renderer is MeshRenderer) ? renderer : null); if (val3 != null) { MeshFilter component = ((Component)val3).GetComponent(); val = (((Object)(object)component != (Object)null) ? component.sharedMesh : null); } } if (!((Object)(object)val != (Object)null)) { return 0; } return val.subMeshCount; } private void ClearPlayerMaskCache() { _playerMaskRenderers.Clear(); _playerMaskOwner = null; _playerMaskRoot = null; } private void ClearXraySelectionInPlace() { ClearXrayCommands(release: false); ClearGeometryParts(_xrayParts); _xrayOwners.Clear(); } private void ReleaseXraySelection() { ClearXrayCommands(release: true); ClearGeometryParts(_xrayParts); _xrayOwners.Clear(); InvalidateXrayCache(); } private void InvalidateXrayCache() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) _xraySelectionDirty = true; _xraySelectionValid = false; _xrayCommandSettingsValid = false; _xraySelectionOrigin = default(Vector3); _xraySelectionRadius = 0f; _xrayLastSelectionRefresh = 0f; _xraySelectionRendererBudget = 0; _xraySelectionDrawBudget = 0; _xrayCommandDrawBudget = 0; } private void ClearXrayCommands(bool release) { if (_xrayCommandBuffer == null) { _xrayCommandCamera = null; } else if (release) { try { _xrayCommandBuffer.Clear(); } catch (Exception) { } if ((Object)(object)_xrayCommandCamera != (Object)null) { try { _xrayCommandCamera.RemoveCommandBuffer((CameraEvent)18, _xrayCommandBuffer); } catch (Exception) { } } try { _xrayCommandBuffer.Release(); } catch (Exception) { } _xrayCommandBuffer = null; _xrayCommandCamera = null; } else { _xrayCommandBuffer.Clear(); } } private void InvalidateXraySelection(ResourceVisual visual) { if (visual != null && _xrayOwners.Contains(visual)) { RemoveXrayParts(visual); _xrayOwners.Remove(visual); _xraySelectionDirty = true; ClearXrayCommands(release: false); } } private void RemoveXrayParts(ResourceVisual visual) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) for (int num = _xrayParts.Count - 1; num >= 0; num--) { GeometryPart geometryPart = _xrayParts[num]; if (geometryPart.Owner == visual) { geometryPart.Owner = null; geometryPart.Renderer = null; geometryPart.Filter = null; geometryPart.Mesh = null; geometryPart.LocalToWorldMatrix = default(Matrix4x4); geometryPart.SourceAlphaBindings = null; geometryPart.MinimumProjection = 0f; geometryPart.MaximumProjection = 0f; _geometryPartPool.Push(geometryPart); _xrayParts.RemoveAt(num); } } } private static void DrawGeometryParts(List parts, bool drawWholeVein, float bandMinimum, float bandMaximum) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < parts.Count; i++) { GeometryPart geometryPart = parts[i]; if (TryGetRenderableMesh(geometryPart, out var mesh) && (drawWholeVein || ProjectionRangesOverlap(geometryPart.MinimumProjection, geometryPart.MaximumProjection, bandMinimum, bandMaximum))) { Graphics.DrawMeshNow(mesh, geometryPart.LocalToWorldMatrix); } } } private bool DrawSourceMaskedGeometryParts(List parts, bool drawWholeVein, float bandMinimum, float bandMaximum, ref int drawBudget) { //IL_006e: 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_00f0: Unknown result type (might be due to invalid IL or missing references) bool passActive = false; SourceAlphaBinding activeBinding = default(SourceAlphaBinding); for (int i = 0; i < parts.Count; i++) { if (drawBudget <= 0) { break; } GeometryPart geometryPart = parts[i]; if (!TryGetRenderableMesh(geometryPart, out var mesh) || (!drawWholeVein && !ProjectionRangesOverlap(geometryPart.MinimumProjection, geometryPart.MaximumProjection, bandMinimum, bandMaximum))) { continue; } SourceAlphaBinding[] sourceAlphaBindings = geometryPart.SourceAlphaBindings; if (sourceAlphaBindings == null || sourceAlphaBindings.Length == 0) { if (!ActivateSweepPass(default(SourceAlphaBinding), ref passActive, ref activeBinding)) { return false; } Graphics.DrawMeshNow(mesh, geometryPart.LocalToWorldMatrix); drawBudget--; continue; } if (sourceAlphaBindings.Length == 1) { if (!ActivateSweepPass(sourceAlphaBindings[0], ref passActive, ref activeBinding)) { return false; } Graphics.DrawMeshNow(mesh, geometryPart.LocalToWorldMatrix); drawBudget--; continue; } int subMeshCount = mesh.subMeshCount; for (int j = 0; j < subMeshCount; j++) { if (drawBudget <= 0) { break; } SourceAlphaBinding binding = sourceAlphaBindings[Mathf.Min(j, sourceAlphaBindings.Length - 1)]; if (!ActivateSweepPass(binding, ref passActive, ref activeBinding)) { return false; } Graphics.DrawMeshNow(mesh, geometryPart.LocalToWorldMatrix, j); drawBudget--; } } return true; } private bool ActivateSweepPass(SourceAlphaBinding binding, ref bool passActive, ref SourceAlphaBinding activeBinding) { if (passActive && SourceAlphaBindingEquals(activeBinding, binding)) { return true; } ApplySourceAlphaBinding(binding); if (!_geometryMaterial.SetPass(_sweepPass)) { return false; } activeBinding = binding; passActive = true; return true; } private void ApplySourceAlphaBinding(SourceAlphaBinding binding) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!_sourceAlphaStateValid || !SourceAlphaBindingEquals(_appliedSourceAlphaBinding, binding)) { if (!binding.Enabled) { _geometryMaterial.SetFloat(SourceAlphaEnabledId, 0f); _geometryMaterial.SetFloat(SourceAlphaClipId, 0f); _geometryMaterial.SetFloat(SourceAlphaBlendId, 0f); _geometryMaterial.SetFloat(SourceCullId, 2f); } else { _geometryMaterial.SetTexture(SourceAlphaTexId, binding.Texture); _geometryMaterial.SetVector(SourceAlphaTexStId, binding.ScaleOffset); _geometryMaterial.SetFloat(SourceAlphaCutoffId, binding.Cutoff); _geometryMaterial.SetFloat(SourceAlphaMultiplierId, binding.Multiplier); _geometryMaterial.SetFloat(SourceAlphaEnabledId, 1f); _geometryMaterial.SetFloat(SourceAlphaClipId, SourceAlphaClips(binding.Mode) ? 1f : 0f); _geometryMaterial.SetFloat(SourceAlphaBlendId, SourceAlphaBlends(binding.Mode) ? 1f : 0f); _geometryMaterial.SetFloat(SourceCullId, binding.Cull); } _appliedSourceAlphaBinding = binding; _sourceAlphaStateValid = true; } } private static bool SourceAlphaBindingEquals(SourceAlphaBinding first, SourceAlphaBinding second) { //IL_0014: 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) if ((Object)(object)first.Texture == (Object)(object)second.Texture && first.ScaleOffset == second.ScaleOffset && Mathf.Approximately(first.Cutoff, second.Cutoff) && Mathf.Approximately(first.Multiplier, second.Multiplier) && Mathf.Approximately(first.Cull, second.Cull)) { return first.Mode == second.Mode; } return false; } private void ApplySweepStencilPolicy(bool pickable) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (!_sweepStencilPolicyValid || _appliedPickableStencilPolicy != pickable) { GetSweepStencilPolicy(pickable, out var comparison, out var writeMask); _geometryMaterial.SetFloat(SweepStencilCompId, (float)comparison); _geometryMaterial.SetFloat(SweepStencilWriteMaskId, (float)writeMask); _appliedPickableStencilPolicy = pickable; _sweepStencilPolicyValid = true; } } internal static void GetSweepStencilPolicy(bool pickable, out CompareFunction comparison, out int writeMask) { comparison = (CompareFunction)(pickable ? 8 : 6); writeMask = ((!pickable) ? 2 : 0); } private static bool TryGetRenderableMesh(GeometryPart part, out Mesh mesh) { mesh = part?.Mesh; if ((Object)(object)mesh != (Object)null && part.Owner != null && part.Owner.Registered && (Object)(object)part.Owner.Root != (Object)null && IsRendererDrawable(part.Renderer)) { return (Object)(object)part.Filter != (Object)null; } return false; } private bool EnsureGeometryMaterial() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown if (_shaderUnavailable) { return false; } if ((Object)(object)_geometryMaterial != (Object)null && _sweepPass >= 0 && _playerMaskPass >= 0 && _xrayPass >= 0) { return true; } if ((Object)(object)_geometryShader == (Object)null && !TryLoadGeometryShader()) { return false; } try { _geometryMaterial = new Material(_geometryShader) { name = "RavenMap geometry highlight", hideFlags = (HideFlags)61 }; InvalidateGeometryMaterialState(); _sweepPass = _geometryMaterial.FindPass("RavenMapSweep"); _playerMaskPass = _geometryMaterial.FindPass("RavenMapPlayerMask"); _xrayPass = _geometryMaterial.FindPass("RavenMapXRay"); if (_sweepPass >= 0 && _playerMaskPass >= 0 && _xrayPass >= 0) { return true; } Object.Destroy((Object)(object)_geometryMaterial); _geometryMaterial = null; InvalidateGeometryMaterialState(); LogShaderFailure("required SWEEP/PLAYER-MASK/XRAY passes are missing"); return false; } catch (Exception ex) { LogShaderFailure(ex.GetType().Name + " - " + ex.Message); return false; } } private bool TryLoadGeometryShader() { AssetBundle val = null; bool flag = false; try { using Stream stream = typeof(ShimmerService).Assembly.GetManifestResourceStream("DragonMotion.RavenMap.Shaders.ravenmap_shaders"); if (stream == null || stream.Length <= 0 || stream.Length > int.MaxValue) { LogShaderFailure("embedded shader bundle is missing"); return false; } byte[] array = new byte[(int)stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { LogShaderFailure("embedded shader bundle is truncated"); return false; } } val = AssetBundle.LoadFromMemory(array); if ((Object)(object)val == (Object)null) { LogShaderFailure("Unity rejected the embedded shader bundle"); return false; } Shader val2 = val.LoadAsset("Assets/Shaders/RavenMapResourceOverlay.shader"); if ((Object)(object)val2 == (Object)null) { Shader[] array2 = val.LoadAllAssets(); if (array2 != null && array2.Length != 0) { val2 = array2[0]; } } if ((Object)(object)val2 == (Object)null || !val2.isSupported) { LogShaderFailure("geometry shader is unavailable for the active graphics API"); return false; } _geometryShader = val2; flag = true; return true; } catch (Exception ex) { LogShaderFailure(ex.GetType().Name + " - " + ex.Message); return false; } finally { if (val != null) { val.Unload(!flag); } } } private void LogShaderFailure(string reason) { DisableGeometryPath(); if (!_shaderFailureLogged) { _shaderFailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("RavenMap geometry highlight is unavailable: " + reason + ". Resource shimmer and X-ray stay disabled; map features continue.")); } } } private void DisableGeometryAfterRenderFailure(string reason) { DisableGeometryPath(); if (!_renderFailureLogged) { _renderFailureLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)("RavenMap geometry highlight was disabled after a render error: " + reason + ". Resource shimmer and X-ray stay disabled; map features continue.")); } } } private void DisableGeometryPath() { if (!_shaderUnavailable) { _shaderUnavailable = true; _sweepActive = false; ((Behaviour)_overlay).enabled = false; for (int num = _sweepVeins.Count - 1; num >= 0; num--) { RecycleSweepVein(_sweepVeins[num]); } _sweepVeins.Clear(); ReleaseXraySelection(); DestroyGeometryObjects(); } } private void RestoreActive() { _sweepActive = false; ((Behaviour)_overlay).enabled = false; for (int num = _sweepVeins.Count - 1; num >= 0; num--) { RecycleSweepVein(_sweepVeins[num]); } _sweepVeins.Clear(); } private void RecycleSweepVein(SweepVein vein) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) ClearGeometryParts(vein.Parts); vein.Axis = default(Vector3); vein.MinimumProjection = 0f; vein.MaximumProjection = 0f; vein.WaveHalfWidth = 0f; vein.TravelDuration = 0f; vein.TerminalFrameRendered = false; vein.HasSourceAlphaMask = false; vein.IsPickable = false; _sweepVeinPool.Push(vein); } private void ClearGeometryParts(List parts) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < parts.Count; i++) { GeometryPart geometryPart = parts[i]; geometryPart.Owner = null; geometryPart.Renderer = null; geometryPart.Filter = null; geometryPart.Mesh = null; geometryPart.LocalToWorldMatrix = default(Matrix4x4); geometryPart.SourceAlphaBindings = null; geometryPart.MinimumProjection = 0f; geometryPart.MaximumProjection = 0f; _geometryPartPool.Push(geometryPart); } parts.Clear(); } private void ReleaseAllVisuals() { foreach (ResourceVisual value in _resources.Values) { ReleaseVisual(value); } _resources.Clear(); _sourceAlphaBindingCache.Clear(); _staleIds.Clear(); _lodGroupBuffer.Clear(); } private static void ReleaseVisual(ResourceVisual visual) { if (visual != null) { visual.Registered = false; visual.LodBindings?.Clear(); visual.LodBindings = null; visual.LodBindingsCached = false; visual.Root = null; visual.Renderers = null; visual.MeshFilters = null; visual.SourceAlphaBindings = null; visual.UseSourceAlphaMask = false; visual.LastSelectedGeneration = 0L; visual.RegistrationOrder = 0L; } } private void DestroyGeometryAssets() { ReleaseXraySelection(); DestroyGeometryObjects(); _shaderUnavailable = false; _shaderFailureLogged = false; _renderFailureLogged = false; } private void DestroyGeometryObjects() { if ((Object)(object)_geometryMaterial != (Object)null) { Object.Destroy((Object)(object)_geometryMaterial); _geometryMaterial = null; } InvalidateGeometryMaterialState(); if ((Object)(object)_geometryShader != (Object)null) { Object.Destroy((Object)(object)_geometryShader); _geometryShader = null; } _sweepPass = -1; _playerMaskPass = -1; _xrayPass = -1; ClearPlayerMaskCache(); } private void InvalidateGeometryMaterialState() { _sourceAlphaStateValid = false; _appliedSourceAlphaBinding = default(SourceAlphaBinding); _sweepStencilPolicyValid = false; _appliedPickableStencilPolicy = false; } } internal sealed class ShimmerOverlayRenderer : MonoBehaviour { internal ShimmerService Owner; private void OnRenderObject() { Owner?.RenderGeometryOverlay(Camera.current); } } internal static class RavenLocalization { private const string Csv = "key,English,Russian\nravenmap_location_underground_ruins,Underground Ruins,Подземные руины\nravenmap_location_forbidden_catacombs,Forbidden Catacombs,Запретные катакомбы\nravenmap_location_catacombs,Catacombs,Катакомбы\nravenmap_location_dungeon,Dungeon,Подземелье\nravenmap_xray_on,X-ray: on,X-ray: включён\nravenmap_xray_off,X-ray: off,X-ray: выключен\n"; private static TextAsset _csvAsset; private static string _loadedLanguage = string.Empty; internal static void EnsureCurrent() { Localization instance = Localization.instance; if (instance != null) { Load(instance, instance.GetSelectedLanguage()); } } internal static void Load(Localization localization, string language) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_005d: Expected O, but got Unknown if (localization == null) { return; } string text = (string.Equals(language, "Russian", StringComparison.OrdinalIgnoreCase) ? "Russian" : "English"); if (!string.Equals(_loadedLanguage, text, StringComparison.Ordinal)) { if ((Object)(object)_csvAsset == (Object)null) { _csvAsset = new TextAsset("key,English,Russian\nravenmap_location_underground_ruins,Underground Ruins,Подземные руины\nravenmap_location_forbidden_catacombs,Forbidden Catacombs,Запретные катакомбы\nravenmap_location_catacombs,Catacombs,Катакомбы\nravenmap_location_dungeon,Dungeon,Подземелье\nravenmap_xray_on,X-ray: on,X-ray: включён\nravenmap_xray_off,X-ray: off,X-ray: выключен\n") { name = "RavenMap.Localization", hideFlags = (HideFlags)61 }; } if (localization.LoadCSV(_csvAsset, text)) { _loadedLanguage = text; } } } internal static void Invalidate() { _loadedLanguage = string.Empty; } internal static void Shutdown() { _loadedLanguage = string.Empty; if (!((Object)(object)_csvAsset == (Object)null)) { if (Application.isPlaying) { Object.Destroy((Object)(object)_csvAsset); } else { Object.DestroyImmediate((Object)(object)_csvAsset); } _csvAsset = null; } } } internal sealed class FilterPanel : IDisposable { internal sealed class CatalogState { private readonly struct LeafSnapshot { internal PinCategory Category { get; } internal string Key { get; } internal Descriptor Before { get; } internal bool IsValid => Key != null; internal LeafSnapshot(PinCategory category, string key, Descriptor before) { Category = category; Key = key; Before = before; } } private readonly struct RecordDescriptorIdentity : IEquatable { private PinCategory Category { get; } private Biome Biome { get; } private string Prefab { get; } private string DisplayName { get; } private string ResourceType { get; } private string Fallback { get; } private RecordDescriptorIdentity(PinCategory category, Biome biome, string prefab, string displayName, string resourceType, string fallback) { //IL_0008: 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) Category = category; Biome = biome; Prefab = prefab ?? string.Empty; DisplayName = displayName ?? string.Empty; ResourceType = resourceType ?? string.Empty; Fallback = fallback ?? string.Empty; } internal static RecordDescriptorIdentity FromRecord(PinRecord record) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) string text; if (!string.IsNullOrWhiteSpace(record.ResourceType) || !string.IsNullOrWhiteSpace(record.Prefab) || !string.IsNullOrWhiteSpace(record.DisplayName)) { text = string.Empty; } else { text = record.Id; if (text == null) { byte category = (byte)record.Category; text = category.ToString(CultureInfo.InvariantCulture); } } string fallback = text; return new RecordDescriptorIdentity(record.Category, record.Biome, record.Prefab, record.DisplayName, record.ResourceType, fallback); } public bool Equals(RecordDescriptorIdentity other) { //IL_0010: 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) if (Category == other.Category && Biome == other.Biome && string.Equals(Prefab, other.Prefab, StringComparison.Ordinal) && string.Equals(DisplayName, other.DisplayName, StringComparison.Ordinal) && string.Equals(ResourceType, other.ResourceType, StringComparison.Ordinal)) { return string.Equals(Fallback, other.Fallback, StringComparison.Ordinal); } return false; } public override bool Equals(object obj) { if (obj is RecordDescriptorIdentity other) { return Equals(other); } return false; } public override int GetHashCode() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0029: 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_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_0057: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected I4, but got Unknown return ((((((((((int)Category * 397) ^ Biome) * 397) ^ StringComparer.Ordinal.GetHashCode(Prefab)) * 397) ^ StringComparer.Ordinal.GetHashCode(DisplayName)) * 397) ^ StringComparer.Ordinal.GetHashCode(ResourceType)) * 397) ^ StringComparer.Ordinal.GetHashCode(Fallback); } } private readonly Func _recordAvailability; private readonly Dictionary _availableResources = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _availablePickables = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _availableDungeons = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _recordBindings = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _recordResources = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _recordPickables = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _recordDungeons = new Dictionary(StringComparer.Ordinal); private readonly Dictionary> _recordContributors = new Dictionary>(StringComparer.Ordinal); private readonly Dictionary _recordPreferredBindings = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _recordDescriptorPool = new Dictionary(); internal int BindingCount => _recordBindings.Count; internal CatalogState(Func recordAvailability = null) { _recordAvailability = recordAvailability; } internal bool TryGetRecordLeafKey(string bindingKey, out string leafKey) { if (!string.IsNullOrEmpty(bindingKey) && _recordBindings.TryGetValue(bindingKey, out var value)) { leafKey = value.Key; return true; } leafKey = string.Empty; return false; } internal bool SetAvailability(IEnumerable entries) { //IL_0083: 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_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_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) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) Dictionary left = MergeResources(); Dictionary left2 = MergePickables(); Dictionary left3 = MergeDungeons(); Dictionary dictionary = new Dictionary(StringComparer.Ordinal); Dictionary dictionary2 = new Dictionary(StringComparer.Ordinal); Dictionary dictionary3 = new Dictionary(StringComparer.Ordinal); if (entries != null) { foreach (FilterCatalogEntry entry in entries) { if (entry == null || (entry.Category != PinCategory.Resource && entry.Category != PinCategory.Pickable && entry.Category != PinCategory.Dungeon)) { continue; } bool flag = false; for (int i = 0; i < 9; i++) { Biome val = KnownBiomeAt(i); if ((entry.Biome & val) != 0) { flag = true; Descriptor descriptor = Descriptor.FromAvailability(entry, val); AddOrPreferDescriptor(CatalogFor(entry.Category, dictionary, dictionary2, dictionary3), descriptor); } } if (!flag) { Descriptor descriptor2 = Descriptor.FromAvailability(entry, entry.Biome); AddOrPreferDescriptor(CatalogFor(entry.Category, dictionary, dictionary2, dictionary3), descriptor2); } } } Replace(_availableResources, dictionary); Replace(_availablePickables, dictionary2); Replace(_availableDungeons, dictionary3); if (CatalogsSame(left, MergeResources()) && CatalogsSame(left2, MergePickables())) { return !CatalogsSame(left3, MergeDungeons()); } return true; } internal bool SetRecords(IEnumerable records) { Dictionary left = MergeResources(); Dictionary left2 = MergePickables(); Dictionary left3 = MergeDungeons(); _recordDescriptorPool.Clear(); _recordBindings.Clear(); _recordResources.Clear(); _recordPickables.Clear(); _recordDungeons.Clear(); _recordContributors.Clear(); _recordPreferredBindings.Clear(); if (records != null) { int num = 0; foreach (PinRecord record in records) { Descriptor descriptor = DescribeAvailableRecord(record); if (descriptor != null) { string bindingKey = ((!string.IsNullOrWhiteSpace(record.Id)) ? record.Id : ("anonymous." + num++.ToString(CultureInfo.InvariantCulture))); AddOrReplaceBinding(bindingKey, descriptor); } } } if (CatalogsSame(left, MergeResources()) && CatalogsSame(left2, MergePickables())) { return !CatalogsSame(left3, MergeDungeons()); } return true; } internal bool Register(PinRecord record) { if (record == null) { return false; } bool flag = IsRecordAvailable(record); string text = ((!string.IsNullOrWhiteSpace(record.Id)) ? record.Id : string.Empty); _recordBindings.TryGetValue(text, out var value); if (text.Length != 0) { if (flag && value != null && value.MatchesRecord(record)) { return false; } if (!flag && value == null) { return false; } } Descriptor descriptor = (flag ? DescribeRecord(record) : null); if (text.Length == 0 && descriptor != null) { text = "semantic." + descriptor.Key; _recordBindings.TryGetValue(text, out value); } if (text.Length == 0) { return false; } if (value != null && descriptor != null && value == descriptor) { return false; } if (value == null && descriptor == null) { return false; } LeafSnapshot snapshot = CaptureLeaf(value); LeafSnapshot snapshot2 = (SameLeaf(value, descriptor) ? default(LeafSnapshot) : CaptureLeaf(descriptor)); if (value != null) { RemoveBinding(text, value); } if (descriptor != null) { AddBinding(text, descriptor); } if (!EffectiveLeafChanged(snapshot)) { return EffectiveLeafChanged(snapshot2); } return true; } private Descriptor DescribeAvailableRecord(PinRecord record) { if (!IsRecordAvailable(record)) { return null; } return DescribeRecord(record); } private bool IsRecordAvailable(PinRecord record) { if (record != null && (_recordAvailability == null || _recordAvailability(record))) { return Descriptor.CanDescribe(record); } return false; } private Descriptor DescribeRecord(PinRecord record) { RecordDescriptorIdentity key = RecordDescriptorIdentity.FromRecord(record); if (_recordDescriptorPool.TryGetValue(key, out var value)) { return value; } value = Descriptor.FromRecord(record); if (value != null) { _recordDescriptorPool.Add(key, value); } return value; } internal bool Remove(string bindingKey) { if (string.IsNullOrWhiteSpace(bindingKey) || !_recordBindings.TryGetValue(bindingKey, out var value)) { return false; } LeafSnapshot snapshot = CaptureLeaf(value); RemoveBinding(bindingKey, value); return EffectiveLeafChanged(snapshot); } internal Dictionary MergeResources() { return MergeCatalog(_availableResources, _recordResources); } internal Dictionary MergePickables() { return MergeCatalog(_availablePickables, _recordPickables); } internal Dictionary MergeDungeons() { return MergeCatalog(_availableDungeons, _recordDungeons); } internal void Clear() { _availableResources.Clear(); _availablePickables.Clear(); _availableDungeons.Clear(); _recordBindings.Clear(); _recordResources.Clear(); _recordPickables.Clear(); _recordDungeons.Clear(); _recordContributors.Clear(); _recordPreferredBindings.Clear(); _recordDescriptorPool.Clear(); } private void AddOrReplaceBinding(string bindingKey, Descriptor descriptor) { if (_recordBindings.TryGetValue(bindingKey, out var value)) { RemoveBinding(bindingKey, value); } AddBinding(bindingKey, descriptor); } private void AddBinding(string bindingKey, Descriptor descriptor) { _recordBindings[bindingKey] = descriptor; if (!_recordContributors.TryGetValue(descriptor.Key, out var value)) { value = new Dictionary(StringComparer.Ordinal); _recordContributors.Add(descriptor.Key, value); } value[bindingKey] = descriptor; Dictionary dictionary = RecordCatalog(descriptor.Category); if (!_recordPreferredBindings.TryGetValue(descriptor.Key, out var value2) || !dictionary.TryGetValue(descriptor.Key, out var value3) || Prefer(descriptor, bindingKey, value3, value2)) { _recordPreferredBindings[descriptor.Key] = bindingKey; dictionary[descriptor.Key] = descriptor; } } private void RemoveBinding(string bindingKey, Descriptor descriptor) { _recordBindings.Remove(bindingKey); if (_recordContributors.TryGetValue(descriptor.Key, out var value)) { value.Remove(bindingKey); string value2; if (value.Count == 0) { _recordContributors.Remove(descriptor.Key); _recordPreferredBindings.Remove(descriptor.Key); RecordCatalog(descriptor.Category).Remove(descriptor.Key); } else if (_recordPreferredBindings.TryGetValue(descriptor.Key, out value2) && string.Equals(value2, bindingKey, StringComparison.Ordinal)) { RecomputeRecordLeaf(descriptor.Category, descriptor.Key, value); } } } private void RecomputeRecordLeaf(PinCategory category, string leafKey, Dictionary contributors) { Descriptor descriptor = null; string text = null; foreach (KeyValuePair contributor in contributors) { if (descriptor == null || Prefer(contributor.Value, contributor.Key, descriptor, text)) { descriptor = contributor.Value; text = contributor.Key; } } Dictionary dictionary = RecordCatalog(category); if (descriptor == null) { _recordPreferredBindings.Remove(leafKey); dictionary.Remove(leafKey); } else { _recordPreferredBindings[leafKey] = text; dictionary[leafKey] = descriptor; } } private static bool Prefer(Descriptor candidate, string candidateBinding, Descriptor current, string currentBinding) { if (IsBetterLabel(candidate.Label, current.Label)) { return true; } if (IsBetterLabel(current.Label, candidate.Label)) { return false; } return string.CompareOrdinal(candidateBinding, currentBinding) < 0; } private Dictionary RecordCatalog(PinCategory category) { return category switch { PinCategory.Resource => _recordResources, PinCategory.Pickable => _recordPickables, PinCategory.Dungeon => _recordDungeons, _ => throw new ArgumentOutOfRangeException("category", category, null), }; } private Dictionary AvailableCatalog(PinCategory category) { return category switch { PinCategory.Resource => _availableResources, PinCategory.Pickable => _availablePickables, PinCategory.Dungeon => _availableDungeons, _ => throw new ArgumentOutOfRangeException("category", category, null), }; } private static Dictionary CatalogFor(PinCategory category, Dictionary resources, Dictionary pickables, Dictionary dungeons) { return category switch { PinCategory.Resource => resources, PinCategory.Pickable => pickables, PinCategory.Dungeon => dungeons, _ => throw new ArgumentOutOfRangeException("category", category, null), }; } private Descriptor EffectiveDescriptor(PinCategory category, string key) { AvailableCatalog(category).TryGetValue(key, out var value); RecordCatalog(category).TryGetValue(key, out var value2); if (value == null) { return value2; } if (value2 == null || !IsBetterLabel(value2.Label, value.Label)) { return value; } return value2; } private LeafSnapshot CaptureLeaf(Descriptor descriptor) { if (descriptor == null) { return default(LeafSnapshot); } return new LeafSnapshot(descriptor.Category, descriptor.Key, EffectiveDescriptor(descriptor.Category, descriptor.Key)); } private bool EffectiveLeafChanged(LeafSnapshot snapshot) { if (!snapshot.IsValid) { return false; } Descriptor right = EffectiveDescriptor(snapshot.Category, snapshot.Key); return !DescriptorsSame(snapshot.Before, right); } private static bool SameLeaf(Descriptor left, Descriptor right) { if (left != null && right != null && left.Category == right.Category) { return string.Equals(left.Key, right.Key, StringComparison.Ordinal); } return false; } private static bool CatalogsSame(Dictionary left, Dictionary right) { if (left.Count != right.Count) { return false; } foreach (KeyValuePair item in left) { if (!right.TryGetValue(item.Key, out var value) || !DescriptorsSame(item.Value, value)) { return false; } } return true; } private static bool DescriptorsSame(Descriptor left, Descriptor right) { if (left != right) { return left?.SameAs(right) ?? false; } return true; } private static void Replace(Dictionary destination, Dictionary source) { destination.Clear(); foreach (KeyValuePair item in source) { destination.Add(item.Key, item.Value); } } } internal sealed class Descriptor { internal PinCategory Category { get; } internal Biome Biome { get; } internal string Prefab { get; } internal string DisplayName { get; } internal string ResourceType { get; } private string Fallback { get; } internal string SemanticType { get; } internal string Key { get; } internal string Label { get; } internal PinRecord IconRecord { get; } private Descriptor(PinCategory category, Biome biome, string prefab, string displayName, string resourceType, string fallback) { //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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) Category = category; Biome = biome; Prefab = prefab ?? string.Empty; DisplayName = displayName ?? string.Empty; ResourceType = resourceType ?? string.Empty; string text; if (!string.IsNullOrWhiteSpace(ResourceType) || !string.IsNullOrWhiteSpace(Prefab) || !string.IsNullOrWhiteSpace(DisplayName)) { text = string.Empty; } else { text = fallback; if (text == null) { byte b = (byte)category; text = b.ToString(CultureInfo.InvariantCulture); } } Fallback = text; SemanticType = SemanticType(category, ResourceType, Prefab, DisplayName, fallback); Key = LeafKey(Category, Biome, SemanticType); Label = DisplayLabel(DisplayName, ResourceType, Prefab); IconRecord = new PinRecord { Category = Category, Status = PinStatus.Active, Biome = Biome, Prefab = Prefab, DisplayName = DisplayName, ResourceType = ResourceType }; } internal static Descriptor FromAvailability(FilterCatalogEntry entry, Biome biome) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return new Descriptor(entry.Category, biome, entry.Prefab, entry.DisplayName, entry.ResourceType, entry.Prefab); } internal static Descriptor FromRecord(PinRecord record) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (!CanDescribe(record)) { return null; } return new Descriptor(record.Category, record.Biome, record.Prefab, record.DisplayName, record.ResourceType, record.Id); } internal static bool CanDescribe(PinRecord record) { if (record != null && record.IsVisibleState) { if (record.Category != PinCategory.Resource && record.Category != PinCategory.Pickable) { return record.Category == PinCategory.Dungeon; } return true; } return false; } internal bool MatchesRecord(PinRecord record) { //IL_0017: 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) if (!CanDescribe(record) || Category != record.Category || Biome != record.Biome || !string.Equals(Prefab, record.Prefab ?? string.Empty, StringComparison.Ordinal) || !string.Equals(DisplayName, record.DisplayName ?? string.Empty, StringComparison.Ordinal) || !string.Equals(ResourceType, record.ResourceType ?? string.Empty, StringComparison.Ordinal)) { return false; } string text; if (!string.IsNullOrWhiteSpace(ResourceType) || !string.IsNullOrWhiteSpace(Prefab) || !string.IsNullOrWhiteSpace(DisplayName)) { text = string.Empty; } else { text = record.Id; if (text == null) { byte category = (byte)record.Category; text = category.ToString(CultureInfo.InvariantCulture); } } string b = text; return string.Equals(Fallback, b, StringComparison.Ordinal); } internal bool SameAs(Descriptor other) { //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) if (other != null && Category == other.Category && Biome == other.Biome && string.Equals(Key, other.Key, StringComparison.Ordinal) && string.Equals(Label, other.Label, StringComparison.Ordinal) && string.Equals(Prefab, other.Prefab, StringComparison.Ordinal) && string.Equals(DisplayName, other.DisplayName, StringComparison.Ordinal) && string.Equals(ResourceType, other.ResourceType, StringComparison.Ordinal)) { return string.Equals(Fallback, other.Fallback, StringComparison.Ordinal); } return false; } } private sealed class PanelDragHandle : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler { private RectTransform _root; private RectTransform _parent; private Action _save; private bool _dragging; internal void Initialize(RectTransform root, RectTransform parent, Action save) { _root = root; _parent = parent; _save = save; ClampToParent(_root, _parent); } public void OnBeginDrag(PointerEventData eventData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if ((int)eventData.button == 0 && !((Object)(object)_root == (Object)null) && !((Object)(object)_parent == (Object)null)) { _dragging = true; ((Transform)_root).SetAsLastSibling(); ((AbstractEventData)eventData).Use(); } } public void OnDrag(PointerEventData eventData) { //IL_0009: 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_001c: 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_0038: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (_dragging && (int)eventData.button == 0) { Vector3 lossyScale = ((Transform)_parent).lossyScale; float num = Mathf.Max(0.0001f, Mathf.Abs(lossyScale.x)); float num2 = Mathf.Max(0.0001f, Mathf.Abs(lossyScale.y)); Vector2 delta = eventData.delta; delta.x /= num; delta.y /= num2; RectTransform root = _root; root.anchoredPosition += delta; ClampToParent(_root, _parent); ((AbstractEventData)eventData).Use(); } } public void OnEndDrag(PointerEventData eventData) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (_dragging && (int)eventData.button == 0) { _dragging = false; ClampToParent(_root, _parent); _save?.Invoke(_root.anchoredPosition); ((AbstractEventData)eventData).Use(); } } internal static void ClampToParent(RectTransform root, RectTransform parent) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0054: 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) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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) if (!((Object)(object)root == (Object)null) && !((Object)(object)parent == (Object)null)) { Rect rect = parent.rect; float width = ((Rect)(ref rect)).width; Rect rect2 = root.rect; float num = Mathf.Max(18f, width - ((Rect)(ref rect2)).width - 18f); float height = ((Rect)(ref rect)).height; rect2 = root.rect; float num2 = 0f - Mathf.Max(18f, height - ((Rect)(ref rect2)).height - 18f); Vector2 anchoredPosition = root.anchoredPosition; anchoredPosition.x = Mathf.Clamp(anchoredPosition.x, 18f, num); anchoredPosition.y = Mathf.Clamp(anchoredPosition.y, num2, -18f); root.anchoredPosition = anchoredPosition; } } } private sealed class PanelBoundsWatcher : MonoBehaviour { private FilterPanel _owner; internal void Initialize(FilterPanel owner) { _owner = owner; } private void OnRectTransformDimensionsChange() { _owner?.RefreshPanelGeometry(); } private void OnDestroy() { _owner = null; } } private sealed class PointerGuard : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { private static int _hoveredCount; private bool _inside; internal static bool IsAnyHovered => _hoveredCount > 0; public void OnPointerEnter(PointerEventData eventData) { if (!_inside) { _inside = true; _hoveredCount++; } } public void OnPointerExit(PointerEventData eventData) { Leave(); } private void OnDisable() { Leave(); } private void OnDestroy() { Leave(); } private void Leave() { if (_inside) { _inside = false; _hoveredCount = Math.Max(0, _hoveredCount - 1); } } } [HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")] private static class FilterWheelGuardPatch { [HarmonyPrefix] private static bool Prefix(ref float __result) { if (!PointerGuard.IsAnyHovered) { return true; } __result = 0f; return false; } } private const float PanelWidth = 320f; private const float PanelDefaultHeight = 720f; private const float PanelMaximumHeight = 820f; private const float HeaderHeight = 40f; private const float PanelMargin = 18f; private const int KnownBiomeCount = 9; private static bool _missingFontLogged; private readonly Action _onChanged; private readonly Func _iconResolver; private readonly string _preferencePrefix; private readonly Dictionary _values = new Dictionary(StringComparer.Ordinal); private readonly CatalogState _catalog; private readonly HashSet _failedIconKeys = new HashSet(StringComparer.Ordinal); private readonly TMP_FontAsset _font; private RectTransform _parentRect; private RectTransform _rootRect; private RectTransform _content; private ScrollRect _scroll; private GameObject _root; private TextMeshProUGUI _titleLabel; private bool _languageSubscribed; private bool _geometryBusy; private bool _preferencesDirty; internal FilterPanel(Minimap map, string worldKey, Action onChanged, Func iconResolver, float scrollSensitivity, Func recordAvailability = null) { if ((Object)(object)map == (Object)null) { throw new ArgumentNullException("map"); } _onChanged = onChanged; _iconResolver = iconResolver; _catalog = new CatalogState(recordAvailability); _preferencePrefix = BuildPreferencePrefix(worldKey); _font = (((Object)(object)map.m_biomeNameLarge != (Object)null && (Object)(object)map.m_biomeNameLarge.font != (Object)null) ? map.m_biomeNameLarge.font : (((Object)(object)map.m_biomeNameSmall != (Object)null) ? map.m_biomeNameSmall.font : null)); if ((Object)(object)_font == (Object)null) { if (!_missingFontLogged) { _missingFontLogged = true; ManualLogSource log = RavenMapPlugin.Log; if (log != null) { log.LogWarning((object)"RavenMap filters were disabled because the active Minimap has no usable TMP font asset."); } } } else { BuildScaffold(map.m_largeRoot.transform); SetScrollSensitivity(scrollSensitivity); Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, new Action(OnLanguageChanged)); _languageSubscribed = true; } } internal void Initialize(IEnumerable availability, IEnumerable records) { _catalog.SetAvailability(availability); _catalog.SetRecords(records); RebuildRows(); } internal void SetCatalog(IEnumerable availability, IEnumerable records) { bool num = _catalog.SetAvailability(availability); bool flag = _catalog.SetRecords(records); if (num || flag) { RebuildRows(); } } internal void SetScrollSensitivity(float value) { if ((Object)(object)_scroll != (Object)null) { _scroll.scrollSensitivity = Mathf.Clamp(value, 40f, 1200f); } } internal bool IsVisible(PinRecord record) { //IL_002a: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) if (record == null) { return false; } if (record.Category == PinCategory.Resource) { string leafKey; string key = (_catalog.TryGetRecordLeafKey(record.Id, out leafKey) ? leafKey : LeafKey(record.Category, record.Biome, SemanticType(record))); if (ReadValue("global.resources", defaultValue: true) && ReadValue(ResourceBiomeKey(record.Biome), defaultValue: true)) { return ReadValue(key, defaultValue: true); } return false; } if (record.Category == PinCategory.Pickable) { string leafKey2; string key2 = (_catalog.TryGetRecordLeafKey(record.Id, out leafKey2) ? leafKey2 : LeafKey(record.Category, record.Biome, SemanticType(record))); if (ReadValue("global.pickables", defaultValue: true) && ReadValue(PickableBiomeKey(record.Biome), defaultValue: true)) { return ReadValue(key2, defaultValue: true); } return false; } if (record.Category == PinCategory.Dungeon) { string leafKey3; string key3 = (_catalog.TryGetRecordLeafKey(record.Id, out leafKey3) ? leafKey3 : LeafKey(record.Category, record.Biome, SemanticType(record))); if (ReadValue("global.dungeons", defaultValue: true) && ReadValue(DungeonBiomeKey(record.Biome), defaultValue: true)) { return ReadValue(key3, defaultValue: true); } return false; } return ReadValue(CategoryKey(record.Category), defaultValue: true); } internal void SetAvailability(IEnumerable entries) { if (_catalog.SetAvailability(entries)) { RebuildRows(); } } internal void SetRecords(IEnumerable records) { if (_catalog.SetRecords(records)) { RebuildRows(); } } internal void Register(PinRecord record) { if (_catalog.Register(record)) { RebuildRows(); } } internal void Remove(string id) { if (_catalog.Remove(id)) { RebuildRows(); } } private void BuildScaffold(Transform parent) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0062: 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_0096: 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_00c1: 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_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Expected O, but got Unknown //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Expected O, but got Unknown _parentRect = (RectTransform)(object)((parent is RectTransform) ? parent : null); _root = NewUiObject("RavenMap.FilterPanel", parent, typeof(Image)); _root.AddComponent(); _rootRect = (RectTransform)_root.transform; _rootRect.anchorMin = new Vector2(0f, 1f); _rootRect.anchorMax = new Vector2(0f, 1f); _rootRect.pivot = new Vector2(0f, 1f); _rootRect.sizeDelta = new Vector2(320f, 720f); _rootRect.anchoredPosition = LoadPanelPosition(); Image component = _root.GetComponent(); ((Graphic)component).color = new Color(0.028f, 0.038f, 0.047f, 0.94f); ((Graphic)component).raycastTarget = true; BuildDragHeader(_rootRect); GameObject val = NewUiObject("Body", (Transform)(object)_rootRect, typeof(Image), typeof(ScrollRect)); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = Vector2.zero; val2.offsetMax = new Vector2(0f, -40f); Image component2 = val.GetComponent(); ((Graphic)component2).color = new Color(0f, 0f, 0f, 0.01f); ((Graphic)component2).raycastTarget = true; GameObject obj = NewUiObject("Viewport", (Transform)(object)val2, typeof(Image), typeof(Mask)); RectTransform val3 = (RectTransform)obj.transform; val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; val3.offsetMin = new Vector2(8f, 8f); val3.offsetMax = new Vector2(-18f, -8f); Image component3 = obj.GetComponent(); ((Graphic)component3).color = new Color(0f, 0f, 0f, 0.01f); ((Graphic)component3).raycastTarget = true; obj.GetComponent().showMaskGraphic = false; GameObject val4 = NewUiObject("Content", (Transform)(object)val3, typeof(VerticalLayoutGroup), typeof(ContentSizeFitter)); _content = (RectTransform)val4.transform; _content.anchorMin = new Vector2(0f, 1f); _content.anchorMax = new Vector2(1f, 1f); _content.pivot = new Vector2(0.5f, 1f); _content.anchoredPosition = Vector2.zero; _content.sizeDelta = Vector2.zero; VerticalLayoutGroup component4 = val4.GetComponent(); ((LayoutGroup)component4).padding = new RectOffset(3, 3, 3, 8); ((HorizontalOrVerticalLayoutGroup)component4).spacing = 4f; ((LayoutGroup)component4).childAlignment = (TextAnchor)0; ((HorizontalOrVerticalLayoutGroup)component4).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)component4).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)component4).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)component4).childForceExpandHeight = false; ContentSizeFitter component5 = val4.GetComponent(); component5.horizontalFit = (FitMode)0; component5.verticalFit = (FitMode)2; Scrollbar verticalScrollbar = CreateScrollbar(val2); ScrollRect val5 = (_scroll = val.GetComponent()); val5.viewport = val3; val5.content = _content; val5.horizontal = false; val5.vertical = true; val5.inertia = true; val5.decelerationRate = 0.12f; val5.scrollSensitivity = 120f; val5.movementType = (MovementType)2; val5.verticalScrollbar = verticalScrollbar; val5.verticalScrollbarVisibility = (ScrollbarVisibility)1; val5.verticalScrollbarSpacing = 2f; _root.AddComponent().Initialize(this); RefreshPanelGeometry(); } private void BuildDragHeader(RectTransform parent) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0035: 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_005f: 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_007f: 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_00f0: 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) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) GameObject obj = NewUiObject("Header", (Transform)(object)parent, typeof(Image)); RectTransform val = (RectTransform)obj.transform; val.anchorMin = new Vector2(0f, 1f); val.anchorMax = new Vector2(1f, 1f); val.pivot = new Vector2(0.5f, 1f); val.anchoredPosition = Vector2.zero; val.sizeDelta = new Vector2(0f, 40f); Image component = obj.GetComponent(); ((Graphic)component).color = new Color(0.12f, 0.18f, 0.21f, 0.96f); ((Graphic)component).raycastTarget = true; _titleLabel = CreateLabel((Transform)(object)val, Ui("RavenMap filters", "Фильтры RavenMap"), 18f, (FontStyles)1); ((Graphic)_titleLabel).color = new Color(0.76f, 0.91f, 0.97f, 1f); RectTransform val2 = (RectTransform)((TMP_Text)_titleLabel).transform; val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = new Vector2(12f, 0f); val2.offsetMax = new Vector2(-12f, 0f); obj.AddComponent().Initialize(_rootRect, _parentRect, SavePanelPosition); } private Scrollbar CreateScrollbar(RectTransform parent) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0043: 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_006d: 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_0097: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) GameObject val = NewUiObject("Scrollbar", (Transform)(object)parent, typeof(Image), typeof(Scrollbar)); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = new Vector2(1f, 0f); val2.anchorMax = new Vector2(1f, 1f); val2.pivot = new Vector2(1f, 1f); val2.offsetMin = new Vector2(-12f, 8f); val2.offsetMax = new Vector2(-5f, -8f); ((Graphic)val.GetComponent()).color = new Color(1f, 1f, 1f, 0.08f); RectTransform val3 = (RectTransform)NewUiObject("Sliding Area", (Transform)(object)val2).transform; Stretch(val3, 1f); GameObject obj = NewUiObject("Handle", (Transform)(object)val3, typeof(Image)); RectTransform val4 = (RectTransform)obj.transform; Stretch(val4, 0f); Image component = obj.GetComponent(); ((Graphic)component).color = new Color(0.55f, 0.78f, 0.88f, 0.72f); Scrollbar component2 = val.GetComponent(); component2.handleRect = val4; ((Selectable)component2).targetGraphic = (Graphic)(object)component; component2.direction = (Direction)2; component2.size = 0.2f; return component2; } private void RebuildRows() { if (!((Object)(object)_content == (Object)null)) { float num = (((Object)(object)_scroll != (Object)null) ? _scroll.verticalNormalizedPosition : 1f); for (int num2 = ((Transform)_content).childCount - 1; num2 >= 0; num2--) { Transform child = ((Transform)_content).GetChild(num2); child.SetParent((Transform)null, false); Object.Destroy((Object)(object)((Component)child).gameObject); } Dictionary catalog = _catalog.MergeResources(); Dictionary catalog2 = _catalog.MergePickables(); Dictionary catalog3 = _catalog.MergeDungeons(); BuildCategorySection("resources", Ui("All resources", "Все ресурсы"), "global.resources", PinCategory.Resource, catalog, defaultExpanded: true); BuildCategorySection("pickables", Ui("All pickables", "Все собираемые ресурсы"), "global.pickables", PinCategory.Pickable, catalog2, defaultExpanded: false); BuildCategorySection("dungeons", Ui("All dungeons", "Все подземелья"), "global.dungeons", PinCategory.Dungeon, catalog3, defaultExpanded: false); BuildOtherSection(); RefreshPanelGeometry(); if ((Object)(object)_scroll != (Object)null) { _scroll.verticalNormalizedPosition = Mathf.Clamp01(num); } } } private void BuildCategorySection(string sectionKey, string label, string globalKey, PinCategory category, Dictionary catalog, bool defaultExpanded) { //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected I4, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) GameObject val = CreateStack((Transform)(object)_content, "Section." + sectionKey, 3f); GameObject val2 = CreateFoldout(val.transform, "section." + sectionKey, globalKey, label, 0, bold: true, defaultExpanded); foreach (IGrouping item in from value in catalog.Values group value by value.Biome into value orderby BiomeSort(value.Key) select value) { List list = item.OrderBy((Descriptor value) => LocalizedLabel(value), StringComparer.CurrentCultureIgnoreCase).ToList(); if (list.Count != 0) { string text = sectionKey + ".biome." + ((int)item.Key).ToString(CultureInfo.InvariantCulture); string gateKey = BiomeKey(category, item.Key); GameObject val3 = CreateStack(val2.transform, "Biome." + text, 2f); GameObject val4 = CreateFoldout(val3.transform, text, gateKey, FriendlyBiomeName(item.Key), 1, bold: true, defaultExpanded: false); for (int num = 0; num < list.Count; num++) { Descriptor descriptor = list[num]; AddLeafToggle(val4.transform, descriptor.Key, LocalizedLabel(descriptor), descriptor, 2); } } } } private void BuildOtherSection() { GameObject val = CreateStack((Transform)(object)_content, "Section.other", 3f); GameObject val2 = CreateFoldout(val.transform, "section.other", null, Ui("Other marks", "Другие отметки"), 0, bold: false, defaultExpanded: false); AddLeafToggle(val2.transform, CategoryKey(PinCategory.Portal), Ui("Portals", "Порталы"), null, 1); AddLeafToggle(val2.transform, CategoryKey(PinCategory.Ship), Ui("Ships", "Корабли"), null, 1); AddLeafToggle(val2.transform, CategoryKey(PinCategory.Cart), Ui("Carts", "Повозки"), null, 1); } private GameObject CreateFoldout(Transform parent, string foldoutKey, string gateKey, string labelText, int indent, bool bold, bool defaultExpanded) { //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown GameObject val = CreateRow(parent, "Foldout." + foldoutKey, indent, bold); if (!string.IsNullOrEmpty(gateKey)) { AddToggleBox(val, gateKey, defaultValue: true); } bool flag = ReadValue("fold." + foldoutKey, defaultExpanded); TextMeshProUGUI label = CreateLabel(val.transform, FoldoutText(flag, labelText), bold ? 15f : 14f, (FontStyles)(bold ? 1 : 0)); ((Graphic)label).raycastTarget = true; LayoutElement obj = ((Component)label).gameObject.AddComponent(); obj.flexibleWidth = 1f; obj.minHeight = (bold ? 24f : 21f); GameObject body = CreateStack(parent, "Children." + foldoutKey, 2f); body.SetActive(flag); Button obj2 = ((Component)label).gameObject.AddComponent