From 9bf80b1b5fa97c6f0219aeca34bf47d84fb652d7 Mon Sep 17 00:00:00 2001 From: Jarrod Doyle Date: Mon, 13 Jan 2025 19:11:06 +0000 Subject: [PATCH] Additional logging around initialisation --- KeepersCompound.LGS/Database/File.cs | 12 +- KeepersCompound.LGS/ResourcePathManager.cs | 142 ++++++++++++++------- KeepersCompound.Lightmapper/LightMapper.cs | 43 ++++++- KeepersCompound.Lightmapper/MeshBuilder.cs | 2 + 4 files changed, 146 insertions(+), 53 deletions(-) diff --git a/KeepersCompound.LGS/Database/File.cs b/KeepersCompound.LGS/Database/File.cs index c8e2c3f..159a0e9 100644 --- a/KeepersCompound.LGS/Database/File.cs +++ b/KeepersCompound.LGS/Database/File.cs @@ -1,5 +1,6 @@ using System.Text; using KeepersCompound.LGS.Database.Chunks; +using Serilog; namespace KeepersCompound.LGS.Database; @@ -84,8 +85,13 @@ public class DbFile public DbFile(string filename) { - // TODO: Throw rather than return - if (!File.Exists(filename)) return; + Log.Information("Loading DbFile: {Path}", filename); + + if (!File.Exists(filename)) + { + Log.Error("Failed to load DbFile. File does not exist."); + throw new FileNotFoundException(); + } using MemoryStream stream = new(File.ReadAllBytes(filename)); using BinaryReader reader = new(stream, Encoding.UTF8, false); @@ -105,6 +111,8 @@ public class DbFile public void Save(string filename) { + Log.Information("Saving DbFile: {Path}", filename); + using var stream = File.Open(filename, FileMode.Create); using var writer = new BinaryWriter(stream, Encoding.UTF8, false); diff --git a/KeepersCompound.LGS/ResourcePathManager.cs b/KeepersCompound.LGS/ResourcePathManager.cs index 5d90425..1841d6a 100644 --- a/KeepersCompound.LGS/ResourcePathManager.cs +++ b/KeepersCompound.LGS/ResourcePathManager.cs @@ -1,4 +1,5 @@ using System.IO.Compression; +using Serilog; namespace KeepersCompound.LGS; @@ -77,33 +78,41 @@ public class ResourcePathManager } } - foreach (var (name, path) in GetTexturePaths(resPath)) + var texPaths = GetTexturePaths(resPath); + var objPaths = GetObjectPaths(resPath); + var objTexPaths = GetObjectTexturePaths(resPath); + Log.Information("Found {TexCount} textures, {ObjCount} objects, {ObjTexCount} object textures for campaign: {CampaignName}", + texPaths.Count, objPaths.Count, objTexPaths.Count, name); + + foreach (var (resName, path) in texPaths) { - _texturePathMap[name] = path; + _texturePathMap[resName] = path; } - foreach (var (name, path) in GetObjectPaths(resPath)) + foreach (var (resName, path) in objPaths) { - _objectPathMap[name] = path; + _objectPathMap[resName] = path; } - foreach (var (name, path) in GetObjectTexturePaths(resPath)) + foreach (var (resName, path) in objTexPaths) { - _objectTexturePathMap[name] = path; + _objectTexturePathMap[resName] = path; } + + initialised = true; } public void Initialise(string misPath, string resPath, CampaignResources parent) { - foreach (var (name, path) in parent._texturePathMap) + foreach (var (resName, path) in parent._texturePathMap) { - _texturePathMap[name] = path; + _texturePathMap[resName] = path; } - foreach (var (name, path) in parent._objectPathMap) + foreach (var (resName, path) in parent._objectPathMap) { - _objectPathMap[name] = path; + _objectPathMap[resName] = path; } - foreach (var (name, path) in parent._objectTexturePathMap) + foreach (var (resName, path) in parent._objectTexturePathMap) { - _objectTexturePathMap[name] = path; + _objectTexturePathMap[resName] = path; } Initialise(misPath, resPath); @@ -126,7 +135,7 @@ public class ResourcePathManager return path.Replace('\\', '/'); } - public void Init(string installPath) + public bool TryInit(string installPath) { // TODO: // - Determine if folder is a thief install @@ -136,22 +145,25 @@ public class ResourcePathManager // - Initialise OM campaign resource paths // - Lazy load FM campaign resource paths (that inherit OM resources) + Log.Information("Initialising path manager"); + if (!DirContainsThiefExe(installPath)) { - throw new ArgumentException($"No Thief installation found at {installPath}", nameof(installPath)); + return false; } // TODO: Should these paths be stored? if (!TryGetConfigPaths(installPath, out var configPaths)) { - throw new InvalidOperationException("Failed to find all installation config paths."); + return false; } // We need to know where all the texture and object resources are var installCfgLines = File.ReadAllLines(configPaths[(int)ConfigFile.Install]); if (!FindConfigVar(installCfgLines, "resname_base", out var resPaths)) { - throw new InvalidOperationException("Failed to find resnames in install config"); + Log.Error("Failed to find `resname_base` in install config"); + return false; } var zipPaths = new List(); @@ -160,6 +172,7 @@ public class ResourcePathManager var dir = Path.Join(installPath, ConvertSeparator(resPath)); if (!Directory.Exists(dir)) { + Log.Warning("Install config references non-existent `resname_base`: {Path}", dir); continue; } @@ -183,7 +196,12 @@ public class ResourcePathManager ZipFile.OpenRead(zipPath).ExtractToDirectory(extractPath, false); } - FindConfigVar(installCfgLines, "load_path", out var omsPath); + if (!FindConfigVar(installCfgLines, "load_path", out var omsPath)) + { + Log.Error("Failed to find `load_path` in install config"); + return false; + } + omsPath = Path.Join(installPath, ConvertSeparator(omsPath)); _omResources = new CampaignResources(); _omResources.name = ""; @@ -192,6 +210,7 @@ public class ResourcePathManager var camModLines = File.ReadAllLines(configPaths[(int)ConfigFile.CamMod]); FindConfigVar(camModLines, "fm_path", out var fmsPath, "FMs"); _fmsDir = Path.Join(installPath, fmsPath); + Log.Information("Searching for FMS at: {FmsPath}", _fmsDir); // Build up the map of FM campaigns. These are uninitialised, we just want // to have their name @@ -205,6 +224,7 @@ public class ResourcePathManager } _initialised = true; + return true; } public List GetCampaignNames() @@ -222,17 +242,19 @@ public class ResourcePathManager { return _omResources; } - else if (_fmResources.TryGetValue(campaignName, out var campaign)) - { - if (!campaign.initialised) - { - var fmPath = Path.Join(_fmsDir, campaignName); - campaign.Initialise(fmPath, fmPath, _omResources); - } - return campaign; - } - throw new ArgumentException("No campaign found with given name", nameof(campaignName)); + if (!_fmResources.TryGetValue(campaignName, out var campaign)) + { + Log.Error("Failed to find campaign: {CampaignName}", campaignName); + throw new ArgumentException("No campaign found with given name", nameof(campaignName)); + } + + if (!campaign.initialised) + { + var fmPath = Path.Join(_fmsDir, campaignName); + campaign.Initialise(fmPath, fmPath, _omResources); + } + return campaign; } private static Dictionary GetObjectTexturePaths(string root) @@ -337,11 +359,12 @@ public class ResourcePathManager } } + Log.Error("No Thief executable found in {InstallPath}. Is this the right directory?", dir); return false; } /// - /// Get an array of of all the Dark config file paths. + /// Get an array of all the Dark config file paths. /// /// Root directory of the Thief installation. /// Output array of config file paths @@ -362,20 +385,21 @@ public class ResourcePathManager foreach (var path in Directory.GetFiles(installPath, "cam*", searchOptions)) { var name = Path.GetFileName(path).ToLower(); - if (name == "cam.cfg") + switch (name) { - configPaths[(int)ConfigFile.Cam] = path; - } - else if (name == "cam_ext.cfg") - { - configPaths[(int)ConfigFile.CamExt] = path; - } - else if (name == "cam_mod.ini") - { - configPaths[(int)ConfigFile.CamMod] = path; + case "cam.cfg": + configPaths[(int)ConfigFile.Cam] = path; + break; + case "cam_ext.cfg": + configPaths[(int)ConfigFile.CamExt] = path; + break; + case "cam_mod.ini": + configPaths[(int)ConfigFile.CamMod] = path; + break; } } - + + // TODO: Verify we found cam/cam_ext/cam_mod var camExtLines = File.ReadAllLines(configPaths[(int)ConfigFile.CamExt]); var camLines = File.ReadAllLines(configPaths[(int)ConfigFile.Cam]); @@ -386,9 +410,24 @@ public class ResourcePathManager } FindCamVar("include_path", out var includePath, "./"); - FindCamVar("game", out var gameName); - FindCamVar($"{gameName}_include_install_cfg", out var installCfgName); - FindCamVar("include_user_cfg", out var userCfgName); + + if (!FindCamVar("game", out var gameName)) + { + Log.Error("`game` not specified in Cam/CamExt"); + return false; + } + + if (!FindCamVar($"{gameName}_include_install_cfg", out var installCfgName)) + { + Log.Error("Install config file path not specified in Cam/CamExt"); + return false; + } + + if (!FindCamVar("include_user_cfg", out var userCfgName)) + { + Log.Error("User config file path not specified in Cam/CamExt"); + return false; + } // TODO: How to handle case-insensitive absolute paths? // Fixup the include path to "work" cross-platform @@ -396,6 +435,7 @@ public class ResourcePathManager includePath = Path.Join(installPath, includePath); if (!Directory.Exists(includePath)) { + Log.Error("Include path specified in Cam/CamExt does not exist: {IncludePath}", includePath); return false; } @@ -417,15 +457,25 @@ public class ResourcePathManager } // Check we found everything - var i = 0; - foreach (var path in configPaths) + var found = 0; + for (var i = 0; i < (int)ConfigFile.ConfigFileCount; i++) { + var path = configPaths[i]; if (path == null || path == "") { - return false; + Log.Error("Failed to find {ConfigFile} config file", (ConfigFile)i); + continue; } - i++; + + found++; } + + if (found != (int)ConfigFile.ConfigFileCount) + { + Log.Error("Failed to find all required config files in Thief installation directory"); + return false; + } + return true; } diff --git a/KeepersCompound.Lightmapper/LightMapper.cs b/KeepersCompound.Lightmapper/LightMapper.cs index 479e8ac..2c6abfd 100644 --- a/KeepersCompound.Lightmapper/LightMapper.cs +++ b/KeepersCompound.Lightmapper/LightMapper.cs @@ -42,12 +42,19 @@ public class LightMapper string campaignName, string missionName) { - var pathManager = SetupPathManager(installPath); + if (!SetupPathManager(installPath, out var pathManager)) + { + Log.Error("Failed to configure path manager"); + throw new Exception("Failed to configure path manager"); + } + _campaign = pathManager.GetCampaign(campaignName); _misPath = _campaign.GetResourcePath(ResourceType.Mission, missionName); _mission = Timing.TimeStage("Parse DB", () => new DbFile(_misPath)); _hierarchy = Timing.TimeStage("Build Hierarchy", BuildHierarchy); _lights = []; + + VerifyRequiredChunksExist(); var mesh = Timing.TimeStage("Build Mesh", BuildMesh); _triangleTypeMap = mesh.TriangleSurfaceMap; @@ -121,12 +128,36 @@ public class LightMapper Timing.TimeStage("Save DB", () => _mission.Save(savePath)); } - private static ResourcePathManager SetupPathManager(string installPath) + private bool VerifyRequiredChunksExist() + { + var requiredChunkNames = new [] + { + "RENDPARAMS", + "LM_PARAM", + "WREXT", + "BRLIST", + "P$AnimLight", + }; + + var allFound = true; + foreach (var name in requiredChunkNames) + { + if (!_mission.Chunks.ContainsKey(name)) + { + Log.Warning("Failed to find required chunk: {ChunkName}", name); + allFound = false; + } + } + + return allFound; + } + + private static bool SetupPathManager(string installPath, out ResourcePathManager pathManager) { var tmpDir = Directory.CreateTempSubdirectory("KCLightmapper"); - var resPathManager = new ResourcePathManager(tmpDir.FullName); - resPathManager.Init(installPath); - return resPathManager; + + pathManager = new ResourcePathManager(tmpDir.FullName); + return pathManager.TryInit(installPath); } private ObjectHierarchy BuildHierarchy() @@ -144,6 +175,8 @@ public class LightMapper { return new ObjectHierarchy(_mission, new DbFile(paths[0])); } + + Log.Warning("Failed to find GameSys"); return new ObjectHierarchy(_mission); } diff --git a/KeepersCompound.Lightmapper/MeshBuilder.cs b/KeepersCompound.Lightmapper/MeshBuilder.cs index ee081ce..a4d3551 100644 --- a/KeepersCompound.Lightmapper/MeshBuilder.cs +++ b/KeepersCompound.Lightmapper/MeshBuilder.cs @@ -2,6 +2,7 @@ using System.Numerics; using KeepersCompound.LGS; using KeepersCompound.LGS.Database; using KeepersCompound.LGS.Database.Chunks; +using Serilog; namespace KeepersCompound.Lightmapper; @@ -117,6 +118,7 @@ public class MeshBuilder var modelPath = campaignResources.GetResourcePath(ResourceType.Object, modelName); if (modelPath == null) { + Log.Warning("Failed to find model file: {Path}", modelPath); continue; }