在 unity 中,我有一个 UMA 角色创建器。
最后它给了我一个头像配方,可以让我加载保存的角色。
我想把这个头像食谱保存到我的mysql数据库中。
所以我将配方传递给服务器上的存储过程并尝试保存它,但它不会加载,因为转义字符已被删除。
这是一个例子:
这是一个有效的 UMA 食谱:
{"packedRecipeType":"DynamicCharacterAvatar","name":"Player","race":"HumanMaleDCS","dna":[{"dnaType":"DynamicUMADna","dnaTypeHash":815443803,"packedDna":"{\"bDnaAsset\":{\"instanceID\":26992},\"bDnaAssetName\":\"HumanMaleDynamicDnaAsset\",\"bDnaSettings\":[{\"name\":\"skinGreenness\",\"value\":128}, etc... it goes on like that for a long time
但在我的数据库中它看起来像这样:
{"packedRecipeType":"DynamicCharacterAvatar","name":"Player","race":"HumanMaleDCS","dna":[{"dnaType":"DynamicUMADna","dnaTypeHash":815443803,"packedDna":"{"bDnaAsset":{"instanceID":26992},"bDnaAssetName":"HumanMaleDynamicDnaAsset","bDnaSettings":[{"name":"skinGreenness","value":128}, etc..
这是关键的区别
\"bDnaAssetName\"
变为 "bDnaAssetName"
和
\"HumanMaleDynamicDnaAsset\"
变为 "HumanMaleDynamicDnaAsset"
等等……
\(s)消失了!!!
所以:
我可以保存这个带有所有反斜杠的字符串,以便在我重新加载它时它能正常工作吗?
这是个好主意吗?我是在自找麻烦吗?有没有更好的方法将 UMA 食谱保存到我的数据库?
我在将食谱保存为 postgresql 中的 json 字段时遇到了类似的问题。问题来自 UMA 开发人员将 json 包装在 json 中。它本质上是一个嵌套的 json 字符串,只会导致问题。我几个月前就告诉过他们,并发布了一些代码来提供帮助,但我认为他们从未更新过它。
在任何情况下,我的代码都会通过将配方的外部 json 转换为泛型来评估问题的根源,并保留内部的。它仍然有点 hack,因为我必须再次嵌套 json 才能加载食谱。这是代码,您可以将其放在 Assets 文件夹中的任何位置:
// Brought to you by Tarball 5/28/2019
// Drop in Asset folder to save your UMA data to generic types
// Call public methods from any script
using UMA.CharacterSystem;
using System.Collections.Generic;
using System.Linq;
namespace UMA
{
namespace EasyMode
{
public static class EasyUMA
{
public static List<UMAPackedRecipeBase.UMAPackedDna> dnaPackedRecipe = new List<UMAPackedRecipeBase.UMAPackedDna>();
public static UMAPackedRecipeBase.UMAPackedDna packedDna = new UMAPackedRecipeBase.UMAPackedDna();
public static Dictionary<int, Dictionary<string, string>> DNAInfo = new Dictionary<int, Dictionary<string, string>>();
public static Dictionary<string, short[]> colorRecipe = new Dictionary<string, short[]>();
public static Dictionary<string, string> wardrobeRecipe = new Dictionary<string, string>();
public static UMATextRecipe.DCSPackRecipe totalRecipe = new UMATextRecipe.DCSPackRecipe();
public static bool saveAsMale;
public static string[] colorNames;
public static short[][] colorData;
private static DynamicCharacterAvatar.SaveOptions saveOptions = DynamicCharacterAvatar.SaveOptions.saveDNA
| DynamicCharacterAvatar.SaveOptions.saveColors | DynamicCharacterAvatar.SaveOptions.saveWardrobe;
private static Dictionary<string, string> wardrobe_slots = new Dictionary<string, string>();
private static Dictionary<string, short[]> UMA_colors = new Dictionary<string, short[]>();
private static List<UMAPackedRecipeBase.UMAPackedDna> dnaList = new List<UMAPackedRecipeBase.UMAPackedDna>();
// Returns the current DCSPackRecipe from a DynamicCharacterAvatar
private static UMATextRecipe.DCSPackRecipe packedRecipe(DynamicCharacterAvatar currentAvatar)
{
if (currentAvatar != null)
{
return new UMATextRecipe.DCSPackRecipe(currentAvatar, currentAvatar.name, "DynamicCharacterAvatar", saveOptions);
}
else return null;
}
/// <summary>
/// Returns a Dictionary with raw DNA information for saving in c# generic types
/// </summary>
public static Dictionary<int, Dictionary<string, string>> PrintDNADictionary(DynamicCharacterAvatar dynamicCharacterAvatar)
{
if (dynamicCharacterAvatar != null)
{
dnaList = packedRecipe(dynamicCharacterAvatar).dna;
if (dnaList != null && dnaList.Count != 0)
{
Dictionary<string, string> tempStrings = new Dictionary<string, string>();
Dictionary<int, Dictionary<string, string>> tempDict = new Dictionary<int, Dictionary<string, string>>();
tempStrings.Add(dnaList.First().dnaType, dnaList.First().packedDna);
tempDict.Add(dnaList.First().dnaTypeHash, tempStrings);
return tempDict;
}
else return null;
}
else return null;
}
/// <summary>
/// Returns a Dictionary with wardrobe information in the format: (string wardrobe_slot_name, string wardrobe_item_name), for example ("Chest", "BreastPlate001")
/// </summary>
public static Dictionary<string, string> PrintWardrobe(DynamicCharacterAvatar dynamicCharacterAvatar)
{
if (dynamicCharacterAvatar != null)
{
var recipe = packedRecipe(dynamicCharacterAvatar);
wardrobe_slots.Clear();
foreach (WardrobeSettings wardrobe_item in recipe.wardrobeSet)
{
wardrobe_slots.Add(wardrobe_item.slot, wardrobe_item.recipe);
}
return wardrobe_slots;
}
else return null;
}
/// <summary>
/// Returns a Dictionary with shared color information (string color_name, short[] RGBA_numbers)
/// </summary>
public static Dictionary<string, short[]> PrintColors(DynamicCharacterAvatar dynamicCharacterAvatar)
{
if (dynamicCharacterAvatar != null)
{
var recipe = packedRecipe(dynamicCharacterAvatar);
colorNames = new string[recipe.characterColors.Count];
colorData = new short[recipe.characterColors.Count][];
int i = 0;
UMA_colors.Clear();
foreach (UMAPackedRecipeBase.PackedOverlayColorDataV3 charColors in recipe.characterColors)
{
UMA_colors.Add(charColors.name, charColors.colors);
colorNames[i] = charColors.name;
colorData[i] = charColors.colors;
i++;
}
return UMA_colors;
}
else return null;
}
/// <summary>
/// Returns the full recipe as a DCSPackRecipe
/// </summary>
public static UMATextRecipe.DCSPackRecipe gatherFullRecipe(DynamicCharacterAvatar currentAvatar, bool isMale,
Dictionary<int, Dictionary<string, string>> DNAInfo, Dictionary<string, short[]> colorsData, Dictionary<string, string> wardrobeData)
{
UMATextRecipe.DCSPackRecipe recipe = new UMATextRecipe.DCSPackRecipe();
UMAPackedRecipeBase.UMAPackedDna item = new UMAPackedRecipeBase.UMAPackedDna();
if (DNAInfo != null && DNAInfo.Count != 0)
{
item.dnaTypeHash = DNAInfo.First().Key;
item.dnaType = DNAInfo.First().Value.First().Key;
item.packedDna = DNAInfo.First().Value.First().Value;
List<UMAPackedRecipeBase.UMAPackedDna> senselessList = new List<UMAPackedRecipeBase.UMAPackedDna>();
senselessList.Add(item);
recipe.dna = senselessList;
}
if (isMale)
recipe.race = "HumanMale";
else recipe.race = "HumanFemale";
if (colorsData != null && colorsData.Count != 0)
{
UMAPackedRecipeBase.PackedOverlayColorDataV3[] overlays = new UMAPackedRecipeBase.PackedOverlayColorDataV3[colorsData.Count];
recipe.characterColors = new List<UMAPackedRecipeBase.PackedOverlayColorDataV3>();
int i = 0;
foreach (var uniqueColor in colorsData)
{
overlays[i] = new UMAPackedRecipeBase.PackedOverlayColorDataV3();
overlays[i].name = uniqueColor.Key;
overlays[i].colors = uniqueColor.Value;
recipe.characterColors.Add(overlays[i]);
i++;
}
}
if (wardrobeData != null && wardrobeData.Count != 0)
{
WardrobeSettings[] wardrobeInfo = new WardrobeSettings[wardrobeData.Count];
recipe.wardrobeSet = new List<WardrobeSettings>();
int i = 0;
foreach (var wardrobePiece in wardrobeData)
{
wardrobeInfo[i] = new WardrobeSettings();
wardrobeInfo[i].slot = wardrobePiece.Key;
wardrobeInfo[i].recipe = wardrobePiece.Value;
recipe.wardrobeSet.Add(wardrobeInfo[i]);
i++;
}
}
return recipe;
}
}
}
}
现在,您应该可以在任何数据库中进行保存,而不会有太多麻烦。然而,现在这个食谱被分成了几部分。要保存/加载,只需将此代码片段放入处理保存和加载的脚本中:
private DynamicCharacterAvatar avatar;
public void SaveRecipe()
{
EasyUMA.DNAInfo = EasyUMA.PrintDNADictionary(avatar);
EasyUMA.colorRecipe = EasyUMA.PrintColors(avatar);
EasyUMA.wardrobeRecipe = EasyUMA.PrintWardrobe(avatar);
if (avatar.umaData.umaRecipe.raceData.raceName == "HumanMale")
EasyUMA.saveAsMale = true;
else EasyUMA.saveAsMale = false;
}
public void LoadRecipe()
{
avatar.ClearSlots();
EasyUMA.dnaPackedRecipe.Clear();
EasyUMA.dnaPackedRecipe.Add(EasyUMA.packedDna);
EasyUMA.totalRecipe = EasyUMA.gatherFullRecipe(avatar, EasyUMA.saveAsMale, EasyUMA.DNAInfo, EasyUMA.colorRecipe, EasyUMA.wardrobeRecipe);
var dummyRecipe = JsonUtility.ToJson(EasyUMA.totalRecipe);
avatar.LoadFromRecipeString(dummyRecipe);
}