🏃‍♂ïļSave / Load

0. í•īë‹đ ęļ€ė˜ ë‚īėšĐ

  • ė„ļ팅 된 ė•„바타ė— 대한 ė •ëģīëĨž ė €ėžĨí•Đ니ë‹Ī.

    • ė–īë–Ī Raceėļė§€

      • ë‚Ļ, ė—Ž, ė—˜í”„ ë‚Ļ, ė—˜í”„ ė—Ž 등등

      • ė˜Ī큎 또는 ė• ë‹ˆėŧĻė…‰ė˜ ė‚ŽëžŒ 등 ė œėž‘하ė—Ž Race로 ė‚ŽėšĐ가ëŠĨ í•Đ니ë‹Ī.

    • ëŠļ ėƒíƒœ 값 DNA

    • ėžĨė°Đ한 ė˜ėƒ (Wardrobe Recipe)

    • Slot Color

  • ė €ėžĨ 형태는 text, asset 등ėī ėžˆėŠĩ니ë‹Ī.

    • ė €ėžĨ된 ëĶŽė†ŒėŠĪ(text, asset)만 가ė§€ęģ  ė•„바타ëĨž 표현ė€ ëķˆę°€ëŠĨ í•Đ니ë‹Ī

    • ęļ°ëģļė ėœžëĄœ 프로ė íŠļė— ėĪ€ëđ„된 race / wardrobe / slot 등ė˜ ëĶŽė†ŒėŠĪ가 ėžˆė–īė•ž í•Đ니ë‹Ī.

  • ė €ėžĨ ęē°ęģžëŽžė€ 3ėĒ…ëĨ˜ę°€ ėžˆėœžëĐ° 각 ėĩœė í™”된 ė •ë„ę°€ ë‹ĪëĶ…니ë‹Ī.

1. Dynamic Character Avater Inspector

  • DCA ė˜ Inspector ė°― ë‚īė—ė„œ save load í•īëģī는 ė˜ˆ

  • 런타ėž„ėĪ‘ 가ëŠĨ하ë‹Ī.

ėĪ€ëđ„ 할 Recipe -> ė˜ˆė œė—ė„œ 가ė ļė˜ī.

ėžë‹Ļ ėž…혀ëģļë‹Ī.

Inspector ė—ė„œ Dynamic Character Avatar Load/Save Options

  • Load File On Start ėēī큎ëĨž í•īė œ 한ë‹Ī.

Load File On Start ėēī큎ëĨž í•īė œ 했ė–īė•ž 했ë‹Ī.

Load/Save Options

Editor Play

  • ė•„ė§ ė €ėžĨ 한 ęēƒėī ė—†ęļ° 때ëŽļė— ė·Ļė†Œ

  • ė‹œėž‘ 하ėžë§ˆėž Load saved Avatar 파ėž ëķˆëŸŽė˜Īęļ° 탐ėƒ‰ęļ° ė°―ėī íŠļëĶŽęą° 된ë‹Ī.

Perform Save

  • ė—ë””í„° play ëĨž 하ëĐī inspector ë‚īė— ëē„튞ėī ėƒė„ąëœë‹Ī.

  • Perform SaveëĨž 눌럮 ė €ėžĨ한ë‹Ī.

  • ė €ėžĨ ėœ„ėđ˜ëĨž ė„ íƒí•  탐ėƒ‰ęļ° ė°―ėī 나ė˜Ī는데 ėžë‹Ļ ėœ„ėđ˜ ė§€ė •í•īėĢžęģ  ė§„í–‰.(Save Path는 ė™œ ėž…ë Ĩ하는ė§€..)

  • 파ėžėī ėƒė„ą 되ė—ˆë‹Ī. (확ėžĨėžëŠ” .txt)

Editor ėĒ…ëĢŒ 후 Load/Save Options -> Load File On Start ėēī큎

ë‹Īė‹œ Editor Play

  • Load 되는ė§€ 확ėļ 하ęļ° ėœ„í•ī, ęļ°ëģļ ė˜·ë§Œ ėž…혀놓ęģ  Load í•ī ëģīė•˜ë‹Ī.

  • ė™ļëķ€ 파ėžëĄœ ėļė‹í•īė„œ ę·ļ런ė§€, Editor ė‹œėž‘하ėžë§ˆėž 파ėž ė„ íƒí•˜ëŠ” 탐ėƒ‰ęļ°ę°€ íŠļëĶŽęą° 된ë‹Ī.

  • ęē°ęģžė ėœžëĄœëŠ” ė˜·ėī ėž˜ Load 되ė–ī ėž…혀ė§„ë‹Ī.

플레ėī 도ėĪ‘ė— ė˜·ė„ load í•īė„œ ėž…혀ëģīęļ°.

  • ėīė „ęģž 같ėī Load File On Start ëĨž ėēī큎 í•īė œ í•īė•ž 한ë‹Ī.

  • Editor Play 후 Inspector / ėƒė„ąëœ Perform Load ëē„튞 íīëĶ­.

  • ëĶŽė†ŒėŠĪëĨž ė„ íƒí•˜ęļ° ėœ„í•œ 탐ėƒ‰ęļ°ė°―ėī íŠļëĶŽęą° 된ë‹Ī.

  • ėīė „ęģž 같ėī ëĶŽė†ŒėŠĪ 파ėžė„ ė„ íƒ 하ëĐī ė˜·ėī ėž…혀ė§„ë‹Ī.

PathType ė— 따ëĨļ ė €ėžĨ ėœ„ėđ˜

  • Resource

    • Assets ë‚īëķ€ ėœ„ėđ˜ Resources static íī래ėŠĪ íī더 ėœ„ėđ˜ę°€ root

      • Assets/Resources/...

      • Save Pathė— ė•„ëŽīęēƒë„ ėž…ë Ĩ ė•ˆí•˜ëĐī root ė— 파ėžėī ėœ„ėđ˜í•Ļ.

  • Persistent Data Path

    • ė•ąë°ėī터 ęē―

    • Save Path (inspector input path) ë‚ī가 ėž…ë Ĩ한 ęē―로.

      • Assets/_UMA-study/SaveLoadRecipe/_PersistentDataPathRecipe

    • ė‹Īė œ ė €ėžĨ ėœ„ėđ˜

      • C:/Users/yangy/AppData/LocalLow/DefaultCompany/study-normal\Assets/_UMA-study/SaveLoadRecipe/_PersistentDataPathRecipe\savedRecipe.txt

      • C:/Users/yangy/AppData/LocalLow/DefaultCompany/[프로ė íŠļ ėīëĶ„]\

        • ė—Žęļ°ęđŒė§€ę°€ root ėœ„ėđ˜ėīë‹Ī.

  • File System

    • ė ˆëŒ€ė ėļ ęē―로.

    • ėœ„ėđ˜ ė„ íƒí•˜ëŠ” 탐ėƒ‰ęļ°ė°― 나ė˜ī.

2. 1ëēˆ ë°Đė‹ė˜ ė―”ë“œ ė˜ˆė œ.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UMA.CharacterSystem;

public class SaveLoadController : MonoBehaviour
{
    public Button saveBtn;
    public Button loadBtn;
    public Button clearBtn;

    public DynamicCharacterAvatar avatar;
    [Space(20)]
    public DynamicCharacterAvatar.savePathTypes savePathType;
    public string savePath;
    public string saveFilename;
    [Space(20)]
    public DynamicCharacterAvatar.loadPathTypes loadPathType;
    public string loadPath;
    public string loadFilename;
    private void OnEnable()
    {
        saveBtn.onClick.AddListener(() =>
        {    
            // saveFilenameė— 확ėžĨėžëĨž ë„Ģė§€ ė•ŠëŠ”ë‹Ī. ėžë™ėœžëĄœ .txt ëķ€
            avatar.savePathType = savePathType;
            avatar.savePath = savePath;
            avatar.saveFilename = saveFilename;
            avatar.DoSave();
        });

        loadBtn.onClick.AddListener(() =>
        {    
            // loadPathTypeėī Resource ėļ ęē―ėš°ė—ëŠ”
            // loadFilenameė— 확ėžĨėžëĨž ë„Ģė„ ęē―ėš° ë§Īėđ˜ę°€ 되ė§€ ė•Šė•˜ë‹Ī.
            if(loadPathType == DynamicCharacterAvatar.loadPathTypes.persistentDataPath)
            {
                loadFilename += ".txt";
            }

            avatar.SetLoadFilename(loadFilename, loadPathType);
            avatar.loadPath = loadPath;
            avatar.DoLoad();
        });
    }

}

Resource Data ëĨž ė ėšĐė‹œí‚Ī는 ëķ€ëķ„

// DynamicCharacterAvatar

public void SetLoadString(string recipeString)
{
    if (_isFirstSettingsBuild)
    {
        loadString = recipeString;
        loadPathType = loadPathTypes.String;
        loadFileOnStart = true;
    }
    else
    {
        LoadFromRecipeString(recipeString);
    }
}

3. Avatar Definition

UMA Example: How to Load and Save a DCA to a string

  • ėīė „ ė˜ˆė œė—ė„œëŠ” LoadFromRecipeString() ëĨž í†ĩ한 recipeString ė ėšĐ ë°Đëē• ėīė—ˆë‹Ī.

  • ė•„래는 AvatarDefinition stringėœžëĄœ save/load 하는 ë°Đė‹ė˜ ė˜ˆė œ.

using System.Collections;
using System.Collections.Generic;
using UMA.CharacterSystem;
using UMA;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.Serialization.Formatters.Binary;

public class SaveAndLoadSample : MonoBehaviour
{
    public DynamicCharacterAvatar Avatar;
    public UMARandomAvatar Randomizer;
    public Button LoadButton;
    public bool useAvatarDefinition;
    public bool useCompressedString;

    public string saveString;
    public string avatarString;
    public string compressedString;
    public int saveStringSize;
    public int avatarStringSize;
    public int compressedStringSize;
    public int asciiStringSize;
    public int binarySize;
    
    public void GenerateANewUMA()
    {
        Randomizer.Randomize(Avatar);
        Avatar.BuildCharacter(false);
    }

    public void SaveUMA()
    {
        avatarString = Avatar.GetAvatarDefinitionString(true);
        saveString = Avatar.GetCurrentRecipe();
        compressedString = Avatar.GetAvatarDefinition(true).ToCompressedString("|");
        asciiStringSize = Avatar.GetAvatarDefinition(true).ToASCIIString().Length;

        binarySize = BinaryDefinition.ToBinary(new BinaryFormatter(), Avatar.GetAvatarDefinition(true)).Length;
        saveStringSize = saveString.Length * 2;
        avatarStringSize = avatarString.Length * 2;
        compressedStringSize = compressedString.Length * 2; // utf-16

        LoadButton.interactable = true;
    }

    public void LoadUMA()
    {
        if (string.IsNullOrEmpty(saveString))
            return; 
        if (useCompressedString)
        {
            AvatarDefinition adf = AvatarDefinition.FromCompressedString(compressedString, '|');
            Avatar.LoadAvatarDefinition(adf);
            Avatar.BuildCharacter(false); // don't restore old DNA...
        }
        else if (useAvatarDefinition)
        {
            Avatar.LoadAvatarDefinition(avatarString);
            Avatar.BuildCharacter(false); // We must not restore the old DNA
        }
        else
        {
            Avatar.LoadFromRecipeString(saveString);
        }
    }
}

Save String

  • ė•„바타ė˜ ëŠĻ든 ė •ëģī 폎í•Ļ.

  • ëŠĻ든 DNA ė†ė„ą 폎í•Ļ.

  • 타 savedString ë“Ī ëģīë‹Ī ė‚ŽėīėĶˆę°€ 큞.

Save String
{
  "packedRecipeType": "DynamicCharacterAvatar",
  "name": "UMADynamicCharacterAvatar",
  "race": "HumanFemale",
  "dna": [
    {
      "dnaType": "DynamicUMADna",
      "dnaTypeHash": 1932961400,
      "packedDna": "{\"bDnaAsset\":{\"instanceID\":33790},\"bDnaAssetName\":\"HumanFemaleDNA 1\",\"bDnaSettings\":[{\"name\":\"height\",\"value\":117},{\"name\":\"headSize\",\"value\":128},{\"name\":\"headWidth\",\"value\":139},{\"name\":\"neckThickness\",\"value\":128},{\"name\":\"armLength\",\"value\":128},{\"name\":\"forearmLength\",\"value\":128},{\"name\":\"armWidth\",\"value\":128},{\"name\":\"forearmWidth\",\"value\":128},{\"name\":\"handsSize\",\"value\":128},{\"name\":\"feetSize\",\"value\":128},{\"name\":\"legSeparation\",\"value\":128},{\"name\":\"upperMuscle\",\"value\":128},{\"name\":\"lowerMuscle\",\"value\":128},{\"name\":\"upperWeight\",\"value\":167},{\"name\":\"lowerWeight\",\"value\":160},{\"name\":\"legsSize\",\"value\":129},{\"name\":\"belly\",\"value\":146},{\"name\":\"waist\",\"value\":128},{\"name\":\"gluteusSize\",\"value\":128},{\"name\":\"earsSize\",\"value\":128},{\"name\":\"earsPosition\",\"value\":128},{\"name\":\"earsRotation\",\"value\":128},{\"name\":\"noseSize\",\"value\":141},{\"name\":\"noseCurve\",\"value\":206},{\"name\":\"noseWidth\",\"value\":128},{\"name\":\"noseInclination\",\"value\":166},{\"name\":\"nosePosition\",\"value\":129},{\"name\":\"nosePronounced\",\"value\":160},{\"name\":\"noseFlatten\",\"value\":106},{\"name\":\"chinSize\",\"value\":122},{\"name\":\"chinPronounced\",\"value\":161},{\"name\":\"chinPosition\",\"value\":169},{\"name\":\"mandibleSize\",\"value\":184},{\"name\":\"jawsSize\",\"value\":128},{\"name\":\"jawsPosition\",\"value\":128},{\"name\":\"cheekSize\",\"value\":101},{\"name\":\"cheekPosition\",\"value\":128},{\"name\":\"lowCheekPronounced\",\"value\":99},{\"name\":\"lowCheekPosition\",\"value\":128},{\"name\":\"foreheadSize\",\"value\":128},{\"name\":\"foreheadPosition\",\"value\":128},{\"name\":\"lipsSize\",\"value\":77},{\"name\":\"mouthSize\",\"value\":156},{\"name\":\"eyeRotation\",\"value\":77},{\"name\":\"eyeSize\",\"value\":165},{\"name\":\"breastSize\",\"value\":90},{\"name\":\"breastCleavage\",\"value\":128},{\"name\":\"eyeSpacing\",\"value\":78}]}"
    }
  ],
  "characterColors": [
    {
      "name": "Skin",
      "colors": [
        204, 201, 193, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255,
        255, 255, 255, 16, 0, 0, 62
      ],
      "ShaderParms": [],
      "alwaysUpdate": false
    },
    {
      "name": "Hair",
      "colors": [
        53, 25, 0, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255,
        255, 255, 0, 0, 0, 0
      ],
      "ShaderParms": [],
      "alwaysUpdate": false
    },
    {
      "name": "Eyes",
      "colors": [
        213, 78, 221, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255,
        255, 255, 34, 31, 31, 154
      ],
      "ShaderParms": [],
      "alwaysUpdate": false
    },
    {
      "name": "Lipstick",
      "colors": [
        35, 0, 0, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255,
        255, 255, 0, 0, 0, 0
      ],
      "ShaderParms": [],
      "alwaysUpdate": false
    },
    {
      "name": "Shirt",
      "colors": [
        94, 172, 74, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255,
        255, 255, 0, 0, 0, 0
      ],
      "ShaderParms": [],
      "alwaysUpdate": false
    },
    {
      "name": "Pants",
      "colors": [
        255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255,
        255, 255, 255, 29, 29, 29, 93
      ],
      "ShaderParms": [],
      "alwaysUpdate": false
    },
    {
      "name": "Pants Accent",
      "colors": [
        236, 211, 109, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255,
        255, 255, 255, 34, 31, 31, 154
      ],
      "ShaderParms": [],
      "alwaysUpdate": false
    }
  ],
  "wardrobeSet": [
    { "slot": "Chest", "recipe": "FemaleTankTop_Recipe" },
    { "slot": "Feet", "recipe": "FemaleTallShoes_White" },
    { "slot": "Hair", "recipe": "FemaleLongHair_Recipe" },
    { "slot": "Legs", "recipe": "FemalePants2" },
    { "slot": "Underwear", "recipe": "FemaleUndies" }
  ],
  "raceAnimatorController": "Locomotion"
}

Avatar String

  • Race, Wardrobe, SlotColor, DNA

  • ė„ļ팅 된 DNA ė •ëģī만 폎í•Ļ.

  • ęļ°ëģļ값 ė„ļ팅 폎í•Ļ x

Avatar String
{
  "RaceName": "HumanFemale",
  "Wardrobe": [
    "FemaleTankTop_Recipe",
    "FemaleTallShoes_White",
    "FemaleLongHair_Recipe",
    "FemalePants2",
    "FemaleUndies"
  ],
  "Colors": [
    {
      "name": "Hair",
      "count": 3,
      "channels": [{ "chan": 0, "mCol": 4281669888, "aCol": 0 }]
    },
    {
      "name": "Eyes",
      "count": 3,
      "channels": [
        { "chan": 0, "mCol": 4292169437, "aCol": 0 },
        { "chan": 2, "mCol": 4294967295, "aCol": 2585927455 }
      ]
    },
    {
      "name": "Skin",
      "count": 3,
      "channels": [
        { "chan": 0, "mCol": 4291611330, "aCol": 0 },
        { "chan": 2, "mCol": 4294967295, "aCol": 1041235968 }
      ]
    },
    {
      "name": "Pants1",
      "count": 3,
      "channels": [{ "chan": 0, "mCol": 4281867784, "aCol": 0 }]
    },
    {
      "name": "Pants",
      "count": 3,
      "channels": [{ "chan": 2, "mCol": 4294967295, "aCol": 1562254878 }]
    },
    {
      "name": "Lipstick",
      "count": 3,
      "channels": [{ "chan": 0, "mCol": 4280549376, "aCol": 0 }]
    },
    {
      "name": "Shirt",
      "count": 1,
      "channels": [{ "chan": 0, "mCol": 4284394571, "aCol": 0 }]
    },
    {
      "name": "Pants Accent",
      "count": 3,
      "channels": [
        { "chan": 0, "mCol": 4293710957, "aCol": 0 },
        { "chan": 2, "mCol": 4294967295, "aCol": 2585927455 }
      ]
    },
    {
      "name": "Undies",
      "count": 3,
      "channels": [{ "chan": 0, "mCol": 4293535821, "aCol": 0 }]
    }
  ],
  "Dna": [
    { "Name": "height", "val": 4602 },
    { "Name": "headWidth", "val": 5465 },
    { "Name": "upperWeight", "val": 6568 },
    { "Name": "lowerWeight", "val": 6263 },
    { "Name": "legsSize", "val": 5073 },
    { "Name": "belly", "val": 5734 },
    { "Name": "noseSize", "val": 5541 },
    { "Name": "noseCurve", "val": 8068 },
    { "Name": "noseInclination", "val": 6513 },
    { "Name": "nosePosition", "val": 5055 },
    { "Name": "nosePronounced", "val": 6269 },
    { "Name": "noseFlatten", "val": 4160 },
    { "Name": "chinSize", "val": 4779 },
    { "Name": "chinPronounced", "val": 6299 },
    { "Name": "chinPosition", "val": 6644 },
    { "Name": "mandibleSize", "val": 7208 },
    { "Name": "cheekSize", "val": 3958 },
    { "Name": "lowCheekPronounced", "val": 3888 },
    { "Name": "lipsSize", "val": 3033 },
    { "Name": "mouthSize", "val": 6109 },
    { "Name": "eyeRotation", "val": 3012 },
    { "Name": "eyeSize", "val": 6465 },
    { "Name": "breastSize", "val": 3523 },
    { "Name": "eyeSpacing", "val": 3041 }
  ]
}

Compressed String

  • Avatar Stringëģīë‹Ī ė••ėķ•ė 

  • split 가ëŠĨ한 string 형ė‹. json ėī ė•„님.

    • compressedStringėœžëĄœ ė œėž‘ ė‹œ split 하ęļ°ėœ„í•œ ęļ°í˜ļ ė„ļ팅í•īėĪ˜ė•ž í•Ļ.(ęļ°ëģļ " \ ")

  • ėŧŽëŸŽí‘œė‹œ 16ė§„ėˆ˜.

  • ė‚ŽėīėĶˆę°€ 가ėžĨ ėž‘ėŒ.

Compressed String

AA*|R:HumanFemale|W:FemaleTankTop_Recipe,FemaleTallShoes_White,FemaleLongHair_Recipe,FemalePants2,FemaleUndies,|C:Hair,3=0,FF351900;|C:Eyes,3=0,FFD54EDD;2,FFFFFFFF,9A221F1F;|C:Skin,3=0,FFCCCAC2;2,FFFFFFFF,3E100000;|C:Pants1,3=0,FF381E08;|C:Pants,3=2,FFFFFFFF,5D1E1E1E;|C:Lipstick,3=0,FF240000;|C:Shirt,1=0,FF5EAC4B;|C:Pants Accent,3=0,FFECD46D;2,FFFFFFFF,9A221F1F;|C:Undies,3=0,FFEA284D;|D:height=11FA;headWidth=1559;upperWeight=19A8;lowerWeight=1877;legsSize=13D1;belly=1666;noseSize=15A5;noseCurve=1F84;noseInclination=1971;nosePosition=13BF;nosePronounced=187D;noseFlatten=1040;chinSize=12AB;chinPronounced=189B;chinPosition=19F4;mandibleSize=1C28;cheekSize=F76;lowCheekPronounced=F30;lipsSize=BD9;mouthSize=17DD;eyeRotation=BC4;eyeSize=1941;breastSize=DC3;eyeSpacing=BE1;|

AA*
R:HumanFemale
W:FemaleShirt3,FemaleTallShoes_White,FemaleHair2,FemaleSportPants_Recipe,FemaleUndies,
C:Hair,3=0,FF2D1010;
C:Eyes,3=0,FF46FF1D;2,FFFFFFFF,9A221F1F;
C:Skin,3=0,FFFFE5E6;
C:Pants1,3=0,FF376AB9;
C:Undies,3=2,FFFFFFFF,80BFBFBF;
C:Shirt,3=0,FFFBFBFB;2,FFFFFFFF,85FFFFFF;
C:Pants,3=0,FF1C1A18;
C:Pants Accent,3=0,FFD39E65;2,FFFFFFFF,9A221F1F;
C:Lipstick,3=0,FFFF0000;2,FFFFFFFF,92880000;
C:Shirt1,3=0,FFE43737;
D:height=1726;headWidth=176A;upperWeight=1335;lowerWeight=1651;legsSize=137A;belly=1B5B;noseSize=154C;noseCurve=1D4C;noseInclination=ED8;nosePosition=158B;nosePronounced=FDC;noseFlatten=1111;chinSize=1414;chinPronounced=1D16;chinPosition=160E;mandibleSize=11F8;cheekSize=19A4;lowCheekPronounced=97F;lipsSize=E64;mouthSize=1C5D;eyeRotation=228D;eyeSize=1D8D;breastSize=578;breastCleavage=1E64;eyeSpacing=1B07;

4. Unity Editor ė—ė„œ Save / Load

  • 런타ėž„ ė‹œ ė ėšĐėī 된ë‹Ī.

Last updated