• Hi Guest!

    We are extremely excited to announce the release of our first Beta for VaM2, the next generation of Virt-A-Mate which is currently in development.
    To participate in the Beta, a subscription to the Entertainer or Creator Tier is required. Once subscribed, download instructions can be found here.

    Click here for information and guides regarding the VaM2 beta. Join our Discord server for more announcements and community discussion about VaM2.
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;

Share this resource

Latest reviews

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