using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Xml.Linq; using Barotrauma; using HarmonyLib; using Microsoft.Xna.Framework; namespace FastLoadMod { public class ParallelLoader : IAssemblyPlugin { private static Harmony harmony; private static ConcurrentDictionary ParsedCache = new ConcurrentDictionary(); private static FieldInfo subElementField; public void Initialize() { #if CLIENT try { harmony = new Harmony("com.parallel.mod"); // Robust method finder from a previous success in testing. Read below, or use ChatGPT to explain it, IDGAF. var originalLoad = AccessTools.Method( typeof(Submarine), "Load", new Type[] { typeof(SubmarineInfo), typeof(bool), typeof(IdRemap) } ); subElementField = AccessTools.Field(typeof(SubmarineInfo), "submarineElement"); if (originalLoad != null && subElementField != null) { var prefix = AccessTools.Method(typeof(ParallelLoader), "PrefixLoad"); harmony.Patch(originalLoad, new HarmonyMethod(prefix)); DebugConsole.NewMessage("[EnLo] PL working.", Color.Green); } else { if (originalLoad == null) DebugConsole.NewMessage("[EnLo] CRITICAL: Submarine.Load not found!", Color.Red); if (subElementField == null) DebugConsole.NewMessage("[EnLo] CRITICAL: SubmarineInfo.submarineElement not found!", Color.Red); } } catch (Exception ex) { DebugConsole.NewMessage($"[EnLo] FATAL ERROR IN INIT: {ex}", Color.Red); } #endif } public void OnLoadCompleted() { } public void PreInitPatching() { } public void Dispose() { #if CLIENT if (harmony != null) Harmony.UnpatchID("com.parallel.mod"); harmony = null; ParsedCache.Clear(); #endif } #if CLIENT public static bool PrefixLoad(SubmarineInfo info, bool unloadPrevious, ref Submarine __result) { if (info == null || string.IsNullOrEmpty(info.FilePath)) return true; if (ParsedCache.TryGetValue(info.FilePath, out XDocument readyDoc)) { try { // Check if the info already has the Element loaded. If not, inject pre-parsed version. var currentVal = subElementField.GetValue(info); if (currentVal == null) { subElementField.SetValue(info, readyDoc.Root); DebugConsole.NewMessage($"[EnLo] Instant Load: {info.Name}", Color.Cyan); } } catch (Exception ex) { DebugConsole.NewMessage($"[EnLo] Injection Failed: {ex.Message}", Color.Orange); } } else { Task.Run(() => PreParseSub(info.FilePath)); } return true; } private static void PreParseSub(string filePath) { try { if (!File.Exists(filePath) || ParsedCache.ContainsKey(filePath)) return; XDocument doc = XDocument.Load(filePath); ParsedCache.TryAdd(filePath, doc); } catch (Exception) { // Ignore errors here; the main thread will catch them when it tries to load normally } } #endif } }