Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of RavenMap v1.7.7
RavenMap.dll
Decompiled 11 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.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<string, ConsoleCommand> 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<string> GetOptions() { return new List<string> { "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<Minimap, bool[]> _explored; private static FieldRef<Minimap, bool[]> _exploredOthers; private static FieldRef<Minimap, Texture2D> _fogTexture; private static FieldRef<Minimap, List<PinData>> _pins; private static FieldRef<Minimap, bool> _pinUpdateRequired; private static FieldRef<MineRock, Collider[]> _mineRockHitAreas; private static FieldRef<MineRock5, MeshRenderer> _mineRock5MeshRenderer; private static Func<MineRock5, object> _mineRock5HitAreas; private static Func<object, float> _mineRock5HitAreaHealth; private static bool _initialized; internal static bool TryInitialize(out string error) { if (_initialized) { error = string.Empty; return true; } try { _explored = AccessTools.FieldRefAccess<Minimap, bool[]>("m_explored"); _exploredOthers = AccessTools.FieldRefAccess<Minimap, bool[]>("m_exploredOthers"); _fogTexture = AccessTools.FieldRefAccess<Minimap, Texture2D>("m_fogTexture"); _pins = AccessTools.FieldRefAccess<Minimap, List<PinData>>("m_pins"); _pinUpdateRequired = AccessTools.FieldRefAccess<Minimap, bool>("m_pinUpdateRequired"); _mineRockHitAreas = AccessTools.FieldRefAccess<MineRock, Collider[]>("m_hitAreas"); _mineRock5MeshRenderer = AccessTools.FieldRefAccess<MineRock5, MeshRenderer>("m_meshRenderer"); FieldInfo fieldInfo = AccessTools.Field(typeof(MineRock5), "m_hitAreas"); if (fieldInfo == null) { throw new MissingFieldException(typeof(MineRock5).FullName, "m_hitAreas"); } _mineRock5HitAreas = BuildObjectFieldGetter<MineRock5>(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<PinData> 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<T, object> BuildObjectFieldGetter<T>(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<T, object>)dynamicMethod.CreateDelegate(typeof(Func<T, object>)); } private static Func<object, float> 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<object, float>)dynamicMethod.CreateDelegate(typeof(Func<object, float>)); } } internal static class ConfigText { private static readonly Dictionary<string, string> Russian = new Dictionary<string, string>(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<bool> Enabled; internal ConfigEntry<bool> ShowPinNames; internal ConfigEntry<bool> ShowPortalNames; internal ConfigEntry<float> PinIconScale; internal ConfigEntry<float> FilterScrollSensitivity; internal ConfigEntry<bool> ShareFog; internal ConfigEntry<bool> SharePins; internal ConfigEntry<float> ResourceDiscoveryRadius; internal ConfigEntry<float> DungeonDiscoveryRadius; internal ConfigEntry<SilverDiscoveryMode> SilverMode; internal ConfigEntry<bool> AutoPinUndergroundResources; internal ConfigEntry<bool> TrackPickables; internal ConfigEntry<float> PickableDiscoveryRadius; internal ConfigEntry<bool> CrossOutRespawningPickables; internal ConfigEntry<float> ResourceRemovalPercent; internal ConfigEntry<float> ResourceProgressStepPercent; internal ConfigEntry<float> ResourceProgressMinInterval; internal ConfigEntry<string> ResourcePrefabAllowList; internal ConfigEntry<string> ResourcePrefabBlockList; internal ConfigEntry<string> ResourceItemBlockList; internal ConfigEntry<string> DungeonPrefabAllowList; internal ConfigEntry<float> RequiredDefeatedEnemiesPercent; internal ConfigEntry<float> DungeonChestInspectionPercent; internal ConfigEntry<int> DungeonMinimumObservedChests; internal ConfigEntry<float> DungeonCensusSettleSeconds; internal ConfigEntry<DungeonRespawnMode> DungeonRespawn; internal ConfigEntry<bool> ReopenDungeonOnRespawn; internal ConfigEntry<KeyCode> ManualDungeonToggleModifier; internal ConfigEntry<bool> AutoPinPortals; internal ConfigEntry<bool> TrackShips; internal ConfigEntry<bool> TrackCarts; internal ConfigEntry<float> VehicleUpdateInterval; internal ConfigEntry<float> VehicleMinimumMoveDistance; internal ConfigEntry<float> ResourceDedupeDistance; internal ConfigEntry<float> PickableDedupeDistance; internal ConfigEntry<float> DungeonDedupeDistance; internal ConfigEntry<float> PortalDedupeDistance; internal ConfigEntry<bool> ShimmerEnabled; internal ConfigEntry<ShimmerAnimationMode> ShimmerMode; internal ConfigEntry<bool> HighlightPickables; internal ConfigEntry<Color> PulseColor; internal ConfigEntry<float> PulseInterval; internal ConfigEntry<float> PulseDuration; internal ConfigEntry<float> PulseIntensity; internal ConfigEntry<Color> SweepColor; internal ConfigEntry<float> SweepInterval; internal ConfigEntry<float> SweepSpeed; internal ConfigEntry<float> SweepMaximumDuration; internal ConfigEntry<float> SweepIntensity; internal ConfigEntry<float> ShimmerRadius; internal ConfigEntry<float> SweepWaveWidth; internal ConfigEntry<float> SweepSoftness; internal ConfigEntry<bool> XrayEnabled; internal ConfigEntry<KeyCode> XrayToggleKey; internal ConfigEntry<Color> XrayColor; internal ConfigEntry<float> XrayIntensity; internal ConfigEntry<float> XrayRadius; internal ConfigEntry<int> XrayRendererBudget; internal ConfigEntry<int> XrayDrawCommandBudget; internal ConfigEntry<int> ShimmerRendererBudget; internal ConfigEntry<float> SaveDebounceSeconds; internal ConfigEntry<int> MaxFogDeltaPixels; internal ConfigEntry<int> FogMergeCellsPerFrame; internal ConfigEntry<int> MaxNetworkEventsPerTenSeconds; internal ConfigEntry<int> MaxPinAddsPerFrame; internal ConfigEntry<bool> ShowPinOverlapDiagnostics; internal ConfigEntry<float> PinOverlapDiagnosticDistance; internal ConfigEntry<bool> ShowStateDiagnostics; internal ConfigEntry<bool> 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("<Description>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<int> val = file.Bind<int>("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<bool>("01 - General", "Enabled", true, Describe("Enable RavenMap. Requires a restart.", "01 - Interface", "Enabled", 1000)), ShowPinNames = file.Bind<bool>("01 - General", "ShowAutomaticPinNames", false, Describe("Show names beside automatic pins. Local setting.", "01 - Interface", "Automatic pin names", 990)), ShowPortalNames = file.Bind<bool>("01 - General", "ShowPortalNames", true, Describe("Show portal names independently. Local setting.", "01 - Interface", "Portal names", 980)), PinIconScale = file.Bind<float>("01 - General", "AutomaticPinIconScale", 0.7f, Describe("Local automatic-pin size multiplier.", "01 - Interface", "Pin icon size", 970, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 3f))), FilterScrollSensitivity = file.Bind<float>("01 - General", "FilterScrollSpeed", 360f, Describe("Map-filter wheel speed in UI pixels per step.", "01 - Interface", "Filter scroll speed", 960, (AcceptableValueBase)(object)new AcceptableValueRange<float>(40f, 1200f))), ShareFog = file.Bind<bool>("02 - Multiplayer", "ShareFog", true, Describe("Merge explored fog into the shared server map.", "02 - Sharing", "Shared fog", 900)), SharePins = file.Bind<bool>("02 - Multiplayer", "ShareAutomaticPins", true, Describe("Share automatic pins with every player.", "02 - Sharing", "Shared automatic pins", 890)), ResourceDiscoveryRadius = file.Bind<float>("03 - Discovery", "ResourceRadius", 30f, Describe("Discovery radius for loaded resources; unloaded zones are never scanned.", "03 - Discovery", "Resource radius", 800, (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 128f))), DungeonDiscoveryRadius = file.Bind<float>("03 - Discovery", "DungeonRadius", 30f, Describe("Discovery radius for loaded dungeons.", "03 - Discovery", "Dungeon radius", 790, (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 256f))), SilverMode = file.Bind<SilverDiscoveryMode>("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<bool>("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<float>("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<float>(1f, 100f))), ResourceProgressStepPercent = file.Bind<float>("04 - Resources", "ProgressUpdateStepPercent", 2f, Describe("Extra depletion required before another progress update.", "04 - Resources", "Progress update step", 690, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), advanced: true)), ResourceProgressMinInterval = file.Bind<float>("04 - Resources", "ProgressUpdateMinIntervalSeconds", 0.25f, Describe("Minimum interval between ordinary updates for one resource.", "04 - Resources", "Progress update interval", 680, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), advanced: true)), ResourcePrefabAllowList = file.Bind<string>("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<string>("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<string>("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<bool>("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<float>("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<float>(5f, 128f))), CrossOutRespawningPickables = file.Bind<bool>("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<string>("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<float>("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<float>(0f, 100f))), DungeonChestInspectionPercent = file.Bind<float>("05 - Dungeons", "RequiredInspectedChestsPercent", 60f, Describe("Observed-chest share required before crossing out a dungeon.", "05 - Dungeons", "Inspected chests required", 590, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))), DungeonMinimumObservedChests = file.Bind<int>("05 - Dungeons", "MinimumObservedChests", 0, Describe("Minimum observed chests required for automatic clearing.", "05 - Dungeons", "Minimum observed chests", 580, (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100))), DungeonCensusSettleSeconds = file.Bind<float>("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<float>(0.5f, 5f), advanced: true)), DungeonRespawn = file.Bind<DungeonRespawnMode>("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<bool>("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<KeyCode>("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<bool>("06 - Portals and vehicles", "AutoPinPortals", true, Describe("Pin portals automatically and keep their tag current.", "06 - Markers", "Automatic portal pins", 500)), TrackShips = file.Bind<bool>("06 - Portals and vehicles", "TrackShips", true, Describe("Track vanilla and modded Ship components.", "06 - Markers", "Track ships", 490)), TrackCarts = file.Bind<bool>("06 - Portals and vehicles", "TrackCarts", true, Describe("Track vanilla and modded Vagon components.", "06 - Markers", "Track carts", 480)), VehicleUpdateInterval = file.Bind<float>("06 - Portals and vehicles", "VehicleUpdateIntervalSeconds", 2f, Describe("Position-report interval for loaded vehicles.", "06 - Markers", "Vehicle update interval", 470, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), advanced: true)), VehicleMinimumMoveDistance = file.Bind<float>("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<float>(0.25f, 25f), advanced: true)), ResourceDedupeDistance = file.Bind<float>("07 - Deduplication", "ResourceDistance", 4f, Describe("Server merge distance for equivalent resource pins.", "07 - Deduplication", "Resource merge distance", 400, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f))), PickableDedupeDistance = file.Bind<float>("07 - Deduplication", "PickableDistance", 4f, Describe("Server merge distance for equivalent pickable pins.", "04.1 - Pickables", "Merge distance", 670, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f))), DungeonDedupeDistance = file.Bind<float>("07 - Deduplication", "DungeonDistance", 12f, Describe("Server merge distance for equivalent dungeon pins.", "07 - Deduplication", "Dungeon merge distance", 390, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f))), PortalDedupeDistance = file.Bind<float>("07 - Deduplication", "PortalDistance", 2f, Describe("Server merge distance for equivalent portal pins.", "07 - Deduplication", "Portal merge distance", 380, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f))), ShimmerEnabled = file.Bind<bool>("08 - Resource shimmer", "Enabled", true, Describe("Periodically highlight nearby visible resources and enabled Pickables without material instances.", "08 - Shimmer", "Enabled", 320)), ShimmerMode = file.Bind<ShimmerAnimationMode>("08 - Resource shimmer", "AnimationMode", ShimmerAnimationMode.Sweep, Describe("Sweep travels across highlighted geometry; Pulse brightens the whole object.", "08 - Shimmer", "Animation", 310)), HighlightPickables = file.Bind<bool>("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<Color>("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<float>("08 - Resource shimmer", "IntervalSeconds", 1f, Describe("Delay between pulse effects.", "08.1 - Pulse", "Pulse interval", 290, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f))), PulseDuration = file.Bind<float>("08 - Resource shimmer", "DurationSeconds", 1f, Describe("Duration of one smooth pulse.", "08.1 - Pulse", "Pulse duration", 280, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f))), PulseIntensity = file.Bind<float>("08 - Resource shimmer", "Intensity", 2f, Describe("Tint and HDR glow strength of the pulse.", "08.1 - Pulse", "Pulse intensity", 270, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f))), SweepColor = file.Bind<Color>("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<float>("08 - Resource shimmer", "SweepIntervalSeconds", 1f, Describe("Delay between sweep effects.", "08.2 - Sweep", "Sweep interval", 290, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f))), SweepSpeed = file.Bind<float>("08 - Resource shimmer", "SweepSpeedMetersPerSecond", 5f, Describe("World-space speed of the travelling wave.", "08.2 - Sweep", "Sweep speed", 280, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f))), SweepMaximumDuration = file.Bind<float>("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<float>(0.5f, 30f))), SweepIntensity = file.Bind<float>("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<float>(1f, 10f))), ShimmerRadius = file.Bind<float>("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<float>(5f, 96f))), SweepWaveWidth = file.Bind<float>("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<float>(0.05f, 2f))), SweepSoftness = file.Bind<float>("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<float>(0f, 1f))), XrayEnabled = file.Bind<bool>("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<KeyCode>("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<Color>("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<float>("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<float>(1f, 10f))), XrayRadius = file.Bind<float>("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<float>(5f, 96f))), XrayRendererBudget = file.Bind<int>("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<int>(16, 512), advanced: true)), XrayDrawCommandBudget = file.Bind<int>("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<int>(64, 2048), advanced: true)), ShimmerRendererBudget = file.Bind<int>("08 - Resource shimmer", "MaxRenderersPerPulse", 256, Describe("Hard total renderer limit for one complete shimmer batch.", "08 - Shimmer", "Renderer budget", 200, (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 256), advanced: true)), SaveDebounceSeconds = file.Bind<float>("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<float>(1f, 120f), advanced: true)), MaxFogDeltaPixels = file.Bind<int>("09 - Performance", "MaxFogPixelsPerPacket", 2048, Describe("Hard fog-delta packet limit.", "09 - Performance", "Fog pixels per packet", 190, (AcceptableValueBase)(object)new AcceptableValueRange<int>(64, 8192), advanced: true)), FogMergeCellsPerFrame = file.Bind<int>("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<int>(4096, 262144), advanced: true)), MaxNetworkEventsPerTenSeconds = file.Bind<int>("09 - Performance", "MaxPeerEventsPerTenSeconds", 500, Describe("Server event-rate guard per peer.", "09 - Performance", "Peer event limit", 170, (AcceptableValueBase)(object)new AcceptableValueRange<int>(200, 5000), advanced: true)), MaxPinAddsPerFrame = file.Bind<int>("09 - Performance", "MaxPinAddsPerFrame", 96, Describe("Frame budget for restoring or enabling automatic pins.", "09 - Performance", "Pin adds per frame", 160, (AcceptableValueBase)(object)new AcceptableValueRange<int>(8, 512), advanced: true)), ShowPinOverlapDiagnostics = file.Bind<bool>("10 - Diagnostics", "ShowPinOverlapCounters", false, Describe("Show local P/S counters for overlapping canonical pins and sources.", "10 - Diagnostics", "Overlap counters", 100)), PinOverlapDiagnosticDistance = file.Bind<float>("10 - Diagnostics", "PinOverlapDistance", 1.5f, Describe("World-space grouping distance for overlap counters.", "10 - Diagnostics", "Overlap distance", 90, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), advanced: true)), ShowStateDiagnostics = file.Bind<bool>("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<bool>("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<ConfigurationManagerAttributes>().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<string, ZDOID> TokenOwners = new Dictionary<string, ZDOID>(StringComparer.Ordinal); private static readonly Dictionary<ZDOID, string> SourcesByZdo = new Dictionary<ZDOID, string>(); 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<string> Enemies = new HashSet<string>(StringComparer.Ordinal); internal readonly HashSet<string> KilledEnemies = new HashSet<string>(StringComparer.Ordinal); internal readonly HashSet<string> ResolvedEnemies = new HashSet<string>(StringComparer.Ordinal); internal readonly HashSet<string> Chests = new HashSet<string>(StringComparer.Ordinal); internal readonly HashSet<string> InspectedChests = new HashSet<string>(StringComparer.Ordinal); internal readonly HashSet<string> ResolvedChests = new HashSet<string>(StringComparer.Ordinal); internal readonly HashSet<string> RespawnSources = new HashSet<string>(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<string> ExistingReplacementSources = new HashSet<string>(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<PinRecord> _submitPin; private readonly Func<string, string, string, Vector3, bool> _isKnownResource; private readonly Action<IReadOnlyList<FilterCatalogEntry>> _publishFilterCatalog; private readonly PrefabClassifier _classifier; private readonly DungeonTracker _dungeons; private readonly ShimmerService _shimmer; private readonly Dictionary<string, Candidate> _loaded = new Dictionary<string, Candidate>(StringComparer.Ordinal); private readonly Dictionary<int, string> _viewSources = new Dictionary<int, string>(); private readonly Dictionary<int, string> _rootSources = new Dictionary<int, string>(); private readonly Dictionary<long, List<Candidate>> _resourceSpatial = new Dictionary<long, List<Candidate>>(); private readonly Dictionary<long, List<Candidate>> _pickableSpatial = new Dictionary<long, List<Candidate>>(); private readonly Dictionary<long, List<Candidate>> _dungeonSpatial = new Dictionary<long, List<Candidate>>(); private readonly Dictionary<string, Candidate> _vehicles = new Dictionary<string, Candidate>(StringComparer.Ordinal); private readonly Dictionary<string, Candidate> _portals = new Dictionary<string, Candidate>(StringComparer.Ordinal); private readonly HashSet<string> _discovered = new HashSet<string>(StringComparer.Ordinal); private readonly HashSet<string> _repairedPersistentSources = new HashSet<string>(StringComparer.Ordinal); private readonly Dictionary<string, PendingShellHandoff> _pendingShellHandoffs = new Dictionary<string, PendingShellHandoff>(StringComparer.Ordinal); private readonly Dictionary<int, ResourceMath.ResourceProbe> _prefabResourceProbes = new Dictionary<int, ResourceMath.ResourceProbe>(); private readonly HashSet<Candidate> _resourceVisualRefreshCandidates = new HashSet<Candidate>(); 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<PinRecord> submitPin, Action<string, DungeonEventType, string, int, string> submitDungeonEvent, Func<string, string, string, Vector3, bool> isKnownResource, Action<string> dungeonDiagnosticChanged, ShimmerService shimmer, Action<IReadOnlyList<FilterCatalogEntry>> 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<ZDO> list = new List<ZDO>(); ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(persisted.Position), num3, num3, list, (List<ZDO>)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 ||