From b1dd9866ef6aca355de59a3861a51a205ee76619 Mon Sep 17 00:00:00 2001 From: AMPW-german Date: Fri, 5 Jun 2026 17:04:17 +0200 Subject: [PATCH] Run KerbalKonstructs.LoadModels with try/catch to prevent a failing model from crashing KK --- src/Core/Log.cs | 10 ++ src/KerbalKonstructs.cs | 196 +++++++++++++++++++++------------------- 2 files changed, 111 insertions(+), 95 deletions(-) diff --git a/src/Core/Log.cs b/src/Core/Log.cs index 810a5324..44e57c06 100644 --- a/src/Core/Log.cs +++ b/src/Core/Log.cs @@ -89,6 +89,16 @@ internal static void Error(string message) #endif } + /// + /// Logs an exception + /// + internal static void Exception(string message, System.Exception ex) + { + StackFrame frame = new StackFrame(1, true); + UnityEngine.Debug.LogError("KK: [" + frame.GetMethod().DeclaringType.Name + "] " + frame.GetMethod().Name + ": " + message); + UnityEngine.Debug.LogException(ex); + } + /// /// prints the current call-trace to the debug log /// diff --git a/src/KerbalKonstructs.cs b/src/KerbalKonstructs.cs index 98982b69..5ab61ebe 100644 --- a/src/KerbalKonstructs.cs +++ b/src/KerbalKonstructs.cs @@ -1000,133 +1000,139 @@ public void LoadModels() foreach (UrlDir.UrlConfig conf in configs) { - - // ignore referenced objects - if (conf.config.HasValue("pointername")) + try { - if ((!String.IsNullOrEmpty(conf.config.GetValue("pointername")) && !conf.config.GetValue("pointername").Equals("none", StringComparison.CurrentCultureIgnoreCase))) + // ignore referenced objects + if (conf.config.HasValue("pointername")) { - continue; + if ((!String.IsNullOrEmpty(conf.config.GetValue("pointername")) && !conf.config.GetValue("pointername").Equals("none", StringComparison.CurrentCultureIgnoreCase))) + { + continue; + } } - } - // Check if an modelname is set we can use, else set one - string modelName = conf.config.GetValue("name"); - if (String.IsNullOrEmpty(modelName)) - { - Log.UserWarning("No Name Found in configuration : " + conf.url.Substring(0, conf.url.LastIndexOf('/')) + ".cfg"); - modelName = Regex.Replace(conf.config.GetValue("title"), @"\s+", ""); + // Check if an modelname is set we can use, else set one + string modelName = conf.config.GetValue("name"); if (String.IsNullOrEmpty(modelName)) { - modelName = conf.url.Substring(0, conf.url.LastIndexOf('/')) + ".cfg"; + Log.UserWarning("No Name Found in configuration : " + conf.url.Substring(0, conf.url.LastIndexOf('/')) + ".cfg"); + modelName = Regex.Replace(conf.config.GetValue("title"), @"\s+", ""); + if (String.IsNullOrEmpty(modelName)) + { + modelName = conf.url.Substring(0, conf.url.LastIndexOf('/')) + ".cfg"; + } + if (!String.IsNullOrEmpty(modelName)) + { + conf.config.SetValue("name", modelName, true); + } + else + { + Log.Error("No Name Found in configuration : " + conf.url.Substring(0, conf.url.LastIndexOf('/')) + ".cfg"); + continue; + } } - if (!String.IsNullOrEmpty(modelName)) + + StaticModel model = new StaticModel + { + path = Path.GetDirectoryName(Path.GetDirectoryName(conf.url)).Replace("\\", "/"), + name = modelName, + config = conf.url, + configPath = conf.url.Substring(0, conf.url.LastIndexOf('/')) + ".cfg" + }; + + ConfigParser.ParseModelConfig(model, conf.config); + + if (model.mesh.Contains('.')) { - conf.config.SetValue("name", modelName, true); + model.mesh = model.mesh.Substring(0, model.mesh.LastIndexOf('.')); + // model.settings = KKAPI.loadConfig(conf.config, KKAPI.getModelSettings()); } - else + model.prefab = GameDatabase.Instance.GetModelPrefab(model.path + "/" + model.mesh); + + if (model.prefab == null) { - Log.Error("No Name Found in configuration : " + conf.url.Substring(0, conf.url.LastIndexOf('/')) + ".cfg"); + Log.UserError("Could not find " + model.path + "/" + model.mesh + ".mu!"); continue; } - } - - StaticModel model = new StaticModel - { - path = Path.GetDirectoryName(Path.GetDirectoryName(conf.url)).Replace("\\", "/"), - name = modelName, - config = conf.url, - configPath = conf.url.Substring(0, conf.url.LastIndexOf('/')) + ".cfg" - }; - - ConfigParser.ParseModelConfig(model, conf.config); - - if (model.mesh.Contains('.')) - { - model.mesh = model.mesh.Substring(0, model.mesh.LastIndexOf('.')); - // model.settings = KKAPI.loadConfig(conf.config, KKAPI.getModelSettings()); - } - model.prefab = GameDatabase.Instance.GetModelPrefab(model.path + "/" + model.mesh); - if (model.prefab == null) - { - Log.UserError("Could not find " + model.path + "/" + model.mesh + ".mu!"); - continue; - } - - //foreach (MeshRenderer renderer in model.prefab.GetComponentsInChildren(true)) - //{ - // renderer.sharedMaterial.shader = KKGraphics.GetShader("Standard"); - //} - //model.prefab.isStatic = true; - //StaticBatchingUtility.Combine(model.prefab); + //foreach (MeshRenderer renderer in model.prefab.GetComponentsInChildren(true)) + //{ + // renderer.sharedMaterial.shader = KKGraphics.GetShader("Standard"); + //} + //model.prefab.isStatic = true; + //StaticBatchingUtility.Combine(model.prefab); - foreach (ConfigNode ins in conf.config.GetNodes("MODULE")) - { - StaticModule module = new StaticModule(); - foreach (ConfigNode.Value value in ins.values) + foreach (ConfigNode ins in conf.config.GetNodes("MODULE")) { - switch (value.name) + StaticModule module = new StaticModule(); + foreach (ConfigNode.Value value in ins.values) { - case "namespace": - module.moduleNamespace = value.value; - break; - case "name": - module.moduleClassname = value.value; - break; - default: - module.moduleFields.Add(value.name, value.value); - break; + switch (value.name) + { + case "namespace": + module.moduleNamespace = value.value; + break; + case "name": + module.moduleClassname = value.value; + break; + default: + module.moduleFields.Add(value.name, value.value); + break; + } } - } - - // check for unused AdvTexture Modules - if (module.moduleClassname == "AdvancedTextures") - { - bool transformFound = false; - string transforms = ""; - string[] seperators = new string[] { " ", ",", ";" }; - List targetTransforms = new List { "Any" }; - if (module.moduleFields.ContainsKey("transforms")) + // check for unused AdvTexture Modules + if (module.moduleClassname == "AdvancedTextures") { - transforms = module.moduleFields["transforms"]; - targetTransforms = transforms.Split(seperators, StringSplitOptions.RemoveEmptyEntries).ToList(); - foreach (MeshRenderer renderer in model.prefab.GetComponentsInChildren(true)) + bool transformFound = false; + string transforms = ""; + string[] seperators = new string[] { " ", ",", ";" }; + List targetTransforms = new List { "Any" }; + + if (module.moduleFields.ContainsKey("transforms")) { - if (!transforms.Equals("Any", StringComparison.CurrentCultureIgnoreCase) && !targetTransforms.Contains(renderer.transform.name)) + transforms = module.moduleFields["transforms"]; + targetTransforms = transforms.Split(seperators, StringSplitOptions.RemoveEmptyEntries).ToList(); + foreach (MeshRenderer renderer in model.prefab.GetComponentsInChildren(true)) { - continue; + if (!transforms.Equals("Any", StringComparison.CurrentCultureIgnoreCase) && !targetTransforms.Contains(renderer.transform.name)) + { + continue; + } + transformFound = true; } + } + else + { transformFound = true; } + if (!transformFound) + { + //Log.Normal("Adv Texture Preload: transforms not found: " + transforms + " on model: " + model.name); + continue; + } } - else - { - transformFound = true; - } - if (!transformFound) + if (model.modules == null) { - //Log.Normal("Adv Texture Preload: transforms not found: " + transforms + " on model: " + model.name); - continue; + model.modules = new List(); } + model.modules.Add(module); } - if (model.modules == null) + + if (model.keepConvex != true) { - model.modules = new List(); + foreach (MeshCollider collider in model.prefab.GetComponentsInChildren(true)) + { + Log.Debug("Making collider " + collider.name + " concave."); + collider.convex = false; + } } - model.modules.Add(module); - } - if (model.keepConvex != true) + StaticDatabase.RegisterModel(model, modelName); + } + catch (Exception ex) { - foreach (MeshCollider collider in model.prefab.GetComponentsInChildren(true)) - { - Log.Debug("Making collider " + collider.name + " concave."); - collider.convex = false; - } + Log.Exception($"Error loading model from config: {conf.url.Substring(0, conf.url.LastIndexOf('/'))}.cfg", ex); } - - StaticDatabase.RegisterModel(model, modelName); } }