public static void CreateFontReplacement()
        {
            var sids = Selection.instanceIDs;

            if (sids != null && sids.Length > 0)
            {
                bool found        = false;
                Font selectedFont = null;
                int  fid          = 0;
                for (int i = sids.Length - 1; i >= 0; --i)
                {
                    var sid = sids[i];
                    var obj = EditorUtility.InstanceIDToObject(sid);
                    if (obj is Font)
                    {
                        var font = obj as Font;
                        try
                        {
                            var fi = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(font)) as TrueTypeFontImporter;
                            if (fi != null)
                            {
                                if (!_PHFontNameToAssetName.ContainsKey(fi.fontTTFName))
                                {
                                    selectedFont = font;
                                    break;
                                }
                            }
                        }
                        catch { }
                    }
                }
                for (int i = sids.Length - 1; i >= 0; --i)
                {
                    var sid = sids[i];
                    if (ProjectWindowUtil.IsFolder(sid))
                    {
                        fid   = sid;
                        found = true;
                        break;
                    }
                }
                string folder;
                if (!found)
                {
                    folder = ProjectWindowUtil.GetContainingFolder(AssetDatabase.GetAssetPath(EditorUtility.InstanceIDToObject(sids[0])));
                }
                else
                {
                    folder = AssetDatabase.GetAssetPath(EditorUtility.InstanceIDToObject(fid));
                }
                var asset = folder;
                folder = CapsModEditor.GetAssetPath(folder); // this seems to be useless. Unity's System.IO lib can handle path like Packages/cn.capstones.phfont/xxx

                var desc = ScriptableObject.CreateInstance <CapsFontReplacement>();
                desc.PlaceHolderFontName = GetFontReplacementPHFontName(asset) ?? "CapstonesPHFont00000";
                desc.SubstituteFont      = selectedFont;

                var fileName = "FontReplacement";
                if (PlatDependant.IsFileExist(folder + "/" + fileName + ".fr.asset"))
                {
                    for (int i = 0; ; ++i)
                    {
                        fileName = "FontReplacement" + i;
                        if (!PlatDependant.IsFileExist(folder + "/" + fileName + ".fr.asset"))
                        {
                            break;
                        }
                    }
                }

                AssetDatabase.CreateAsset(desc, asset + "/" + fileName + ".fr.asset");
                AssetDatabase.ImportAsset(asset + "/" + fileName + ".fr.asset");
            }
        }
        public static void CreatePlaceHolderFont()
        {
            var srcpath = CapsModEditor.GetPackageOrModRoot(CapsEditorUtils.__MOD__);

            srcpath += "/~Tools~/CapstonesPlaceHolder.otf";

            if (PlatDependant.IsFileExist(srcpath))
            {
                var sids = Selection.instanceIDs;
                if (sids != null && sids.Length > 0)
                {
                    bool found = false;
                    int  fid   = 0;
                    for (int i = sids.Length - 1; i >= 0; --i)
                    {
                        var sid = sids[i];
                        if (ProjectWindowUtil.IsFolder(sid))
                        {
                            fid   = sid;
                            found = true;
                            break;
                        }
                    }
                    string folder;
                    if (!found)
                    {
                        folder = ProjectWindowUtil.GetContainingFolder(AssetDatabase.GetAssetPath(EditorUtility.InstanceIDToObject(sids[0])));
                    }
                    else
                    {
                        folder = AssetDatabase.GetAssetPath(EditorUtility.InstanceIDToObject(fid));
                    }
                    var asset = folder;
                    folder = CapsModEditor.GetAssetPath(folder); // this seems to be useless. Unity's System.IO lib can handle path like Packages/cn.capstones.phfont/xxx

                    string fontName = "";
                    string fileName;

                    for (int i = 1; i <= 99999; ++i)
                    {
                        fontName = "CapstonesPHFont" + i.ToString("00000");
                        if (!_PHFontNameToAssetName.ContainsKey(fontName))
                        {
                            break;
                        }
                    }
                    fileName = fontName;
                    if (PlatDependant.IsFileExist(folder + "/" + fileName + ".otf"))
                    {
                        for (int i = 0; ; ++i)
                        {
                            fileName = fontName + "_" + i;
                            if (!PlatDependant.IsFileExist(folder + "/" + fileName + ".otf"))
                            {
                                break;
                            }
                        }
                    }

                    PlatDependant.CopyFile(srcpath, folder + "/" + fileName + ".otf");

                    // Modify the otf file.
                    using (var stream = PlatDependant.OpenAppend(folder + "/" + fileName + ".otf"))
                    {
                        stream.Seek(0x3cc, System.IO.SeekOrigin.Begin);
                        var buffer = System.Text.Encoding.ASCII.GetBytes(fontName);
                        stream.Write(buffer, 0, buffer.Length);
                        stream.Seek(0x4d0, System.IO.SeekOrigin.Begin);
                        buffer = System.Text.Encoding.BigEndianUnicode.GetBytes(fontName);
                        stream.Write(buffer, 0, buffer.Length);
                    }
                    AssetDatabase.ImportAsset(asset + "/" + fileName + ".otf");

                    PlatDependant.CopyFile(asset + "/" + fileName + ".otf", asset + "/" + fileName + ".otf.~");
                    PlatDependant.CopyFile(asset + "/" + fileName + ".otf.meta", asset + "/" + fileName + ".otf.meta.~");

                    AssetDatabase.CreateAsset(ScriptableObject.CreateInstance <CapsPHFontDesc>(), asset + "/" + fileName + ".phf.asset");
                    AssetDatabase.ImportAsset(asset + "/" + fileName + ".phf.asset");
                    AddPHFont(asset + "/" + fileName + ".phf.asset");
                    SaveCachedPHFonts();
                }
            }
        }