Browse Source

Make preset loading defensive

Add a whole load of exceptions to check for and reinitialize presets
where appropriate.
habeebweeb 4 years ago
parent
commit
df38842f26
1 changed files with 102 additions and 33 deletions
  1. 102 33
      COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/Meido.cs

+ 102 - 33
COM3D2.MeidoPhotoStudio.Plugin/MeidoPhotoStudio/Meido/Meido.cs

@@ -272,9 +272,24 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
             if (pose.StartsWith(Constants.customPosePath))
             {
-                byte[] poseBuffer = File.ReadAllBytes(pose);
-                string hash = Path.GetFileName(pose).GetHashCode().ToString();
-                Body.CrossFade(hash, poseBuffer, loop: true, fade: 0f);
+                string poseFilename = Path.GetFileNameWithoutExtension(pose);
+                try
+                {
+                    byte[] poseBuffer = File.ReadAllBytes(pose);
+                    string hash = Path.GetFileName(pose).GetHashCode().ToString();
+                    Body.CrossFade(hash, poseBuffer, loop: true, fade: 0f);
+                }
+                catch (Exception e) when (e is DirectoryNotFoundException || e is FileNotFoundException)
+                {
+                    Utility.LogWarning($"{poseFilename}: Could not open because {e.Message}");
+                    Constants.InitializeCustomPoses();
+                    return;
+                }
+                catch (Exception e)
+                {
+                    Utility.LogWarning($"{poseFilename}: Could not apply pose because {e.Message}");
+                    return;
+                }
             }
             else
             {
@@ -317,20 +332,40 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
         public void SetHandPreset(string filename, bool right)
         {
-            XDocument handDocument = XDocument.Load(filename);
-            XElement handElement = handDocument.Element("FingerData");
-            if (handElement.IsEmpty || handElement.Element("GameVersion").IsEmpty
-                || handElement.Element("RightData").IsEmpty || handElement.Element("BinaryData").IsEmpty
-            ) return;
+            string faceFilename = Path.GetFileNameWithoutExtension(filename);
+            try
+            {
+                XDocument handDocument = XDocument.Load(filename);
+                XElement handElement = handDocument.Element("FingerData");
+
+                if (handElement?.Elements().Any(element => element?.IsEmpty ?? true) ?? true)
+                {
+                    Utility.LogWarning($"{faceFilename}: Could not apply hand preset because it is invalid.");
+                    return;
+                }
 
-            Stop = true;
+                Stop = true;
 
-            bool rightData = bool.Parse(handElement.Element("RightData").Value);
-            string base64Data = handElement.Element("BinaryData").Value;
+                bool rightData = bool.Parse(handElement.Element("RightData").Value);
+                string base64Data = handElement.Element("BinaryData").Value;
 
-            byte[] handData = Convert.FromBase64String(base64Data);
+                byte[] handData = Convert.FromBase64String(base64Data);
 
-            IKManager.DeserializeHand(handData, right, rightData != right);
+                IKManager.DeserializeHand(handData, right, rightData != right);
+            }
+            catch (System.Xml.XmlException e)
+            {
+                Utility.LogWarning($"{faceFilename}: Hand preset data is malformed because {e.Message}");
+            }
+            catch (Exception e) when (e is DirectoryNotFoundException || e is FileNotFoundException)
+            {
+                Utility.LogWarning($"{faceFilename}: Could not open hand preset because {e.Message}");
+                Constants.InitializeHandPresets();
+            }
+            catch (Exception e)
+            {
+                Utility.LogWarning($"{faceFilename}: Could not parse hand preset because {e.Message}");
+            }
         }
 
         public byte[] SerializePose(bool frameBinary = false)
@@ -359,26 +394,63 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
         {
             if (custom)
             {
-                XDocument faceDocument = XDocument.Load(blendSet);
-                XElement faceDataElement = faceDocument.Element("FaceData");
-                if (faceDataElement.IsEmpty) return;
-
-                HashSet<string> hashKeys = new HashSet<string>(faceKeys.Concat(faceToggleKeys));
-
-                foreach (XElement element in faceDataElement.Elements())
+                string blendSetFileName = Path.GetFileNameWithoutExtension(blendSet);
+                try
                 {
-                    string key;
-                    if ((key = (string)element.Attribute("name")) != null && !hashKeys.Contains(key)) continue;
+                    XDocument faceDocument = XDocument.Load(blendSet, LoadOptions.SetLineInfo);
+                    XElement faceDataElement = faceDocument.Element("FaceData");
+                    if (faceDataElement?.IsEmpty ?? true)
+                    {
+                        Utility.LogWarning($"{blendSetFileName}: Could not apply face preset because it is invalid.");
+                        return;
+                    }
 
-                    if (float.TryParse(element.Value, out float value))
+                    HashSet<string> hashKeys = new HashSet<string>(faceKeys.Concat(faceToggleKeys));
+
+                    foreach (XElement element in faceDataElement.Elements())
                     {
-                        try
+                        System.Xml.IXmlLineInfo info = element;
+                        int line = info.HasLineInfo() ? info.LineNumber : -1;
+                        string key;
+
+                        if ((key = (string)element.Attribute("name")) == null)
+                        {
+                            Utility.LogWarning($"{blendSetFileName}: Could not read face blend key at line {line}.");
+                            continue;
+                        }
+
+                        if (!hashKeys.Contains(key))
+                        {
+                            Utility.LogWarning($"{blendSetFileName}: Invalid face blend key '{key}' at line {line}.");
+                            continue;
+                        }
+
+                        if (float.TryParse(element.Value, out float value))
                         {
-                            SetFaceBlendValue(key, value);
+                            try { SetFaceBlendValue(key, value); }
+                            catch { }
                         }
-                        catch { }
+                        else Utility.LogWarning(
+                            $"{blendSetFileName}: Could not parse value '{element.Value}' of '{key}' at line {line}"
+                        );
                     }
                 }
+                catch (System.Xml.XmlException e)
+                {
+                    Utility.LogWarning($"{blendSetFileName}: Face preset data is malformed because {e.Message}");
+                    return;
+                }
+                catch (Exception e) when (e is DirectoryNotFoundException || e is FileNotFoundException)
+                {
+                    Utility.LogWarning($"{blendSetFileName}: Could not open face preset because {e.Message}");
+                    Constants.InitializeCustomFaceBlends();
+                    return;
+                }
+                catch (Exception e)
+                {
+                    Utility.LogWarning($"{blendSetFileName}: Could not parse face preset because {e.Message}");
+                    return;
+                }
             }
             else
             {
@@ -386,7 +458,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
 
                 CurrentFaceBlendSet = blendSet;
 
-                BackupBlendSetValuess();
+                BackupBlendSetValues();
 
                 Maid.FaceAnime(blendSet, 0f);
             }
@@ -402,10 +474,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             else
             {
                 hash = Utility.GP01FbFaceHash(morph, hash);
-                try
-                {
-                    morph.dicBlendSet[CurrentFaceBlendSet][(int)morph.hash[hash]] = value;
-                }
+                try { morph.dicBlendSet[CurrentFaceBlendSet][(int)morph.hash[hash]] = value; }
                 catch { }
             }
         }
@@ -490,7 +559,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
             if (control != null) control.transform.localPosition = position;
         }
 
-        private void BackupBlendSetValuess()
+        private void BackupBlendSetValues()
         {
             float[] values = Body.Face.morph.dicBlendSet[CurrentFaceBlendSet];
             BlendSetValueBackup = new float[values.Length];
@@ -527,7 +596,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
                 initialized = true;
             }
 
-            if (BlendSetValueBackup == null) BackupBlendSetValuess();
+            if (BlendSetValueBackup == null) BackupBlendSetValues();
 
             if (HairGravityValid) hairGravityDragPoint.Move += OnGravityEvent;
             if (SkirtGravityValid) skirtGravityDragPoint.Move += OnGravityEvent;