public override void Render(ref GameObject targetObject, RenderContext renderContext, GameObject parentObject) { targetObject = renderContext.OccupyObject(Guid, name, parentObject); if (targetObject != null) { if (!PrefabUtility.IsAnyPrefabInstanceRoot(targetObject)) { Debug.LogWarning($"CreateInstanceだが、プレハブのインスタンスではない:{targetObject.name}"); // 使われないように xd guidを書き換え var xdGuidComponent = targetObject.GetComponent <XdGuid>(); if (xdGuidComponent != null) { xdGuidComponent.guid = "old:" + xdGuidComponent.guid; } // Freeに戻す renderContext.AddFreeObject(targetObject); // 見つからなかったことにする targetObject = null; } } if (targetObject == null) { // 見つからなかった場合は プレハブの生成をする var path = EditorUtil.GetOutputPrefabsFolderAssetPath() + "/" + master + ".prefab"; var prefabObject = AssetDatabase.LoadAssetAtPath <GameObject>(path); if (prefabObject == null) { // 読み込むPrefabが存在しなかった // ダミーのPrefabを作成する Debug.LogWarning($"[{Importer.NAME}] {master}.prefab not found. Create a temporary prefab. path:{path}"); var tempObject = new GameObject("temporary object"); tempObject.AddComponent <RectTransform>(); // ダミーとわかるようにmagentaイメージを置く -> non-destructiive importで、このイメージを採用してしまうためコメントアウト // var image = tempObject.AddComponent<Image>(); // image.color = Color.magenta; // フォルダの用意 EditorUtil.CreateFolder(path.Substring(0, path.LastIndexOf('/'))); // prefabの作成 var savedAsset = PrefabUtility.SaveAsPrefabAsset(tempObject, path); AssetDatabase.Refresh(); // Debug.Log($"[{Importer.Name}] Created temporary prefab. {path}", savedAsset); Object.DestroyImmediate(tempObject); prefabObject = AssetDatabase.LoadAssetAtPath <GameObject>(path); } // 仮のプレハブをセットする targetObject = PrefabUtility.InstantiatePrefab(prefabObject) as GameObject; } var rect = ElementUtil.GetOrAddComponent <RectTransform>(targetObject); if (parentObject != null) { /* * if (PrefabUtility.IsPartOfPrefabInstance(parentObject)) * { * Debug.Log($"parent part of prefab:{parentObject.name}"); * } */ rect.SetParent(null); rect.SetParent(parentObject.transform); } if (renderContext.OptionAddXdGuidComponent) { // PrehabのXdGuidにインスタンスGuidを書き込む // 注意点: // 仮プレハブに書き込んだ場合、正規のプレハブが生成されたとき、 // インスタンスGUIDがPrefabGuidにもどってしまうかもしれない var xdGuid = ElementUtil.GetOrAddComponent <XdGuid>(targetObject); xdGuid.guid = Guid; } targetObject.name = Name; /* * ElementUtil.SetLayer(targetObject, Layer); * ElementUtil.SetupRectTransform(targetObject, RectTransformJson); * if (Active != null) targetObject.SetActive(Active.Value); * ElementUtil.SetupLayoutElement(targetObject, LayoutElementJson); */ // Nested Prefab Creator var prefabCreator = new PrefabCreator(null); // Groupに変更しないと再帰が延々と繰り返される instanceRootJson["type"] = "Group"; var subRenderContext = new RenderContext(renderContext.SpriteOutputFolderAssetPath, renderContext.FontFolderAssetPath, targetObject); prefabCreator.Create(ref targetObject, subRenderContext, instanceRootJson); }
/// <summary> /// Assetディレクトリに追加されたファイルを確認、インポート処理を行う /// </summary> /// <param name="importedAssetPaths"></param> /// <param name="optionOverwriteImport"></param> /// <param name="optionDeleteImportedAssets"></param> private static async Task <int> Import(string baseFolderPath, IEnumerable <string> importedAssetPaths, bool optionOverwriteImport, bool optionDeleteImportedAssets) { var importedPaths = importedAssetPaths.ToList(); _progressTotal = importedPaths.Count(); if (_progressTotal == 0) { return(0); } _progressCount = 0; // Png->Spriteに変換するリストをクリアする PreprocessTexture.SlicedTextures = null; // インポートされたファイルからフォルダパスリストを作成する // Key: AssetPath // Value: ディレクトリにあるファイルの拡張子 var importedFolderAssetPaths = new FolderInfos(); foreach (var importedAssetPath in importedAssetPaths) { if (EditorUtil.IsFolder(importedAssetPath) == true) { // すでにフォルダパスはスルー continue; } var folderPath = Path.GetDirectoryName(importedAssetPath); var extension = Path.GetExtension(importedAssetPath); importedFolderAssetPaths.Add(folderPath, extension); } // 出力フォルダの作成 foreach (var importedFolderInfo in importedFolderAssetPaths) { if (EditorUtil.IsFolder(importedFolderInfo.Key) != true) { continue; } // フォルダであった場合 var importedFullPath = Path.GetFullPath(importedFolderInfo.Key); var subFolderName = EditorUtil.GetSubFolderName(baseFolderPath, importedFolderInfo.Key + "/file.tmp"); // このフォルダには.pngファイルがあるか var isSpriteFolder = importedFolderInfo.Value.Contains(".png"); // スプライト出力フォルダの準備 if (isSpriteFolder) { var outputSpritesFolderAssetPath = Path.Combine( EditorUtil.GetOutputSpritesFolderAssetPath(), subFolderName); if (Directory.Exists(outputSpritesFolderAssetPath)) { // フォルダがすでにある インポートファイルと比較して、出力先にある必要のないファイルを削除する // ダブっている分は比較し、異なっている場合に上書きするようにする var outputFolderInfo = new DirectoryInfo(outputSpritesFolderAssetPath); var importFolderInfo = new DirectoryInfo(importedFullPath); var existSpritePaths = outputFolderInfo.GetFiles("*.png", SearchOption.AllDirectories); var importSpritePaths = importFolderInfo.GetFiles("*.png", SearchOption.AllDirectories); // outputフォルダにある importにはないファイルをリストアップする // そしてそれを削除するという処理であったが不具合が発生する // 別のLayout.Jsonから参照されているテクスチャも消えてしまう // テクスチャについて未使用を削除するには // - フォルダを消して再インポート // - imageHashMapキャッシュファイルからつかわれていないものを削除する という処理をいれなければならない // var deleteEntries = existSpritePaths.Except(importSpritePaths, new FileInfoComparer()).ToList(); var deleteEntries = new List <FileInfo>(); // スプライト出力フォルダがすでにある場合はTextureハッシュキャッシュを削除する deleteEntries.Add(new FileInfo(outputSpritesFolderAssetPath + "/" + TextureUtil.ImageHashMapCacheFileName)); deleteEntries.Add(new FileInfo(outputSpritesFolderAssetPath + "/" + TextureUtil.ImagePathMapCacheFileName)); if (!optionOverwriteImport) { // 削除する foreach (var fileInfo in deleteEntries) { AssetDatabase.DeleteAsset(EditorUtil.ToAssetPath(fileInfo.FullName)); } } } else { // Debug.Log($"[{Importer.Name}] Create Folder: {subFolderName}"); EditorUtil.CreateFolder(outputSpritesFolderAssetPath); } } var outputPrefabsFolderAssetPath = Path.Combine(EditorUtil.GetOutputPrefabsFolderAssetPath(), subFolderName); if (!Directory.Exists(outputPrefabsFolderAssetPath)) { EditorUtil.CreateFolder(outputPrefabsFolderAssetPath); } UpdateDisplayProgressBar($"Import Folder Preparation: {subFolderName}"); } await Task.Delay(1000); // ディレクトリが作成されたり、画像が削除されるためRefresh AssetDatabase.Refresh(); // フォルダが作成され、そこに画像を出力する場合 // Refresh後、DelayCallで画像生成することで、処理が安定した // await Task.Delay(1000); // SpriteイメージのハッシュMapをクリアしたかどうかのフラグ // importedAssetsに一気に全部の新規ファイルが入ってくる前提の処理 // 全スライス処理が走る前、最初にClearImageMapをする var clearedImageMap = false; // 画像コンバート スライス処理 var messageCounter = new Dictionary <string, int>(); var total = 0; try { foreach (var pngAssetPath in importedPaths) { // Debug.Log($"Slice: {importedAsset}"); if (!pngAssetPath.EndsWith(".png", StringComparison.Ordinal)) { continue; } // if (!clearedImageMap) { clearedImageMap = true; } var subFolderName = EditorUtil.GetSubFolderName(baseFolderPath, pngAssetPath); var outputFolderPath = Path.Combine(EditorUtil.GetOutputSpritesFolderAssetPath(), subFolderName); var outputFilePath = Path.Combine(outputFolderPath, Path.GetFileName(pngAssetPath)); // スライス処理 var message = TextureUtil.SliceSprite(outputFilePath, pngAssetPath); total++; _progressCount += 2; // pngファイル と png.jsonファイル UpdateDisplayProgressBar(message); // 出力されたログをカウントする if (messageCounter.ContainsKey(message)) { messageCounter[message] = messageCounter[message] + 1; } else { messageCounter.Add(message, 1); } } } catch (Exception ex) { Debug.LogAssertion(ex.Message); Debug.LogAssertion(ex.StackTrace); } foreach (var keyValuePair in messageCounter) { Debug.Log($"[{Importer.NAME}] {keyValuePair.Key} {keyValuePair.Value}/{total}"); } var importLayoutFilePaths = new List <string>(); foreach (var layoutFilePath in importedPaths) { if (!layoutFilePath.EndsWith(".layout.json", StringComparison.OrdinalIgnoreCase)) { continue; } importLayoutFilePaths.Add(layoutFilePath); } string GetPrefabPath(string layoutFilePath) { var prefabFileName = Path.GetFileName(layoutFilePath).Replace(".layout.json", "") + ".prefab"; var subFolderName = EditorUtil.GetSubFolderName(baseFolderPath, layoutFilePath); var saveAssetPath = Path.Combine(Path.Combine(EditorUtil.GetOutputPrefabsFolderAssetPath(), subFolderName), prefabFileName); return(saveAssetPath); } string GetPrefabName(string layoutFilePath) { var prefabFileName = Path.GetFileName(layoutFilePath).Replace(".layout.json", ""); var subFolderName = EditorUtil.GetSubFolderName(baseFolderPath, layoutFilePath); return(subFolderName + "/" + prefabFileName); } // 出力されたスライスPNGをSpriteに変換する処理を走らせるために必須 // ここでPreprocessTextureが実行されなければいけない AssetDatabase.Refresh(); await Task.Delay(1000); if (PreprocessTexture.SlicedTextures != null && PreprocessTexture.SlicedTextures.Count != 0) { // Debug.LogWarning($"[{Importer.Name}] SlicedTextures is still available."); } var prefabs = new List <GameObject>(); // .layout.jsonを全て読み込んで、コンバート順をソートする // Item1: prefab name dependensyチェック用 // Item2: file path // Item3: json data var layoutJsons = new List <Tuple <string, string, Dictionary <string, object> > >(); foreach (var layoutFilePath in importLayoutFilePaths) { var prefabName = GetPrefabName(layoutFilePath); // Load JSON var jsonText = File.ReadAllText(layoutFilePath); var json = Json.Deserialize(jsonText) as Dictionary <string, object>; layoutJsons.Add( new Tuple <string, string, Dictionary <string, object> >(prefabName, layoutFilePath, json)); } // コンバートする順番を決める layoutJsons.Sort((a, b) => { List <object> GetDependency(Dictionary <string, object> json) { return(json.GetDic("info")?.GetArray("dependency")); } int GetDependencyCount(Dictionary <string, object> json) { var dr = GetDependency(json); return(dr?.Count ?? 0); } bool Check(string name, Dictionary <string, object> json) { var nameList = GetDependency(json); if (nameList == null) { return(false); } return(nameList.Any(o => name == o as string)); } // aはbより先に処理すべきか if (Check(a.Item1, b.Item3)) { return(-1); } // bはaより先に処理すべきか if (Check(b.Item1, a.Item3)) { return(1); } // 依存ファイル数で決着をつける return(GetDependencyCount(a.Item3) - GetDependencyCount(b.Item3)); }); // Create Prefab foreach (var layoutJson in layoutJsons) { UpdateDisplayProgressBar($"Layout: {layoutJson.Item1}"); _progressCount += 1; var layoutFilePath = layoutJson.Item2; var subFolderName = EditorUtil.GetSubFolderName(baseFolderPath, layoutFilePath); GameObject go = null; try { // Debug.Log($"[{Importer.Name}] in process...{Path.GetFileName(layoutFilePath)}"); var saveAssetPath = GetPrefabPath(layoutFilePath); var spriteOutputFolderAssetPath = Path.Combine(EditorUtil.GetOutputSpritesFolderAssetPath(), subFolderName); var fontAssetPath = EditorUtil.GetFontsFolderAssetPath(); // overwriteImportFlagがTrueなら、ベースとなるPrefab上に生成していく // 利用できるオブジェクトは利用していく if (optionOverwriteImport) { // すでにあるプレハブを読み込む var prefab = AssetDatabase.LoadAssetAtPath <GameObject>(saveAssetPath); if (prefab != null) { go = PrefabUtility.InstantiatePrefab(prefab) as GameObject; PrefabUtility.UnpackPrefabInstance(go, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction); } } // Render Context var renderContext = new RenderContext(spriteOutputFolderAssetPath, fontAssetPath, go); if (optionOverwriteImport) { renderContext.OptionAddXdGuidComponent = true; } // Load JSON var jsonText = File.ReadAllText(layoutFilePath); var json = Json.Deserialize(jsonText) as Dictionary <string, object>; //var info = json.GetDic("info"); //Validation(info); var rootJson = json.GetDic("root"); // Create Prefab var prefabCreator = new PrefabCreator(prefabs); prefabCreator.Create(ref go, renderContext, rootJson); // Save Prefab EditorUtil.CreateFolder(Path.GetDirectoryName(saveAssetPath)); var savedAsset = PrefabUtility.SaveAsPrefabAsset(go, saveAssetPath); Debug.Log($"[{Importer.NAME}] Created: <color=#7FD6FC>{Path.GetFileName(saveAssetPath)}</color>", savedAsset); } catch (Exception ex) { Debug.LogAssertion($"[{Importer.NAME}] " + ex.Message + "\n" + ex.StackTrace); // 変換中例外が起きた場合もテンポラリGameObjectを削除する EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("Import Failed", ex.Message, "Close"); throw; } finally { Object.DestroyImmediate(go); } AssetDatabase.Refresh(); await Task.Delay(100); } // インポートしたファイルを削除し、そのフォルダが空になったらフォルダも削除する if (optionDeleteImportedAssets) { foreach (var forImportAssetPath in importedAssetPaths) { // フォルダの場合はスルー if (EditorUtil.IsFolder(forImportAssetPath) == true) { continue; } // インポートするファイルを削除 AssetDatabase.DeleteAsset(forImportAssetPath); // ファイルがあったフォルダが空になったかチェック var folderName = Path.GetDirectoryName(forImportAssetPath); var files = Directory.GetFiles(folderName); if (files.Length == 0) { // フォルダの削除 // Debug.Log($"ディレクトリ削除{folderName}"); AssetDatabase.DeleteAsset(folderName); } } } AssetDatabase.Refresh(); EditorUtility.ClearProgressBar(); return(0); }