Storyline+Dialog初步

This commit is contained in:
SoulliesOfficial
2026-07-05 16:08:23 -04:00
parent afa8a56e1d
commit d031afd075
464 changed files with 25716 additions and 4209 deletions

View File

@@ -0,0 +1,44 @@
using System;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace SubAssetsToolbox.Editor
{
/// <summary>
/// When the user creates a new asset via the right-click menu and the selected asset is a main asset,
/// this class adds it to the target asset as a sub-asset.
/// </summary>
public class AssetRelocator : AssetModificationProcessor
{
public static Object LastSelectionOnRightClick;
static void OnWillCreateAsset(string path)
{
// Used to check if the creation happened as a right-click on an asset
if (LastSelectionOnRightClick == null) return;
string newParentPath = AssetDatabase.GetAssetPath(LastSelectionOnRightClick);
if (TypeChecker.HasDefaultAction(path, newParentPath)) return; // There's already a default action
if (!TypeChecker.ValidateSubAssetType(path, false)) return; // Can't be a sub-asset
if (!TypeChecker.ValidateDestinationType(newParentPath)) return; // Can't contain a sub-asset
EditorApplication.delayCall += () => RelocateAsset(path);
}
private static void RelocateAsset(string path)
{
Type t = AssetDatabase.GetMainAssetTypeAtPath(path);
Object justCreatedAsset = AssetDatabase.LoadAssetAtPath(path, t);
string parentObjectPath = AssetDatabase.GetAssetPath(LastSelectionOnRightClick);
SubAssetsToolbox.AddSubAsset(parentObjectPath, justCreatedAsset, out _);
AssetDatabase.DeleteAsset(path);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 4e535f19b37134abe8c379ec1e5a87d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/AssetRelocator.cs
uploadId: 869944

View File

@@ -0,0 +1,90 @@
using UnityEditor;
using UnityEngine;
namespace SubAssetsToolbox.Editor
{
[InitializeOnLoad]
public static class ContextualActions
{
static ContextualActions()
{
EditorApplication.projectWindowItemOnGUI += OnProjectWindowItemGUI;
}
private static void OnProjectWindowItemGUI(string guid, Rect selectionRect)
{
Event current = Event.current;
Object obj;
switch (current.type)
{
case EventType.MouseDown:
ClearLastSelection();
break;
case EventType.KeyUp when current.keyCode == KeyCode.Delete ||
current.keyCode == KeyCode.Backspace && current.command:
obj = Selection.activeObject;
if (obj == null) return;
if(AssetDatabase.IsSubAsset(obj))
{
// It's a sub-asset
bool decision = EditorUtility.DisplayDialog("Delete Sub-Asset",
string.Format(Constants.ConfirmDeleteSubAsset, obj.name), "Delete",
"Cancel");
if (decision)
{
string parentObjectPath = AssetDatabase.GetAssetPath(obj);
SubAssetsToolbox.RemoveSubAsset(parentObjectPath, obj);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
ClearLastSelection();
current.Use();
break;
case EventType.KeyUp when
#if UNITY_EDITOR_WIN
current.keyCode == KeyCode.F2:
#else
current.keyCode == KeyCode.Return:
#endif
obj = Selection.activeObject;
if (obj == null || Selection.objects.Length > 1) return;
if (AssetDatabase.IsSubAsset(obj))
{
RenameSubAssetWindow.Open(obj);
current.Use();
}
break;
case EventType.ContextClick when selectionRect.Contains(current.mousePosition):
{
string path = AssetDatabase.GUIDToAssetPath(guid);
if (AssetDatabase.IsValidFolder(path))
{
ClearLastSelection();
return;
}
obj = AssetDatabase.LoadAssetAtPath<Object>(path);
if (obj != null)
{
AssetRelocator.LastSelectionOnRightClick = obj;
}
break;
}
}
}
private static void ClearLastSelection()
{
AssetRelocator.LastSelectionOnRightClick = null;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f285d3fcf48e4fda8094f38477ff8f0b
timeCreated: 1719562257
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/ContextualActions.cs
uploadId: 869944

View File

@@ -0,0 +1,241 @@
using System.IO;
using System.Linq;
using SubAssetsToolbox.Utilities;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace SubAssetsToolbox.Editor
{
internal static class DragAndDropAddon
{
#if UNITY_6000_3_OR_NEWER
[InitializeOnLoadMethod]
public static void AddDragProjectHandler()
{
DragAndDrop.AddDropHandlerV2(ProjectWindowHandler);
}
private static DragAndDropVisualMode ProjectWindowHandler(EntityId id, string destinationPath, bool released)
{
#else
[InitializeOnLoadMethod]
public static void AddDragProjectHandler() => DragAndDrop.AddDropHandler(ProjectWindowHandler);
private static DragAndDropVisualMode ProjectWindowHandler(int id, string destinationPath, bool released)
{
#endif
if (DragAndDrop.paths.Length == 0 || DragAndDrop.objectReferences.Length == 0)
// Was not dragging from another window
return DragAndDropVisualMode.None;
bool destinationIsFolder = AssetDatabase.IsValidFolder(destinationPath);
if (released)
{
bool isDraggingSubAssets = DragAndDrop.objectReferences.Any(AssetDatabase.IsSubAsset);
foreach (string path in DragAndDrop.paths)
{
if (string.Equals(path, destinationPath)) return DragAndDropVisualMode.None;
if (destinationIsFolder) continue;
if (isDraggingSubAssets) continue;
if (!TypeChecker.ValidateSubAssetType(path)) return DragAndDropVisualMode.Rejected;
if (!TypeChecker.ValidateDestinationType(destinationPath)) return DragAndDropVisualMode.Rejected;
}
if (!destinationIsFolder)
{
// Adding sub-asset(s)
// (drag destination is an asset)
string objectName = Path.GetFileNameWithoutExtension(destinationPath);
bool isOne = DragAndDrop.objectReferences.Length == 1;
int choice = EditorUtility.DisplayDialogComplex(
isOne ? "Add as Sub-Asset" : "Add as Sub-Assets",
isOne
? string.Format(Constants.ConfirmAddAsSubAsset, DragAndDrop.objectReferences[0].name,
objectName)
: string.Format(Constants.ConfirmAddAsSubAssets, DragAndDrop.objectReferences[0].name,
DragAndDrop.objectReferences[1].name, objectName),
isOne ? "Add" : "Add all",
"Cancel",
isOne ? "Add and Keep Original" : "Add and Keep Originals");
int redirectRefChoice = -1;
if (choice == 0)
{
ReferencePatchingMode mode = SubAssetsToolboxSettings.PatchReferences.value;
if (mode == ReferencePatchingMode.AutoApply)
redirectRefChoice = 0;
else if (mode == ReferencePatchingMode.AskEachTime)
redirectRefChoice = EditorUtility.DisplayDialogComplex("Patch references",
Constants.PatchRefsToSubAssetPrompt,
"Patch References", "Don't Patch", "Cancel Moving Assets");
}
// Cancelled the operation
if (choice == 1 || redirectRefChoice == 2) return DragAndDropVisualMode.Rejected;
foreach (Object draggedObject in DragAndDrop.objectReferences)
{
string draggedObjectPath = AssetDatabase.GetAssetPath(draggedObject);
string draggedObjectName = draggedObject.name;
bool wasMainAsset = AssetDatabase.IsMainAsset(draggedObject);
// TODO: preserve selection if the object selected was the one being destroyed
SubAssetsToolbox.AddSubAsset(destinationPath, draggedObject, out Object newSubasset);
if (choice == 2) continue; // Keep previous objects
if (redirectRefChoice == 0)
{
AssetDatabase.SaveAssets();
if (!AssetReferenceRedirector.RedirectToSubAsset(draggedObject, newSubasset))
{
Debug.LogWarning(string.Format(Constants.RedirectionFailed, draggedObjectName));
continue;
}
}
// Do not keep previous
if (wasMainAsset)
{
#if ADDRESSABLES_INSTALLED
AddressableEntryMigrator.MigrateOrRemoveEntry(
AssetDatabase.AssetPathToGUID(draggedObjectPath),
AssetDatabase.AssetPathToGUID(destinationPath),
objectName);
#endif
AssetDatabase.DeleteAsset(draggedObjectPath);
}
else
{
// After redirect, Refresh() may have invalidated the original reference.
// Reload the sub-asset from disk if needed.
Object objectToRemove = draggedObject;
if (objectToRemove == null)
{
Object[] subAssets = AssetDatabase.LoadAllAssetRepresentationsAtPath(draggedObjectPath);
objectToRemove = subAssets.FirstOrDefault(a => a.name == draggedObjectName);
}
if (objectToRemove != null)
SubAssetsToolbox.RemoveSubAsset(draggedObjectPath, objectToRemove);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
return DragAndDropVisualMode.Link;
}
// Removing sub-asset(s)
// (drag destination is a folder or an empty space)
if (!DragAndDrop.objectReferences.Any(AssetDatabase.IsSubAsset))
return Path.GetDirectoryName(DragAndDrop.paths[0]) == destinationPath
? DragAndDropVisualMode.Move
: DragAndDropVisualMode.None;
ReferencePatchingMode redirectMode = SubAssetsToolboxSettings.PatchReferences.value;
int redirectRefsChoice;
if (redirectMode == ReferencePatchingMode.AutoApply)
redirectRefsChoice = 0;
else if (redirectMode == ReferencePatchingMode.AskEachTime)
redirectRefsChoice = EditorUtility.DisplayDialogComplex("Patch references",
Constants.PatchRefsToStandalonePrompt,
"Patch References", "Don't Patch", "Cancel Sub-Asset Removal");
else
redirectRefsChoice = 1;
if (redirectRefsChoice == 2) return DragAndDropVisualMode.Rejected;
int rejected = 0;
foreach (Object draggedObject in DragAndDrop.objectReferences)
{
string draggedObjectPath = AssetDatabase.GetAssetPath(draggedObject);
if (AssetDatabase.IsSubAsset(draggedObject))
{
// Was dragging a sub-asset: un-parent
// Check if its parent is in selection too
Object mainAssetAtPath = AssetDatabase.LoadMainAssetAtPath(draggedObjectPath);
string fileExtension = ExtensionMap.GetFileExtensionByType(draggedObject.GetType());
if (DragAndDrop.objectReferences.Contains(mainAssetAtPath)) continue;
// Verify if there's an object with the same name
string desiredName = Path.Combine(destinationPath, $"{draggedObject.name}.{fileExtension}");
if (AssetDatabase.LoadAssetAtPath<Object>(desiredName) != null)
{
Debug.LogWarning(string.Format(Constants.ImpossibleToExtract, draggedObject.name));
rejected++;
continue;
}
string draggedObjectName = draggedObject.name;
Object newObject = Object.Instantiate(draggedObject);
newObject.name = draggedObjectName;
AssetDatabase.CreateAsset(newObject, desiredName);
if (redirectRefsChoice == 0)
{
AssetDatabase.SaveAssets();
if (!AssetReferenceRedirector.RedirectToStandaloneAsset(draggedObject, newObject))
{
Debug.LogWarning(string.Format(Constants.RedirectionFailed, draggedObjectName));
continue;
}
}
// After redirect, Refresh() may have invalidated the original reference.
// Reload the sub-asset from disk if needed.
Object objectToRemove = draggedObject;
if (objectToRemove == null)
{
Object[] subAssets = AssetDatabase.LoadAllAssetRepresentationsAtPath(draggedObjectPath);
objectToRemove = subAssets.FirstOrDefault(a => a.name == draggedObjectName);
}
if (objectToRemove != null)
SubAssetsToolbox.RemoveSubAsset(draggedObjectPath, objectToRemove);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
if (rejected != 0) return DragAndDropVisualMode.Rejected;
if (Path.GetDirectoryName(DragAndDrop.paths[0]) != destinationPath)
return DragAndDropVisualMode.None; // Allows relocation of main assets
return DragAndDropVisualMode.Move; // Avoid confirmation popup when drag/dropping in the same folder
}
// While dragging
if (destinationIsFolder)
return DragAndDropVisualMode.Generic;
if (DragAndDrop.objectReferences.Any(AssetDatabase.IsSubAsset))
return DragAndDropVisualMode.Link;
foreach (string path in DragAndDrop.paths)
{
if (string.Equals(path, destinationPath)) return DragAndDropVisualMode.None;
if (!TypeChecker.ValidateSubAssetType(path, true)) return DragAndDropVisualMode.Rejected;
if (!TypeChecker.ValidateDestinationType(destinationPath, true)) return DragAndDropVisualMode.Rejected;
}
return DragAndDropVisualMode.Link;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0e7efb048b08b4c78807019c63dfda0e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/DragAndDropAddon.cs
uploadId: 869944

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 61c997c4c033849a6ac3e750b0b07069
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using UnityEngine;
namespace SubAssetsToolbox.Editor
{
public enum ReferencePatchingMode
{
Disabled = 0,
AskEachTime = 1,
AutoApply = 2
}
public class SubAssetsToolboxSettings
{
public static PackageSetting<bool> WelcomeWindowSeen = new("general.welcomeWindowSeen", false);
public static readonly string[] DefaultExtensionsToScan =
{
"unity", "prefab", "asset", "mat", "controller", "overrideController",
"playable", "signal", "mixer", "preset", "lighting", "giparams",
"spriteatlas", "spriteatlasv2", "terrainlayer", "brush", "anim",
"guiskin", "fontsettings", "flare", "renderTexture", "cubemap"
};
public static PackageSetting<ReferencePatchingMode> PatchReferences =
new("referencePatching.mode", ReferencePatchingMode.AskEachTime);
public static PackageSetting<string[]> PatchExtensions =
new("referencePatching.extensions", DefaultExtensionsToScan);
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: e40b070acac1a4ec488641be6b410275
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/Settings/SubAssetsToolboxSettings.cs
uploadId: 869944

View File

@@ -0,0 +1,33 @@
using UnityEditor;
using UnityEditor.SettingsManagement;
namespace SubAssetsToolbox.Editor
{
static class SubAssetsToolboxSettingsManager
{
private static Settings instance;
internal static Settings settings
{
get
{
if (instance == null)
instance = new Settings(Constants.PackageName, "Settings");
return instance;
}
}
}
public class PackageSetting<T> : UserSetting<T>
{
public PackageSetting(string key, T value)
: base(SubAssetsToolboxSettingsManager.settings, key, value, SettingsScope.Project) { }
}
public class UserPref<T> : UserSetting<T>
{
public UserPref(string key, T value)
: base(SubAssetsToolboxSettingsManager.settings, key, value, SettingsScope.User) { }
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 866ebc740692e48a6818f6a8a101bb8c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/Settings/SubAssetsToolboxSettingsManager.cs
uploadId: 869944

View File

@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine.UIElements;
namespace SubAssetsToolbox.Editor
{
internal static class SubAssetsToolboxSettingsProvider
{
private const string SettingsPath = "Project/SubAssets Toolbox";
private const string UxmlPath = "Packages/io.continis.subassets/UI/UIToolkit/ProjectSettings.uxml";
private static List<string> _extensions;
private static ListView _listView;
private static EnumField _redirectionModeField;
private static Button _resetFileTypesBtn;
[SettingsProvider]
private static SettingsProvider CreateSettingsProvider()
{
return new SettingsProvider(SettingsPath, SettingsScope.Project)
{
activateHandler = (_, rootElement) => CreateUI(rootElement),
keywords = new[] { "subassets", "sub-assets", "redirect", "extensions" }
};
}
private static void SyncToSetting()
{
SubAssetsToolboxSettings.PatchExtensions.SetValue(_extensions.ToArray(), true);
}
private static void CreateUI(VisualElement root)
{
ReferencePatchingMode currentMode = SubAssetsToolboxSettings.PatchReferences.value;
bool redirectionIsEnabled = currentMode != ReferencePatchingMode.Disabled;
_extensions = new List<string>(SubAssetsToolboxSettings.PatchExtensions.value);
VisualTreeAsset visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(UxmlPath);
VisualElement template = visualTree.Instantiate();
template.style.flexGrow = 1f;
_redirectionModeField = template.Q<EnumField>("RedirectionModeField");
_redirectionModeField.Init(ReferencePatchingMode.Disabled);
_redirectionModeField.SetValueWithoutNotify(currentMode);
_redirectionModeField.RegisterValueChangedCallback(OnRedirectionModeChanged);
_listView = template.Q<ListView>("ExtensionsList");
_listView.itemsSource = _extensions;
_listView.SetEnabled(redirectionIsEnabled);
_listView.makeItem = MakeItem;
_listView.bindItem = BindItem;
_listView.unbindItem = UnbindItem;
_listView.itemsAdded += indices =>
{
foreach (int i in indices)
_extensions[i] = "ext";
_listView.RefreshItems();
SyncToSetting();
};
_listView.itemsRemoved += _ => SyncToSetting();
_listView.itemIndexChanged += (_, _) => SyncToSetting();
_resetFileTypesBtn = template.Q<Button>("ResetBtn");
_resetFileTypesBtn.SetEnabled(redirectionIsEnabled);
_resetFileTypesBtn.clicked += ResetExtensionsToDefaults;
root.Add(template);
}
private static void OnRedirectionModeChanged(ChangeEvent<Enum> evt)
{
ReferencePatchingMode mode = (ReferencePatchingMode)evt.newValue;
SubAssetsToolboxSettings.PatchReferences.SetValue(mode, true);
bool enabled = mode != ReferencePatchingMode.Disabled;
_listView.SetEnabled(enabled);
_resetFileTypesBtn.SetEnabled(enabled);
}
private static void ResetExtensionsToDefaults()
{
_extensions.Clear();
_extensions.AddRange(SubAssetsToolboxSettings.DefaultExtensionsToScan);
_listView.RefreshItems();
SyncToSetting();
}
private static VisualElement MakeItem()
{
return new TextField();
}
private static void BindItem(VisualElement element, int index)
{
TextField field = (TextField)element;
field.SetValueWithoutNotify(_extensions[index]);
field.userData = index;
field.RegisterValueChangedCallback(OnExtensionChanged);
}
private static void UnbindItem(VisualElement element, int index)
{
TextField field = (TextField)element;
field.UnregisterValueChangedCallback(OnExtensionChanged);
}
private static void OnExtensionChanged(ChangeEvent<string> evt)
{
TextField field = (TextField)evt.target;
int index = (int)field.userData;
_extensions[index] = evt.newValue;
SyncToSetting();
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f9fe270b76b734b60a6b7c24fcf38c43
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/Settings/SubAssetsToolboxSettingsProvider.cs
uploadId: 869944

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 15039554cb524e5e8b2c5e8a3f858acc
timeCreated: 1720124815

View File

@@ -0,0 +1,26 @@
using UnityEditor;
using UnityEngine;
namespace SubAssetsToolbox.Editor.SubAssetAware
{
static class SubAssetAwareMethods
{
public static void NotifyAwareObjectOfAddition(string parentObjectPath, Object newObject)
{
Object newParentObject = AssetDatabase.LoadAssetAtPath(parentObjectPath, typeof(Object));
if (newParentObject is ISubAssetAware awareObject)
{
awareObject.AddSubAsset(newObject);
}
}
public static void NotifyAwareObjectOfRemoval(string parentObjectPath, Object objectToRemove)
{
Object oldParentObject = AssetDatabase.LoadAssetAtPath(parentObjectPath, typeof(Object));
if (oldParentObject is ISubAssetAware awareObject)
{
awareObject.RemoveSubAsset(objectToRemove);
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 33b5b9d4670b4206bc714f3c45a52c59
timeCreated: 1720022287
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/SubAssetAware/SubAssetAwareMethods.cs
uploadId: 869944

View File

@@ -0,0 +1,58 @@
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace SubAssetsToolbox.Editor
{
public static class SubAssetContextMenu
{
#if UNITY_6000
private const int MenuPriority = 20;
#else
private const int MenuPriority = 19;
#endif
[MenuItem("Assets/Delete Sub-Asset(s)", false, MenuPriority)]
private static void DeleteSubAsset()
{
bool isOne = Selection.objects.Length == 1;
bool decision = EditorUtility.DisplayDialog(
isOne ? "Delete Sub-Asset" : "Delete Sub-Assets",
isOne
? string.Format(Constants.ConfirmDeleteSubAsset, Selection.objects[0].name)
: string.Format(Constants.ConfirmDeleteSubAssets, Selection.objects[0].name, Selection.objects[1].name),
isOne ? "Delete" : "Delete all",
"Cancel");
if (!decision) return;
foreach (Object obj in Selection.objects)
{
string parentObjectPath = AssetDatabase.GetAssetPath(obj);
SubAssetsToolbox.RemoveSubAsset(parentObjectPath, obj);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
[MenuItem("Assets/Delete Sub-Asset(s)", true)]
private static bool ValidateDeleteSubAsset()
{
return Selection.objects.Length > 0 && Selection.objects.All(AssetDatabase.IsSubAsset);
}
[MenuItem("Assets/Rename Sub-Asset", false, MenuPriority)]
private static void RenameSubAsset()
{
RenameSubAssetWindow.Open(Selection.activeObject);
}
[MenuItem("Assets/Rename Sub-Asset", true)]
private static bool ValidateRenameSubAsset()
{
return Selection.objects.Length == 1 && AssetDatabase.IsSubAsset(Selection.activeObject);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 8ed8576868e8473292b2e9e96fa41ac0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/SubAssetContextMenu.cs
uploadId: 869944

View File

@@ -0,0 +1,26 @@
{
"name": "SubAssetsToolbox.Editor",
"rootNamespace": "SubAssetsToolbox",
"references": [
"GUID:4fe8e68b5bc1841d0906774ad72212e0",
"GUID:49818357e697641afb75d2f8acaf1861",
"GUID:69448af7b92c7f342b298e06a37122aa"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.addressables",
"expression": "1.0.0",
"define": "ADDRESSABLES_INSTALLED"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 33f3227df0b844d9ebd60340b54d45ae
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/SubAssetsToolbox.Editor.asmdef
uploadId: 869944

View File

@@ -0,0 +1,25 @@
using SubAssetsToolbox.Editor.SubAssetAware;
using UnityEditor;
using UnityEngine;
namespace SubAssetsToolbox.Editor
{
static class SubAssetsToolbox
{
public static void AddSubAsset(string destinationPath, Object objectToClone, out Object newClone)
{
newClone = Object.Instantiate(objectToClone);
newClone.name = objectToClone.name;
AssetDatabase.AddObjectToAsset(newClone, destinationPath);
SubAssetAwareMethods.NotifyAwareObjectOfAddition(destinationPath, newClone);
}
public static void RemoveSubAsset(string oldParentPath, Object objectToRemove)
{
SubAssetAwareMethods.NotifyAwareObjectOfRemoval(oldParentPath, objectToRemove);
AssetDatabase.RemoveObjectFromAsset(objectToRemove);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: af033a8f131d48e3a34167d2ff27a519
timeCreated: 1719906421
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/SubAssetsToolbox.cs
uploadId: 869944

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dd9b62119243e4abb9b82c65372d038f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
#if ADDRESSABLES_INSTALLED
using System.Collections.Generic;
using SubAssetsToolbox.Editor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
namespace SubAssetsToolbox.Utilities
{
internal static class AddressableEntryMigrator
{
internal static void MigrateOrRemoveEntry(string oldGuid, string parentGuid, string parentName)
{
AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null) return;
AddressableAssetEntry oldEntry = settings.FindAssetEntry(oldGuid);
if (oldEntry == null) return;
string oldName = oldEntry.MainAsset != null ? oldEntry.MainAsset.name : oldGuid;
string address = oldEntry.address;
AddressableAssetGroup group = oldEntry.parentGroup;
HashSet<string> labels = new(oldEntry.labels);
AddressableAssetEntry parentEntry = settings.FindAssetEntry(parentGuid);
if (parentEntry != null)
{
// New host asset was already an Addressable, so the new sub-asset
// is now addressable thanks to its parent and the old entry can be removed.
settings.RemoveAssetEntry(oldGuid);
Debug.Log(string.Format(Constants.AddressableEntryRemoved, oldName, address, parentName));
return;
}
// The new host asset wasn't an Addressable, so the new host needs to become one
settings.RemoveAssetEntry(oldGuid);
AddressableAssetEntry newEntry = settings.CreateOrMoveEntry(parentGuid, group, false, false);
newEntry.address = address;
foreach (string label in labels)
newEntry.SetLabel(label, true, true, false);
settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, newEntry, true);
Debug.Log(string.Format(Constants.AddressableEntryMigrated, oldName, address, parentName));
}
}
}
#endif

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2573a7e815d364c93b34c2a9efda007f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/Utilities/AddressableEntryMigrator.cs
uploadId: 869944

View File

@@ -0,0 +1,102 @@
using System.IO;
using System.Linq;
using System.Reflection;
using SubAssetsToolbox.Editor;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace SubAssetsToolbox.Utilities
{
public static class AssetReferenceRedirector
{
public static bool RedirectToSubAsset(Object sourceAsset, Object destinationSubAsset)
{
string sourceFileID = GetFileID(sourceAsset);
string destFileID = GetFileID(destinationSubAsset);
if (sourceFileID == null || destFileID == null) return false;
string sourceGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(sourceAsset));
string destGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(destinationSubAsset));
RedirectReferencesInYaml(sourceGuid, sourceFileID, destGuid, destFileID);
return true;
}
public static bool RedirectToStandaloneAsset(Object sourceSubAsset, Object destinationAsset)
{
string sourceFileID = GetFileID(sourceSubAsset);
string destFileID = GetFileID(destinationAsset);
if (sourceFileID == null || destFileID == null) return false;
string sourceGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(sourceSubAsset));
string destGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(destinationAsset));
RedirectReferencesInYaml(sourceGuid, sourceFileID, destGuid, destFileID);
return true;
}
private static void RedirectReferencesInYaml(string oldGuid, string oldFileID, string newGuid, string newFileID)
{
string[] extensions = SubAssetsToolboxSettings.PatchExtensions.value;
string[] allFiles = Directory.GetFiles("Assets", "*.*", SearchOption.AllDirectories)
.Where(f => extensions.Any(ext => f.EndsWith("." + ext)))
.ToArray();
// Save and cache open scenes, if needed
bool needToRestoreScenes = false;
SceneSetup[] sceneManagerSetup = EditorSceneManager.GetSceneManagerSetup();
string[] sceneFiles = allFiles.Where(f => f.EndsWith(".unity")).ToArray();
if (sceneFiles.Length > 0)
{
needToRestoreScenes = sceneManagerSetup.Any(sceneSetup => sceneFiles.Any(f => f == sceneSetup.path));
if (needToRestoreScenes)
{
EditorSceneManager.SaveOpenScenes();
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
}
}
foreach (string filePath in allFiles)
{
string content = File.ReadAllText(filePath);
if (!content.Contains(oldGuid)) continue;
string oldPattern = $"{{fileID: {oldFileID}, guid: {oldGuid}";
string replacement = $"{{fileID: {newFileID}, guid: {newGuid}";
string newContent = content.Replace(oldPattern, replacement);
if (newContent == content) continue;
//Debug.Log($"Updated references in {filePath}");
File.WriteAllText(filePath, newContent);
}
AssetDatabase.Refresh();
if (needToRestoreScenes)
EditorApplication.delayCall += () =>
EditorSceneManager.RestoreSceneManagerSetup(sceneManagerSetup);
}
static string GetFileID(Object obj)
{
long id = (long)Unsupported.GetLocalIdentifierInFileForPersistentObject(obj);
if (id != 0) return id.ToString();
// Reflection fallback
SerializedObject so = new(obj);
PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance);
inspectorModeInfo?.SetValue(so, InspectorMode.Debug, null);
SerializedProperty localIdProp = so.FindProperty("m_LocalIdentifierInFile");
if (localIdProp != null && localIdProp.longValue != 0)
return localIdProp.longValue.ToString();
Debug.LogError(string.Format(Constants.FileIdRetrievalFailed, obj.name));
return null;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: e19698ca5817474fbc5e211dae150119
timeCreated: 1770839624
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/Utilities/AssetReferenceRedirector.cs
uploadId: 869944

View File

@@ -0,0 +1,64 @@
namespace SubAssetsToolbox.Editor
{
public static class Constants
{
public const string MenuItemBaseName = "Tools/SubAssets Toolbox/";
// URLs
public const string ReviewUrl = "https://assetstore.unity.com/packages/tools/utilities/subassets-toolbox-284154#reviews";
public const string DiscordUrl = "https://discord.com/invite/rCRug7Szr8";
public const string DocumentationUrl = "https://tools.continis.io/v/subassets-toolbox";
public const string OtherToolsUrl = "https://assetstore.unity.com/publishers/87819";
public const string SupportEmail = "mailto:buoybase@gmail.com";
public const string PackageName = "io.continis.subassets-toolbox";
public const string PackageAssetsFolder = "Packages/io.continis.subassets-toolbox";
public const string PackageReadableName = "SubAssets Toolbox";
// Error messages - Sub-asset type restrictions
internal static readonly string AddingPrefabAsSubAsset = $"({PackageReadableName}) Adding a Prefab as a SubAsset is not allowed.";
internal static readonly string AddingFolderAsSubAsset = $"({PackageReadableName}) Adding a Folder as a SubAsset is not allowed.";
internal static readonly string AddingScriptAsSubAsset = $"({PackageReadableName}) Adding a script as a SubAsset is not allowed.";
internal static readonly string Adding3DModelAsSubAsset = $"({PackageReadableName}) Adding a 3D model as a SubAsset is not allowed.";
internal static readonly string AddingShaderAsSubAsset = $"({PackageReadableName}) Adding a shader as a SubAsset is not allowed.";
// Error messages - Destination type restrictions
internal static readonly string AddingSubAssetToScript = $"({PackageReadableName}) Adding SubAssets to a script is not allowed.";
internal static readonly string AddingSubAssetToShader = $"({PackageReadableName}) Adding SubAssets to a Shader is not allowed.";
internal static readonly string AddingSubAssetTo3DModel = $"({PackageReadableName}) Adding SubAssets to a 3D model is not allowed.";
internal static readonly string AddingSubAssetToMixer = $"({PackageReadableName}) Adding SubAssets to an AudioMixer is not allowed.";
internal static readonly string AddingSubAssetToScene = $"({PackageReadableName}) Adding SubAssets to a scene is not allowed.";
// Warnings
internal static readonly string ExtensionDefaultedToAsset = $"({PackageReadableName}) It was impossible to determine the removed sub-assets extension, so it has defaulted to \".asset\". " +
"We recommend to change it now in your file system, if it matters.";
internal static readonly string ImpossibleToExtract =
$"({PackageReadableName}) Impossible to extract {{0}} from its main asset. An asset with the same name already exists in the same location.";
internal static readonly string RedirectionFailed = $"({PackageReadableName}) Reference patching failed for {{0}}. The original asset was kept to avoid broken references.";
internal static readonly string FileIdRetrievalFailed = $"({PackageReadableName}) Could not retrieve fileID for {{0}}. Reference redirection skipped for this object.";
// Dialog messages
internal const string LossOfDataWarning = "If you choose not to, you will have to " +
"fix those references manually.\n\n" +
"This process might lead to loss of data, " +
"so make sure you have your project under version control.";
internal const string ConfirmAddAsSubAsset = "Are you sure you want to add {0} as a sub-asset to {1}?";
internal const string ConfirmAddAsSubAssets = "Are you sure you want to add {0}, {1}, (...) as sub-assets to {2}?";
internal const string ConfirmDeleteSubAsset = "Are you sure you want to delete {0}?";
internal const string ConfirmDeleteSubAssets = "Are you sure you want to delete {0}, {1}, (...)?";
internal const string PatchRefsToSubAssetPrompt =
"Do you want to patch all references to the dragged asset(s) to point to the newly-created sub-asset(s)? " + LossOfDataWarning;
internal const string PatchRefsToStandalonePrompt =
"Do you want to patch all references to the dragged sub-asset(s) to point to the newly-created asset(s)? " + LossOfDataWarning;
// Addressable messages
internal static readonly string AddressableEntryMigrated =
$"({PackageReadableName}) Addressable entry '{{0}}' (address: {{1}}) was migrated to the parent asset {{2}}.";
internal static readonly string AddressableEntryRemoved =
$"({PackageReadableName}) Addressable entry '{{0}}' (address: {{1}}) was removed. The parent asset {{2}} is already Addressable.";
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ebbd0fca8514146f8bcbc90035ba23d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/Utilities/Constants.cs
uploadId: 869944

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using SubAssetsToolbox.Editor;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.U2D;
namespace SubAssetsToolbox.Utilities
{
public static class ExtensionMap
{
public static string GetFileExtensionByType(Type t)
{
if (_extensions.TryGetValue(t, out string ext))
return ext;
else
{
if(!typeof(ScriptableObject).IsAssignableFrom(t))
Debug.LogWarning(Constants.ExtensionDefaultedToAsset);
return "asset";
}
}
private static readonly Dictionary<Type, string> _extensions = new()
{
// Rendering / Shaders
{ typeof(Material), "mat" },
{ typeof(Shader), "shader" },
{ typeof(ComputeShader), "compute" },
{ typeof(ShaderVariantCollection), "shadervariants" },
{ typeof(LightmapParameters), "giparams" },
{ typeof(LightingSettings), "lighting" },
// Animation
{ typeof(AnimationClip), "anim" },
{ typeof(AnimatorController), "controller" },
{ typeof(AnimatorOverrideController), "overrideController" },
{ typeof(AvatarMask), "mask" },
{ typeof(Avatar), "avatar" },
// Physics
#if UNITY_6000_0_OR_NEWER
{ typeof(PhysicsMaterial), "physicsMaterial" },
#else
{ typeof(PhysicMaterial), "physicMaterial" },
#endif
{ typeof(PhysicsMaterial2D), "physicsMaterial2D" },
// Audio
{ typeof(AudioMixer), "mixer" },
// 2D
{ typeof(SpriteAtlas), "spriteatlas" },
// Textures
{ typeof(Cubemap), "cubemap" },
{ typeof(RenderTexture), "rendertexture" },
// 3D
{ typeof(Mesh), "mesh" },
{ typeof(TerrainLayer), "terrainlayer" },
// GUI
{ typeof(Font), "fontsettings" },
{ typeof(GUISkin), "guiskin" },
// Effects
{ typeof(Flare), "flare" },
{ typeof(LightingDataAsset), "lighting" }
};
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: d3732dc6b75842c8a5d9f63611840216
timeCreated: 1757267868
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/Utilities/ExtensionMap.cs
uploadId: 869944

View File

@@ -0,0 +1,130 @@
using UnityEditor;
using UnityEngine;
namespace SubAssetsToolbox.Editor
{
public static class TypeChecker
{
/// <summary>
/// Checks if a path contains a type that can be made into a sub-asset
/// </summary>
public static bool ValidateSubAssetType(string path, bool silent = false)
{
if (AssetDatabase.IsValidFolder(path))
{
if (!silent) Debug.LogError(Constants.AddingFolderAsSubAsset);
return false;
}
if (path.EndsWith(".prefab"))
{
if (!silent) Debug.LogError(Constants.AddingPrefabAsSubAsset);
return false;
}
if (path.EndsWith(".cs"))
{
if (!silent) Debug.LogError(Constants.AddingScriptAsSubAsset);
return false;
}
if (IsShader(path))
{
if (!silent) Debug.LogError(Constants.AddingShaderAsSubAsset);
return false;
}
if (Is3DModel(path))
{
if (!silent) Debug.LogError(Constants.Adding3DModelAsSubAsset);
return false;
}
if (path.EndsWith(".meta"))
{
return false;
}
return true;
}
/// <summary>
/// Checks if a path contains a type that can accept sub-assets
/// </summary>
public static bool ValidateDestinationType(string destinationPath, bool silent = false)
{
if (destinationPath.EndsWith(".cs"))
{
if (!silent) Debug.LogError(Constants.AddingSubAssetToScript);
return false;
}
if (destinationPath.EndsWith(".unity"))
{
if (!silent) Debug.LogError(Constants.AddingSubAssetToScene);
return false;
}
if (IsShader(destinationPath))
{
if (!silent) Debug.LogError(Constants.AddingSubAssetToShader);
return false;
}
if (Is3DModel(destinationPath))
{
if (!silent) Debug.LogError(Constants.AddingSubAssetTo3DModel);
return false;
}
if (destinationPath.EndsWith(".mixer"))
{
if (!silent) Debug.LogError(Constants.AddingSubAssetToMixer);
return false;
}
if (destinationPath.EndsWith(".meta"))
{
return false;
}
return true;
}
/// <summary>
/// Checks if a path contains a type where the right-click is already doing something else
/// i.e. when right-clicking on a Shader and creating a Material, it should create a Material
/// with that Shader and not a Material as a sub-object of a Shader.
/// </summary>
public static bool HasDefaultAction(string newObjectPath, string destinationPath)
{
// Prefab variants
if (newObjectPath.EndsWith(".prefab") && destinationPath.EndsWith(".prefab"))
{
return true;
}
// Variant of a 3D model
bool destinationIs3DModel = Is3DModel(destinationPath);
if (newObjectPath.EndsWith(".prefab") && destinationIs3DModel)
{
return true;
}
// Material from shader
bool destinationIsShader = IsShader(destinationPath);
if (newObjectPath.EndsWith(".mat") && destinationIsShader)
{
return true;
}
return false;
}
private static bool IsShader(string path) => path.EndsWith(".shader") || path.EndsWith(".shadergraph");
private static bool Is3DModel(string path) =>
path.EndsWith(".fbx") || path.EndsWith(".blend") ||
path.EndsWith(".obj") || path.EndsWith(".3ds");
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: e015603f942f4b20bafb85236f2ac50d
timeCreated: 1741992985
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/Utilities/TypeChecker.cs
uploadId: 869944

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 626be9248eedc46f8933a153c87205f4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using UnityEditor;
using UnityEngine;
namespace SubAssetsToolbox.Editor
{
public static class MenuItems
{
[InitializeOnLoadMethod]
public static void CheckShowWelcomeScreen()
{
if (!SubAssetsToolboxSettings.WelcomeWindowSeen.value)
{
EditorApplication.delayCall += WelcomeScreen.Init;
SubAssetsToolboxSettings.WelcomeWindowSeen.SetValue(true, true);
}
}
[MenuItem(Constants.MenuItemBaseName + "Documentation", false, 100)]
public static void OpenDocumentation() => Application.OpenURL(Constants.DocumentationUrl);
[MenuItem(Constants.MenuItemBaseName + "Email support", false, 101)]
public static void EmailSupport() => Application.OpenURL(Constants.SupportEmail);
[MenuItem(Constants.MenuItemBaseName + "Join Discord", false, 102)]
public static void JoinDiscord() => Application.OpenURL(Constants.ReviewUrl);
[MenuItem(Constants.MenuItemBaseName + "Write a review", false, 105)]
public static void LeaveAReview() => Application.OpenURL(Constants.ReviewUrl);
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: fcfb5b3277a0f43c292486d6198f002b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/WindowsAndMenus/MenuItems.cs
uploadId: 869944

View File

@@ -0,0 +1,87 @@
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace SubAssetsToolbox.Editor
{
internal class RenameSubAssetWindow : EditorWindow
{
[SerializeField] private VisualTreeAsset _visualTreeAsset;
private Object _target;
private TextField _nameField;
private Button _renameButton;
public static void Open(Object subAsset)
{
RenameSubAssetWindow window = GetWindow<RenameSubAssetWindow>(true, "Rename Sub-Asset");
window._target = subAsset;
window.minSize = new Vector2(300f, 70f);
window.maxSize = new Vector2(300f, 70f);
window.Populate();
window.Show();
}
private void CreateGUI()
{
VisualElement root = rootVisualElement;
VisualElement template = _visualTreeAsset.Instantiate();
template.style.flexGrow = 1f;
_nameField = template.Q<TextField>("NameField");
_nameField.selectAllOnFocus = true;
_nameField.RegisterValueChangedCallback(_ => UpdateRenameButton());
_nameField.RegisterCallback<KeyUpEvent>(OnKeyUp);
template.Q<Button>("CancelBtn").clicked += Close;
_renameButton = template.Q<Button>("RenameBtn");
_renameButton.clicked += PerformRename;
root.Add(template);
UpdateRenameButton();
}
private void OnKeyUp(KeyUpEvent evt)
{
switch (evt.keyCode)
{
case KeyCode.Return:
case KeyCode.KeypadEnter:
PerformRename();
break;
case KeyCode.Escape:
Close();
break;
}
}
private void Populate()
{
_nameField.value = _target != null ? _target.name : "";
UpdateRenameButton();
_nameField.schedule.Execute(() =>
{
_nameField.Focus();
_nameField.SelectAll();
});
}
private void UpdateRenameButton()
{
bool valid = _target != null
&& !string.IsNullOrWhiteSpace(_nameField.value)
&& _nameField.value != _target.name;
_renameButton.SetEnabled(valid);
}
private void PerformRename()
{
_target.name = _nameField.value;
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Close();
}
}
}

View File

@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: d6c1e8c8d4e4648ff89db9289140ebc1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_ViewDataDictionary: {instanceID: 0}
- _visualTreeAsset: {fileID: 9197481963319205126, guid: b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7,
type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/WindowsAndMenus/RenameSubAssetWindow.cs
uploadId: 869944

View File

@@ -0,0 +1,37 @@
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace SubAssetsToolbox.Editor
{
public class WelcomeScreen : EditorWindow
{
[SerializeField] private VisualTreeAsset _visualTreeAsset;
private static WelcomeScreen _window;
[MenuItem(Constants.MenuItemBaseName + "Welcome screen", false, 0)]
public static void Init()
{
_window = GetWindow<WelcomeScreen>(true);
_window.titleContent = new GUIContent("SubAssets Toolbox");
_window.minSize = new Vector2(300f, 400f);
_window.maxSize = new Vector2(300f, 400f);
_window.Show();
}
private void CreateGUI()
{
VisualElement root = rootVisualElement;
VisualElement templateWindow = _visualTreeAsset.Instantiate();
templateWindow.style.flexGrow = 1f;
templateWindow.Q<Button>("DocsBtn").clicked += () => Application.OpenURL(Constants.DocumentationUrl);
templateWindow.Q<Button>("EmailBtn").clicked += () => Application.OpenURL(Constants.SupportEmail);
templateWindow.Q<Button>("DiscordBtn").clicked += () => Application.OpenURL(Constants.DiscordUrl);
templateWindow.Q<Button>("OtherToolsBtn").clicked += () => Application.OpenURL(Constants.OtherToolsUrl);
templateWindow.Q<Button>("ReviewBtn").clicked += () => Application.OpenURL(Constants.ReviewUrl);
root.Add(templateWindow);
}
}
}

View File

@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: a17879cf1b9d14c45a1c43136fa833e2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_ViewDataDictionary: {instanceID: 0}
- _visualTreeAsset: {fileID: 9197481963319205126, guid: 1ad4f2b6f50fc4b74a7886c0f754da60,
type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Editor/WindowsAndMenus/WelcomeScreen.cs
uploadId: 869944