using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using MimirsWell.Core.Domain; using MimirsWell.Core.Formatting; using MimirsWell.Core.Indexing; using MimirsWell.Core.Interpretation; using MimirsWell.Core.Resolution; using MimirsWell.Core.Services; using MimirsWell.Indexing; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("MimirsWell")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("An offline, read-only, runtime-indexed Valheim wiki.")] [assembly: AssemblyFileVersion("0.5.4.0")] [assembly: AssemblyInformationalVersion("0.5.4+e9ead6b8be5d9ac71509b88d6e713cfa6d095cc3")] [assembly: AssemblyProduct("MimirsWell")] [assembly: AssemblyTitle("MimirsWell")] [assembly: AssemblyMetadata("ValheimVersion", "0.221.12")] [assembly: AssemblyMetadata("ValheimNetworkVersion", "36")] [assembly: AssemblyMetadata("UnityVersion", "6000.0.61f1")] [assembly: AssemblyMetadata("BepInExPackVersion", "5.4.2333")] [assembly: AssemblyMetadata("BepInExCoreVersion", "5.4.23.3")] [assembly: AssemblyMetadata("JotunnVersion", "2.29.1")] [assembly: AssemblyVersion("0.5.4.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace MimirsWell { [BepInPlugin("com.braxt.mimirswell", "Mimir's Well", "0.5.4")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class MimirsWellPlugin : BaseUnityPlugin { private WikiRuntime? runtime; private void Awake() { //IL_008b: Unknown result type (might be due to invalid IL or missing references) WikiConfiguration wikiConfiguration = new WikiConfiguration(((BaseUnityPlugin)this).Config); if (wikiConfiguration.EnableModSourceDetection.Value) { ModQuery.Enable(); } runtime = new WikiRuntime(this, wikiConfiguration, ((BaseUnityPlugin)this).Logger); runtime.Attach(); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new WikiCommand(runtime)); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded with Jotunn {2}. Command: {3}. Offline/read-only; knowledge visibility: {4}; immutable index: all loaded content.", "Mimir's Well", "0.5.4", "2.29.1", runtime.CommandName, wikiConfiguration.EffectiveKnowledgePolicy)); } private void OnDestroy() { runtime?.Dispose(); runtime = null; } private void Update() { runtime?.Tick(); } } internal static class PluginInfo { internal const string Guid = "com.braxt.mimirswell"; internal const string Name = "Mimir's Well"; internal const string Version = "0.5.4"; } internal sealed class WikiCommand : ConsoleCommand { private readonly WikiRuntime runtime; public override string Name => runtime.CommandName; public override string Help => "Ask about loaded Valheim knowledge, current held/equipped/food context, or bounded diagnostics."; public override bool IsNetwork => false; internal WikiCommand(WikiRuntime runtime) { this.runtime = runtime ?? throw new ArgumentNullException("runtime"); } public override void Run(string[] args, Terminal context) { if (!((Object)(object)context == (Object)null)) { string input = string.Join(" ", args ?? Array.Empty()); ChatPage val = runtime.Execute(input); runtime.LogAcceptanceTranscript(input, val); for (int i = 0; i < val.Lines.Count; i++) { string text = ((i == 0) ? (runtime.ResponsePrefix + " ") : " "); context.AddString(text + val.Lines[i]); } } } } internal sealed class WikiConfiguration { private readonly ConfigFile file; internal ConfigEntry CommandName { get; } internal ConfigEntry ResponsePrefix { get; } internal ConfigEntry EnableNaturalLanguagePatterns { get; } internal ConfigEntry EnableBuildPieces { get; } internal ConfigEntry EnableModSourceDetection { get; } internal ConfigEntry FuzzyMatchingEnabled { get; } internal ConfigEntry FuzzyMatchThreshold { get; } internal ConfigEntry AmbiguityMargin { get; } internal ConfigEntry MaxLinesPerPage { get; } internal ConfigEntry MaxResultsPerPage { get; } internal ConfigEntry PaginationTimeoutSeconds { get; } internal ConfigEntry ShowInternalNames { get; } internal ConfigEntry ShowSourceMod { get; } internal ConfigEntry ShowComparisonAssumptions { get; } internal ConfigEntry SpoilerPolicy { get; } internal ConfigEntry LogLevel { get; } internal ConfigEntry WriteIndexSnapshot { get; } internal ConfigEntry LogAcceptanceTranscript { get; } internal bool DebugLogging => string.Equals(LogLevel.Value, "Debug", StringComparison.OrdinalIgnoreCase); internal WikiKnowledgePolicy EffectiveKnowledgePolicy { get { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!TryKnowledgePolicy(SpoilerPolicy.Value, out var policy)) { return (WikiKnowledgePolicy)3; } return policy; } } internal bool KnowledgePolicyIsValid { get { WikiKnowledgePolicy policy; return TryKnowledgePolicy(SpoilerPolicy.Value, out policy); } } internal WikiConfiguration(ConfigFile file) { //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Expected O, but got Unknown //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Expected O, but got Unknown this.file = file ?? throw new ArgumentNullException("file"); CommandName = file.Bind("General", "CommandName", "wiki", "Command name. Startup-only; changing it requires a game restart."); ResponsePrefix = file.Bind("General", "ResponsePrefix", "[Mimir's Well]", "Short prefix added to command responses."); EnableNaturalLanguagePatterns = file.Bind("General", "EnableNaturalLanguagePatterns", true, "Enable deterministic natural-language patterns after explicit commands."); EnableBuildPieces = file.Bind("General", "EnableBuildPieces", true, "Include build-piece material requirements in the runtime index."); EnableModSourceDetection = file.Bind("General", "EnableModSourceDetection", false, "Enable Jotunn ModQuery at startup. Startup-only because it changes loading instrumentation."); FuzzyMatchingEnabled = file.Bind("Matching", "FuzzyMatchingEnabled", true, "Allow minor misspellings after exact matching fails."); FuzzyMatchThreshold = file.Bind("Matching", "FuzzyMatchThreshold", 0.82, new ConfigDescription("Minimum fuzzy similarity.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5, 1.0), Array.Empty())); AmbiguityMargin = file.Bind("Matching", "AmbiguityMargin", 0.05, new ConfigDescription("Return candidates when top scores are this close.", (AcceptableValueBase)(object)new AcceptableValueRange(0.0, 0.25), Array.Empty())); MaxLinesPerPage = file.Bind("Display", "MaxLinesPerPage", 8, new ConfigDescription("Maximum content lines per page.", (AcceptableValueBase)(object)new AcceptableValueRange(3, 30), Array.Empty())); MaxResultsPerPage = file.Bind("Display", "MaxResultsPerPage", 6, new ConfigDescription("Maximum result rows targeted per page.", (AcceptableValueBase)(object)new AcceptableValueRange(2, 20), Array.Empty())); PaginationTimeoutSeconds = file.Bind("Display", "PaginationTimeoutSeconds", 120, new ConfigDescription("Seconds before /wiki more expires.", (AcceptableValueBase)(object)new AcceptableValueRange(15, 600), Array.Empty())); ShowInternalNames = file.Bind("Display", "ShowInternalNames", false, "Show prefab/internal names in item information."); ShowSourceMod = file.Bind("Display", "ShowSourceMod", true, "Show source-mod labels when startup detection is enabled and attribution is available."); ShowComparisonAssumptions = file.Bind("Display", "ShowComparisonAssumptions", true, "Show the limitations of comparison metrics."); SpoilerPolicy = file.Bind("Knowledge", "SpoilerPolicy", "AllLoaded", "Query visibility: AllLoaded, KnownItems, KnownRecipes, or KnownToCharacter. The complete runtime index is always retained."); LogLevel = file.Bind("Diagnostics", "LogLevel", "Info", "Mimir's Well diagnostic verbosity: Info or Debug."); WriteIndexSnapshot = file.Bind("Diagnostics", "WriteIndexSnapshot", false, "Write metadata-only index counts to the BepInEx config folder."); LogAcceptanceTranscript = file.Bind("Diagnostics", "LogAcceptanceTranscript", false, "Opt in to logging only wiki commands and their displayed response pages for local acceptance testing. Diagnostic bundles remove these lines."); } internal void Reload() { file.Reload(); } private static bool TryKnowledgePolicy(string value, out WikiKnowledgePolicy policy) { if (Enum.TryParse(value?.Trim(), ignoreCase: true, out policy)) { return Enum.IsDefined(typeof(WikiKnowledgePolicy), policy); } return false; } } internal sealed class WikiRuntime : IDisposable { private static readonly WikiIndex EmptyIndex = new WikiIndex((IEnumerable)Array.Empty(), (IEnumerable)Array.Empty(), (IEnumerable)Array.Empty(), DateTimeOffset.MinValue, TimeSpan.Zero, "unknown", 0, string.Empty, 0, false, (IEnumerable)null, (IEnumerable)null, (IEnumerable)null, 0); private readonly MimirsWellPlugin host; private readonly WikiConfiguration configuration; private readonly ManualLogSource log; private readonly RuleBasedQuestionInterpreter interpreter = new RuleBasedQuestionInterpreter(); private readonly ChatPaginator paginator = new ChatPaginator(); private readonly string startupCommandName; private readonly bool startupSourceDetection; private WikiIndex? index; private bool itemsRegistered; private bool piecesRegistered; private bool prefabsRegistered; private bool creaturesRegistered; private bool buildQueued; private int lifecycleGeneration; private bool disposed; internal string ResponsePrefix { get { if (!string.IsNullOrWhiteSpace(configuration.ResponsePrefix.Value)) { return configuration.ResponsePrefix.Value.Trim(); } return "[Mimir's Well]"; } } internal string CommandName => startupCommandName; internal WikiRuntime(MimirsWellPlugin host, WikiConfiguration configuration, ManualLogSource log) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown this.host = host ?? throw new ArgumentNullException("host"); this.configuration = configuration ?? throw new ArgumentNullException("configuration"); this.log = log ?? throw new ArgumentNullException("log"); startupCommandName = EffectiveCommandName(configuration.CommandName.Value); startupSourceDetection = configuration.EnableModSourceDetection.Value; } internal void Attach() { if (!configuration.KnowledgePolicyIsValid) { log.LogWarning((object)("SpoilerPolicy '" + configuration.SpoilerPolicy.Value + "' is invalid; failing closed to KnownToCharacter.")); } ItemManager.OnItemsRegistered += OnItemsRegistered; ItemManager.OnItemsRegisteredFejd += OnItemsRegisteredFejd; PieceManager.OnPiecesRegistered += OnPiecesRegistered; PrefabManager.OnPrefabsRegistered += OnPrefabsRegistered; CreatureManager.OnCreaturesRegistered += OnCreaturesRegistered; Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, new Action(OnLanguageChanged)); } internal ChatPage Execute(string input) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between Unknown and I4 //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Invalid comparison between Unknown and I4 //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Invalid comparison between Unknown and I4 //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Invalid comparison between Unknown and I4 //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Invalid comparison between Unknown and I4 //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01e0: Unknown result type (might be due to invalid IL or missing references) WikiQuery val = interpreter.Interpret(input, new InterpretationContext(CurrentLanguage(), configuration.EnableNaturalLanguagePatterns.Value)); if (configuration.DebugLogging) { log.LogDebug((object)$"Intent={val.Intent}; confidence={val.Confidence:0.00}; diagnostic={val.Diagnostic}"); } if ((int)val.Intent == 22) { return paginator.More(configuration.MaxLinesPerPage.Value, DateTimeOffset.Now, configuration.MaxResultsPerPage.Value); } if ((int)val.Intent == 25) { return ReloadConfiguration(); } if ((int)val.Intent == 24) { return RequestManualReindex(); } WikiIndex val2 = Volatile.Read(in index); if ((int)val.Intent == 23 && val2 == null) { return Page(new WikiAnswer("Index not ready", (IEnumerable)new string[6] { $"Items registered: {itemsRegistered}", $"Pieces registered: {piecesRegistered}", $"Prefabs registered: {prefabsRegistered}", $"Creatures registered: {creaturesRegistered}", KnowledgePolicyStatus(), "Waiting for the required Jotunn registration phases." }, (IEnumerable)null, (IEnumerable)null, false)); } if ((int)val.Intent != 1 && val2 == null) { return Page(new WikiAnswer("Index not ready", (IEnumerable)new string[1] { "Mimir's Well is waiting for the active ObjectDB and Jotunn registration events." }, (IEnumerable)null, (IEnumerable)new string[1] { "Try /wiki status." }, false)); } WikiEngine val3 = CreateEngine(); WikiIndex val4 = val2 ?? EmptyIndex; WikiVisibilitySnapshot val5 = CreateVisibilitySnapshot(val4); WikiAnswer answer = (IsContextIntent(val.Intent) ? val3.ExecuteContext(val4, val, CaptureContext(val.Intent, val4), val5) : val3.Execute(val4, val, val5)); return Page(answer); } internal void LogAcceptanceTranscript(string input, ChatPage page) { if (configuration.LogAcceptanceTranscript.Value && page != null) { string text = SingleLine(input, 512); log.LogInfo((object)("[AcceptanceTranscript] Command: /" + CommandName + ((text.Length > 0) ? (" " + text) : string.Empty))); for (int i = 0; i < page.Lines.Count; i++) { string text2 = ((i == 0) ? (ResponsePrefix + " ") : " "); log.LogInfo((object)("[AcceptanceTranscript] Response: " + text2 + SingleLine(page.Lines[i], 2048))); } } } internal void Tick() { WikiIndex val = Volatile.Read(in index); if (!disposed && !buildQueued && val != null && !val.WorldContextAvailable && (Object)(object)Game.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null && Object.op_Implicit((Object)(object)ObjectDB.instance)) { log.LogInfo((object)"World context became available; scheduling one calculator-complete index refresh."); QueueBuild(force: true); } } public void Dispose() { if (!disposed) { disposed = true; ItemManager.OnItemsRegistered -= OnItemsRegistered; ItemManager.OnItemsRegisteredFejd -= OnItemsRegisteredFejd; PieceManager.OnPiecesRegistered -= OnPiecesRegistered; PrefabManager.OnPrefabsRegistered -= OnPrefabsRegistered; CreatureManager.OnCreaturesRegistered -= OnCreaturesRegistered; Localization.OnLanguageChange = (Action)Delegate.Remove(Localization.OnLanguageChange, new Action(OnLanguageChanged)); paginator.Clear(); Volatile.Write(ref index, null); } } private void OnItemsRegistered() { itemsRegistered = true; QueueLifecycleBuildIfReady(); } private void OnPiecesRegistered() { piecesRegistered = true; QueueLifecycleBuildIfReady(); } private void OnPrefabsRegistered() { prefabsRegistered = true; QueueLifecycleBuildIfReady(); } private void OnCreaturesRegistered() { creaturesRegistered = true; QueueLifecycleBuildIfReady(); } private void OnItemsRegisteredFejd() { lifecycleGeneration++; itemsRegistered = false; piecesRegistered = false; prefabsRegistered = false; creaturesRegistered = false; buildQueued = false; paginator.Clear(); Volatile.Write(ref index, null); log.LogInfo((object)"Invalidated the wiki index for the Fejd/main-menu ObjectDB lifecycle."); } private void OnLanguageChanged() { if (Volatile.Read(in index) != null && Object.op_Implicit((Object)(object)ObjectDB.instance)) { log.LogInfo((object)"Language changed; scheduling a localized index rebuild."); QueueBuild(force: true); } } private void QueueLifecycleBuildIfReady() { if (LifecycleRegistrationsReady()) { QueueBuild(force: false); } } private void QueueBuild(bool force) { if (!disposed && !buildQueued && (force || LifecycleRegistrationsReady())) { buildQueued = true; int generation = lifecycleGeneration; ((MonoBehaviour)host).StartCoroutine(BuildOnNextFrame(generation)); } } private IEnumerator BuildOnNextFrame(int generation) { yield return null; buildQueued = false; if (disposed || generation != lifecycleGeneration || !Object.op_Implicit((Object)(object)ObjectDB.instance)) { yield break; } try { log.LogInfo((object)"Building runtime wiki index from loaded game data."); AliasRepository aliases = AliasRepository.Load(Path.Combine(Paths.ConfigPath, "MimirsWell.aliases.json"), log); WikiIndex val = new GameDataIndexer(log, aliases).Build(configuration.EnableBuildPieces.Value, startupSourceDetection); Volatile.Write(ref index, val); paginator.Clear(); log.LogInfo((object)$"Wiki index ready in {val.BuildDuration.TotalMilliseconds:0} ms: {val.Items.Count} items, {val.Recipes.Count} recipes, {val.Conversions.Count} conversions, {val.Sources.Count} acquisition sources, {val.Pieces.Count} pieces, {val.SkippedEntries} skipped, {val.UnavailableStatistics} optional statistics unavailable."); log.LogInfo((object)$"Acquisition source categories: creature {val.Sources.Count((WikiAcquisitionSource source) => (int)source.Kind == 0)}, purchased {val.Sources.Count((WikiAcquisitionSource source) => (int)source.Kind == 1)}, passive {val.Sources.Count((WikiAcquisitionSource source) => (int)source.Kind == 2)}, harvested {val.Sources.Count((WikiAcquisitionSource source) => (int)source.Kind == 3)}, mined/destroyed {val.Sources.Count((WikiAcquisitionSource source) => (int)source.Kind == 4)}, fishing {val.Sources.Count((WikiAcquisitionSource source) => (int)source.Kind == 5)}."); log.LogInfo((object)string.Format("Acquisition source adapters: MineRock {0}, MineRock5 {1}, TreeBase {2}, TreeLog {3}, DropOnDestroyed {4}, Fish {5}.", val.Sources.Count((WikiAcquisitionSource source) => source.Adapter == "MineRock"), val.Sources.Count((WikiAcquisitionSource source) => source.Adapter == "MineRock5"), val.Sources.Count((WikiAcquisitionSource source) => source.Adapter == "TreeBase"), val.Sources.Count((WikiAcquisitionSource source) => source.Adapter == "TreeLog"), val.Sources.Count((WikiAcquisitionSource source) => source.Adapter == "DropOnDestroyed"), val.Sources.Count((WikiAcquisitionSource source) => source.Adapter == "Fish"))); log.LogInfo((object)$"Environmental quantity semantics: fixed {val.Sources.Count((WikiAcquisitionSource source) => (int)source.Kind == 4 && (int)source.QuantitySemantics == 0)}, guaranteed-variable {val.Sources.Count((WikiAcquisitionSource source) => (int)source.QuantitySemantics == 1)}."); log.LogInfo((object)$"Diagnostics retained: {val.Diagnostics.Count}; omitted after bound: {val.OmittedDiagnostics}."); WriteMetadataSnapshot(val); } catch (Exception arg) { Volatile.Write(ref index, null); log.LogError((object)$"Wiki index build failed: {arg}"); } } private ChatPage ReloadConfiguration() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Expected O, but got Unknown bool value = configuration.EnableBuildPieces.Value; WikiKnowledgePolicy effectiveKnowledgePolicy = configuration.EffectiveKnowledgePolicy; try { configuration.Reload(); } catch (Exception ex) { log.LogError((object)$"Configuration reload failed: {ex}"); return Page(new WikiAnswer("Reload failed", (IEnumerable)new string[1] { ex.Message }, (IEnumerable)null, (IEnumerable)null, false)); } List list = new List { "Runtime-safe settings reloaded." }; if (!string.Equals(EffectiveCommandName(configuration.CommandName.Value), startupCommandName, StringComparison.OrdinalIgnoreCase)) { list.Add("CommandName remains '" + startupCommandName + "' until the game restarts."); } if (configuration.EnableModSourceDetection.Value != startupSourceDetection) { list.Add($"EnableModSourceDetection remains '{startupSourceDetection}' until the game restarts."); } if (value != configuration.EnableBuildPieces.Value) { list.Add("Build-piece coverage changed; an index rebuild was scheduled."); QueueBuild(force: true); } if (effectiveKnowledgePolicy != configuration.EffectiveKnowledgePolicy) { list.Add($"Knowledge visibility changed to {configuration.EffectiveKnowledgePolicy}; the immutable runtime index was not rebuilt."); } if (!configuration.KnowledgePolicyIsValid) { list.Add("SpoilerPolicy '" + configuration.SpoilerPolicy.Value + "' is invalid; failing closed to KnownToCharacter."); } paginator.Clear(); log.LogInfo((object)"Runtime-safe configuration settings reloaded."); return Page(new WikiAnswer("Configuration reloaded", (IEnumerable)list, (IEnumerable)null, (IEnumerable)null, false)); } private ChatPage RequestManualReindex() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)ObjectDB.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance) || !LifecycleRegistrationsReady()) { return Page(new WikiAnswer("Reindex unavailable", (IEnumerable)new string[1] { "A fully registered active world is required; main-menu data would produce an incomplete index." }, (IEnumerable)null, (IEnumerable)null, false)); } log.LogInfo((object)"Manual reindex requested; scheduling a fresh runtime index build."); QueueBuild(force: true); return Page(new WikiAnswer("Reindex scheduled", (IEnumerable)new string[1] { "The loaded game data will be copied into a new index on the next frame." }, (IEnumerable)null, (IEnumerable)null, false)); } private WikiEngine CreateEngine() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_010c: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown return new WikiEngine(new EntityResolver(new EntityResolverOptions { FuzzyMatchingEnabled = configuration.FuzzyMatchingEnabled.Value, FuzzyMatchThreshold = configuration.FuzzyMatchThreshold.Value, AmbiguityMargin = configuration.AmbiguityMargin.Value, MaximumCandidates = configuration.MaxResultsPerPage.Value }), new WikiEngineOptions { ShowInternalNames = configuration.ShowInternalNames.Value, ShowSourceMod = configuration.ShowSourceMod.Value, ShowComparisonAssumptions = configuration.ShowComparisonAssumptions.Value, MaximumAlternativeResults = Math.Min(5, configuration.MaxResultsPerPage.Value), FuzzyMatchingEnabled = configuration.FuzzyMatchingEnabled.Value, FuzzyMatchThreshold = configuration.FuzzyMatchThreshold.Value, AmbiguityMargin = configuration.AmbiguityMargin.Value }); } private WikiContextSnapshot CaptureContext(WikiIntent intent, WikiIndex current) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected I4, but got Unknown //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Expected O, but got Unknown //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Expected O, but got Unknown //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown WikiContextKind val = ContextKind(intent); Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { List list = new List(); int errors = 0; try { switch ((int)val) { case 0: { ItemData val2 = ((Humanoid)localPlayer).GetRightItem(); string role = "right hand"; if (val2 == null) { val2 = ((Humanoid)localPlayer).GetLeftItem(); role = "left-hand fallback"; } if (val2 == null) { val2 = EquippedHandFallback(localPlayer, ref errors); role = "equipped hand-item fallback (direct hand slots unavailable)"; } AddContextItem(list, val2, role, current, ref errors); break; } case 1: { Inventory inventory = ((Humanoid)localPlayer).GetInventory(); foreach (ItemData item in ((inventory != null) ? inventory.GetEquippedItems() : null) ?? new List()) { AddContextItem(list, item, "equipped", current, ref errors); } break; } case 2: foreach (Food item2 in localPlayer.GetFoods() ?? new List()) { try { if (item2?.m_item == null) { errors++; continue; } string text3 = ContextItemId(item2.m_item, current); if (string.IsNullOrWhiteSpace(text3)) { errors++; } else { list.Add(new WikiContextItem(text3, "active food", (double?)item2.m_health, (double?)item2.m_stamina, (double?)item2.m_eitr, (double?)item2.m_time)); } } catch { errors++; } } break; case 3: { CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); string text = (Object.op_Implicit((Object)(object)currentCraftingStation) ? ContextDisplayName(currentCraftingStation.m_name, ((Object)((Component)currentCraftingStation).gameObject).name) : null); string text2 = (Object.op_Implicit((Object)(object)currentCraftingStation) ? ((Object)((Component)currentCraftingStation).gameObject).name : null); return new WikiContextSnapshot(val, true, (IEnumerable)null, text, text2, errors); } } } catch (Exception ex) { errors++; if (configuration.DebugLogging) { log.LogDebug((object)$"Context shortcut isolated a {val} read failure: {ex.GetType().Name}."); } } return new WikiContextSnapshot(val, true, (IEnumerable)list, (string)null, (string)null, errors); } return new WikiContextSnapshot(val, false, (IEnumerable)null, (string)null, (string)null, 0); } private static ItemData? EquippedHandFallback(Player player, ref int errors) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) try { ItemData result = null; int num = int.MaxValue; Inventory inventory = ((Humanoid)player).GetInventory(); foreach (ItemData item in ((inventory != null) ? inventory.GetEquippedItems() : null) ?? new List()) { try { if (item?.m_shared != null) { int num2 = HandItemPriority(item.m_shared.m_itemType); if (num2 < num) { result = item; num = num2; } } } catch { errors++; } } return result; } catch { errors++; return null; } } private static int HandItemPriority(ItemType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Invalid comparison between Unknown and I4 //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected I4, but got Unknown if (type - 3 > 1) { if ((int)type == 5) { return 3; } switch (type - 14) { case 0: case 6: case 8: break; case 5: return 1; case 1: return 2; default: return int.MaxValue; } } return 0; } private static void AddContextItem(ICollection output, ItemData? item, string role, WikiIndex current, ref int errors) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown if (item == null) { return; } try { string text = ContextItemId(item, current); if (string.IsNullOrWhiteSpace(text)) { errors++; } else { output.Add(new WikiContextItem(text, role, (double?)null, (double?)null, (double?)null, (double?)null)); } } catch { errors++; } } private static string ContextItemId(ItemData item, WikiIndex current) { if (Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return ((Object)item.m_dropPrefab).name; } string key = item.m_shared?.m_name; if (string.IsNullOrWhiteSpace(key)) { return string.Empty; } WikiItem? obj = current.Items.Values.FirstOrDefault((Func)((WikiItem candidate) => string.Equals(candidate.KnowledgeKey, key, StringComparison.Ordinal))); return ((obj != null) ? obj.Id : null) ?? string.Empty; } private static string ContextDisplayName(string? token, string fallback) { if (string.IsNullOrWhiteSpace(token)) { return PrettifyContextName(fallback); } string text = ((Localization.instance != null) ? Localization.instance.Localize(token) : token); if (string.IsNullOrWhiteSpace(text) || (text == token && token.StartsWith("$", StringComparison.Ordinal))) { return PrettifyContextName(fallback); } string text2 = Regex.Replace(text, "<[^>]+>", string.Empty).Trim(); if (!string.IsNullOrWhiteSpace(text2)) { return text2; } return PrettifyContextName(fallback); } private static string PrettifyContextName(string value) { string text = TextNormalizer.Normalize(value); if (!string.IsNullOrWhiteSpace(text)) { return string.Join(" ", from word in text.Split(new char[1] { ' ' }) select char.ToUpperInvariant(word[0]) + word.Substring(1)); } return value; } private static bool IsContextIntent(WikiIntent intent) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 if (intent - 15 <= 3) { return true; } return false; } private static WikiContextKind ContextKind(WikiIntent intent) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected I4, but got Unknown return (WikiContextKind)((intent - 15) switch { 0 => 0, 1 => 1, 2 => 2, _ => 3, }); } private WikiVisibilitySnapshot CreateVisibilitySnapshot(WikiIndex current) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between Unknown and I4 //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Invalid comparison between Unknown and I4 //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Invalid comparison between Unknown and I4 WikiKnowledgePolicy effectiveKnowledgePolicy = configuration.EffectiveKnowledgePolicy; if ((int)effectiveKnowledgePolicy == 0) { return WikiVisibilitySnapshot.AllLoaded; } Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); HashSet hashSet2 = new HashSet(StringComparer.OrdinalIgnoreCase); int num = 0; foreach (WikiItem value in current.Items.Values) { try { bool flag = (int)effectiveKnowledgePolicy != 2 && localPlayer.IsKnownMaterial(value.KnowledgeKey); bool flag2 = (int)effectiveKnowledgePolicy != 1 && localPlayer.IsRecipeKnown(value.KnowledgeKey); if (flag || flag2) { hashSet.Add(value.Id); } } catch (Exception ex) { num++; if (configuration.DebugLogging) { log.LogDebug((object)("Knowledge visibility isolated one indexed-item check: " + ex.GetType().Name + ".")); } } } foreach (WikiPiece piece in current.Pieces) { try { if ((int)effectiveKnowledgePolicy != 1 && localPlayer.IsRecipeKnown(piece.KnowledgeKey)) { hashSet2.Add(piece.Id); } } catch (Exception ex2) { num++; if (configuration.DebugLogging) { log.LogDebug((object)("Knowledge visibility isolated one indexed-piece check: " + ex2.GetType().Name + ".")); } } } return new WikiVisibilitySnapshot(effectiveKnowledgePolicy, (IEnumerable)hashSet, true, num, (IEnumerable)hashSet2); } return new WikiVisibilitySnapshot(effectiveKnowledgePolicy, (IEnumerable)Array.Empty(), false, 0, (IEnumerable)null); } private string KnowledgePolicyStatus() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) string arg = (configuration.KnowledgePolicyIsValid ? string.Empty : (" (invalid configured value '" + configuration.SpoilerPolicy.Value + "' failed closed)")); return $"Knowledge visibility: {configuration.EffectiveKnowledgePolicy}{arg}."; } private ChatPage Page(WikiAnswer answer) { return paginator.Begin(answer, configuration.MaxLinesPerPage.Value, TimeSpan.FromSeconds(configuration.PaginationTimeoutSeconds.Value), DateTimeOffset.Now, configuration.MaxResultsPerPage.Value); } private void WriteMetadataSnapshot(WikiIndex built) { if (!configuration.WriteIndexSnapshot.Value) { return; } try { string path = Path.Combine(Paths.ConfigPath, "MimirsWell.index-metadata.json"); string contents = new StringBuilder().AppendLine("{").Append(" \"pluginVersion\": \"").Append("0.5.4") .AppendLine("\",") .Append(" \"builtAt\": \"") .Append(built.BuiltAt.ToString("O")) .AppendLine("\",") .Append(" \"language\": \"") .Append(JsonEscape(built.Language)) .AppendLine("\",") .Append(" \"items\": ") .Append(built.Items.Count) .AppendLine(",") .Append(" \"recipes\": ") .Append(built.Recipes.Count) .AppendLine(",") .Append(" \"conversions\": ") .Append(built.Conversions.Count) .AppendLine(",") .Append(" \"sources\": ") .Append(built.Sources.Count) .AppendLine(",") .Append(" \"pieces\": ") .Append(built.Pieces.Count) .AppendLine(",") .Append(" \"skippedEntries\": ") .Append(built.SkippedEntries) .AppendLine(",") .Append(" \"unavailableStatistics\": ") .Append(built.UnavailableStatistics) .AppendLine(",") .Append(" \"diagnosticsRetained\": ") .Append(built.Diagnostics.Count) .AppendLine(",") .Append(" \"diagnosticsOmitted\": ") .Append(built.OmittedDiagnostics) .AppendLine(",") .Append(" \"worldContextAvailable\": ") .Append(built.WorldContextAvailable ? "true" : "false") .AppendLine() .AppendLine("}") .ToString(); File.WriteAllText(path, contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); log.LogInfo((object)"Wrote metadata-only index snapshot to the BepInEx config folder."); } catch (Exception ex) { log.LogWarning((object)("Could not write the optional index metadata snapshot: " + ex.Message)); } } private static string JsonEscape(string value) { return (value ?? string.Empty).Replace("\\", "\\\\").Replace("\"", "\\\""); } private bool LifecycleRegistrationsReady() { if (itemsRegistered && prefabsRegistered && creaturesRegistered) { if (configuration.EnableBuildPieces.Value) { return piecesRegistered; } return true; } return false; } private static string SingleLine(string? value, int maximumLength) { string text = (value ?? string.Empty).Replace('\r', ' ').Replace('\n', ' ').Trim(); if (text.Length > maximumLength) { return text.Substring(0, maximumLength) + "…"; } return text; } private static string EffectiveCommandName(string value) { if (!string.IsNullOrWhiteSpace(value)) { return value.Trim().TrimStart(new char[1] { '/' }); } return "wiki"; } private static string CurrentLanguage() { Localization instance = Localization.instance; return ((instance != null) ? instance.GetSelectedLanguage() : null) ?? "unknown"; } } } namespace MimirsWell.Indexing { internal sealed class AcquisitionSourceExtractor { private readonly bool includeModSources; private readonly Action skip; internal AcquisitionSourceExtractor(bool includeModSources, Action skip) { this.includeModSources = includeModSources; this.skip = skip ?? throw new ArgumentNullException("skip"); } internal IReadOnlyList Scan(IEnumerable prefabs) { List list = new List(); foreach (GameObject item in prefabs ?? Array.Empty()) { if (Object.op_Implicit((Object)(object)item)) { ExtractCreatureDrops(item, list); ExtractTraderInventory(item, list); ExtractBeehive(item, list); ExtractSapCollector(item, list); ExtractPickable(item, list); ExtractPickableItem(item, list); ExtractMineRock(item, list); ExtractMineRock5(item, list); ExtractTreeBase(item, list); ExtractTreeLog(item, list); ExtractDropOnDestroyed(item, list); ExtractFish(item, list); } } return (from @group in list.GroupBy((RawAcquisitionSource source) => source.Id, StringComparer.OrdinalIgnoreCase) select @group.First()).ToArray(); } internal IReadOnlyList Build(IEnumerable rawSources, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown List list = new List(); foreach (RawAcquisitionSource rawSource in rawSources) { try { if (!items.TryGetValue(rawSource.OutputItemId, out WikiItem value)) { throw new InvalidOperationException("Output item '" + rawSource.OutputItemId + "' is not present in the published item index."); } string text = (string.IsNullOrWhiteSpace(rawSource.CostItemId) ? null : ItemName(rawSource.CostItemId, items, rawItems)); list.Add(new WikiAcquisitionSource(rawSource.Id, rawSource.Kind, rawSource.Certainty, rawSource.Adapter, rawSource.SourceInternalName, rawSource.SourceName, rawSource.SourceMod, rawSource.OutputItemId, value.DisplayName, rawSource.MinimumAmount, rawSource.MaximumAmount, rawSource.Chance, rawSource.CostItemId, text, rawSource.Price, rawSource.UnlockRequirement, rawSource.ProductionIntervalSeconds, rawSource.Capacity, rawSource.RespawnSeconds, rawSource.OnePerPlayer, rawSource.LevelScaled, rawSource.WorldScaled, rawSource.Method, rawSource.MinimumToolTier, rawSource.QuantitySemantics, rawSource.ConfiguredMinimumAmount, rawSource.ConfiguredMaximumAmount, rawSource.LoadedResourceRate)); } catch (Exception arg) { skip("acquisition source", rawSource.Id, arg); } } return list; } private void ExtractCreatureDrops(GameObject prefab, ICollection sources) { try { CharacterDrop component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } Character component2 = prefab.GetComponent(); string sourceName = Localize(Object.op_Implicit((Object)(object)component2) ? component2.m_name : null, Prettify(((Object)prefab).name)); List list = component.m_drops ?? new List(); for (int i = 0; i < list.Count; i++) { Drop val = list[i]; if ((Object)(object)val?.m_prefab == (Object)null || val.m_chance <= 0f) { continue; } try { if (Object.op_Implicit((Object)(object)val.m_prefab.GetComponent())) { if (float.IsNaN(val.m_chance) || float.IsInfinity(val.m_chance) || val.m_chance > 1f) { throw new InvalidOperationException($"Drop chance '{val.m_chance}' is outside the supported 0..1 range."); } if (val.m_amountMin < 0 || val.m_amountMax < val.m_amountMin) { throw new InvalidOperationException($"Drop quantity range '{val.m_amountMin}..{val.m_amountMax}' is invalid."); } string name = ((Object)val.m_prefab).name; string id = $"{((Object)prefab).name}:CharacterDrop:{i}:{name}"; bool num = !(val.m_chance >= 1f); string name2 = ((Object)prefab).name; string? sourceMod = SourceMod(((Object)prefab).name); int amountMin = val.m_amountMin; int amountMax = val.m_amountMax; double? chance = val.m_chance; bool onePerPlayer = val.m_onePerPlayer; bool levelMultiplier = val.m_levelMultiplier; bool worldScaled = !val.m_dontScale; sources.Add(new RawAcquisitionSource(id, (WikiSourceKind)0, (WikiSourceCertainty)num, "CharacterDrop", name2, sourceName, sourceMod, name, amountMin, amountMax, chance, null, null, null, null, null, null, onePerPlayer, levelMultiplier, worldScaled, null, null, (WikiQuantitySemantics)0)); } } catch (Exception arg) { skip("creature-drop entry", $"{((Object)prefab).name}[{i}]", arg); } } } catch (Exception arg2) { skip("creature-drop component", SafeName((Object?)(object)prefab), arg2); } } private void ExtractTraderInventory(GameObject prefab, ICollection sources) { try { Trader component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } string sourceName = Localize(component.m_name, Prettify(((Object)prefab).name)); List list = component.m_items ?? new List(); for (int i = 0; i < list.Count; i++) { TradeItem val = list[i]; if ((Object)(object)val?.m_prefab == (Object)null) { continue; } try { if (val.m_stack <= 0 || val.m_price < 0) { throw new InvalidOperationException($"Trader stack/price '{val.m_stack}/{val.m_price}' is invalid."); } string name = ((Object)((Component)val.m_prefab).gameObject).name; string id = $"{((Object)prefab).name}:Trader:{i}:{name}"; int num = ((!string.IsNullOrWhiteSpace(val.m_requiredGlobalKey)) ? 2 : 0); string name2 = ((Object)prefab).name; string? sourceMod = SourceMod(((Object)prefab).name); int stack = val.m_stack; int stack2 = val.m_stack; int? price = val.m_price; string requiredGlobalKey = val.m_requiredGlobalKey; sources.Add(new RawAcquisitionSource(id, (WikiSourceKind)1, (WikiSourceCertainty)num, "Trader", name2, sourceName, sourceMod, name, stack, stack2, null, "Coins", price, requiredGlobalKey, null, null, null, onePerPlayer: false, levelScaled: false, worldScaled: false, null, null, (WikiQuantitySemantics)0)); } catch (Exception arg) { skip("trader entry", $"{((Object)prefab).name}[{i}]", arg); } } } catch (Exception arg2) { skip("trader component", SafeName((Object?)(object)prefab), arg2); } } private void ExtractBeehive(GameObject prefab, ICollection sources) { try { Beehive component = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_honeyItem)) { string name = ((Object)((Component)component.m_honeyItem).gameObject).name; string id = ((Object)prefab).name + ":Beehive:" + name; string name2 = ((Object)prefab).name; string sourceName = ComponentName(prefab, component.m_name); string? sourceMod = SourceMod(((Object)prefab).name); double? productionIntervalSeconds = Positive(component.m_secPerUnit); int? capacity = NonNegative(component.m_maxHoney); sources.Add(new RawAcquisitionSource(id, (WikiSourceKind)2, (WikiSourceCertainty)2, "Beehive", name2, sourceName, sourceMod, name, 1, 1, null, null, null, null, productionIntervalSeconds, capacity, null, onePerPlayer: false, levelScaled: false, worldScaled: false, null, null, (WikiQuantitySemantics)0)); } } catch (Exception arg) { skip("beehive component", SafeName((Object?)(object)prefab), arg); } } private void ExtractSapCollector(GameObject prefab, ICollection sources) { try { SapCollector component = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_spawnItem)) { string name = ((Object)((Component)component.m_spawnItem).gameObject).name; string id = ((Object)prefab).name + ":SapCollector:" + name; string name2 = ((Object)prefab).name; string sourceName = ComponentName(prefab, component.m_name); string? sourceMod = SourceMod(((Object)prefab).name); double? productionIntervalSeconds = Positive(component.m_secPerUnit); int? capacity = NonNegative(component.m_maxLevel); sources.Add(new RawAcquisitionSource(id, (WikiSourceKind)2, (WikiSourceCertainty)2, "SapCollector", name2, sourceName, sourceMod, name, 1, 1, null, null, null, null, productionIntervalSeconds, capacity, null, onePerPlayer: false, levelScaled: false, worldScaled: false, null, null, (WikiQuantitySemantics)0)); } } catch (Exception arg) { skip("sap-collector component", SafeName((Object?)(object)prefab), arg); } } private void ExtractPickable(GameObject prefab, ICollection sources) { try { Pickable component = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_itemPrefab)) { if (component.m_amount <= 0) { throw new InvalidOperationException($"Pickable base amount '{component.m_amount}' is not positive."); } string name = ((Object)component.m_itemPrefab).name; string id = ((Object)prefab).name + ":Pickable:" + name; string name2 = ((Object)prefab).name; string sourceName = Localize(component.m_overrideName, Prettify(((Object)prefab).name)); string? sourceMod = SourceMod(((Object)prefab).name); int amount = component.m_amount; int amount2 = component.m_amount; double? respawnSeconds = ((component.m_respawnTimeMinutes > 0f) ? new double?((double)component.m_respawnTimeMinutes * 60.0) : ((double?)null)); bool worldScaled = !component.m_dontScale; sources.Add(new RawAcquisitionSource(id, (WikiSourceKind)3, (WikiSourceCertainty)0, "Pickable", name2, sourceName, sourceMod, name, amount, amount2, null, null, null, null, null, null, respawnSeconds, onePerPlayer: false, levelScaled: false, worldScaled, null, null, (WikiQuantitySemantics)0)); } } catch (Exception arg) { skip("pickable component", SafeName((Object?)(object)prefab), arg); } } private void ExtractPickableItem(GameObject prefab, ICollection sources) { try { PickableItem component = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component) && (component.m_randomItemPrefabs == null || !component.m_randomItemPrefabs.Any((RandomItem entry) => (Object)(object)entry.m_itemPrefab != (Object)null)) && Object.op_Implicit((Object)(object)component.m_itemPrefab)) { if (component.m_stack <= 0) { throw new InvalidOperationException($"Pickable-item stack '{component.m_stack}' is not positive."); } string name = ((Object)((Component)component.m_itemPrefab).gameObject).name; sources.Add(new RawAcquisitionSource(((Object)prefab).name + ":PickableItem:" + name, (WikiSourceKind)3, (WikiSourceCertainty)0, "PickableItem", ((Object)prefab).name, Prettify(((Object)prefab).name), SourceMod(((Object)prefab).name), name, component.m_stack, component.m_stack, null, null, null, null, null, null, null, onePerPlayer: false, levelScaled: false, worldScaled: false, null, null, (WikiQuantitySemantics)0)); } } catch (Exception arg) { skip("pickable-item component", SafeName((Object?)(object)prefab), arg); } } private void ExtractMineRock(GameObject prefab, ICollection sources) { try { MineRock component = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { ExtractDeterministicDropTable(prefab, component.m_dropItems, "MineRock", Localize(component.m_name, Prettify(((Object)prefab).name)), "mine", component.m_minToolTier, sources); } } catch (Exception arg) { skip("mine-rock component", SafeName((Object?)(object)prefab), arg); } } private void ExtractMineRock5(GameObject prefab, ICollection sources) { try { MineRock5 component = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { ExtractDeterministicDropTable(prefab, component.m_dropItems, "MineRock5", Localize(component.m_name, Prettify(((Object)prefab).name)), "mine", component.m_minToolTier, sources); } } catch (Exception arg) { skip("mine-rock-5 component", SafeName((Object?)(object)prefab), arg); } } private void ExtractTreeBase(GameObject prefab, ICollection sources) { try { TreeBase component = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { ExtractDeterministicDropTable(prefab, component.m_dropWhenDestroyed, "TreeBase", Prettify(((Object)prefab).name), "chop", component.m_minToolTier, sources); } } catch (Exception arg) { skip("tree-base component", SafeName((Object?)(object)prefab), arg); } } private void ExtractTreeLog(GameObject prefab, ICollection sources) { try { TreeLog component = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { ExtractDeterministicDropTable(prefab, component.m_dropWhenDestroyed, "TreeLog", Prettify(((Object)prefab).name), "chop", component.m_minToolTier, sources); } } catch (Exception arg) { skip("tree-log component", SafeName((Object?)(object)prefab), arg); } } private void ExtractDropOnDestroyed(GameObject prefab, ICollection sources) { try { DropOnDestroyed component = prefab.GetComponent(); Destructible component2 = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2) && !Object.op_Implicit((Object)(object)prefab.GetComponent())) { ExtractDeterministicDropTable(prefab, component.m_dropWhenDestroyed, "DropOnDestroyed", Prettify(((Object)prefab).name), "destroy", component2.m_minToolTier, sources); } } catch (Exception arg) { skip("drop-on-destroyed component", SafeName((Object?)(object)prefab), arg); } } private void ExtractFish(GameObject prefab, ICollection sources) { try { Fish component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } GameObject val = component.m_pickupItem; if (!Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)prefab.GetComponent())) { val = prefab; } if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.GetComponent())) { if (component.m_pickupItemStackSize <= 0) { throw new InvalidOperationException($"Fish pickup stack '{component.m_pickupItemStackSize}' is not positive."); } string name = ((Object)val).name; sources.Add(new RawAcquisitionSource(((Object)prefab).name + ":Fish:" + name, (WikiSourceKind)5, (WikiSourceCertainty)2, "Fish", ((Object)prefab).name, Localize(component.m_name, Prettify(((Object)prefab).name)), SourceMod(((Object)prefab).name), name, component.m_pickupItemStackSize, component.m_pickupItemStackSize, null, null, null, null, null, null, null, onePerPlayer: false, levelScaled: false, worldScaled: false, "catch or collect", null, (WikiQuantitySemantics)0)); } } catch (Exception arg) { skip("fish component", SafeName((Object?)(object)prefab), arg); } } private void ExtractDeterministicDropTable(GameObject prefab, DropTable? table, string adapter, string sourceName, string method, int minimumToolTier, ICollection sources) { //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) if (table == null || table.m_drops == null || table.m_drops.Count == 0) { return; } if (table.m_drops.Count > 128) { throw new InvalidOperationException($"Drop table contains {table.m_drops.Count} entries; the P1 limit is 128."); } if (float.IsNaN(table.m_dropChance) || float.IsInfinity(table.m_dropChance) || table.m_dropChance < 0f || table.m_dropChance > 1f) { throw new InvalidOperationException($"Drop-table chance '{table.m_dropChance}' is outside the supported 0..1 range."); } if (table.m_dropChance < 1f) { return; } if (table.m_dropMin < 0 || table.m_dropMax < table.m_dropMin) { throw new InvalidOperationException($"Drop-table roll range '{table.m_dropMin}..{table.m_dropMax}' is invalid."); } if (table.m_dropMin == 0) { return; } DropData[] array = table.m_drops.Where((DropData entry) => Object.op_Implicit((Object)(object)entry.m_item)).ToArray(); DropData[] array2 = array; foreach (DropData val in array2) { if (float.IsNaN(val.m_weight) || float.IsInfinity(val.m_weight) || val.m_weight < 0f) { throw new InvalidOperationException($"Drop-table weight '{val.m_weight}' is invalid."); } } if (array.Length != 1 || array[0].m_weight <= 0f) { return; } DropData val2 = array[0]; if (Object.op_Implicit((Object)(object)val2.m_item.GetComponent())) { if (val2.m_stackMin <= 0 || val2.m_stackMax < val2.m_stackMin) { throw new InvalidOperationException($"Drop-table stack range '{val2.m_stackMin}..{val2.m_stackMax}' is invalid."); } EnvironmentalQuantityBounds val3 = EnvironmentalQuantityCalculator.CalculateGuaranteedSingleOutput(table.m_dropMin, table.m_dropMax, val2.m_stackMin, val2.m_stackMax, table.m_oneOfEach, val2.m_dontScale, 1.0); float resourceRate = Game.m_resourceRate; EnvironmentalQuantityBounds val4 = EnvironmentalQuantityCalculator.CalculateGuaranteedSingleOutput(table.m_dropMin, table.m_dropMax, val2.m_stackMin, val2.m_stackMax, table.m_oneOfEach, val2.m_dontScale, (double)resourceRate); string name = ((Object)val2.m_item).name; string id = ((Object)prefab).name + ":" + adapter + ":" + name; string name2 = ((Object)prefab).name; string? sourceMod = SourceMod(((Object)prefab).name); int minimum = val4.Minimum; int maximum = val4.Maximum; bool worldScaled = !val2.m_dontScale; int? minimumToolTier2 = ((minimumToolTier >= 0) ? new int?(minimumToolTier) : ((int?)null)); WikiQuantitySemantics quantitySemantics = (WikiQuantitySemantics)(val4.IsVariable ? 1 : 0); int? configuredMinimumAmount = val3.Minimum; int? configuredMaximumAmount = val3.Maximum; double? loadedResourceRate = ((!val2.m_dontScale) ? new double?(resourceRate) : ((double?)null)); sources.Add(new RawAcquisitionSource(id, (WikiSourceKind)4, (WikiSourceCertainty)0, adapter, name2, sourceName, sourceMod, name, minimum, maximum, null, null, null, null, null, null, null, onePerPlayer: false, levelScaled: false, worldScaled, method, minimumToolTier2, quantitySemantics, configuredMinimumAmount, configuredMaximumAmount, loadedResourceRate)); } } private string? SourceMod(string prefabName) { if (!includeModSources) { return null; } IModPrefab prefab = ModQuery.GetPrefab(prefabName); if (prefab == null) { return null; } BepInPlugin sourceMod = prefab.SourceMod; if (sourceMod == null) { return null; } return sourceMod.Name; } private static string ComponentName(GameObject prefab, string? componentName) { Piece component = prefab.GetComponent(); if (Object.op_Implicit((Object)(object)component) && !string.IsNullOrWhiteSpace(component.m_name)) { return Localize(component.m_name, Prettify(((Object)prefab).name)); } return Localize(componentName, Prettify(((Object)prefab).name)); } private static string ItemName(string itemId, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { if (items.TryGetValue(itemId, out WikiItem value)) { return value.DisplayName; } if (!rawItems.TryGetValue(itemId, out ItemDrop value2)) { return Prettify(itemId); } return Localize(value2.m_itemData.m_shared.m_name, itemId); } private static double? Positive(float value) { if (!(value > 0f) || float.IsNaN(value) || float.IsInfinity(value)) { return null; } return value; } private static int? NonNegative(int value) { if (value < 0) { return null; } return value; } private static string Localize(string? token, string fallback) { if (string.IsNullOrWhiteSpace(token)) { return fallback; } string text = ((Localization.instance != null) ? Localization.instance.Localize(token) : token) ?? string.Empty; if (string.IsNullOrWhiteSpace(text) || (text == token && token.StartsWith("$", StringComparison.Ordinal))) { return fallback; } return StripMarkup(text); } private static string StripMarkup(string value) { string text = Regex.Replace(value, "<[^>]+>", string.Empty).Trim(); if (!string.IsNullOrWhiteSpace(text)) { return text; } return value; } private static string Prettify(string value) { string text = TextNormalizer.Normalize(value); if (!string.IsNullOrWhiteSpace(text)) { return string.Join(" ", from word in text.Split(new char[1] { ' ' }) select char.ToUpperInvariant(word[0]) + word.Substring(1)); } return value; } private static string SafeName(Object? value) { if (!Object.op_Implicit(value)) { return ""; } return value.name; } } internal sealed class RawAcquisitionSource { internal string Id { get; } internal WikiSourceKind Kind { get; } internal WikiSourceCertainty Certainty { get; } internal string Adapter { get; } internal string SourceInternalName { get; } internal string SourceName { get; } internal string? SourceMod { get; } internal string OutputItemId { get; } internal int MinimumAmount { get; } internal int MaximumAmount { get; } internal double? Chance { get; } internal string? CostItemId { get; } internal int? Price { get; } internal string? UnlockRequirement { get; } internal double? ProductionIntervalSeconds { get; } internal int? Capacity { get; } internal double? RespawnSeconds { get; } internal bool OnePerPlayer { get; } internal bool LevelScaled { get; } internal bool WorldScaled { get; } internal string? Method { get; } internal int? MinimumToolTier { get; } internal WikiQuantitySemantics QuantitySemantics { get; } internal int? ConfiguredMinimumAmount { get; } internal int? ConfiguredMaximumAmount { get; } internal double? LoadedResourceRate { get; } internal RawAcquisitionSource(string id, WikiSourceKind kind, WikiSourceCertainty certainty, string adapter, string sourceInternalName, string sourceName, string? sourceMod, string outputItemId, int minimumAmount, int maximumAmount, double? chance = null, string? costItemId = null, int? price = null, string? unlockRequirement = null, double? productionIntervalSeconds = null, int? capacity = null, double? respawnSeconds = null, bool onePerPlayer = false, bool levelScaled = false, bool worldScaled = false, string? method = null, int? minimumToolTier = null, WikiQuantitySemantics quantitySemantics = (WikiQuantitySemantics)0, int? configuredMinimumAmount = null, int? configuredMaximumAmount = null, double? loadedResourceRate = null) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) Id = id; Kind = kind; Certainty = certainty; Adapter = adapter; SourceInternalName = sourceInternalName; SourceName = sourceName; SourceMod = sourceMod; OutputItemId = outputItemId; MinimumAmount = minimumAmount; MaximumAmount = maximumAmount; Chance = chance; CostItemId = costItemId; Price = price; UnlockRequirement = unlockRequirement; ProductionIntervalSeconds = productionIntervalSeconds; Capacity = capacity; RespawnSeconds = respawnSeconds; OnePerPlayer = onePerPlayer; LevelScaled = levelScaled; WorldScaled = worldScaled; Method = method; MinimumToolTier = minimumToolTier; QuantitySemantics = quantitySemantics; ConfiguredMinimumAmount = configuredMinimumAmount; ConfiguredMaximumAmount = configuredMaximumAmount; LoadedResourceRate = loadedResourceRate; } } internal sealed class AliasRepository { [DataContract] private sealed class AliasFile { [DataMember(Name = "aliases")] public Dictionary? Aliases { get; set; } } private readonly IReadOnlyDictionary> aliasesByTarget; private AliasRepository(IReadOnlyDictionary> aliasesByTarget) { this.aliasesByTarget = aliasesByTarget; } internal static AliasRepository Load(string path, ManualLogSource log) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if (!File.Exists(path)) { return Empty(); } try { DataContractJsonSerializer val = new DataContractJsonSerializer(typeof(AliasFile), new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true }); using FileStream fileStream = File.OpenRead(path); Dictionary> dictionary = ((((XmlObjectSerializer)val).ReadObject((Stream)fileStream) as AliasFile)?.Aliases ?? new Dictionary()).Where>((KeyValuePair pair) => !string.IsNullOrWhiteSpace(pair.Key) && !string.IsNullOrWhiteSpace(pair.Value)).GroupBy, string, string>((KeyValuePair pair) => pair.Value.Trim(), (KeyValuePair pair) => pair.Key.Trim(), StringComparer.OrdinalIgnoreCase).ToDictionary, string, IReadOnlyList>((IGrouping group) => group.Key, (IGrouping group) => Array.AsReadOnly(group.Distinct(StringComparer.OrdinalIgnoreCase).ToArray()), StringComparer.OrdinalIgnoreCase); log.LogInfo((object)$"Loaded {dictionary.Sum((KeyValuePair> pair) => pair.Value.Count)} local item aliases from the BepInEx config folder."); return new AliasRepository(new ReadOnlyDictionary>(dictionary)); } catch (Exception ex) { log.LogWarning((object)("Could not load local alias JSON '" + Path.GetFileName(path) + "': " + ex.Message)); return Empty(); } } internal IReadOnlyList For(string internalName, string displayName) { List list = new List(); if (aliasesByTarget.TryGetValue(internalName, out IReadOnlyList value)) { list.AddRange(value); } if (aliasesByTarget.TryGetValue(displayName, out IReadOnlyList value2)) { list.AddRange(value2); } return Array.AsReadOnly(list.Distinct(StringComparer.OrdinalIgnoreCase).ToArray()); } private static AliasRepository Empty() { return new AliasRepository(new ReadOnlyDictionary>(new Dictionary>(StringComparer.OrdinalIgnoreCase))); } } internal sealed class GameDataIndexer { private const int BaseWorldLevel = 0; private readonly ManualLogSource log; private readonly AliasRepository aliases; private int skipped; private int unavailableStatistics; private readonly HashSet unavailableStatisticKeys = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly List diagnostics = new List(); private int omittedDiagnostics; internal GameDataIndexer(ManualLogSource log, AliasRepository aliases) { this.log = log ?? throw new ArgumentNullException("log"); this.aliases = aliases ?? throw new ArgumentNullException("aliases"); } internal WikiIndex Build(bool includeBuildPieces, bool includeModSources) { //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Expected O, but got Unknown Stopwatch stopwatch = Stopwatch.StartNew(); skipped = 0; unavailableStatistics = 0; unavailableStatisticKeys.Clear(); diagnostics.Clear(); omittedDiagnostics = 0; ObjectDB instance = ObjectDB.instance; if (!Object.op_Implicit((Object)(object)instance)) { throw new InvalidOperationException("ObjectDB is unavailable."); } List runtimePrefabs = GetRuntimePrefabs(); List processorPrefabs = GetProcessorPrefabs(runtimePrefabs); AcquisitionSourceExtractor acquisitionSourceExtractor = new AcquisitionSourceExtractor(includeModSources, Skip); IReadOnlyList readOnlyList = acquisitionSourceExtractor.Scan(runtimePrefabs); Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (GameObject item in instance.m_items ?? new List()) { try { if (Object.op_Implicit((Object)(object)item)) { ItemDrop component = item.GetComponent(); if (component?.m_itemData?.m_shared != null) { dictionary[((Object)item).name] = component; } } } catch (Exception exception) { Skip("item prefab", SafeName((Object?)(object)item), exception); } } HashSet hashSet = CollectRecipeRelationships(instance); hashSet.UnionWith(CollectConversionRelationships(processorPrefabs)); hashSet.UnionWith(readOnlyList.Select((RawAcquisitionSource source) => source.OutputItemId)); Dictionary dictionary2 = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair item2 in dictionary) { try { if (IsPlayerFacing(item2.Value, hashSet.Contains(item2.Key))) { dictionary2[item2.Key] = ExtractItem(item2.Key, item2.Value, includeModSources); } } catch (Exception exception2) { Skip("item", item2.Key, exception2); } } List list = ExtractRecipes(instance, dictionary2, dictionary); List list2 = (List)(includeBuildPieces ? ((IList)ExtractPieces(dictionary2, dictionary)) : ((IList)new List())); List list3 = ExtractConversions(processorPrefabs, dictionary2, dictionary); IReadOnlyList readOnlyList2 = acquisitionSourceExtractor.Build(readOnlyList, dictionary2, dictionary); stopwatch.Stop(); return new WikiIndex((IEnumerable)dictionary2.Values, (IEnumerable)list, (IEnumerable)list2, DateTimeOffset.Now, stopwatch.Elapsed, CurrentLanguage(), skipped, includeBuildPieces ? "Coverage: enabled ObjectDB recipes, registered build pieces, processing conversions, reliable direct sources, guaranteed fixed or exact-range mineable/destructible/tree drops, and direct fish pickup. Chance/weighted/multi-output/zero-minimum environmental tables, fish extra drops, bait probabilities, containers, locations, biome inference, and procedural loot excluded. The immutable index contains all loaded content; the configured query visibility is applied separately." : "Coverage: enabled ObjectDB recipes, processing conversions, reliable direct sources, guaranteed fixed or exact-range environmental drops, and direct fish pickup; build pieces and chance/weighted/location sources excluded. The immutable index contains all loaded content; the configured query visibility is applied separately.", unavailableStatistics, WorldCalculatorContextAvailable(), (IEnumerable)list3, (IEnumerable)readOnlyList2, (IEnumerable)diagnostics, omittedDiagnostics); } private List GetRuntimePrefabs() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); ZNetScene instance = ZNetScene.instance; if (!Object.op_Implicit((Object)(object)instance)) { log.LogWarning((object)"ZNetScene is unavailable; processing conversions and acquisition sources cannot be indexed in this lifecycle."); return new List(); } foreach (GameObject item in (instance.m_prefabs ?? new List()).Concat(instance.m_nonNetViewPrefabs ?? new List())) { if (Object.op_Implicit((Object)(object)item)) { dictionary[((Object)item).name] = item; } } return dictionary.Values.ToList(); } private List GetProcessorPrefabs(IEnumerable runtimePrefabs) { List list = new List(); foreach (GameObject runtimePrefab in runtimePrefabs) { try { if (Object.op_Implicit((Object)(object)runtimePrefab.GetComponent()) || Object.op_Implicit((Object)(object)runtimePrefab.GetComponent()) || Object.op_Implicit((Object)(object)runtimePrefab.GetComponent()) || Object.op_Implicit((Object)(object)runtimePrefab.GetComponent())) { list.Add(runtimePrefab); } } catch (Exception exception) { Skip("processor prefab", SafeName((Object?)(object)runtimePrefab), exception); } } return list; } private HashSet CollectRecipeRelationships(ObjectDB objectDb) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (Recipe item in objectDb.m_recipes ?? new List()) { try { if (!Object.op_Implicit((Object)(object)item) || !item.m_enabled) { continue; } if (Object.op_Implicit((Object)(object)item.m_item)) { hashSet.Add(((Object)((Component)item.m_item).gameObject).name); } Requirement[] array = item.m_resources ?? Array.Empty(); foreach (Requirement val in array) { if (Object.op_Implicit((Object)(object)val?.m_resItem)) { hashSet.Add(((Object)((Component)val.m_resItem).gameObject).name); } } } catch (Exception exception) { Skip("recipe relationship", SafeName((Object?)(object)item), exception); } } return hashSet; } private HashSet CollectConversionRelationships(IEnumerable processorPrefabs) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (GameObject processorPrefab in processorPrefabs) { try { Smelter component = processorPrefab.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { AddItem(hashSet, component.m_fuelItem); foreach (ItemConversion item in component.m_conversion ?? new List()) { if (item != null) { AddItem(hashSet, item.m_from); AddItem(hashSet, item.m_to); } } } CookingStation component2 = processorPrefab.GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { AddItem(hashSet, component2.m_fuelItem); foreach (ItemConversion item2 in component2.m_conversion ?? new List()) { if (item2 != null) { AddItem(hashSet, item2.m_from); AddItem(hashSet, item2.m_to); } } } Fermenter component3 = processorPrefab.GetComponent(); if (Object.op_Implicit((Object)(object)component3)) { foreach (ItemConversion item3 in component3.m_conversion ?? new List()) { if (item3 != null) { AddItem(hashSet, item3.m_from); AddItem(hashSet, item3.m_to); } } } Incinerator component4 = processorPrefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component4)) { continue; } foreach (IncineratorConversion item4 in component4.m_conversions ?? new List()) { if (item4 == null) { continue; } AddItem(hashSet, item4.m_result); foreach (Requirement item5 in item4.m_requirements ?? new List()) { if (item5 != null) { AddItem(hashSet, item5.m_resItem); } } } } catch (Exception exception) { Skip("conversion relationship", SafeName((Object?)(object)processorPrefab), exception); } } return hashSet; } private WikiItem ExtractItem(string id, ItemDrop drop, bool includeModSources) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Invalid comparison between Unknown and I4 //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Invalid comparison between Unknown and I4 //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Invalid comparison between Unknown and I4 //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Invalid comparison between Unknown and I4 //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Invalid comparison between Unknown and I4 //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Invalid comparison between Unknown and I4 //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Expected O, but got Unknown //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Invalid comparison between Unknown and I4 //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Invalid comparison between Unknown and I4 //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Expected O, but got Unknown ItemData data = drop.m_itemData; SharedData shared = data.m_shared; string text = Localize(shared.m_name, id); WikiItemKind val = Classify(shared); string text2 = Category(shared, val); int num = Math.Max(1, shared.m_maxQuality); Attack attack = shared.m_attack; Attack secondaryAttack = shared.m_secondaryAttack; List list = new List(num); int quality; for (quality = 1; quality <= num; quality++) { list.Add(new WikiQualityStats(quality, TryDamage(id, data, shared, quality), ((int)val == 3) ? TryArmor(id, data, quality) : ((double?)null), shared.m_useDurability ? TryStatistic(id, "durability", () => data.GetMaxDurability(quality)) : ((double?)null), ((int)val == 1 || (int)val == 2) ? TryStatistic(id, "block", () => data.GetBaseBlockPower(quality)) : ((double?)null), ((int)val == 1 || (int)val == 2) ? TryStatistic(id, "deflection", () => data.GetDeflectionForce(quality)) : ((double?)null), TryAttackStamina(id, "primary attack stamina", attack), TryAttackStamina(id, "secondary attack stamina", secondaryAttack))); } bool flag = (int)val == 4; return new WikiItem(id, id, text, Localize(shared.m_description, string.Empty), val, text2, (IEnumerable)aliases.For(id, text), includeModSources ? SourceMod(id) : null, shared.m_maxStackSize, (double)shared.m_weight, num, (double)shared.m_movementModifier, flag ? new double?(shared.m_food) : ((double?)null), flag ? new double?(shared.m_foodStamina) : ((double?)null), flag ? new double?(shared.m_foodEitr) : ((double?)null), flag ? new double?(shared.m_foodBurnTime) : ((double?)null), flag ? new double?(shared.m_foodRegen) : ((double?)null), ((int)val == 1 || (int)val == 2) ? new double?(shared.m_timedBlockBonus) : ((double?)null), (IEnumerable)list, shared.m_name); } private List ExtractRecipes(ObjectDB objectDb, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown List list = new List(); foreach (Recipe recipe in objectDb.m_recipes ?? new List()) { try { if (!Object.op_Implicit((Object)(object)recipe) || !recipe.m_enabled || !Object.op_Implicit((Object)(object)recipe.m_item)) { continue; } string name = ((Object)((Component)recipe.m_item).gameObject).name; if (!items.TryGetValue(name, out WikiItem value)) { continue; } IEnumerable> enumerable = from quality in Enumerable.Range(1, value.MaxQuality) select new KeyValuePair(quality, recipe.GetRequiredStationLevel(quality)); List list2 = new List(); Requirement[] array = recipe.m_resources ?? Array.Empty(); foreach (Requirement requirement in array) { if (!((Object)(object)requirement?.m_resItem == (Object)null)) { string name2 = ((Object)((Component)requirement.m_resItem).gameObject).name; WikiItem value2; ItemDrop value3; string text = (items.TryGetValue(name2, out value2) ? value2.DisplayName : (rawItems.TryGetValue(name2, out value3) ? Localize(value3.m_itemData.m_shared.m_name, name2) : Prettify(name2))); IEnumerable> enumerable2 = from quality in Enumerable.Range(1, value.MaxQuality) select new KeyValuePair(quality, requirement.GetAmount(quality)); list2.Add(new WikiRequirement(name2, text, enumerable2)); } } list.Add(new WikiRecipe(string.IsNullOrWhiteSpace(((Object)recipe).name) ? name : ((Object)recipe).name, name, value.DisplayName, recipe.m_amount, StationName(recipe.m_craftingStation), enumerable, recipe.m_requireOnlyOneIngredient, (IEnumerable)list2)); } catch (Exception exception) { Skip("recipe", SafeName((Object?)(object)recipe), exception); } } return list; } private List ExtractPieces(IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown List list = new List(); foreach (PieceTable item in PieceManager.Instance.GetPieceTables() ?? new List()) { if (!Object.op_Implicit((Object)(object)item)) { continue; } try { foreach (GameObject item2 in item.m_pieces ?? new List()) { try { if (!Object.op_Implicit((Object)(object)item2)) { continue; } Piece component = item2.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.m_enabled) { continue; } List list2 = new List(); Requirement[] array = component.m_resources ?? Array.Empty(); foreach (Requirement val in array) { if (!((Object)(object)val?.m_resItem == (Object)null)) { string name = ((Object)((Component)val.m_resItem).gameObject).name; WikiItem value; ItemDrop value2; string text = (items.TryGetValue(name, out value) ? value.DisplayName : (rawItems.TryGetValue(name, out value2) ? Localize(value2.m_itemData.m_shared.m_name, name) : Prettify(name))); list2.Add(new WikiPieceRequirement(name, text, Math.Max(0, val.m_amount))); } } list.Add(new WikiPiece(((Object)((Component)item).gameObject).name + ":" + ((Object)item2).name, Localize(component.m_name, ((Object)item2).name), ((object)Unsafe.As(ref component.m_category)/*cast due to .constrained prefix*/).ToString(), ((Object)((Component)item).gameObject).name, StationName(component.m_craftingStation), (IEnumerable)list2, component.m_name)); } catch (Exception exception) { Skip("piece", SafeName((Object?)(object)item2), exception); } } } catch (Exception exception2) { Skip("piece table", SafeName((Object?)(object)item), exception2); } } return list; } private List ExtractConversions(IEnumerable processorPrefabs, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { List list = new List(); foreach (GameObject processorPrefab in processorPrefabs) { ExtractSmelterConversions(processorPrefab, list, items, rawItems); ExtractCookingConversions(processorPrefab, list, items, rawItems); ExtractFermenterConversions(processorPrefab, list, items, rawItems); ExtractIncineratorConversions(processorPrefab, list, items, rawItems); } return (from @group in list.GroupBy((WikiConversion conversion) => conversion.Id, StringComparer.OrdinalIgnoreCase) select @group.First()).ToList(); } private void ExtractSmelterConversions(GameObject prefab, ICollection conversions, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { try { Smelter component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } string stationName = Localize(component.m_name, Prettify(((Object)prefab).name)); foreach (ItemConversion item in component.m_conversion ?? new List()) { if ((Object)(object)item?.m_from == (Object)null || (Object)(object)item.m_to == (Object)null) { continue; } try { List list = new List { ConversionRequirement(item.m_from, 1.0, "Input", items, rawItems) }; if (Object.op_Implicit((Object)(object)component.m_fuelItem) && component.m_fuelPerProduct > 0) { list.Add(ConversionRequirement(component.m_fuelItem, component.m_fuelPerProduct, "Fuel", items, rawItems)); } conversions.Add(CreateConversion(((Object)prefab).name + ":processing:" + ((Object)((Component)item.m_from).gameObject).name + ":" + ((Object)((Component)item.m_to).gameObject).name, (WikiProcessKind)0, ((Object)prefab).name, stationName, item.m_to, 1, list, (component.m_secPerProduct > 0f) ? new double?(component.m_secPerProduct) : ((double?)null), requireOnlyOneIngredient: false, items, rawItems)); } catch (Exception exception) { Skip("smelter conversion", SafeName((Object?)(object)prefab), exception); } } } catch (Exception exception2) { Skip("smelter component", SafeName((Object?)(object)prefab), exception2); } } private void ExtractCookingConversions(GameObject prefab, ICollection conversions, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { try { CookingStation component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } string stationName = Localize(component.m_name, Prettify(((Object)prefab).name)); foreach (ItemConversion item in component.m_conversion ?? new List()) { if ((Object)(object)item?.m_from == (Object)null || (Object)(object)item.m_to == (Object)null) { continue; } try { List list = new List { ConversionRequirement(item.m_from, 1.0, "Input", items, rawItems) }; if (component.m_useFuel && Object.op_Implicit((Object)(object)component.m_fuelItem)) { list.Add(ConversionRequirement(component.m_fuelItem, null, "Fuel", items, rawItems)); } conversions.Add(CreateConversion(((Object)prefab).name + ":cooking:" + ((Object)((Component)item.m_from).gameObject).name + ":" + ((Object)((Component)item.m_to).gameObject).name, (WikiProcessKind)1, ((Object)prefab).name, stationName, item.m_to, 1, list, (item.m_cookTime > 0f) ? new double?(item.m_cookTime) : ((double?)null), requireOnlyOneIngredient: false, items, rawItems)); } catch (Exception exception) { Skip("cooking conversion", SafeName((Object?)(object)prefab), exception); } } } catch (Exception exception2) { Skip("cooking component", SafeName((Object?)(object)prefab), exception2); } } private void ExtractFermenterConversions(GameObject prefab, ICollection conversions, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { try { Fermenter component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } string stationName = Localize(component.m_name, Prettify(((Object)prefab).name)); foreach (ItemConversion item in component.m_conversion ?? new List()) { if (!((Object)(object)item?.m_from == (Object)null) && !((Object)(object)item.m_to == (Object)null)) { try { conversions.Add(CreateConversion(((Object)prefab).name + ":fermenting:" + ((Object)((Component)item.m_from).gameObject).name + ":" + ((Object)((Component)item.m_to).gameObject).name, (WikiProcessKind)2, ((Object)prefab).name, stationName, item.m_to, item.m_producedItems, (IEnumerable)(object)new WikiConversionRequirement[1] { ConversionRequirement(item.m_from, 1.0, "Input", items, rawItems) }, (component.m_fermentationDuration > 0f) ? new double?(component.m_fermentationDuration) : ((double?)null), requireOnlyOneIngredient: false, items, rawItems)); } catch (Exception exception) { Skip("fermenter conversion", SafeName((Object?)(object)prefab), exception); } } } } catch (Exception exception2) { Skip("fermenter component", SafeName((Object?)(object)prefab), exception2); } } private void ExtractIncineratorConversions(GameObject prefab, ICollection conversions, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { try { Incinerator component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } Piece component2 = prefab.GetComponent(); string stationName = (Object.op_Implicit((Object)(object)component2) ? Localize(component2.m_name, Prettify(((Object)prefab).name)) : Prettify(((Object)prefab).name)); foreach (IncineratorConversion item in component.m_conversions ?? new List()) { if ((Object)(object)item?.m_result == (Object)null) { continue; } try { WikiConversionRequirement[] requirements = (from requirement in item.m_requirements ?? new List() where (Object)(object)requirement?.m_resItem != (Object)null select ConversionRequirement(requirement.m_resItem, requirement.m_amount, "Input", items, rawItems)).ToArray(); conversions.Add(CreateConversion($"{((Object)prefab).name}:incinerating:{((Object)((Component)item.m_result).gameObject).name}:{item.m_priority}", (WikiProcessKind)3, ((Object)prefab).name, stationName, item.m_result, item.m_resultAmount, requirements, null, item.m_requireOnlyOneIngredient, items, rawItems)); } catch (Exception exception) { Skip("incinerator conversion", SafeName((Object?)(object)prefab), exception); } } } catch (Exception exception2) { Skip("incinerator component", SafeName((Object?)(object)prefab), exception2); } } private static WikiConversion CreateConversion(string id, WikiProcessKind kind, string stationInternalName, string stationName, ItemDrop output, int outputAmount, IEnumerable requirements, double? durationSeconds, bool requireOnlyOneIngredient, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown string name = ((Object)((Component)output).gameObject).name; return new WikiConversion(id, kind, stationInternalName, stationName, name, ItemName(name, items, rawItems), outputAmount, requirements, durationSeconds, requireOnlyOneIngredient); } private static WikiConversionRequirement ConversionRequirement(ItemDrop item, double? amount, string role, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown string name = ((Object)((Component)item).gameObject).name; return new WikiConversionRequirement(name, ItemName(name, items, rawItems), amount, role); } private static string ItemName(string itemId, IReadOnlyDictionary items, IReadOnlyDictionary rawItems) { if (items.TryGetValue(itemId, out WikiItem value)) { return value.DisplayName; } if (!rawItems.TryGetValue(itemId, out ItemDrop value2)) { return Prettify(itemId); } return Localize(value2.m_itemData.m_shared.m_name, itemId); } private static void AddItem(ISet related, ItemDrop? item) { if (Object.op_Implicit((Object)(object)item)) { related.Add(((Object)((Component)item).gameObject).name); } } private static WikiDamageProfile Damage(DamageTypes value) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown return new WikiDamageProfile((IEnumerable>)new KeyValuePair[10] { Pair((DamageKind)0, value.m_blunt), Pair((DamageKind)1, value.m_slash), Pair((DamageKind)2, value.m_pierce), Pair((DamageKind)3, value.m_fire), Pair((DamageKind)4, value.m_frost), Pair((DamageKind)5, value.m_lightning), Pair((DamageKind)6, value.m_poison), Pair((DamageKind)7, value.m_spirit), Pair((DamageKind)8, value.m_chop), Pair((DamageKind)9, value.m_pickaxe) }); } private static KeyValuePair Pair(DamageKind kind, float value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return new KeyValuePair(kind, value); } private static WikiItemKind Classify(SharedData shared) { string text = ((object)Unsafe.As(ref shared.m_itemType)/*cast due to .constrained prefix*/).ToString(); if (!(shared.m_food > 0f) && !(shared.m_foodStamina > 0f) && !(shared.m_foodEitr > 0f)) { if (text.IndexOf("Shield", StringComparison.OrdinalIgnoreCase) < 0) { bool flag; switch (text) { case "Helmet": case "Chest": case "Legs": case "Hands": case "Shoulder": flag = true; break; default: flag = false; break; } if (!flag) { flag = text.IndexOf("Weapon", StringComparison.OrdinalIgnoreCase) >= 0; if (!flag) { bool flag2 = ((text == "Bow" || text == "Attach_Atgeir") ? true : false); flag = flag2; } if (!flag) { if (text.IndexOf("Tool", StringComparison.OrdinalIgnoreCase) < 0) { if (text.IndexOf("Material", StringComparison.OrdinalIgnoreCase) < 0) { if (text.IndexOf("Consumable", StringComparison.OrdinalIgnoreCase) < 0) { return (WikiItemKind)8; } return (WikiItemKind)7; } return (WikiItemKind)6; } return (WikiItemKind)5; } return (WikiItemKind)1; } return (WikiItemKind)3; } return (WikiItemKind)2; } return (WikiItemKind)4; } private unsafe static string Category(SharedData shared, WikiItemKind kind) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)kind == 1) { string text = ((object)Unsafe.As(ref shared.m_skillType)/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); if (text.EndsWith("s", StringComparison.Ordinal) && text.Length > 1) { text = text.Substring(0, text.Length - 1); } return text switch { "sword" => "sword", "knife" => "knife", "club" => "club", "polearm" => "polearm", "spear" => "spear", "axe" => "axe", "bow" => "bow", "crossbow" => "crossbow", "elementalmagic" => "elemental magic", "bloodmagic" => "blood magic", _ => TextNormalizer.Normalize(((object)Unsafe.As(ref shared.m_itemType)/*cast due to .constrained prefix*/).ToString()), }; } return ((object)(*(WikiItemKind*)(&kind))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); } private static bool IsPlayerFacing(ItemDrop drop, bool referencedByRecipe) { SharedData shared = drop.m_itemData.m_shared; if (string.Equals(((object)Unsafe.As(ref shared.m_itemType)/*cast due to .constrained prefix*/).ToString(), "None", StringComparison.OrdinalIgnoreCase)) { return false; } bool flag = shared.m_icons != null && shared.m_icons.Any((Sprite icon) => Object.op_Implicit((Object)(object)icon)); bool flag2 = !string.IsNullOrWhiteSpace(shared.m_name); if (!referencedByRecipe) { return flag && flag2; } return true; } private WikiDamageProfile? TryDamage(string itemId, ItemData data, SharedData shared, int quality) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) try { return Damage(data.GetDamage(quality, 0f)); } catch (Exception exception) { UnavailableStatistic(itemId, "damage", exception); return (quality == 1) ? Damage(shared.m_damages) : null; } } private double? TryArmor(string itemId, ItemData data, int quality) { if (!WorldCalculatorContextAvailable()) { UnavailableStatistic(itemId, "armor", "The active Game and local Player calculator context is not available yet."); return null; } return TryStatistic(itemId, "armor", () => data.GetArmor(quality, 0f)); } private double? TryAttackStamina(string itemId, string statistic, Attack? attack) { if (attack == null || string.IsNullOrWhiteSpace(attack.m_attackAnimation)) { return null; } return TryStatistic(itemId, statistic, () => attack.m_attackStamina); } private double? TryStatistic(string itemId, string statistic, Func reader) { try { return reader(); } catch (Exception exception) { UnavailableStatistic(itemId, statistic, exception); return null; } } private static string? SourceMod(string prefabName) { IModPrefab prefab = ModQuery.GetPrefab(prefabName); if (prefab == null) { return null; } BepInPlugin sourceMod = prefab.SourceMod; if (sourceMod == null) { return null; } return sourceMod.Name; } private static string? StationName(CraftingStation? station) { if (!Object.op_Implicit((Object)(object)station)) { return null; } return Localize(station.m_name, Prettify(((Object)((Component)station).gameObject).name)); } private static string CurrentLanguage() { if (Localization.instance == null) { return "unknown"; } return Localization.instance.GetSelectedLanguage(); } private static bool WorldCalculatorContextAvailable() { if ((Object)(object)Game.instance != (Object)null) { return (Object)(object)Player.m_localPlayer != (Object)null; } return false; } private static string Localize(string? token, string fallback) { if (string.IsNullOrWhiteSpace(token)) { return fallback; } string text = ((Localization.instance != null) ? Localization.instance.Localize(token) : token) ?? string.Empty; if (string.IsNullOrWhiteSpace(text) || (text == token && token.StartsWith("$", StringComparison.Ordinal))) { return fallback; } return StripMarkup(text); } private static string StripMarkup(string value) { string text = Regex.Replace(value, "<[^>]+>", string.Empty).Trim(); if (!string.IsNullOrWhiteSpace(text)) { return text; } return value; } private static string Prettify(string value) { string text = TextNormalizer.Normalize(value); if (!string.IsNullOrWhiteSpace(text)) { return string.Join(" ", from word in text.Split(new char[1] { ' ' }) select char.ToUpperInvariant(word[0]) + word.Substring(1)); } return value; } private void Skip(string kind, string name, Exception exception) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown skipped++; RecordDiagnostic(new WikiDiagnosticIssue((WikiDiagnosticKind)0, kind, name, (string)null, exception.GetType().Name)); if (skipped <= 25) { log.LogWarning((object)("Skipped malformed " + kind + " '" + name + "': " + exception.GetType().Name + ": " + exception.Message)); } else if (skipped == 26) { log.LogWarning((object)"Additional malformed-entry warnings are suppressed for this index build."); } } private void UnavailableStatistic(string itemId, string statistic, Exception exception) { UnavailableStatistic(itemId, statistic, exception.GetType().Name + ": " + exception.Message, exception.GetType().Name); log.LogDebug((object)exception); } private void UnavailableStatistic(string itemId, string statistic, string reason) { UnavailableStatistic(itemId, statistic, reason, "ContextUnavailable"); } private void UnavailableStatistic(string itemId, string statistic, string reason, string reasonCode) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown string item = itemId + ":" + statistic; if (unavailableStatisticKeys.Add(item)) { unavailableStatistics++; RecordDiagnostic(new WikiDiagnosticIssue((WikiDiagnosticKind)1, statistic, itemId, itemId, reasonCode)); if (unavailableStatistics <= 25) { log.LogWarning((object)("Optional statistic '" + statistic + "' is unavailable for item '" + itemId + "': " + reason)); } else if (unavailableStatistics == 26) { log.LogWarning((object)"Additional optional-statistic warnings are suppressed for this index build."); } } } private void RecordDiagnostic(WikiDiagnosticIssue issue) { if (diagnostics.Count < 256) { diagnostics.Add(issue); } else { omittedDiagnostics++; } } private static string SafeName(Object? value) { if (!Object.op_Implicit(value)) { return ""; } return value.name; } } }