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 BetterMapFix v1.1.12
plugins/BetterMapFix/BetterMapFix.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("BetterMapFix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.11.0")] [assembly: AssemblyInformationalVersion("1.1.11")] [assembly: AssemblyProduct("BetterMapFix")] [assembly: AssemblyTitle("BetterMapFix")] [assembly: AssemblyVersion("1.1.11.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BetterMapFix { internal static class BetterMapApi { internal const string PluginGuid = "xtav1m.BetterMap"; internal static Type PluginType; internal static Type PinRulesType; internal static Type RuleType; internal static Type AutoPinsType; internal static Type PinRecordType; internal static Type PinNamesType; internal static MethodInfo MMinimapAddPin; internal static MethodInfo MMinimapUpdate; internal static FieldInfo FAutoPin; internal static FieldInfo FMergeDistance; internal static FieldInfo FExplorationRadius; internal static MethodInfo MBindPinRules; internal static ConfigFile BetterMapConfig; internal static FieldInfo FRulesAll; internal static FieldInfo FName; internal static FieldInfo FDescription; internal static FieldInfo FNameToken; internal static FieldInfo FPrefabs; internal static FieldInfo FBiome; internal static FieldInfo FCategory; internal static FieldInfo FDefaultOn; internal static FieldInfo FIsLocation; internal static FieldInfo FEnabled; internal static FieldInfo FComponent; internal static MethodInfo MSweep; internal static MethodInfo MBuild; internal static MethodInfo MPlace; internal static MethodInfo MPinRecordHas; internal static MethodInfo MPinNamesFor; internal static bool Ready { get; private set; } internal static string FailReason { get; private set; } internal static bool SupportsComponent => FComponent != null; internal static bool Init(Assembly betterMap, ConfigFile betterMapConfig) { List<string> list = new List<string>(); try { BetterMapConfig = betterMapConfig; PluginType = betterMap.GetType("BetterMap.Plugin", throwOnError: false); PinRulesType = betterMap.GetType("BetterMap.Scripts.Pins.PinRules", throwOnError: false); RuleType = betterMap.GetType("BetterMap.Scripts.Pins.PinRules+Rule", throwOnError: false); AutoPinsType = betterMap.GetType("BetterMap.Scripts.Pins.AutoPins", throwOnError: false); PinRecordType = betterMap.GetType("BetterMap.Scripts.Pins.PinRecord", throwOnError: false); PinNamesType = betterMap.GetType("BetterMap.Scripts.Pins.PinNames", throwOnError: false); if (PluginType == null) { list.Add("BetterMap.Plugin"); } if (PinRulesType == null) { list.Add("PinRules"); } if (RuleType == null) { list.Add("PinRules+Rule"); } if (AutoPinsType == null) { list.Add("AutoPins"); } if (PinRecordType == null) { list.Add("PinRecord"); } if (PinNamesType == null) { list.Add("PinNames"); } if (list.Count > 0) { FailReason = "缺少类型:" + string.Join(", ", list); return false; } MBindPinRules = Find(PluginType, "BindPinRules", list, "Plugin.BindPinRules"); MSweep = Find(AutoPinsType, "Sweep", list, "AutoPins.Sweep"); MBuild = Find(AutoPinsType, "Build", list, "AutoPins.Build"); MPlace = Find(AutoPinsType, "Place", list, "AutoPins.Place"); MPinRecordHas = Find(PinRecordType, "Has", list, "PinRecord.Has"); MPinNamesFor = AccessTools.Method(PinNamesType, "For", new Type[2] { RuleType, typeof(GameObject) }, (Type[])null); if (MPinNamesFor == null) { list.Add("PinNames.For(Rule, GameObject)"); } MMinimapAddPin = AccessTools.Method(typeof(Minimap), "AddPin", (Type[])null, (Type[])null); MMinimapUpdate = AccessTools.Method(typeof(Minimap), "Update", (Type[])null, (Type[])null); FAutoPin = Field(PluginType, "autoPin", list); FMergeDistance = Field(PluginType, "autoPinMergeDistance", list); FExplorationRadius = Field(PluginType, "explorationRadius", list); FRulesAll = Field(PinRulesType, "All", list); FName = Field(RuleType, "Name", list); FDescription = Field(RuleType, "Description", list); FNameToken = Field(RuleType, "NameToken", list); FPrefabs = Field(RuleType, "Prefabs", list); FBiome = Field(RuleType, "Biome", list); FCategory = Field(RuleType, "Category", list); FDefaultOn = Field(RuleType, "DefaultOn", list); FIsLocation = Field(RuleType, "IsLocation", list); FEnabled = Field(RuleType, "Enabled", list); if (list.Count > 0) { FailReason = "缺少成员:" + string.Join(", ", list); return false; } FComponent = AccessTools.Field(RuleType, "Component"); Ready = true; return true; } catch (Exception ex) { FailReason = ex.ToString(); return false; } } private static MethodInfo Find(Type t, string name, List<string> missing, string label) { MethodInfo methodInfo = AccessTools.Method(t, name, (Type[])null, (Type[])null); if (methodInfo == null) { missing.Add(label); } return methodInfo; } private static FieldInfo Field(Type t, string name, List<string> missing) { FieldInfo fieldInfo = AccessTools.Field(t, name); if (fieldInfo == null) { missing.Add(t.Name + "." + name); } return fieldInfo; } internal static IList Rules() { return FRulesAll.GetValue(null) as IList; } internal static bool AutoPinEnabled() { return Value<bool>(FAutoPin); } internal static float ExplorationRadius() { return Value<float>(FExplorationRadius); } internal static float MergeDistance() { return Value<float>(FMergeDistance); } private static T Value<T>(FieldInfo configEntryField) { if (!(configEntryField.GetValue(null) is ConfigEntry<T> val)) { return default(T); } return val.Value; } internal static string Name(object rule) { return (string)FName.GetValue(rule); } internal static Biome BiomeOf(object rule) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return (Biome)FBiome.GetValue(rule); } internal static object Category(object rule) { return FCategory.GetValue(rule); } internal static string[] PrefabsOf(object rule) { try { return FPrefabs.GetValue(rule) as string[]; } catch { return null; } } internal static bool IsLocation(object rule) { return (bool)FIsLocation.GetValue(rule); } internal static bool HasComponent(object rule) { if (FComponent != null) { return FComponent.GetValue(rule) != null; } return false; } internal static bool? RuleEnabled(object rule) { if (!(FEnabled.GetValue(rule) is ConfigEntry<bool> val)) { return null; } return val.Value; } internal static object NewRule(string name, string description, string nameToken, string[] prefabs, Biome biome, object category, bool defaultOn, bool isLocation, Type component = null) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) object obj = Activator.CreateInstance(RuleType); FName.SetValue(obj, name); FDescription.SetValue(obj, description); FNameToken.SetValue(obj, nameToken); FPrefabs.SetValue(obj, (component != null) ? null : prefabs); FBiome.SetValue(obj, biome); FCategory.SetValue(obj, category); FDefaultOn.SetValue(obj, defaultOn); FIsLocation.SetValue(obj, isLocation); FEnabled.SetValue(obj, null); if (component != null && FComponent != null) { FComponent.SetValue(obj, component); } return obj; } internal static void Place(object rule, Vector3 pos) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) MPlace.Invoke(null, new object[3] { rule, null, pos }); } internal static void BindRule(object rule) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown if (BetterMapConfig != null && FEnabled.GetValue(rule) == null) { ConfigEntry<bool> value = BetterMapConfig.Bind<bool>("Auto Pins - " + FBiome.GetValue(rule), (string)FName.GetValue(rule), (bool)FDefaultOn.GetValue(rule), new ConfigDescription((string)FDescription.GetValue(rule), (AcceptableValueBase)null, Array.Empty<object>())); FEnabled.SetValue(rule, value); } } internal static bool AlreadyRecorded(object category, Vector3 pos, float mergeDistance) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return (bool)MPinRecordHas.Invoke(null, new object[3] { category, pos, mergeDistance }); } } [BepInPlugin("bettermapfix.client.only", "BetterMapFix", "1.1.11")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class BetterMapFixPlugin : BaseUnityPlugin { public const string Guid = "bettermapfix.client.only"; public const string PluginName = "BetterMapFix"; public const string PluginVersion = "1.1.11"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> ScanVegvisirs; internal static ConfigEntry<bool> InjectCaveRules; internal static ConfigEntry<bool> LogUnknownPinNames; internal static ConfigEntry<bool> ChineseLabelEnabled; internal static ConfigEntry<string> NameMap; internal static ConfigEntry<bool> MergeDefaultMap; internal static ConfigEntry<bool> RenameExistingPins; internal static ConfigEntry<bool> DumpLocations; internal static ConfigEntry<string> DumpZNetNames; internal static ConfigEntry<bool> VerbosePinLog; private void Awake() { //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Expected O, but got Unknown //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Expected O, but got Unknown //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Expected O, but got Unknown //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Expected O, but got Unknown //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Expected O, but got Unknown //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Expected O, but got Unknown //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "总开关。关掉后本补丁完全不介入 BetterMap(重新加载生效)。\nMaster switch. Off = this patch does nothing at all."); ScanVegvisirs = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Vegvisirs", "Scan Vegvisirs", true, "修复「Boss 指引石被找到后不落图钉」。\n做法:沿用原模组自己的扫描节奏(Sweep Interval)与探索半径(Exploration Radius),\n补扫玩家附近真实存在的指引石,再调用原模组自己的落钉函数。\n开关仍然听 BetterMap 各群系里的 Vegvisirs 选项(本补丁不改它)。\n【BetterMap 1.0.4 起】上游自己已经会用「Location 生成事件 + 扫内部组件」标记指引石,\n本补丁也把迷雾之地那条规则交给它(填 Rule.Component)。此时这一项相当于**兜底**:\n上游落过钉的位置会被去重记录挡住,所以不会出现重复图钉,只是多扫一遍。\nFix: pin boss vegvisir stones, using BetterMap's own sweep cadence / radius / pin code."); InjectCaveRules = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Caves", "Inject Cave Rules", true, "向 BetterMap 补几条它漏掉的地牢入口规则(腐疫矿区、腐朽之穴等)。\n注入后这些开关出现在 BetterMap 自己的 cfg 里,按群系排在其它洞穴选项旁边:\n [Auto Pins - Mistlands] Infested Mines(腐疫矿区)\n [Auto Pins - AshLands] Morgen Holes(腐朽之穴)\n [Auto Pins - Mountain] Frost Caves / Hildir Cave\n [Auto Pins - BlackForest] Half Burried Crypt / Hildir Crypt\n [Auto Pins - Plains] Hildir Fortress\n原模组自己已经有的条目(如 1.0.4 的 Frost Caves)会被自动跳过,不会重复。\nAdds the dungeon-entrance rules BetterMap is missing (infested mines, morgen holes etc.).\nTheir switches show up in BetterMap's own config file, next to the other caves."); LogUnknownPinNames = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Labels", "Log Unknown Pin Names", true, "**诊断开关**:把「映射表没命中」的图钉名打进日志(去重,最多 60 个,满就停)。\n用途:有些图钉名不是规则名(比如生物走 Character.m_name),静态分析看不出来,\n只能靠真机日志。看到不认识的英文名,加进 `Name Map` 就能翻。\nDiagnostic: log pin names the name map did not match (deduped, max 60)."); ChineseLabelEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Labels", "Chinese Labels", true, "把地图图钉上的英文名换成中文(洞穴、要塞、祭坛那类地点图钉)。\n只改图钉标签这一层:不动 BetterMap 的 cfg 键名、规则表、图标与去重记录。\n做法是给原模组算图钉名的函数做一个精确整串替换。\nRename map pin labels to Chinese. Only the label string changes - config keys, rules,\nicons and the de-dup record are untouched."); NameMap = ((BaseUnityPlugin)this).Config.Bind<string>("4 - Labels", "Name Map", "Burial Chambers=陪葬墓室,Troll Caves=巨魔洞穴,Bear Caves=巨熊洞穴,Sunken Crypts=沉没墓穴,Frost Caves=冰霜洞穴,Half Burried Crypt=半埋墓穴,Hildir Cave=希尔迪洞穴,Hildir Crypt=希尔迪墓穴,Hildir Fortress=希尔迪平原要塞,Entrance to the Queen=女王巢穴入口,Charred Fortresses=焦黑要塞,Dvergr Town=矮人村落,Infested Mines=腐疫矿区,Putrid Holes=腐朽之穴,Morkhalla=黑暗大厅,The Hole=冰窟营地,Memorial Places=纪念之地,Places of Mystery=谜团之地,Tar Pits=焦油坑,Sulfur Arches=硫磺拱,Frozen Trolls=冰冻巨魔遗骸,Boar Runestones=鬓猪符文石,Draugr Runestones=尸鬼符文石,Greydwarf Runestones=灰矮人符文石,Altar of Eikthyr=埃克提尔祭坛,Altar of the Elder=上古者祭坛,Altar of Bonemass=骨魔祭坛,Altar of Moder=龙母祭坛,Altar of Yagluth=亚格鲁斯祭坛,Altar of Fader=法德祭坛,Copper Deposits=铜矿源,Tin Deposits=锡矿源,Silver Deposits=银矿源,Obsidian Deposits=黑曜石矿源,Flametal=焰金属,Muddy Scrap Piles=泥泞废料堆,Giant Remains=巨人遗骸,Yggdrasil Roots=世界之树根,Flint=燧石,Thistle=蓟草,Mushrooms=蘑菇,Dandelions=蒲公英,Blueberry Bushes=蓝莓丛,Raspberry Bushes=覆盆子丛,Cloudberry Bushes=云莓丛,Lingonberry Bushes=越橘丛,Carrot Seeds=胡萝卜种子,Turnip Seeds=芜菁种子,Kale Seeds=羽衣甘蓝种子,Vineberries=酒莓,Smoke Puffs=余烬泡泡,Jotun Puffs=巨人泡泡,Magecap=法师帽菇,Snowballs=雪球,Beehives=蜂房,Greydwarf Nests=灰矮人巢穴,Greydwarf Nest=灰矮人巢穴,Drake Nests=幼龙巢,Surtling Fire Holes=苏尔特尔火洞,Volture Nests=兀鹰巢,Fuling Totems=丑地精图腾,Dvergr Needle Crates=矮人针箱,Dvergr Excavations=矮人挖掘场,Charred Skulls=焦黑头骨,Charred Tower Ruins=焦黑塔遗迹,Charred Spawner Towers=焦黑刷怪塔,Ash Pots=灰烬陶罐,Ash Pot=灰烬陶罐,Unstable Lava Rock=不稳定熔岩,Leviathans=甲壳素,Leviathan=甲壳素,Vegvisirs=导向符文石,Soft Tissue=软组织", "英文名=中文名,用逗号分隔。只做**整串精确匹配**,不在这张表里的名字原样保留。\n规则名可以照抄 BetterMap cfg 里的键名。\n※ 本表会与内置默认表**合并**(见下面 Merge Default Map)。\n※ 内置表已覆盖 BetterMap **全部规则名**(69 条),所以正常情况下你不用动这里。\n※ `英文名=`(值留空)表示**删掉这一条**,用来去掉不想要的内置译名。\n想改某条内置译名,直接写 `英文名=你的译名`(你的优先),例如:\n Thistle=蓟,Leviathans=大海龟,Silver Deposits=银矿脉\n(在游戏里改这项会立即生效;直接改 cfg 文件要重启游戏。)\nComma-separated English=Chinese pairs, matched as a whole string only.\nMerged with the built-in table (which already covers all 69 rule names);\n`Name=` with an empty value removes that entry."); MergeDefaultMap = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Labels", "Merge Default Map", true, "把**内置默认译名表**合并进你上面那张 `Name Map`(你的条目优先、可覆盖内置译名)。\n为什么需要它:BepInEx 的配置有个特性 —— 当 cfg 文件里**已经存在**某个键时,\n它**不会**用新的默认值去覆盖你文件里的旧值。于是本补丁每次升级新增的内置译名,\n对老用户(cfg 里已写过旧表)**永远不会生效**,表现为\n「新补的地牢图钉标出来了,但名字还是英文」。\n开着这项就会自动补齐,你不必手动去改 cfg。(补丁 1.1.0 起有这个开关。)\n· 想完全自己掌控映射表(只认你写的那张):关掉本项;\n· 想删掉某条内置译名:在 Name Map 里写「英文名=」(值留空),或直接关掉本项。\nMerge the built-in default map into your Name Map (yours wins). Needed because\nBepInEx keeps the value already written in your config file, so newly added\nbuilt-in entries would otherwise never take effect after a mod update."); RenameExistingPins = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Labels", "Rename Existing Pins", true, "连**已经放上去的旧图钉**也一并改名(名字是落钉那一刻写进地图数据的,所以要单独跑一趟)。\n只重命名名字精确命中映射表的图钉,其余一概不碰;关掉它就只影响新落的钉。\nAlso rename pins that are already on the map. Only exact matches are touched."); DumpLocations = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Debug", "Dump Location Names", false, "打开后,世界加载完把游戏的地点表整表打进日志(名字 / 预制体名 / 群系 / 是否启用)。\n用来核对洞穴位置名对不对(例如确认 MountainCave02 就是冰霜洞穴)。\nLog the whole location table once per world load — to verify the injected prefab names."); DumpZNetNames = ((BaseUnityPlugin)this).Config.Bind<string>("9 - Debug", "Dump ZNet Names", "giant", "**诊断**:把 `ZNetScene` 里名字含该关键词的预制体 / 世界里活着的实例打进日志\n(一个世界只打一次)。多个关键词用逗号分隔;留空即关闭。\n回答两个问题:① 规则里写的预制体名**到底注册没有**(没注册 ⇒ 永远匹配不到);\n② 世界里那个东西的**实际名字**是什么。\nDump ZNetScene prefab/instance names matching these substrings. Empty = off."); VerbosePinLog = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Debug", "Verbose Pin Log", true, "每落一个指引石图钉就打一行日志(群系 + 坐标 + 距离)。\nLog every vegvisir pin this patch places."); if (!Enabled.Value) { Log.LogInfo((object)"BetterMapFix: 配置里已关闭,不介入。"); return; } if (!Chainloader.PluginInfos.TryGetValue("xtav1m.BetterMap", out var value) || (Object)(object)value.Instance == (Object)null) { Log.LogWarning((object)"BetterMapFix: 没检测到 BetterMap(xtav1m.BetterMap),补丁不生效。装上 BetterMap 后重启游戏即可。"); return; } if (!BetterMapApi.Init(((object)value.Instance).GetType().Assembly, value.Instance.Config)) { Log.LogError((object)("BetterMapFix: BetterMap 内部接口自检不通过(多半是它换了版本),补丁不生效。\n 原因:" + BetterMapApi.FailReason)); return; } Harmony val = new Harmony("bettermapfix.client.only"); try { val.Patch((MethodBase)BetterMapApi.MBuild, new HarmonyMethod(AccessTools.Method(typeof(RuleInjection), "BuildPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)BetterMapApi.MBindPinRules, new HarmonyMethod(AccessTools.Method(typeof(RuleInjection), "BindPinRulesPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (ScanVegvisirs.Value) { val.Patch((MethodBase)BetterMapApi.MSweep, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(VegvisirScanner), "Postfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } if (ChineseLabelEnabled.Value && BetterMapApi.MPinNamesFor != null) { val.Patch((MethodBase)BetterMapApi.MPinNamesFor, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(ChineseLabels), "PinNamesForPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (BetterMapApi.MMinimapAddPin != null) { val.Patch((MethodBase)BetterMapApi.MMinimapAddPin, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(ChineseLabels), "AddPinPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Log.LogWarning((object)"BetterMapFix: 找不到 Minimap.AddPin,非规则路径落钉的图钉名不会中文。"); } if (RenameExistingPins.Value) { if (BetterMapApi.MMinimapUpdate != null) { val.Patch((MethodBase)BetterMapApi.MMinimapUpdate, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(ChineseLabels), "MinimapUpdatePostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Log.LogWarning((object)"BetterMapFix: 找不到 Minimap.Update,已有图钉不会改名(新落钉仍为中文)。"); } } ChineseLabels.ReloadMap(); NameMap.SettingChanged += delegate { ChineseLabels.ReloadMap(); }; MergeDefaultMap.SettingChanged += delegate { ChineseLabels.ReloadMap(); }; } } catch (Exception ex) { Log.LogError((object)("BetterMapFix: 挂 Harmony 补丁失败:" + ex)); return; } Log.LogInfo((object)string.Format("BetterMapFix {0} 已加载:洞穴规则注入={1},指引石扫描={2},中文图钉名={3}(接口自检通过)。", "1.1.11", InjectCaveRules.Value, ScanVegvisirs.Value, ChineseLabelEnabled.Value)); Log.LogInfo((object)("BetterMapFix: 检测到 BetterMap 支持 Rule.Component(1.0.4+):" + (BetterMapApi.SupportsComponent ? "是 —— 迷雾之地 Vegvisirs 交给它自己的「Location 内部组件」通道,本补丁扫描仅兜底。" : "否(1.0.2/1.0.3)—— 迷雾之地 Vegvisirs 只能靠本补丁自己扫描落钉。"))); } private void Update() { DebugDump.Tick(); } } internal static class ChineseLabels { private static Dictionary<string, string> _map = new Dictionary<string, string>(StringComparer.Ordinal); private static FieldInfo _mPins; private static PropertyInfo _pinNameTextProp; private static PropertyInfo _tmpTextProp; private static bool _reflectBroken; private static bool _loggedTextFail; private static float _nextRenamePass; private static int _renamedTotal; internal const float RenameInterval = 2f; internal const string DefaultMap = "Burial Chambers=陪葬墓室,Troll Caves=巨魔洞穴,Bear Caves=巨熊洞穴,Sunken Crypts=沉没墓穴,Frost Caves=冰霜洞穴,Half Burried Crypt=半埋墓穴,Hildir Cave=希尔迪洞穴,Hildir Crypt=希尔迪墓穴,Hildir Fortress=希尔迪平原要塞,Entrance to the Queen=女王巢穴入口,Charred Fortresses=焦黑要塞,Dvergr Town=矮人村落,Infested Mines=腐疫矿区,Putrid Holes=腐朽之穴,Morkhalla=黑暗大厅,The Hole=冰窟营地,Memorial Places=纪念之地,Places of Mystery=谜团之地,Tar Pits=焦油坑,Sulfur Arches=硫磺拱,Frozen Trolls=冰冻巨魔遗骸,Boar Runestones=鬓猪符文石,Draugr Runestones=尸鬼符文石,Greydwarf Runestones=灰矮人符文石,Altar of Eikthyr=埃克提尔祭坛,Altar of the Elder=上古者祭坛,Altar of Bonemass=骨魔祭坛,Altar of Moder=龙母祭坛,Altar of Yagluth=亚格鲁斯祭坛,Altar of Fader=法德祭坛,Copper Deposits=铜矿源,Tin Deposits=锡矿源,Silver Deposits=银矿源,Obsidian Deposits=黑曜石矿源,Flametal=焰金属,Muddy Scrap Piles=泥泞废料堆,Giant Remains=巨人遗骸,Yggdrasil Roots=世界之树根,Flint=燧石,Thistle=蓟草,Mushrooms=蘑菇,Dandelions=蒲公英,Blueberry Bushes=蓝莓丛,Raspberry Bushes=覆盆子丛,Cloudberry Bushes=云莓丛,Lingonberry Bushes=越橘丛,Carrot Seeds=胡萝卜种子,Turnip Seeds=芜菁种子,Kale Seeds=羽衣甘蓝种子,Vineberries=酒莓,Smoke Puffs=余烬泡泡,Jotun Puffs=巨人泡泡,Magecap=法师帽菇,Snowballs=雪球,Beehives=蜂房,Greydwarf Nests=灰矮人巢穴,Greydwarf Nest=灰矮人巢穴,Drake Nests=幼龙巢,Surtling Fire Holes=苏尔特尔火洞,Volture Nests=兀鹰巢,Fuling Totems=丑地精图腾,Dvergr Needle Crates=矮人针箱,Dvergr Excavations=矮人挖掘场,Charred Skulls=焦黑头骨,Charred Tower Ruins=焦黑塔遗迹,Charred Spawner Towers=焦黑刷怪塔,Ash Pots=灰烬陶罐,Ash Pot=灰烬陶罐,Unstable Lava Rock=不稳定熔岩,Leviathans=甲壳素,Leviathan=甲壳素,Vegvisirs=导向符文石,Soft Tissue=软组织"; private const int UnknownNameLimit = 60; private static HashSet<string> _unknownNames; private static List<KeyValuePair<string, string>> ParsePairs(string raw) { List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>(); if (string.IsNullOrEmpty(raw)) { return list; } string[] array = raw.Split(',', '\n'); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0) { continue; } int num = text.IndexOf('='); if (num > 0) { string text2 = text.Substring(0, num).Trim(); string value = text.Substring(num + 1).Trim(); if (text2.Length > 0) { list.Add(new KeyValuePair<string, string>(text2, value)); } } } return list; } internal static void ReloadMap() { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); int num = 0; if (BetterMapFixPlugin.MergeDefaultMap.Value) { foreach (KeyValuePair<string, string> item in ParsePairs("Burial Chambers=陪葬墓室,Troll Caves=巨魔洞穴,Bear Caves=巨熊洞穴,Sunken Crypts=沉没墓穴,Frost Caves=冰霜洞穴,Half Burried Crypt=半埋墓穴,Hildir Cave=希尔迪洞穴,Hildir Crypt=希尔迪墓穴,Hildir Fortress=希尔迪平原要塞,Entrance to the Queen=女王巢穴入口,Charred Fortresses=焦黑要塞,Dvergr Town=矮人村落,Infested Mines=腐疫矿区,Putrid Holes=腐朽之穴,Morkhalla=黑暗大厅,The Hole=冰窟营地,Memorial Places=纪念之地,Places of Mystery=谜团之地,Tar Pits=焦油坑,Sulfur Arches=硫磺拱,Frozen Trolls=冰冻巨魔遗骸,Boar Runestones=鬓猪符文石,Draugr Runestones=尸鬼符文石,Greydwarf Runestones=灰矮人符文石,Altar of Eikthyr=埃克提尔祭坛,Altar of the Elder=上古者祭坛,Altar of Bonemass=骨魔祭坛,Altar of Moder=龙母祭坛,Altar of Yagluth=亚格鲁斯祭坛,Altar of Fader=法德祭坛,Copper Deposits=铜矿源,Tin Deposits=锡矿源,Silver Deposits=银矿源,Obsidian Deposits=黑曜石矿源,Flametal=焰金属,Muddy Scrap Piles=泥泞废料堆,Giant Remains=巨人遗骸,Yggdrasil Roots=世界之树根,Flint=燧石,Thistle=蓟草,Mushrooms=蘑菇,Dandelions=蒲公英,Blueberry Bushes=蓝莓丛,Raspberry Bushes=覆盆子丛,Cloudberry Bushes=云莓丛,Lingonberry Bushes=越橘丛,Carrot Seeds=胡萝卜种子,Turnip Seeds=芜菁种子,Kale Seeds=羽衣甘蓝种子,Vineberries=酒莓,Smoke Puffs=余烬泡泡,Jotun Puffs=巨人泡泡,Magecap=法师帽菇,Snowballs=雪球,Beehives=蜂房,Greydwarf Nests=灰矮人巢穴,Greydwarf Nest=灰矮人巢穴,Drake Nests=幼龙巢,Surtling Fire Holes=苏尔特尔火洞,Volture Nests=兀鹰巢,Fuling Totems=丑地精图腾,Dvergr Needle Crates=矮人针箱,Dvergr Excavations=矮人挖掘场,Charred Skulls=焦黑头骨,Charred Tower Ruins=焦黑塔遗迹,Charred Spawner Towers=焦黑刷怪塔,Ash Pots=灰烬陶罐,Ash Pot=灰烬陶罐,Unstable Lava Rock=不稳定熔岩,Leviathans=甲壳素,Leviathan=甲壳素,Vegvisirs=导向符文石,Soft Tissue=软组织")) { dictionary[item.Key] = item.Value; num++; } } int num2 = 0; int num3 = 0; int num4 = 0; foreach (KeyValuePair<string, string> item2 in ParsePairs(BetterMapFixPlugin.NameMap.Value)) { if (item2.Value.Length == 0) { if (dictionary.Remove(item2.Key)) { num4++; } continue; } if (dictionary.ContainsKey(item2.Key)) { num3++; } else { num2++; } dictionary[item2.Key] = item2.Value; } _map = dictionary; string text = (BetterMapFixPlugin.MergeDefaultMap.Value ? $"内置 {num} 条 ∪ 用户表" : "只用用户表(不合并内置)"); BetterMapFixPlugin.Log.LogInfo((object)string.Format("BetterMapFix: 中文名映射 = {0}(覆盖 {1} / 用户新增 {2} / 显式删除 {3})→ 生效 {4} 条{5}", text, num3, num2, num4, dictionary.Count, (dictionary.Count == 0) ? "(映射为空 ⇒ 图钉名保持原样)" : "")); } internal static void PinNamesForPostfix(ref string __result) { try { if (BetterMapFixPlugin.ChineseLabelEnabled.Value && !string.IsNullOrEmpty(__result) && _map.TryGetValue(__result, out var value)) { __result = value; } } catch (Exception ex) { BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: 图钉名替换出错(已忽略):" + ex.Message)); } } internal static void AddPinPostfix(PinData __result) { try { if (__result == null || !BetterMapFixPlugin.ChineseLabelEnabled.Value) { return; } string name = __result.m_name; if (!string.IsNullOrEmpty(name)) { if (_map.TryGetValue(name, out var value)) { RenamePin(__result, value); } else { LogUnknownName(name); } } } catch (Exception ex) { BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: AddPin 改名出错(已忽略):" + ex.Message)); } } internal static void MinimapUpdatePostfix() { try { if (BetterMapFixPlugin.ChineseLabelEnabled.Value && !(Time.time < _nextRenamePass)) { _nextRenamePass = Time.time + 2f; if (BetterMapFixPlugin.RenameExistingPins.Value && _map.Count > 0) { RenameExisting(); } } } catch (Exception ex) { BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: 图钉重命名出错(已忽略):" + ex.Message)); } } private static void RenameExisting() { Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || _map.Count == 0) { return; } if (_mPins == null) { _mPins = AccessTools.Field(typeof(Minimap), "m_pins"); } if (_mPins == null) { if (!_reflectBroken) { _reflectBroken = true; BetterMapFixPlugin.Log.LogWarning((object)"BetterMapFix: 找不到 Minimap.m_pins,已有图钉无法改名(新落钉仍是中文)。"); } } else { if (!(_mPins.GetValue(instance) is IList list)) { return; } int num = 0; for (int i = 0; i < list.Count; i++) { object? obj = list[i]; PinData val = (PinData)((obj is PinData) ? obj : null); if (val != null) { string name = val.m_name; if (!string.IsNullOrEmpty(name) && _map.TryGetValue(name, out var value)) { RenamePin(val, value); num++; } } } if (num > 0) { _renamedTotal += num; BetterMapFixPlugin.Log.LogInfo((object)$"BetterMapFix: 已有图钉改中文名 {num} 个(累计 {_renamedTotal} 个)。"); } } } private static void LogUnknownName(string name) { if (!BetterMapFixPlugin.LogUnknownPinNames.Value || name.StartsWith("$")) { return; } for (int i = 0; i < name.Length; i++) { if (name[i] > '~') { return; } } if (_unknownNames == null) { _unknownNames = new HashSet<string>(StringComparer.Ordinal); } if (_unknownNames.Count < 60 && _unknownNames.Add(name)) { BetterMapFixPlugin.Log.LogInfo((object)$"BetterMapFix: [诊断] 未翻译的图钉名 #{_unknownNames.Count}: \"{name}\"(满 {60} 个后停止记录)"); } } private static void RenamePin(PinData pin, string zh) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown pin.m_name = zh; PinNameData namePinData = pin.m_NamePinData; if (namePinData == null) { pin.m_NamePinData = new PinNameData(pin); return; } try { if (_pinNameTextProp == null) { _pinNameTextProp = ((object)namePinData).GetType().GetProperty("PinNameText"); } object obj = ((_pinNameTextProp != null) ? _pinNameTextProp.GetValue(namePinData) : null); if (obj == null) { pin.m_NamePinData = new PinNameData(pin); return; } if (_tmpTextProp == null) { _tmpTextProp = obj.GetType().GetProperty("text"); } if (_tmpTextProp != null) { _tmpTextProp.SetValue(obj, zh); } } catch (Exception ex) { if (!_loggedTextFail) { _loggedTextFail = true; BetterMapFixPlugin.Log.LogWarning((object)("BetterMapFix: 改图钉显示文本失败(数据里的名字已是中文,下次加载世界会正确显示):" + ex.Message)); } } } } internal static class DebugDump { private static ZoneSystem _lastZoneSystem; private static int _lastCount = -1; private static ZNetScene _lastScene; private static bool _znetLogged; private static FieldInfo _mInstances; internal static void TickZNet() { try { string value = BetterMapFixPlugin.DumpZNetNames.Value; if (string.IsNullOrEmpty(value)) { return; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || (_znetLogged && _lastScene == instance)) { return; } _lastScene = instance; _znetLogged = true; List<string> list = new List<string>(); string[] array = value.Split(',', '\n'); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } if (list.Count == 0) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("BetterMapFix: [诊断] ZNetScene 名字核查(关键词:").Append(value).Append(")"); foreach (string item in list) { GameObject val = null; try { val = instance.GetPrefab(item); } catch { } if ((Object)(object)val == (Object)null) { stringBuilder.Append("\n [注册检查] «").Append(item).Append("» → **未注册**:规则写这个名字永远匹配不到!"); continue; } int value2 = 0; try { value2 = instance.GetPrefabHash(val); } catch { } stringBuilder.Append("\n [注册检查] «").Append(item).Append("» → 已注册,hash=") .Append(value2); } List<string> list2 = new List<string>(); try { if (instance.m_prefabs != null) { foreach (GameObject prefab in instance.m_prefabs) { if ((Object)(object)prefab != (Object)null && Contains(((Object)prefab).name, list)) { list2.Add(((Object)prefab).name); } } } } catch (Exception ex) { stringBuilder.Append("\n <读 m_prefabs 失败:").Append(ex.Message).Append(">"); } list2.Sort(StringComparer.OrdinalIgnoreCase); stringBuilder.Append("\n [已注册预制体] 命中 ").Append(list2.Count).Append(" 个:"); for (int j = 0; j < list2.Count && j < 80; j++) { stringBuilder.Append("\n ").Append(list2[j]); } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); try { if (_mInstances == null) { _mInstances = AccessTools.Field(typeof(ZNetScene), "m_instances"); } IDictionary dictionary = ((_mInstances == null) ? null : (_mInstances.GetValue(instance) as IDictionary)); if (dictionary != null) { foreach (DictionaryEntry item2 in dictionary) { object? value3 = item2.Value; ZNetView val2 = (ZNetView)((value3 is ZNetView) ? value3 : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null)) { string name = ((Object)((Component)val2).gameObject).name; if (name != null && Contains(name, list)) { hashSet.Add(name); } } } } else { stringBuilder.Append("\n <m_instances 取不到(字段没找到)>"); } } catch (Exception ex2) { stringBuilder.Append("\n <读 m_instances 失败:").Append(ex2.Message).Append(">"); } List<string> list3 = new List<string>(hashSet); list3.Sort(StringComparer.OrdinalIgnoreCase); stringBuilder.Append("\n [世界里活着] 命中 ").Append(list3.Count).Append(" 个:"); for (int k = 0; k < list3.Count && k < 80; k++) { stringBuilder.Append("\n ").Append(list3[k]); } BetterMapFixPlugin.Log.LogInfo((object)stringBuilder.ToString()); } catch (Exception ex3) { BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: ZNetScene 名字核查出错:" + ex3)); BetterMapFixPlugin.DumpZNetNames.Value = string.Empty; } } private static bool Contains(string name, List<string> keys) { for (int i = 0; i < keys.Count; i++) { if (name.IndexOf(keys[i], StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } internal static void Tick() { TickLocations(); TickZNet(); } private static void TickLocations() { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) try { if (!BetterMapFixPlugin.DumpLocations.Value) { return; } ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null || instance.m_locations == null || instance.m_locations.Count == 0 || (_lastZoneSystem == instance && _lastCount == instance.m_locations.Count)) { return; } _lastZoneSystem = instance; _lastCount = instance.m_locations.Count; List<string> list = new List<string>(); foreach (ZoneLocation location in instance.m_locations) { if (location != null) { list.Add($"{location.m_name,-34} | prefab={location.m_prefabName,-34} | biome={location.m_biome,-12} | enable={location.m_enable}"); } } list.Sort(StringComparer.OrdinalIgnoreCase); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("BetterMapFix: 世界地点表共 ").Append(list.Count).Append(" 条(找洞穴就看 prefab 这一列):"); for (int i = 0; i < list.Count; i++) { stringBuilder.Append("\n ").Append(list[i]); } BetterMapFixPlugin.Log.LogInfo((object)stringBuilder.ToString()); } catch (Exception ex) { BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: 打印地点表出错:" + ex)); BetterMapFixPlugin.DumpLocations.Value = false; } } } internal static class RuleInjection { private static bool _injected; private static readonly List<object> _injectedRules = new List<object>(); private static readonly char[] ForbiddenKeyChars = new char[8] { '=', '\n', '\t', '\\', '"', '\'', '[', ']' }; private static bool KeySafe(string name, out string bad) { bad = null; if (string.IsNullOrEmpty(name)) { bad = "(空)"; return false; } char[] forbiddenKeyChars = ForbiddenKeyChars; for (int i = 0; i < forbiddenKeyChars.Length; i++) { char c = forbiddenKeyChars[i]; if (name.IndexOf(c) >= 0) { bad = c switch { '\t' => "\\t", '\n' => "\\n", _ => c.ToString(), }; return false; } } return true; } private static bool SamePrefabSet(string[] a, string[] b) { if (a == null || b == null) { return false; } if (a.Length != b.Length) { return false; } HashSet<string> hashSet = new HashSet<string>(a, StringComparer.Ordinal); for (int i = 0; i < b.Length; i++) { if (!hashSet.Contains(b[i])) { return false; } } return true; } internal static void BindPinRulesPrefix() { Guarded(selfBind: false); } internal static void BuildPrefix() { Guarded(selfBind: true); } private static void Guarded(bool selfBind) { try { EnsureInjected(selfBind); } catch (Exception ex) { BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: 规则注入/绑定出错,已吞掉以免影响 BetterMap:" + ex)); } } private static void EnsureInjected(bool selfBind) { if (!_injected) { try { Inject(); } catch (Exception ex) { BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: 注入洞穴规则失败:" + ex)); return; } } if (!selfBind) { return; } for (int i = 0; i < _injectedRules.Count; i++) { object rule = _injectedRules[i]; try { BetterMapApi.BindRule(rule); } catch (Exception ex2) { BetterMapFixPlugin.Log.LogError((object)$"BetterMapFix: 给规则 {BetterMapApi.Name(rule)} 建开关失败(这条不会生效,其余照常):{ex2.Message}"); } } } private static void Inject() { if (_injected) { return; } IList list = BetterMapApi.Rules(); if (list == null) { BetterMapFixPlugin.Log.LogWarning((object)"BetterMapFix: PinRules.All 取不到,这次不注入规则。"); return; } object category = CategoryOf(list, "Troll Caves"); object category2 = CategoryOf(list, "Vegvisirs"); object category3 = CategoryOf(list, "Giant Remains"); if (BetterMapFixPlugin.InjectCaveRules.Value) { AddRule(list, "Frost Caves", "冰霜洞穴的入口(Mountains / MountainCave02)。原版 BetterMap 只在黑森林补了墓穴、巨魔洞、熊洞,山脉这一整段没有洞穴条目。", new string[1] { "MountainCave02" }, (Biome)4, category, defaultOn: true, null, isLocation: true); AddRule(list, "Half Burried Crypt", "半埋的森林墓穴入口(BlackForest / HalfBurried_ForestCrypt)。默认关:实测游戏地点表里它的 m_enable=False,原版不会放置它,所以正常情况下不会落钉。", new string[1] { "HalfBurried_ForestCrypt" }, (Biome)8, category, defaultOn: false, null, isLocation: true); AddRule(list, "Hildir Cave", "希尔迪的洞穴入口(Mountains / Hildir_cave)。默认关:随希尔迪内容出现。", new string[1] { "Hildir_cave" }, (Biome)4, category, defaultOn: false, null, isLocation: true); AddRule(list, "Hildir Crypt", "希尔迪的墓穴入口(BlackForest / Hildir_crypt)。默认关:随希尔迪内容出现。", new string[1] { "Hildir_crypt" }, (Biome)8, category, defaultOn: false, null, isLocation: true); AddRule(list, "Hildir Fortress", "希尔迪的平原要塞入口(Plains / Hildir_plainsfortress)。默认关:随希尔迪内容出现。", new string[1] { "Hildir_plainsfortress" }, (Biome)16, category, defaultOn: false, null, isLocation: true); AddRule(list, "Soft Tissue", "软组织(Mistlands / giant_brain)。上游的 Giant Remains 只钉骨与盔甲武器,不认软组织。", new string[1] { "giant_brain" }, (Biome)512, category3, defaultOn: true, null, isLocation: false); } if (BetterMapApi.SupportsComponent) { AddRule(list, "Vegvisirs", "指引石:迷雾之地的女王(SeekerQueen)。原模组每段都有 Vegvisirs,唯独迷雾之地缺这一条。", null, (Biome)512, category2, defaultOn: true, "$piece_vegvisir", isLocation: false, typeof(Vegvisir)); } else { AddRule(list, "Vegvisirs", "指引石:迷雾之地的女王(SeekerQueen)。原模组每段都有 Vegvisirs,唯独迷雾之地缺这一条。", new string[1] { "Vegvisir_SeekerQueen" }, (Biome)512, category2, defaultOn: true, "$piece_vegvisir", isLocation: false); } _injected = true; BetterMapFixPlugin.Log.LogInfo((object)("BetterMapFix: 规则注入完成(洞穴 " + (BetterMapFixPlugin.InjectCaveRules.Value ? "已开" : "已关") + ",含迷雾之地 Vegvisirs" + (BetterMapApi.SupportsComponent ? "(走上游 Component 通道)" : "(走预制体通道)") + "),共 " + _injectedRules.Count + " 条。")); } private static object CategoryOf(IList all, string ruleName) { for (int i = 0; i < all.Count; i++) { object obj = all[i]; if (obj != null && BetterMapApi.Name(obj) == ruleName) { return BetterMapApi.Category(obj); } } BetterMapFixPlugin.Log.LogWarning((object)("BetterMapFix: 没找到规则 «" + ruleName + "»,类别留空。")); return null; } private unsafe static void AddRule(IList all, string name, string description, string[] prefabs, Biome biome, object category, bool defaultOn, string nameToken, bool isLocation, Type component = null) { //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) if (!KeySafe(name, out var bad)) { BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: 规则名 «" + name + "» 含 BepInEx 禁用字符 «" + bad + "»,跳过注入 —— 这个名字会被原模组当成 cfg 键,带非法字符会让它 Bind 时抛异常。")); return; } for (int i = 0; i < all.Count; i++) { object obj = all[i]; if (obj != null && BetterMapApi.Name(obj) == name && BetterMapApi.BiomeOf(obj) == biome) { BetterMapFixPlugin.Log.LogInfo((object)("BetterMapFix: 规则 [" + ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString() + "] " + name + " 已存在(原模组自己提供,或本补丁已注入过),跳过。")); return; } } if (prefabs != null && prefabs.Length != 0) { for (int j = 0; j < all.Count; j++) { object obj2 = all[j]; if (obj2 != null) { string[] array = BetterMapApi.PrefabsOf(obj2); if (array != null && array.Length != 0 && SamePrefabSet(array, prefabs)) { BetterMapFixPlugin.Log.LogInfo((object)("BetterMapFix: 规则 «" + name + "» 盯的 prefab 已被上游规则 «" + BetterMapApi.Name(obj2) + "» 覆盖 ⇒ 跳过注入(上游已提供,不需要补)。")); return; } } } } object obj3 = BetterMapApi.NewRule(name, description, nameToken, prefabs, biome, category, defaultOn, isLocation, component); all.Add(obj3); _injectedRules.Add(obj3); string text = ((component != null) ? ("组件 " + component.Name) : ((prefabs != null) ? string.Join(", ", prefabs) : "(无)")); BetterMapFixPlugin.Log.LogInfo((object)string.Format("BetterMapFix: +规则 [{0}] {1} → {2}(默认 {3},{4})", biome, name, text, defaultOn ? "开" : "关", isLocation ? "地点类" : ((component != null) ? "组件类" : "预制体类"))); } } internal static class VegvisirScanner { private static readonly Dictionary<Biome, object> _ruleCache = new Dictionary<Biome, object>(); private static bool _placeBroken; internal static void Postfix() { try { Scan(); } catch (Exception ex) { BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: 指引石扫描出错:" + ex)); } } private static void Scan() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) if (!BetterMapFixPlugin.ScanVegvisirs.Value || !BetterMapApi.AutoPinEnabled()) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } float num = BetterMapApi.ExplorationRadius(); if (num <= 0f) { return; } float num2 = num * num; float mergeDistance = BetterMapApi.MergeDistance(); Vector3 position = ((Component)localPlayer).transform.position; Vegvisir[] array = Object.FindObjectsByType<Vegvisir>((FindObjectsSortMode)0); if (array == null || array.Length == 0) { return; } int num3 = 0; int num4 = 0; int num5 = 0; foreach (Vegvisir val in array) { if ((Object)(object)val == (Object)null) { continue; } Vector3 position2 = ((Component)val).transform.position; Vector3 val2 = position2 - position; if (((Vector3)(ref val2)).sqrMagnitude > num2) { continue; } num3++; Biome val3 = Heightmap.FindBiome(position2); object obj = RuleFor(val3); if (obj == null) { num5++; continue; } bool? flag = BetterMapApi.RuleEnabled(obj); if (flag.HasValue && !flag.Value) { num5++; } else if (BetterMapApi.AlreadyRecorded(BetterMapApi.Category(obj), position2, mergeDistance)) { num5++; } else if (Place(obj, position2)) { num4++; if (BetterMapFixPlugin.VerbosePinLog.Value) { BetterMapFixPlugin.Log.LogInfo((object)$"BetterMapFix: 指引石已标记 [{val3}] 位置 {position2.x:0.0},{position2.z:0.0}(距玩家 {Vector3.Distance(position2, position):0.0} m)"); } } } if (num4 > 0 || (num3 > 0 && BetterMapFixPlugin.VerbosePinLog.Value)) { BetterMapFixPlugin.Log.LogInfo((object)$"BetterMapFix: 本轮扫到附近指引石 {num3} 块 → 新落钉 {num4},跳过 {num5}(已记过账 / 该段开关关着)。"); } } private static object RuleFor(Biome biome) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (_ruleCache.TryGetValue(biome, out var value)) { return value; } object obj = null; IList list = BetterMapApi.Rules(); if (list != null) { for (int i = 0; i < list.Count; i++) { object obj2 = list[i]; if (obj2 != null && !(BetterMapApi.Name(obj2) != "Vegvisirs") && !BetterMapApi.IsLocation(obj2) && BetterMapApi.BiomeOf(obj2) == biome) { obj = obj2; break; } } } _ruleCache[biome] = obj; return obj; } private static bool Place(object rule, Vector3 pos) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (_placeBroken) { return false; } try { BetterMapApi.Place(rule, pos); return true; } catch (Exception ex) { _placeBroken = true; BetterMapFixPlugin.Log.LogError((object)("BetterMapFix: 调用 AutoPins.Place 失败,指引石补标记停用(其余功能不受影响):" + ex)); return false; } } } }