Resource icon

Guides The way to read Appearance Presets(*.vap) Directly

"Appearance Presets" file (*.vap) is JSON formatted.

target vap file example.
JSON:
{
   "setUnlistedParamsToDefault" : "true",
   "storables" : [
      {
         "id" : "geometry",
         "useAdvancedColliders" : "true",
         "useAuxBreastColliders" : "true",
         "disableAnatomy" : "false",
         "useMaleMorphsOnFemale" : "false",
         "useFemaleMorphsOnMale" : "false",
         "character" : "Female Custom",
         "clothing" : [
            {
               "id" : "...",
               "internalId" : "...",
               "enabled" : "true"
            }, ...
         ],
         "hair" : [
            {
               "id" : "...",
               "internalId" : "...",
               "enabled" : "true"
            }, ...
         ],
         "morphs" : [
            {
               "uid" : "...",
               "name" : "...",
               "value" : "0.5"
            }, ...
        ],...
        {
            "id" : "rescaleObject",
            "scale" : "0.95"
         },

But it is not a strict format and cannot be parsed.
i.e. this not works.

C#:
string jsonStr = SuperController.singleton.ReadFileIntoString(@"Custom\Atom\Person\Appearance\Preset_presetname.vap");  // OK
JsonNode jn = JSON.Parse(jsonStr);  // partially fails silently...
// jn["storables"]["morphs"]  is null

Therefore, let's get a part of JSON that can be interpreted by low-level processing, using this code.

C#:
        /// <summary>
        /// Read values from ".vap" file.
        /// Although vap is JSON, it is not a strict format and cannot be parsed, so it is converted to JSON that can be interpreted by low-level processing and then parsed.
        /// </summary>
        /// <param name="filepath"></param>
        /// <param name="tag">lowest array key.  ex. hair, morphs, ...</param>
        /// <returns></returns>
        public static JSONNode parseVap(string filepath, string tag)
        {
            string json = "";
            try { json = SuperController.singleton.ReadFileIntoString(filepath); }
            catch(Exception e) { dUtil.error($"Error while reading`{filepath}`.\n{e.Message}"); }  // not work b/c error squeeze&clashed.
            if(json == "") return new JSONNode();

            int start = json.IndexOf(tag) - 1;
            int end = json.IndexOf("]\n", start);
            json = json.Substring(start, end - start + 1);
            var ret = JSON.Parse(json);
            if (ret == null)
            {
                string mes = $"'${tag}' not found in '${filepath}'.";
                dUtil.error(mes);
                throw new Exception(mes);
            }
            return ret;
        }

        /// <summary>
        /// Read values from ".vap" file.
        /// Although vap is JSON, it is not a strict format and cannot be parsed, so it is converted to JSON that can be interpreted by low-level processing and then parsed.
        /// </summary>
        /// <param name="filepath"></param>
        /// <param name="tag">lowest dictionary id.  ex. rescaleObject, ...</param>
        /// <returns></returns>
        public static JSONNode parseVapDictionary(string filepath, string tag)
        {
            var json = SuperController.singleton.ReadFileIntoString(filepath);
            int start = json.IndexOf($"\"id\" : \"{tag}") - 1;
            int end = json.IndexOf("}", start);
            json = "{" + json.Substring(start, end - start + 1);
            var ret = JSON.Parse(json);
            if (ret == null)
            {
                string mes = $"'${tag}' not found in '${filepath}'.";
                dUtil.error(mes);
                throw new Exception(mes);
            }
            return ret;
        }

Usage

C#:
appearancePath = @"Custom\Atom\Person\Appearance\Preset_presetname.vap";
// morph
var morphs = new Dictionary<string, float>();  // k,v : name,value
foreach (var j in CharacterFusioner.parseVap(appearancePath, "morphs").Childs)
    morphs[j["name"]] = j["value"].AsFloat;

// rescaleObject
float scale = CharacterFusioner.parseVapDictionary(appearancePath, "rescaleObject")["scale"].AsFloat;
Author
dynms1337
Views
2,503
First release
Last update
Rating
5.00 star(s) 1 ratings

More resources from dynms1337

Latest reviews

I just felt my brain get bigger. Thanks!
Upvote 0
Back
Top Bottom