First commit for private source control. Older commits available on Github.

This commit is contained in:
2026-03-26 12:52:52 +00:00
parent a04c602626
commit 2d449c4a17
2176 changed files with 408185 additions and 0 deletions

View 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
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d63909dd781c643ecbc1295f0dc761a3
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1954361a8cce45498b2c8b2888144b5e
timeCreated: 1771172177

View 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;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 627cc55408bb4796839600a1516a5eba
timeCreated: 1771172177

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5c40c1262cbd4128a9b3c3446304a845
timeCreated: 1773921681

View File

@@ -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}");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2f49114100e741bb849cbdfb5fc457cc
timeCreated: 1773602794

View File

@@ -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}");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 04adf387d1e94429a6c320005150cb90
timeCreated: 1773921705

View 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}");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a9e6445d7af341b6995266514b666497
timeCreated: 1773921699

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 62c44b8b6745497c8ec129a63cbabd07
timeCreated: 1773597607

View 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);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 09ff6a774c3b4bb18d1fc39ac9d70284
timeCreated: 1773668525

View 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);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b81754fd377748c6a539d9077fa199b5
timeCreated: 1773597607