Files
BarotraumaModServer/LocalMods/Enhanced Loading/CSharp/Client/ParallelLoader.cs

110 lines
3.9 KiBLFS
C#
Executable File

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<string, XDocument> ParsedCache = new ConcurrentDictionary<string, XDocument>();
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
}
}