From 4ff668ee4850afcb196944e245ec797d8be2b6c9 Mon Sep 17 00:00:00 2001 From: papacoder Date: Sat, 22 Nov 2025 08:43:16 +0900 Subject: [PATCH] feat(editor): create actors under active project --- .../FUnity/Editor/GenerateActorUITemplate.cs | 186 +++++++++++++++++- 1 file changed, 178 insertions(+), 8 deletions(-) diff --git a/Assets/FUnity/Editor/GenerateActorUITemplate.cs b/Assets/FUnity/Editor/GenerateActorUITemplate.cs index 4647539..687c796 100644 --- a/Assets/FUnity/Editor/GenerateActorUITemplate.cs +++ b/Assets/FUnity/Editor/GenerateActorUITemplate.cs @@ -85,7 +85,12 @@ private void OnGUI() m_PrimaryColor = EditorGUILayout.ColorField("Primary Color", m_PrimaryColor); var actorName = GetActorName(); var hasValidActorName = !string.IsNullOrEmpty(actorName); - var baseFolderPreview = string.IsNullOrEmpty(m_Folder) ? "Assets/FUnity/Actors" : m_Folder; + var activeProjectActorsFolder = GetActiveProjectActorsFolder(false); + var baseFolderPreview = string.IsNullOrEmpty(m_Folder) ? activeProjectActorsFolder : m_Folder; + if (string.IsNullOrEmpty(baseFolderPreview)) + { + baseFolderPreview = "Assets"; + } var folderValid = IsFolderInAssets(baseFolderPreview); if (!hasValidActorName) @@ -125,19 +130,31 @@ private void CreateFilesAndLink() return; } - var baseFolder = NormalizeFolderPath(m_Folder); - if (string.IsNullOrEmpty(baseFolder)) + if (!TryGetActiveFUnityProject(out var projectData, true)) + { + return; + } + + if (!TryGetActorsFolderPath(projectData, true, out var actorsFolderPath)) { - baseFolder = "Assets/FUnity/Actors"; + return; } + var baseFolder = NormalizeFolderPath(string.IsNullOrEmpty(m_Folder) ? actorsFolderPath : m_Folder); + if (!IsFolderInAssets(baseFolder)) { EditorUtility.DisplayDialog("Error", "Output Folder must be inside the Assets directory.", "OK"); return; } - var actorFolder = ResolveActorFolder(baseFolder, actorName); + if (!IsFolderInsideActorsRoot(baseFolder, actorsFolderPath)) + { + EditorUtility.DisplayDialog("Error", "Output Folder must be inside the current project's Actors folder.", "OK"); + return; + } + + var actorFolder = ResolveActorFolder(baseFolder, actorName, actorsFolderPath); if (!IsFolderInAssets(actorFolder)) { EditorUtility.DisplayDialog("Error", "Actor folder must be inside the Assets directory.", "OK"); @@ -341,7 +358,13 @@ private void SuggestOutputFolder(bool force) return; } - var suggested = $"Assets/FUnity/Actors/{actorName}"; + var activeProjectActorsFolder = GetActiveProjectActorsFolder(false); + if (string.IsNullOrEmpty(activeProjectActorsFolder)) + { + return; + } + + var suggested = $"{activeProjectActorsFolder}/{actorName}"; if (force) { if (string.IsNullOrEmpty(m_Folder)) @@ -403,12 +426,12 @@ private string CombinePath(string folder, string fileName) /// /// 基底フォルダから俳優名サブフォルダを計算し、二重付与を避けた正規化パスを返す。 /// - private string ResolveActorFolder(string baseFolder, string actorName) + private string ResolveActorFolder(string baseFolder, string actorName, string actorsRootFolder) { var normalizedBase = NormalizeFolderPath(baseFolder); if (string.IsNullOrEmpty(normalizedBase)) { - normalizedBase = "Assets/FUnity/Actors"; + normalizedBase = NormalizeFolderPath(actorsRootFolder); } if (normalizedBase.EndsWith($"/{actorName}", System.StringComparison.Ordinal)) @@ -452,6 +475,153 @@ private ScriptGraphAsset CreateScriptGraphAsset(string assetPath) Debug.Log($"[FUnity] Created ScriptGraphAsset: {assetPath}"); return graph; } + + /// + /// 現在のシーンに存在する FUnityManager から ProjectData を取得し、適合しない場合はダイアログ表示を行う。 + /// + /// 取得した 。 + /// 問題発生時にダイアログを表示するかどうか。 + private static bool TryGetActiveFUnityProject(out FUnityProjectData projectData, bool showDialog) + { + projectData = null; + + var managers = Object.FindObjectsOfType(); + if (managers == null || managers.Length == 0) + { + if (showDialog) + { + EditorUtility.DisplayDialog( + "FUnity Actor 作成", + "現在のシーンに FUnityManager が見つかりません。\nFUnityManager を配置してから Actor を作成してください。", + "OK"); + } + + return false; + } + + if (managers.Length > 1) + { + if (showDialog) + { + EditorUtility.DisplayDialog( + "FUnity Actor 作成", + "現在のシーンに複数の FUnityManager が存在します。\n1 つに絞ってから実行してください。", + "OK"); + } + + return false; + } + + var manager = managers[0]; + if (manager.ProjectData == null) + { + if (showDialog) + { + EditorUtility.DisplayDialog( + "FUnity Actor 作成", + "FUnityManager の Project (FUnityProjectData) が設定されていません。\n有効なプロジェクトを設定してから実行してください。", + "OK"); + } + + return false; + } + + projectData = manager.ProjectData; + return true; + } + + /// + /// 指定された ProjectData から Actors フォルダパスを算出し、存在しなければ作成する。 + /// + /// フォルダを導出する 。 + /// 失敗時にダイアログを表示するかどうか。 + /// 算出された Actors フォルダパス。 + private static bool TryGetActorsFolderPath(FUnityProjectData projectData, bool showDialog, out string actorsFolderPath) + { + actorsFolderPath = string.Empty; + if (projectData == null) + { + if (showDialog) + { + EditorUtility.DisplayDialog( + "FUnity Actor 作成", + "FUnityProjectData が null です。", + "OK"); + } + + return false; + } + + var projectDataPath = AssetDatabase.GetAssetPath(projectData); + if (string.IsNullOrEmpty(projectDataPath)) + { + if (showDialog) + { + EditorUtility.DisplayDialog( + "FUnity Actor 作成", + "FUnityProjectData のパスを取得できませんでした。", + "OK"); + } + + return false; + } + + var projectFolder = Path.GetDirectoryName(projectDataPath); + if (string.IsNullOrEmpty(projectFolder)) + { + if (showDialog) + { + EditorUtility.DisplayDialog( + "FUnity Actor 作成", + "FUnityProjectData のフォルダを特定できませんでした。", + "OK"); + } + + return false; + } + + projectFolder = projectFolder.Replace("\\", "/"); + actorsFolderPath = projectFolder + "/Actors"; + + if (!AssetDatabase.IsValidFolder(actorsFolderPath)) + { + AssetDatabase.CreateFolder(projectFolder, "Actors"); + actorsFolderPath = projectFolder + "/Actors"; + } + + return true; + } + + /// + /// 現在アクティブなプロジェクトの Actors フォルダパスを取得し、取得失敗時は空文字を返す。 + /// + /// 問題発生時にダイアログを表示するかどうか。 + private static string GetActiveProjectActorsFolder(bool showDialog) + { + if (!TryGetActiveFUnityProject(out var projectData, showDialog)) + { + return string.Empty; + } + + return TryGetActorsFolderPath(projectData, showDialog, out var actorsFolderPath) ? actorsFolderPath : string.Empty; + } + + /// + /// 指定フォルダが現在のプロジェクト Actors 直下に存在するか判定する。 + /// + /// 判定対象のフォルダ。 + /// 許可される Actors ルートフォルダ。 + private bool IsFolderInsideActorsRoot(string folderPath, string actorsRootFolder) + { + var normalizedFolder = NormalizeFolderPath(folderPath); + var normalizedActorsRoot = NormalizeFolderPath(actorsRootFolder); + if (string.IsNullOrEmpty(normalizedFolder) || string.IsNullOrEmpty(normalizedActorsRoot)) + { + return false; + } + + return normalizedFolder == normalizedActorsRoot || normalizedFolder.StartsWith(normalizedActorsRoot + "/", System.StringComparison.Ordinal); + } } } #endif