First commit for private source control. Older commits available on Github.
This commit is contained in:
19
Assets/Scripts/Editor/BriarQueen.Editor.asmdef
Normal file
19
Assets/Scripts/Editor/BriarQueen.Editor.asmdef
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "BriarQueen.Editor",
|
||||
"rootNamespace": "BriarQueen",
|
||||
"references": [
|
||||
"GUID:bdf0eff65032c4178bf18aa9c96b1c70",
|
||||
"GUID:ac1be664c635c449eb9f3f52cf5c97f5"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
Assets/Scripts/Editor/BriarQueen.Editor.asmdef.meta
Normal file
7
Assets/Scripts/Editor/BriarQueen.Editor.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d63909dd781c643ecbc1295f0dc761a3
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Assets/Scripts/Editor/Drawers.meta
Normal file
3
Assets/Scripts/Editor/Drawers.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1954361a8cce45498b2c8b2888144b5e
|
||||
timeCreated: 1771172177
|
||||
79
Assets/Scripts/Editor/Drawers/BaseInteractionDrawer.cs
Normal file
79
Assets/Scripts/Editor/Drawers/BaseInteractionDrawer.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using BriarQueen.Framework.Managers.Interaction.Data;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Editor.Drawers
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(BaseInteraction), true)]
|
||||
public class BaseItemInteractionDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
if (property.managedReferenceValue == null)
|
||||
{
|
||||
if (GUI.Button(position, "Select Interaction Type"))
|
||||
{
|
||||
ShowTypeMenu(property);
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
return;
|
||||
}
|
||||
|
||||
var type = property.managedReferenceValue.GetType();
|
||||
var headerRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
|
||||
|
||||
if (GUI.Button(headerRect, type.Name, EditorStyles.popup))
|
||||
{
|
||||
ShowTypeMenu(property);
|
||||
}
|
||||
|
||||
var bodyRect = new Rect(
|
||||
position.x,
|
||||
position.y + EditorGUIUtility.singleLineHeight + 2,
|
||||
position.width,
|
||||
position.height - EditorGUIUtility.singleLineHeight - 2);
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUI.PropertyField(bodyRect, property, GUIContent.none, true);
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private void ShowTypeMenu(SerializedProperty property)
|
||||
{
|
||||
var menu = new GenericMenu();
|
||||
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a => a.GetTypes())
|
||||
.Where(t =>
|
||||
!t.IsAbstract &&
|
||||
typeof(BaseInteraction).IsAssignableFrom(t));
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
menu.AddItem(new GUIContent(type.Name), false, () =>
|
||||
{
|
||||
property.serializedObject.Update();
|
||||
property.managedReferenceValue = Activator.CreateInstance(type);
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
}
|
||||
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (property.managedReferenceValue == null)
|
||||
return EditorGUIUtility.singleLineHeight;
|
||||
|
||||
return EditorGUI.GetPropertyHeight(property, true) + EditorGUIUtility.singleLineHeight + 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 627cc55408bb4796839600a1516a5eba
|
||||
timeCreated: 1771172177
|
||||
3
Assets/Scripts/Editor/Drawers/Registries.meta
Normal file
3
Assets/Scripts/Editor/Drawers/Registries.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c40c1262cbd4128a9b3c3446304a845
|
||||
timeCreated: 1773921681
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.Collections.Generic;
|
||||
using BriarQueen.Data.Assets;
|
||||
using BriarQueen.Framework.Registries;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Editor.Drawers.Registries
|
||||
{
|
||||
[CustomEditor(typeof(AssetRegistry))]
|
||||
public class AssetRegistryFill : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Discover AssetEntry Assets"))
|
||||
{
|
||||
Populate((AssetRegistry)target);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Populate(AssetRegistry registry)
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets("t:AssetEntry");
|
||||
|
||||
var scenes = new List<AssetEntry>();
|
||||
var levels = new List<AssetEntry>();
|
||||
var items = new List<AssetEntry>();
|
||||
var ui = new List<AssetEntry>();
|
||||
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var entry = AssetDatabase.LoadAssetAtPath<AssetEntry>(path);
|
||||
|
||||
if (entry == null)
|
||||
continue;
|
||||
|
||||
switch (entry.EntryType)
|
||||
{
|
||||
case AssetEntry.AssetEntryType.Scene:
|
||||
scenes.Add(entry);
|
||||
break;
|
||||
|
||||
case AssetEntry.AssetEntryType.Level:
|
||||
levels.Add(entry);
|
||||
break;
|
||||
|
||||
case AssetEntry.AssetEntryType.Item:
|
||||
items.Add(entry);
|
||||
break;
|
||||
|
||||
case AssetEntry.AssetEntryType.UI:
|
||||
ui.Add(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scenes.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
levels.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
items.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
ui.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
|
||||
Undo.RecordObject(registry, "Discover AssetEntry Assets");
|
||||
registry.SetDiscoveredEntries(scenes, levels, items, ui);
|
||||
EditorUtility.SetDirty(registry);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
Debug.Log($"[AssetRegistry] Discovery complete. Scenes: {scenes.Count}, Levels: {levels.Count}, Items: {items.Count}, UI: {ui.Count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f49114100e741bb849cbdfb5fc457cc
|
||||
timeCreated: 1773602794
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Framework.Managers.Player.Data;
|
||||
using BriarQueen.Framework.Registries;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Editor.Drawers.Registries
|
||||
{
|
||||
[CustomEditor(typeof(CodexRegistry))]
|
||||
public class CodexRegistryFill : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Discover Codex Entry Assets"))
|
||||
{
|
||||
Populate((CodexRegistry)target);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Populate(CodexRegistry registry)
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets("t:CodexEntrySo");
|
||||
|
||||
var books = new List<CodexEntrySo>();
|
||||
var clues = new List<CodexEntrySo>();
|
||||
var photos = new List<CodexEntrySo>();
|
||||
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var entry = AssetDatabase.LoadAssetAtPath<CodexEntrySo>(path);
|
||||
|
||||
if (entry == null)
|
||||
continue;
|
||||
|
||||
switch (entry.EntryType)
|
||||
{
|
||||
case CodexType.BookEntry:
|
||||
books.Add(entry);
|
||||
break;
|
||||
|
||||
case CodexType.PuzzleClue:
|
||||
clues.Add(entry);
|
||||
break;
|
||||
|
||||
case CodexType.Photo:
|
||||
photos.Add(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
books.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
clues.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
photos.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
|
||||
Undo.RecordObject(registry, "Discover Codex Assets");
|
||||
registry.SetDiscoveredEntries(books, clues, photos);
|
||||
EditorUtility.SetDirty(registry);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
Debug.Log($"[AssetRegistry] Discovery complete. Books: {books.Count}, Clues: {clues.Count}, Photos: {photos.Count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04adf387d1e94429a6c320005150cb90
|
||||
timeCreated: 1773921705
|
||||
69
Assets/Scripts/Editor/Drawers/Registries/ItemRegistryFill.cs
Normal file
69
Assets/Scripts/Editor/Drawers/Registries/ItemRegistryFill.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using BriarQueen.Framework.Managers.Player.Data;
|
||||
using BriarQueen.Framework.Registries;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Editor.Drawers.Registries
|
||||
{
|
||||
[CustomEditor(typeof(ItemRegistry))]
|
||||
public class ItemRegistryFill : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Discover Item Assets"))
|
||||
{
|
||||
Populate((ItemRegistry)target);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Populate(ItemRegistry registry)
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets("t:ItemDataSo");
|
||||
|
||||
var puzzleSlots = new List<ItemDataSo>();
|
||||
var pickupItems = new List<ItemDataSo>();
|
||||
var environmentInteractables = new List<ItemDataSo>();
|
||||
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var entry = AssetDatabase.LoadAssetAtPath<ItemDataSo>(path);
|
||||
|
||||
if (entry == null)
|
||||
continue;
|
||||
|
||||
switch (entry.IdType)
|
||||
{
|
||||
case ItemDataSo.ItemIdType.PuzzleSlot:
|
||||
puzzleSlots.Add(entry);
|
||||
break;
|
||||
|
||||
case ItemDataSo.ItemIdType.Pickup:
|
||||
pickupItems.Add(entry);
|
||||
break;
|
||||
|
||||
case ItemDataSo.ItemIdType.Environment:
|
||||
environmentInteractables.Add(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
puzzleSlots.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
pickupItems.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
environmentInteractables.Sort((a, b) => string.CompareOrdinal(a.name, b.name));
|
||||
|
||||
Undo.RecordObject(registry, "Discover Item Assets");
|
||||
registry.SetDiscoveredEntries(puzzleSlots, pickupItems, environmentInteractables);
|
||||
EditorUtility.SetDirty(registry);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
Debug.Log(
|
||||
$"[ItemRegistry] Discovery complete. Puzzle Slots: {puzzleSlots.Count}, Pickup Items: {pickupItems.Count}, Environment Interactables: {environmentInteractables.Count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9e6445d7af341b6995266514b666497
|
||||
timeCreated: 1773921699
|
||||
3
Assets/Scripts/Editor/Windows.meta
Normal file
3
Assets/Scripts/Editor/Windows.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62c44b8b6745497c8ec129a63cbabd07
|
||||
timeCreated: 1773597607
|
||||
93
Assets/Scripts/Editor/Windows/FilePathsWindow.cs
Normal file
93
Assets/Scripts/Editor/Windows/FilePathsWindow.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System.IO;
|
||||
using BriarQueen.Data.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Editor.Windows
|
||||
{
|
||||
public class FilePathsWindow : EditorWindow
|
||||
{
|
||||
[MenuItem("Briar Queen/IO/Open Persistent Data/Save Data")]
|
||||
private static void OpenSaveDataFolder()
|
||||
{
|
||||
OpenFolder(FilePaths.SaveDataFolder);
|
||||
}
|
||||
|
||||
[MenuItem("Briar Queen/IO/Open Persistent Data/Save Backups")]
|
||||
private static void OpenSaveBackupFolder()
|
||||
{
|
||||
OpenFolder(FilePaths.SaveBackupDataFolder);
|
||||
}
|
||||
|
||||
[MenuItem("Briar Queen/IO/Open Persistent Data/Configs")]
|
||||
private static void OpenConfigFolder()
|
||||
{
|
||||
OpenFolder(FilePaths.ConfigFolder);
|
||||
}
|
||||
|
||||
[MenuItem("Briar Queen/IO/Open Persistent Data/All Paths Window")]
|
||||
private static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<FilePathsWindow>("Persistent Data Paths");
|
||||
window.minSize = new Vector2(520f, 180f);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Space(10f);
|
||||
EditorGUILayout.LabelField("BriarQueen Persistent Data Paths", EditorStyles.boldLabel);
|
||||
GUILayout.Space(8f);
|
||||
|
||||
DrawPathRow("Save Data", FilePaths.SaveDataFolder);
|
||||
DrawPathRow("Save Backups", FilePaths.SaveBackupDataFolder);
|
||||
DrawPathRow("Configs", FilePaths.ConfigFolder);
|
||||
|
||||
GUILayout.Space(12f);
|
||||
|
||||
if (GUILayout.Button("Open Application Persistent Data Root", GUILayout.Height(28f)))
|
||||
{
|
||||
OpenFolder(Application.persistentDataPath);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawPathRow(string label, string path)
|
||||
{
|
||||
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
|
||||
{
|
||||
EditorGUILayout.LabelField(label, EditorStyles.boldLabel);
|
||||
EditorGUILayout.SelectableLabel(path, EditorStyles.textField, GUILayout.Height(18f));
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Open", GUILayout.Height(24f)))
|
||||
{
|
||||
OpenFolder(path);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Copy Path", GUILayout.Height(24f)))
|
||||
{
|
||||
EditorGUIUtility.systemCopyBuffer = path;
|
||||
Debug.Log($"Copied path: {path}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OpenFolder(string folderPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(folderPath))
|
||||
{
|
||||
Debug.LogError("Cannot open folder: path is null or empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(folderPath))
|
||||
{
|
||||
Directory.CreateDirectory(folderPath);
|
||||
Debug.Log($"Created folder: {folderPath}");
|
||||
}
|
||||
|
||||
EditorUtility.RevealInFinder(folderPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Editor/Windows/FilePathsWindow.cs.meta
Normal file
3
Assets/Scripts/Editor/Windows/FilePathsWindow.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09ff6a774c3b4bb18d1fc39ac9d70284
|
||||
timeCreated: 1773668525
|
||||
655
Assets/Scripts/Editor/Windows/ScriptableObjectGenerator.cs
Normal file
655
Assets/Scripts/Editor/Windows/ScriptableObjectGenerator.cs
Normal file
@@ -0,0 +1,655 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BriarQueen.Data.Assets;
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Framework.Managers.Player.Data;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Editor.Windows
|
||||
{
|
||||
public class ScriptableObjectGenerator : EditorWindow
|
||||
{
|
||||
private const string DEFAULT_ITEM_ROOT_FOLDER = "Assets/Data/Information/Items";
|
||||
private const string DEFAULT_ICON_FOLDER = "Assets/Data/Artwork/Icons";
|
||||
private const string DEFAULT_ASSET_ENTRY_ROOT_FOLDER = "Assets/Data/Information/Asset Keys";
|
||||
private const string DEFAULT_CODEX_ROOT_FOLDER = "Assets/Data/Information/Codex";
|
||||
|
||||
private string _itemRootFolder = DEFAULT_ITEM_ROOT_FOLDER;
|
||||
private string _iconFolder = DEFAULT_ICON_FOLDER;
|
||||
private string _assetEntryRootFolder = DEFAULT_ASSET_ENTRY_ROOT_FOLDER;
|
||||
private string _codexRootFolder = DEFAULT_CODEX_ROOT_FOLDER;
|
||||
|
||||
private bool _overwriteExisting;
|
||||
private bool _assignIconsDuringCreate = true;
|
||||
private bool _overwriteExistingIcons;
|
||||
|
||||
private bool _createPickups = true;
|
||||
private bool _createEnvironment = true;
|
||||
private bool _createPuzzleSlots = true;
|
||||
|
||||
private bool _createUIAssetEntries = true;
|
||||
private bool _createSceneAssetEntries = true;
|
||||
private bool _createLevelAssetEntries = true;
|
||||
private bool _createItemAssetEntries = true;
|
||||
|
||||
private bool _createBookEntries = true;
|
||||
private bool _createPuzzleClues = true;
|
||||
private bool _createPhotos = true;
|
||||
|
||||
[MenuItem("Briar Queen/Tools/Assets/Scriptable Object Generator")]
|
||||
public static void Open()
|
||||
{
|
||||
var window = GetWindow<ScriptableObjectGenerator>("ItemDataSO Generator");
|
||||
window.minSize = new Vector2(700f, 600f);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Content Generator", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"Create or update ItemDataSo assets from enums, assign icons to existing ItemDataSo assets, create/update AssetEntry assets from asset enums, and create/update CodexEntrySO assets from codex enums.",
|
||||
MessageType.Info);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
DrawItemDataSection();
|
||||
EditorGUILayout.Space(10f);
|
||||
DrawAssetEntrySection();
|
||||
EditorGUILayout.Space(10f);
|
||||
DrawCodexSection();
|
||||
}
|
||||
|
||||
private void DrawItemDataSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("ItemDataSo", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.LabelField("Folders", EditorStyles.miniBoldLabel);
|
||||
_itemRootFolder = EditorGUILayout.TextField("Items Root Folder", _itemRootFolder);
|
||||
_iconFolder = EditorGUILayout.TextField("Icons Folder", _iconFolder);
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.LabelField("Create / Update Options", EditorStyles.miniBoldLabel);
|
||||
_overwriteExisting = EditorGUILayout.Toggle("Overwrite Existing Assets", _overwriteExisting);
|
||||
_assignIconsDuringCreate = EditorGUILayout.Toggle("Assign Icons During Create", _assignIconsDuringCreate);
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.LabelField("Generate Groups", EditorStyles.miniBoldLabel);
|
||||
_createPickups = EditorGUILayout.Toggle("Pickups", _createPickups);
|
||||
_createEnvironment = EditorGUILayout.Toggle("Environment", _createEnvironment);
|
||||
_createPuzzleSlots = EditorGUILayout.Toggle("Puzzle Slots", _createPuzzleSlots);
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.LabelField("Icon Assignment Options", EditorStyles.miniBoldLabel);
|
||||
_overwriteExistingIcons = EditorGUILayout.Toggle("Overwrite Existing Icons", _overwriteExistingIcons);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Create / Update ItemDataSO Assets", GUILayout.Height(32f)))
|
||||
CreateOrUpdateItemAssets();
|
||||
|
||||
if (GUILayout.Button("Assign Icons To Existing ItemDataSOs", GUILayout.Height(32f)))
|
||||
AssignIconsToExistingItemAssets();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Reveal Items Folder", GUILayout.Height(28f)))
|
||||
RevealFolder(_itemRootFolder);
|
||||
|
||||
if (GUILayout.Button("Reveal Icons Folder", GUILayout.Height(28f)))
|
||||
RevealFolder(_iconFolder);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAssetEntrySection()
|
||||
{
|
||||
EditorGUILayout.LabelField("AssetEntry", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.LabelField("Folders", EditorStyles.miniBoldLabel);
|
||||
_assetEntryRootFolder = EditorGUILayout.TextField("AssetEntry Root Folder", _assetEntryRootFolder);
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.LabelField("Generate AssetEntry Groups", EditorStyles.miniBoldLabel);
|
||||
_createUIAssetEntries = EditorGUILayout.Toggle("UI Entries", _createUIAssetEntries);
|
||||
_createSceneAssetEntries = EditorGUILayout.Toggle("Scene Entries", _createSceneAssetEntries);
|
||||
_createLevelAssetEntries = EditorGUILayout.Toggle("Level Entries", _createLevelAssetEntries);
|
||||
_createItemAssetEntries = EditorGUILayout.Toggle("Item Entries", _createItemAssetEntries);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Create / Update AssetEntry Assets", GUILayout.Height(32f)))
|
||||
CreateOrUpdateAssetEntries();
|
||||
|
||||
if (GUILayout.Button("Reveal AssetEntry Folder", GUILayout.Height(32f)))
|
||||
RevealFolder(_assetEntryRootFolder);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCodexSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("CodexEntrySO", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.LabelField("Folders", EditorStyles.miniBoldLabel);
|
||||
_codexRootFolder = EditorGUILayout.TextField("Codex Root Folder", _codexRootFolder);
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.LabelField("Generate Codex Groups", EditorStyles.miniBoldLabel);
|
||||
_createBookEntries = EditorGUILayout.Toggle("Book Entries", _createBookEntries);
|
||||
_createPuzzleClues = EditorGUILayout.Toggle("Puzzle Clues", _createPuzzleClues);
|
||||
_createPhotos = EditorGUILayout.Toggle("Photos", _createPhotos);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Create / Update CodexEntrySO Assets", GUILayout.Height(32f)))
|
||||
CreateOrUpdateCodexEntries();
|
||||
|
||||
if (GUILayout.Button("Reveal Codex Folder", GUILayout.Height(32f)))
|
||||
RevealFolder(_codexRootFolder);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateOrUpdateItemAssets()
|
||||
{
|
||||
if (!IsValidAssetsPath(_itemRootFolder))
|
||||
{
|
||||
Debug.LogError("[Content Generator] Items Root Folder must start with 'Assets'.");
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureFolderExists(_itemRootFolder);
|
||||
|
||||
int created = 0;
|
||||
int updated = 0;
|
||||
int skipped = 0;
|
||||
|
||||
if (_createPickups)
|
||||
{
|
||||
ProcessEnum<ItemKey, ItemDataSo>(
|
||||
rootFolder: _itemRootFolder,
|
||||
folderName: "Pickups",
|
||||
noneValue: ItemKey.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<ItemDataSo>(path),
|
||||
createAsset: () => CreateInstance<ItemDataSo>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_idType", (int)ItemDataSo.ItemIdType.Pickup);
|
||||
SetEnumField(so, "_itemKey", (int)key);
|
||||
SetEnumField(so, "_environmentKey", (int)EnvironmentKey.None);
|
||||
SetEnumField(so, "_puzzleSlotKey", (int)PuzzleSlotKey.None);
|
||||
SetStringFieldIfEmpty(so, "_itemName", ObjectNames.NicifyVariableName(key.ToString()));
|
||||
|
||||
if (_assignIconsDuringCreate)
|
||||
AssignIcon(so, key.ToString(), _overwriteExistingIcons);
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
if (_createEnvironment)
|
||||
{
|
||||
ProcessEnum<EnvironmentKey, ItemDataSo>(
|
||||
rootFolder: _itemRootFolder,
|
||||
folderName: "Environment",
|
||||
noneValue: EnvironmentKey.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<ItemDataSo>(path),
|
||||
createAsset: () => CreateInstance<ItemDataSo>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_idType", (int)ItemDataSo.ItemIdType.Environment);
|
||||
SetEnumField(so, "_itemKey", (int)ItemKey.None);
|
||||
SetEnumField(so, "_environmentKey", (int)key);
|
||||
SetEnumField(so, "_puzzleSlotKey", (int)PuzzleSlotKey.None);
|
||||
SetStringFieldIfEmpty(so, "_itemName", ObjectNames.NicifyVariableName(key.ToString()));
|
||||
|
||||
if (_assignIconsDuringCreate)
|
||||
AssignIcon(so, key.ToString(), _overwriteExistingIcons);
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
if (_createPuzzleSlots)
|
||||
{
|
||||
ProcessEnum<PuzzleSlotKey, ItemDataSo>(
|
||||
rootFolder: _itemRootFolder,
|
||||
folderName: "PuzzleSlots",
|
||||
noneValue: PuzzleSlotKey.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<ItemDataSo>(path),
|
||||
createAsset: () => CreateInstance<ItemDataSo>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_idType", (int)ItemDataSo.ItemIdType.PuzzleSlot);
|
||||
SetEnumField(so, "_itemKey", (int)ItemKey.None);
|
||||
SetEnumField(so, "_environmentKey", (int)EnvironmentKey.None);
|
||||
SetEnumField(so, "_puzzleSlotKey", (int)key);
|
||||
SetStringFieldIfEmpty(so, "_itemName", ObjectNames.NicifyVariableName(key.ToString()));
|
||||
|
||||
if (_assignIconsDuringCreate)
|
||||
AssignIcon(so, key.ToString(), _overwriteExistingIcons);
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
Debug.Log($"[Content Generator] ItemDataSO generation complete. Created: {created}, Updated: {updated}, Skipped: {skipped}");
|
||||
}
|
||||
|
||||
private void AssignIconsToExistingItemAssets()
|
||||
{
|
||||
if (!IsValidAssetsPath(_iconFolder))
|
||||
{
|
||||
Debug.LogError("[Content Generator] Icons Folder must start with 'Assets'.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AssetDatabase.IsValidFolder(_iconFolder))
|
||||
{
|
||||
Debug.LogError($"[Content Generator] Icons folder not found: {_iconFolder}");
|
||||
return;
|
||||
}
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets("t:ItemDataSo", new[] { _itemRootFolder });
|
||||
|
||||
int assigned = 0;
|
||||
int skipped = 0;
|
||||
int missing = 0;
|
||||
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<ItemDataSo>(assetPath);
|
||||
|
||||
if (asset == null)
|
||||
continue;
|
||||
|
||||
var so = new SerializedObject(asset);
|
||||
so.Update();
|
||||
|
||||
bool changed = AssignIcon(so, asset.name, _overwriteExistingIcons);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorUtility.SetDirty(asset);
|
||||
assigned++;
|
||||
}
|
||||
else
|
||||
{
|
||||
var iconProp = so.FindProperty("_icon");
|
||||
if (iconProp != null && iconProp.objectReferenceValue != null && !_overwriteExistingIcons)
|
||||
skipped++;
|
||||
else
|
||||
missing++;
|
||||
}
|
||||
}
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
Debug.Log($"[Content Generator] Icon assignment complete. Assigned: {assigned}, Skipped: {skipped}, Missing Icons: {missing}");
|
||||
}
|
||||
|
||||
private void CreateOrUpdateAssetEntries()
|
||||
{
|
||||
if (!IsValidAssetsPath(_assetEntryRootFolder))
|
||||
{
|
||||
Debug.LogError("[Content Generator] AssetEntry Root Folder must start with 'Assets'.");
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureFolderExists(_assetEntryRootFolder);
|
||||
|
||||
int created = 0;
|
||||
int updated = 0;
|
||||
int skipped = 0;
|
||||
|
||||
if (_createUIAssetEntries)
|
||||
{
|
||||
ProcessEnum<UIKey, AssetEntry>(
|
||||
rootFolder: _assetEntryRootFolder,
|
||||
folderName: "UI",
|
||||
noneValue: UIKey.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<AssetEntry>(path),
|
||||
createAsset: () => CreateInstance<AssetEntry>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_entryType", (int)AssetEntry.AssetEntryType.UI);
|
||||
SetEnumField(so, "_uiKey", (int)key);
|
||||
SetEnumField(so, "_sceneKey", (int)SceneKey.None);
|
||||
SetEnumField(so, "_levelKey", (int)LevelKey.None);
|
||||
SetEnumField(so, "_itemKey", (int)AssetItemKey.None);
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
if (_createSceneAssetEntries)
|
||||
{
|
||||
ProcessEnum<SceneKey, AssetEntry>(
|
||||
rootFolder: _assetEntryRootFolder,
|
||||
folderName: "Scenes",
|
||||
noneValue: SceneKey.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<AssetEntry>(path),
|
||||
createAsset: () => CreateInstance<AssetEntry>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_entryType", (int)AssetEntry.AssetEntryType.Scene);
|
||||
SetEnumField(so, "_uiKey", (int)UIKey.None);
|
||||
SetEnumField(so, "_sceneKey", (int)key);
|
||||
SetEnumField(so, "_levelKey", (int)LevelKey.None);
|
||||
SetEnumField(so, "_itemKey", (int)AssetItemKey.None);
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
if (_createLevelAssetEntries)
|
||||
{
|
||||
ProcessEnum<LevelKey, AssetEntry>(
|
||||
rootFolder: _assetEntryRootFolder,
|
||||
folderName: "Levels",
|
||||
noneValue: LevelKey.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<AssetEntry>(path),
|
||||
createAsset: () => CreateInstance<AssetEntry>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_entryType", (int)AssetEntry.AssetEntryType.Level);
|
||||
SetEnumField(so, "_uiKey", (int)UIKey.None);
|
||||
SetEnumField(so, "_sceneKey", (int)SceneKey.None);
|
||||
SetEnumField(so, "_levelKey", (int)key);
|
||||
SetEnumField(so, "_itemKey", (int)AssetItemKey.None);
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
if (_createItemAssetEntries)
|
||||
{
|
||||
ProcessEnum<AssetItemKey, AssetEntry>(
|
||||
rootFolder: _assetEntryRootFolder,
|
||||
folderName: "Items",
|
||||
noneValue: AssetItemKey.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<AssetEntry>(path),
|
||||
createAsset: () => CreateInstance<AssetEntry>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_entryType", (int)AssetEntry.AssetEntryType.Item);
|
||||
SetEnumField(so, "_uiKey", (int)UIKey.None);
|
||||
SetEnumField(so, "_sceneKey", (int)SceneKey.None);
|
||||
SetEnumField(so, "_levelKey", (int)LevelKey.None);
|
||||
SetEnumField(so, "_itemKey", (int)key);
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
Debug.Log($"[Content Generator] AssetEntry generation complete. Created: {created}, Updated: {updated}, Skipped: {skipped}");
|
||||
}
|
||||
|
||||
private void CreateOrUpdateCodexEntries()
|
||||
{
|
||||
if (!IsValidAssetsPath(_codexRootFolder))
|
||||
{
|
||||
Debug.LogError("[Content Generator] Codex Root Folder must start with 'Assets'.");
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureFolderExists(_codexRootFolder);
|
||||
|
||||
int created = 0;
|
||||
int updated = 0;
|
||||
int skipped = 0;
|
||||
|
||||
if (_createBookEntries)
|
||||
{
|
||||
ProcessEnum<BookEntryID, CodexEntrySo>(
|
||||
rootFolder: _codexRootFolder,
|
||||
folderName: "Books",
|
||||
noneValue: BookEntryID.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<CodexEntrySo>(path),
|
||||
createAsset: () => CreateInstance<CodexEntrySo>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_codexType", (int)CodexType.BookEntry);
|
||||
SetEnumField(so, "_bookEntryID", (int)key);
|
||||
SetEnumField(so, "_clueEntryID", (int)ClueEntryID.None);
|
||||
SetEnumField(so, "_photoEntryID", (int)PhotoEntryID.None);
|
||||
SetStringFieldIfEmpty(so, "_title", ObjectNames.NicifyVariableName(key.ToString()));
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
if (_createPuzzleClues)
|
||||
{
|
||||
ProcessEnum<ClueEntryID, CodexEntrySo>(
|
||||
rootFolder: _codexRootFolder,
|
||||
folderName: "Clues",
|
||||
noneValue: ClueEntryID.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<CodexEntrySo>(path),
|
||||
createAsset: () => CreateInstance<CodexEntrySo>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_codexType", (int)CodexType.PuzzleClue);
|
||||
SetEnumField(so, "_bookEntryID", (int)BookEntryID.None);
|
||||
SetEnumField(so, "_clueEntryID", (int)key);
|
||||
SetEnumField(so, "_photoEntryID", (int)PhotoEntryID.None);
|
||||
SetStringFieldIfEmpty(so, "_title", ObjectNames.NicifyVariableName(key.ToString()));
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
if (_createPhotos)
|
||||
{
|
||||
ProcessEnum<PhotoEntryID, CodexEntrySo>(
|
||||
rootFolder: _codexRootFolder,
|
||||
folderName: "Photos",
|
||||
noneValue: PhotoEntryID.None,
|
||||
assetExtensionName: key => key.ToString(),
|
||||
loadExistingAsset: path => AssetDatabase.LoadAssetAtPath<CodexEntrySo>(path),
|
||||
createAsset: () => CreateInstance<CodexEntrySo>(),
|
||||
applyValues: (so, key) =>
|
||||
{
|
||||
SetEnumField(so, "_codexType", (int)CodexType.Photo);
|
||||
SetEnumField(so, "_bookEntryID", (int)BookEntryID.None);
|
||||
SetEnumField(so, "_clueEntryID", (int)ClueEntryID.None);
|
||||
SetEnumField(so, "_photoEntryID", (int)key);
|
||||
SetStringFieldIfEmpty(so, "_title", ObjectNames.NicifyVariableName(key.ToString()));
|
||||
},
|
||||
ref created,
|
||||
ref updated,
|
||||
ref skipped);
|
||||
}
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
Debug.Log($"[Content Generator] CodexEntrySO generation complete. Created: {created}, Updated: {updated}, Skipped: {skipped}");
|
||||
}
|
||||
|
||||
private void ProcessEnum<TEnum, TAsset>(
|
||||
string rootFolder,
|
||||
string folderName,
|
||||
TEnum noneValue,
|
||||
Func<TEnum, string> assetExtensionName,
|
||||
Func<string, TAsset> loadExistingAsset,
|
||||
Func<TAsset> createAsset,
|
||||
Action<SerializedObject, TEnum> applyValues,
|
||||
ref int created,
|
||||
ref int updated,
|
||||
ref int skipped)
|
||||
where TEnum : struct, Enum
|
||||
where TAsset : UnityEngine.Object
|
||||
{
|
||||
string folderPath = $"{rootFolder}/{folderName}";
|
||||
EnsureFolderExists(folderPath);
|
||||
|
||||
foreach (TEnum key in Enum.GetValues(typeof(TEnum)))
|
||||
{
|
||||
if (EqualityComparer<TEnum>.Default.Equals(key, noneValue))
|
||||
continue;
|
||||
|
||||
string assetName = assetExtensionName(key);
|
||||
string assetPath = $"{folderPath}/{assetName}.asset";
|
||||
|
||||
var existing = loadExistingAsset(assetPath);
|
||||
|
||||
if (existing != null && !_overwriteExisting)
|
||||
{
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
TAsset asset;
|
||||
bool isNew = false;
|
||||
|
||||
if (existing == null)
|
||||
{
|
||||
asset = createAsset();
|
||||
AssetDatabase.CreateAsset(asset, assetPath);
|
||||
isNew = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
asset = existing;
|
||||
}
|
||||
|
||||
var so = new SerializedObject(asset);
|
||||
so.Update();
|
||||
|
||||
applyValues(so, key);
|
||||
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorUtility.SetDirty(asset);
|
||||
|
||||
if (isNew)
|
||||
created++;
|
||||
else
|
||||
updated++;
|
||||
}
|
||||
}
|
||||
|
||||
private bool AssignIcon(SerializedObject so, string assetOrEnumName, bool overwriteExisting)
|
||||
{
|
||||
var iconProp = so.FindProperty("_icon");
|
||||
if (iconProp == null)
|
||||
return false;
|
||||
|
||||
if (!overwriteExisting && iconProp.objectReferenceValue != null)
|
||||
return false;
|
||||
|
||||
Sprite sprite = FindIconByName(assetOrEnumName);
|
||||
if (sprite == null)
|
||||
return false;
|
||||
|
||||
iconProp.objectReferenceValue = sprite;
|
||||
return true;
|
||||
}
|
||||
|
||||
private Sprite FindIconByName(string iconName)
|
||||
{
|
||||
if (!AssetDatabase.IsValidFolder(_iconFolder))
|
||||
return null;
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets($"{iconName} t:Sprite", new[] { _iconFolder });
|
||||
if (guids == null || guids.Length == 0)
|
||||
return null;
|
||||
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||
return AssetDatabase.LoadAssetAtPath<Sprite>(path);
|
||||
}
|
||||
|
||||
private static void SetEnumField(SerializedObject so, string propertyName, int enumValue)
|
||||
{
|
||||
var prop = so.FindProperty(propertyName);
|
||||
if (prop != null)
|
||||
prop.enumValueIndex = enumValue;
|
||||
}
|
||||
|
||||
private static void SetStringFieldIfEmpty(SerializedObject so, string propertyName, string value)
|
||||
{
|
||||
var prop = so.FindProperty(propertyName);
|
||||
if (prop == null)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(prop.stringValue))
|
||||
prop.stringValue = value;
|
||||
}
|
||||
|
||||
private static bool IsValidAssetsPath(string path)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(path) && path.StartsWith("Assets", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static void EnsureFolderExists(string fullPath)
|
||||
{
|
||||
string[] parts = fullPath.Split('/');
|
||||
if (parts.Length == 0 || parts[0] != "Assets")
|
||||
throw new InvalidOperationException($"Invalid Unity folder path: {fullPath}");
|
||||
|
||||
string current = "Assets";
|
||||
|
||||
for (int i = 1; i < parts.Length; i++)
|
||||
{
|
||||
string next = $"{current}/{parts[i]}";
|
||||
if (!AssetDatabase.IsValidFolder(next))
|
||||
AssetDatabase.CreateFolder(current, parts[i]);
|
||||
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
private static void RevealFolder(string folderPath)
|
||||
{
|
||||
if (!IsValidAssetsPath(folderPath))
|
||||
return;
|
||||
|
||||
EnsureFolderExists(folderPath);
|
||||
|
||||
UnityEngine.Object folder = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(folderPath);
|
||||
if (folder != null)
|
||||
{
|
||||
Selection.activeObject = folder;
|
||||
EditorGUIUtility.PingObject(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b81754fd377748c6a539d9077fa199b5
|
||||
timeCreated: 1773597607
|
||||
Reference in New Issue
Block a user