diff --git a/Libraries/SPTarkov.Server.Core/Extensions/SptModExtensions.cs b/Libraries/SPTarkov.Server.Core/Extensions/SptModExtensions.cs new file mode 100644 index 00000000..9327f13d --- /dev/null +++ b/Libraries/SPTarkov.Server.Core/Extensions/SptModExtensions.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SPTarkov.Server.Core.Models.Spt.Mod; + +namespace SPTarkov.Server.Core.Extensions +{ + public static class SptModExtensions + { + public static string GetModPath(this SptMod sptMod) + { + var relativeModPath = Path.GetRelativePath( + Directory.GetCurrentDirectory(), + sptMod.Directory + ) + .Replace('\\', '/'); + + return relativeModPath; + } + } +} diff --git a/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs b/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs index b32c0bca..05249654 100644 --- a/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs +++ b/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs @@ -1,9 +1,10 @@ using System.Text.Json.Serialization; using SPTarkov.DI.Annotations; +using SPTarkov.Server.Core.Extensions; +using SPTarkov.Server.Core.Models.Spt.Mod; using SPTarkov.Server.Core.Models.Utils; using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils; -using SPTarkov.Server.Core.Utils.Cloners; namespace SPTarkov.Server.Core.Loaders; @@ -18,40 +19,66 @@ namespace SPTarkov.Server.Core.Loaders; "Crc" : 1030040371, "Dependencies" : [ ] } */ -public class BundleInfo +public class BundleInfo(string modPath, BundleManifestEntry bundle, uint bundleHash) { - public BundleInfo() { } + public string ModPath { get; private set; } = modPath; - public BundleInfo(string modPath, BundleManifestEntry bundle, uint bundleHash) - { - ModPath = modPath; - FileName = bundle.Key; - Bundle = bundle; - Crc = bundleHash; - Dependencies = bundle?.DependencyKeys ?? []; - } + public string FileName { get; private set; } = bundle.Key; - public string? ModPath { get; set; } + public BundleManifestEntry Bundle { get; private set; } = bundle; - public string FileName { get; set; } + public uint Crc { get; private set; } = bundleHash; - public BundleManifestEntry Bundle { get; set; } - - public uint Crc { get; set; } - - public List Dependencies { get; set; } + public List Dependencies { get; private set; } = bundle?.DependencyKeys ?? []; } [Injectable(InjectionType.Singleton)] public class BundleLoader( ISptLogger logger, JsonUtil jsonUtil, - FileUtil fileUtil, - BundleHashCacheService bundleHashCacheService, - ICloner cloner + BundleHashCacheService bundleHashCacheService ) { - private readonly Dictionary _bundles = new(); + private readonly Dictionary _bundles = []; + + public async Task LoadBundlesAsync(SptMod mod) + { + var modPath = mod.GetModPath(); + + var modBundles = await jsonUtil.DeserializeFromFileAsync( + Path.Join(Directory.GetCurrentDirectory(), modPath, "bundles.json") + ); + + var bundleManifests = modBundles?.Manifest ?? []; + + foreach (var bundleManifest in bundleManifests) + { + var relativeModPath = modPath.Replace('\\', '/'); + + var bundleLocalPath = Path.Join(relativeModPath, "bundles", bundleManifest.Key) + .Replace('\\', '/'); + + if (!File.Exists(bundleLocalPath)) + { + logger.Warning( + $"Could not find bundle {bundleManifest.Key} for mod {mod.ModMetadata.Name}" + ); + continue; + } + + if (!bundleHashCacheService.CalculateAndMatchHash(bundleLocalPath)) + { + await bundleHashCacheService.CalculateAndStoreHash(bundleLocalPath); + } + + var bundleHash = bundleHashCacheService.GetStoredValue(bundleLocalPath); + + AddBundle( + bundleManifest.Key, + new BundleInfo(relativeModPath, bundleManifest, bundleHash) + ); + } + } /// /// Handle singleplayer/bundles @@ -71,39 +98,7 @@ public class BundleLoader( public BundleInfo? GetBundle(string bundleKey) { - return cloner.Clone(_bundles.GetValueOrDefault(bundleKey)); - } - - public void AddBundles(string modPath) - { - // modPath should be relative to the server exe - ./user/mods/Mod3 - // TODO: make sure the mod is passing a path that is relative from the server exe - - var modBundlesJson = fileUtil.ReadFile( - Path.Join(Directory.GetCurrentDirectory(), modPath, "bundles.json") - ); - var modBundles = jsonUtil.Deserialize(modBundlesJson); - var bundleManifestArr = modBundles?.Manifest; - - foreach (var bundleManifest in bundleManifestArr) - { - var relativeModPath = modPath.Replace('\\', '/'); - - var bundleLocalPath = Path.Join(relativeModPath, "bundles", bundleManifest.Key) - .Replace('\\', '/'); - - if (!bundleHashCacheService.CalculateAndMatchHash(bundleLocalPath)) - { - bundleHashCacheService.CalculateAndStoreHash(bundleLocalPath); - } - - var bundleHash = bundleHashCacheService.GetStoredValue(bundleLocalPath); - - AddBundle( - bundleManifest.Key, - new BundleInfo(relativeModPath, bundleManifest, bundleHash) - ); - } + return _bundles.GetValueOrDefault(bundleKey); } public void AddBundle(string key, BundleInfo bundle) @@ -119,13 +114,13 @@ public class BundleLoader( public record BundleManifest { [JsonPropertyName("manifest")] - public List Manifest { get; set; } + public List? Manifest { get; set; } } public record BundleManifestEntry { [JsonPropertyName("key")] - public string Key { get; set; } + public required string Key { get; set; } [JsonPropertyName("dependencyKeys")] public List? DependencyKeys { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Services/BundleHashCacheService.cs b/Libraries/SPTarkov.Server.Core/Services/BundleHashCacheService.cs index 69b7ec20..41a2b76f 100644 --- a/Libraries/SPTarkov.Server.Core/Services/BundleHashCacheService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/BundleHashCacheService.cs @@ -14,7 +14,7 @@ public class BundleHashCacheService( { protected const string _bundleHashCachePath = "./user/cache/"; protected const string _cacheName = "bundleHashCache.json"; - protected readonly Dictionary _bundleHashes = new(); + protected readonly Dictionary _bundleHashes = []; public uint GetStoredValue(string key) { @@ -26,7 +26,7 @@ public class BundleHashCacheService( return value; } - public void StoreValue(string bundlePath, uint hash) + public async Task StoreValue(string bundlePath, uint hash) { _bundleHashes.Add(bundlePath, hash); @@ -35,7 +35,7 @@ public class BundleHashCacheService( Directory.CreateDirectory(_bundleHashCachePath); } - fileUtil.WriteFile( + await fileUtil.WriteFileAsync( Path.Join(_bundleHashCachePath, _cacheName), jsonUtil.Serialize(_bundleHashes) ); @@ -48,9 +48,9 @@ public class BundleHashCacheService( return MatchWithStoredHash(BundlePath, CalculateHash(BundlePath)); } - public void CalculateAndStoreHash(string BundlePath) + public async Task CalculateAndStoreHash(string BundlePath) { - StoreValue(BundlePath, CalculateHash(BundlePath)); + await StoreValue(BundlePath, CalculateHash(BundlePath)); } public uint CalculateHash(string BundlePath) diff --git a/SPTarkov.Server/Services/SptServerBackgroundService.cs b/SPTarkov.Server/Services/SptServerBackgroundService.cs index b5b03369..68b9a906 100644 --- a/SPTarkov.Server/Services/SptServerBackgroundService.cs +++ b/SPTarkov.Server/Services/SptServerBackgroundService.cs @@ -19,14 +19,7 @@ public class SptServerBackgroundService( { if (mod.ModMetadata?.IsBundleMod == true) { - // Convert to relative path - var relativeModPath = Path.GetRelativePath( - Directory.GetCurrentDirectory(), - mod.Directory - ) - .Replace('\\', '/'); - - bundleLoader.AddBundles(relativeModPath); + await bundleLoader.LoadBundlesAsync(mod); } } }