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

@@ -10,14 +10,9 @@
"overrideReferences": false,
"precompiledReferences": [
"Newtonsoft.Json.dll",
"Microsoft.CSharp.dll",
"Microsoft.CodeAnalysis.dll",
"Microsoft.CodeAnalysis.CSharp.dll",
"System.Collections.Immutable.dll",
"System.Reflection.Metadata.dll",
"System.Runtime.CompilerServices.Unsafe.dll"
"Microsoft.CSharp.dll"
],
"autoReferenced": true,
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false

View File

@@ -14,7 +14,7 @@
"bezi3d"
],
"unity": "2018.3",
"version": "0.90.0",
"version": "0.97.0",
"type": "library",
"hideInEditor": false,
"dependencies": {

View File

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

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

View File

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

View File

@@ -0,0 +1,13 @@
using UnityEngine;
namespace SubAssetsToolbox
{
/// <summary>
/// Implement this interface in your ScriptableObjects, to make them compatible with the editor workflows of SubAssets Toolbox.
/// </summary>
public interface ISubAssetAware
{
public void AddSubAsset(Object newSubAsset);
public void RemoveSubAsset(Object removedSubAsset);
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c7022673594b440fb6065b51d03bd283
timeCreated: 1720126068
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/Runtime/ISubAssetAware.cs
uploadId: 869944

View File

@@ -0,0 +1,14 @@
{
"name": "SubAssetsToolbox.Runtime",
"rootNamespace": "SubAssetsToolbox",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

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

View File

@@ -0,0 +1,47 @@
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace SubAssetsToolbox.Samples.Editor
{
[CustomEditor(typeof(SubAssetAwareSO), true)]
public class SubAssetAwareSOEditor : UnityEditor.Editor
{
public VisualTreeAsset lineTemplate;
public VisualTreeAsset extrasTemplate;
private SerializedProperty _subAssetsProp;
public override VisualElement CreateInspectorGUI()
{
VisualElement inspector = new();
InspectorElement.FillDefaultInspector(inspector, serializedObject, this);
_subAssetsProp = serializedObject.FindProperty("_subAssets");
if (_subAssetsProp.arraySize != 0)
{
extrasTemplate.CloneTree(inspector);
// Draw sub-assets list
ListView subAssetsList = inspector.Q<ListView>("SubAssetsList");
subAssetsList.makeItem += MakeItem;
subAssetsList.bindItem += BindItem;
subAssetsList.BindProperty(_subAssetsProp);
}
return inspector;
}
private VisualElement MakeItem()
{
return lineTemplate.Instantiate();
}
private void BindItem(VisualElement visualElement, int index)
{
Object subAsset = _subAssetsProp.GetArrayElementAtIndex(index).objectReferenceValue;
visualElement.Q<ObjectField>("SubAssetField").value = subAsset;
}
}
}

View File

@@ -0,0 +1,22 @@
fileFormatVersion: 2
guid: 21cab18be96345ce975cfe1380654953
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- lineTemplate: {fileID: 9197481963319205126, guid: a3eb80c229d604b8a8483f6df0d7f204,
type: 3}
- extrasTemplate: {fileID: 9197481963319205126, guid: 213eed75602b6410d8cdd7fd24509144,
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/Samples~/SubAssetAwareScriptableObjects/Editor/SubAssetAwareSOEditor.cs
uploadId: 869944

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using UnityEngine;
namespace SubAssetsToolbox.Samples
{
/// <summary>
/// ScriptableObject class that implements the <see cref="ISubAssetAware"/> interface to interact with sub-asset workflows.
/// Contains a List to keep references to its sub-assets. The list is displayed in the asset's Inspector using a custom editor.
/// Use this class as a starting point, and implement your own sub-asset aware ScriptableObjects.
/// </summary>
[CreateAssetMenu(menuName = "SubAssets Toolbox/SubAsset Aware SO", fileName = "SubAssetAwareSO")]
public class SubAssetAwareSO : ScriptableObject, ISubAssetAware
{
[SerializeField, HideInInspector] private List<Object> _subAssets = new();
public void AddSubAsset(Object newSubAsset) => _subAssets.Add(newSubAsset);
public void RemoveSubAsset(Object removedSubAsset) => _subAssets.Remove(removedSubAsset);
public virtual Object GetSubAssetByName(string subAssetName) => _subAssets.Find(o => o.name == subAssetName);
public virtual List<Object> GetAllSubAssetsByName(string subAssetName) => _subAssets.FindAll(o => o.name == subAssetName);
public virtual Object GetSubAssetByType<T>() => _subAssets.Find(o => o.GetType() == typeof(T));
public virtual List<Object> GetAllSubAssetsByType<T>() => _subAssets.FindAll(o => o.GetType() == typeof(T));
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ff267a32cfc64732a2ca1cc5b4acf09f
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/Samples~/SubAssetAwareScriptableObjects/SubAssetAwareSO.cs
uploadId: 869944

View File

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

View File

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

View File

@@ -0,0 +1,28 @@
fileFormatVersion: 2
guid: 79347a679a7e7497f8e487e1232b87ce
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontNames:
- Inter
fallbackFontReferences: []
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/Fonts/Inter-SemiBold.ttf
uploadId: 869944

View File

@@ -0,0 +1,92 @@
Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION AND CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 6cedb71ee602f4b94885d660f56ec40a
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/Fonts/LICENSE.txt
uploadId: 869944

View File

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

Binary file not shown.

View File

@@ -0,0 +1,121 @@
fileFormatVersion: 2
guid: fa7bd99e0d67f4c099433f6fdb324f3b
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 1
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/Images/Header.png
uploadId: 869944

View File

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

View File

@@ -0,0 +1,12 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
<Style src="project://database/Packages/io.continis.subassets/UI/UIToolkit/ProjectSettings_Styles.uss?fileID=7433441132597879392&amp;guid=c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8&amp;type=3#ProjectSettings_Styles" />
<ui:VisualElement name="Container" style="flex-grow: 1;">
<ui:Label name="Title" text="SubAssets Toolbox" class="header" />
<ui:ScrollView name="ContentScroll">
<ui:Label text="Patch References" class="subtitle" />
<ui:EnumField name="RedirectionModeField" label="Interaction Mode" tooltip="Controls how reference redirection behaves when moving assets/sub-assets." type="SubAssetsToolbox.Editor.ReferencePatchingMode, SubAssetsToolbox.Editor" value="AskEachTime" />
<ui:ListView name="ExtensionsList" reorderable="true" reorder-mode="Animated" show-border="true" show-foldout-header="true" header-title="File Types To Scan For References" show-add-remove-footer="true" tooltip="File extensions to scan when redirecting references. Only YAML-serialized assets that can contain object references need to be listed." />
<ui:Button name="ResetBtn" text="Reset to Default" tooltip="Resets the extensions to a sensible list of defaults." />
</ui:ScrollView>
</ui:VisualElement>
</ui:UXML>

View File

@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: a8aa26680d8cc45b99cd7b474fafc455
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/UIToolkit/ProjectSettings.uxml
uploadId: 869944

View File

@@ -0,0 +1,31 @@
#Container {
right: 3px;
margin-left: 12px;
margin-top: 1px;
}
#Title {
font-size: 19px;
-unity-font: initial;
margin-bottom: 10px;
-unity-font-definition: url("project://database/Packages/io.continis.subassets/UI/Fonts/Inter-SemiBold.ttf?fileID=12800000&guid=79347a679a7e7497f8e487e1232b87ce&type=3#Inter-SemiBold");
}
.subtitle {
-unity-font-definition: url("project://database/Packages/io.continis.subassets/UI/Fonts/Inter-SemiBold.ttf?fileID=12800000&guid=79347a679a7e7497f8e487e1232b87ce&type=3#Inter-SemiBold");
}
#ExtensionsList {
margin-top: 6px;
}
#ResetBtn {
align-self: flex-end;
margin-top: 4px;
}
#ContentScroll #unity-content-container {
margin-right: 4px;
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/UIToolkit/ProjectSettings_Styles.uss
uploadId: 869944

View File

@@ -0,0 +1,10 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<Style src="project://database/Packages/io.continis.subassets/UI/UIToolkit/RenameSubAssetWindow_Styles.uss?fileID=7433441132597879392&amp;guid=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6&amp;type=3#RenameSubAssetWindow_Styles"/>
<ui:VisualElement name="RenameRoot">
<ui:TextField name="NameField" label="New name"/>
<ui:VisualElement name="ButtonRow">
<ui:Button name="CancelBtn" text="Cancel"/>
<ui:Button name="RenameBtn" text="Rename"/>
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>

View File

@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/UIToolkit/RenameSubAssetWindow.uxml
uploadId: 869944

View File

@@ -0,0 +1,18 @@
#RenameRoot {
padding: 8px;
}
#ButtonRow {
flex-direction: row;
justify-content: flex-end;
margin-top: 8px;
}
#NameField > Label {
min-width: 70px;
}
#ButtonRow > Button {
width: 80px;
height: 24px;
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/UIToolkit/RenameSubAssetWindow_Styles.uss
uploadId: 869944

View File

@@ -0,0 +1,15 @@
#Separator {
background-color: var(--unity-colors-inspector_titlebar-border);
width: 100%;
height: 1px;
margin-top: 6px;
margin-bottom: 3px;
}
#SubAssetField .unity-object-field__selector {
display: none;
}
#SubAssetsList .unity-foldout__toggle {
margin-bottom: 2px;
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6e16c6dfd32f847f4a11bb13556553e5
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/UIToolkit/Styles.uss
uploadId: 869944

View File

@@ -0,0 +1,5 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<Style src="project://database/Packages/io.continis.subassets/UI/UIToolkit/Styles.uss?fileID=7433441132597879392&amp;guid=6e16c6dfd32f847f4a11bb13556553e5&amp;type=3#Styles"/>
<ui:VisualElement name="Separator"/>
<ui:ListView show-foldout-header="true" header-title="Sub-Assets" show-bound-collection-size="false" selection-type="Single" name="SubAssetsList" reorderable="true" show-add-remove-footer="false" reorder-mode="Animated" show-border="false" show-alternating-row-backgrounds="None" horizontal-scrolling="false"/>
</ui:UXML>

View File

@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: 213eed75602b6410d8cdd7fd24509144
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/UIToolkit/SubassetAwareExtras.uxml
uploadId: 869944

View File

@@ -0,0 +1,5 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<Style src="project://database/Packages/io.continis.subassets/UI/UIToolkit/Styles.uss?fileID=7433441132597879392&amp;guid=6e16c6dfd32f847f4a11bb13556553e5&amp;type=3#Styles"/>
<ui:VisualElement style="flex-direction: row; align-items: center;"/>
<uie:ObjectField name="SubAssetField"/>
</ui:UXML>

View File

@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: a3eb80c229d604b8a8483f6df0d7f204
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/UIToolkit/SubassetLine.uxml
uploadId: 869944

View File

@@ -0,0 +1,21 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<Style src="project://database/Packages/io.continis.subassets/UI/UIToolkit/WelcomeScreen_Styles.uss?fileID=7433441132597879392&amp;guid=28d9a404ff38a4f2abf61d0507d2dc56&amp;type=3#WelcomeScreen_Styles" />
<ui:VisualElement name="WelcomeScreen" style="flex-grow: 1;">
<ui:VisualElement name="Header">
<ui:VisualElement name="Logo" />
</ui:VisualElement>
<ui:VisualElement name="MainBody" style="flex-grow: 1;">
<ui:VisualElement name="Spacer" />
<ui:Label tabindex="-1" text="Welcome to SubAssets Toolbox!" parse-escape-sequences="true" display-tooltip-when-elided="true" class="Message" style="white-space: normal;" />
<ui:Label tabindex="-1" text="If you&apos;re new, take a moment to read the documentation." parse-escape-sequences="true" display-tooltip-when-elided="true" class="Message" style="white-space: normal;" />
<ui:Button text="Open documentation" parse-escape-sequences="true" display-tooltip-when-elided="true" name="DocsBtn" class="BigButton" />
<ui:VisualElement name="Spacer" style="flex-grow: 1;" />
<ui:Button text="Email support" parse-escape-sequences="true" display-tooltip-when-elided="true" name="EmailBtn" class="MediumButton" />
<ui:Button text="Join Discord" parse-escape-sequences="true" display-tooltip-when-elided="true" name="DiscordBtn" class="MediumButton" />
<ui:Button text="Explore other tools" display-tooltip-when-elided="true" name="OtherToolsBtn" class="MediumButton" />
<ui:Button text="Write a review" display-tooltip-when-elided="true" name="ReviewBtn" class="MediumButton" />
<ui:Label tabindex="-1" text="Note: You can always access this window again from the &lt;b&gt;Tools &gt; Codecks Scene Notes &gt; Welcome screen&lt;/b&gt; menu." parse-escape-sequences="true" display-tooltip-when-elided="true" class="Message" style="white-space: normal; display: none;" />
<ui:VisualElement name="Spacer" />
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>

View File

@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: 1ad4f2b6f50fc4b74a7886c0f754da60
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/UIToolkit/WelcomeScreen.uxml
uploadId: 869944

View File

@@ -0,0 +1,55 @@
#MainBody {
margin-right: 20px;
margin-left: 20px;
margin-top: 10px;
margin-bottom: 10px;
}
.BigButton {
height: 40px;
margin-top: 1px;
margin-bottom: 3px;
}
.MediumButton {
height: 24px;
margin-top: 1px;
margin-bottom: 3px;
}
.Message {
margin-top: 0;
margin-bottom: 10px;
}
#Spacer {
height: 10px;
}
#Header {
padding-top: 0;
padding-right: 0;
padding-bottom: 0;
padding-left: 0;
flex-grow: 1;
flex-shrink: 1;
min-height: 80px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
max-height: 120px;
-unity-background-scale-mode: scale-and-crop;
margin-bottom: 0;
margin-top: 10px;
-unity-font-style: bold;
margin-right: 10px;
margin-left: 10px;
background-image: url("project://database/Packages/io.continis.subassets/UI/Images/Header.png?fileID=2800000&guid=fa7bd99e0d67f4c099433f6fdb324f3b&type=3#Header");
}
#Logo {
-unity-background-scale-mode: scale-to-fit;
flex-grow: 1;
flex-shrink: 1;
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 28d9a404ff38a4f2abf61d0507d2dc56
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/UI/UIToolkit/WelcomeScreen_Styles.uss
uploadId: 869944

View File

@@ -0,0 +1,33 @@
{
"name": "io.continis.subassets",
"displayName": "SubAssets Toolbox",
"version": "1.1.0",
"unity": "2022.1",
"description": "A toolbox of workflows and API to easily create, delete, move and reference sub-assets.",
"keywords": [
"subassets",
"sub",
"assets",
"sub-assets",
"scriptable",
"scriptableObjects"
],
"author": {
"name": "Ciro Continisio",
"url": "https://tools.continis.io/",
"email": "buoybase@gmail.com"
},
"type": "tool",
"dependencies": {
"com.unity.settings-manager": "2.0.1"
},
"documentationUrl": "https://tools.continis.io/v/subassets-toolbox/",
"changelogUrl": "https://tools.continis.io/v/subassets-toolbox/changelog",
"samples": [
{
"displayName": "SubAsset Aware ScriptableObjects",
"description": "This sample demonstrates how to create ScriptableObjects that can keep a reference to their sub-assets.",
"path": "Samples~/SubAssetAwareScriptableObjects"
}
]
}

View File

@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 894ceaca850e84a0cb2dbee2e88cdd23
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 284154
packageName: SubAssets Toolbox
packageVersion: 1.1.0
assetPath: Packages/io.continis.subassets/package.json
uploadId: 869944

View File

@@ -10,6 +10,7 @@
"com.unity.ide.rider": "3.0.39",
"com.unity.ide.visualstudio": "2.0.26",
"com.unity.inputsystem": "1.18.0",
"com.unity.localization": "1.5.12",
"com.unity.multiplayer.center": "1.0.1",
"com.unity.nuget.newtonsoft-json": "3.2.1",
"com.unity.render-pipelines.universal": "17.3.0",

View File

@@ -142,6 +142,22 @@
},
"url": "https://packages.unity.com"
},
"com.unity.addressables": {
"version": "2.8.0",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.profiling.core": "1.0.2",
"com.unity.test-framework": "1.4.5",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.scriptablebuildpipeline": "2.5.1",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.burst": {
"version": "1.8.27",
"depth": 0,
@@ -228,6 +244,16 @@
},
"url": "https://packages.unity.com"
},
"com.unity.localization": {
"version": "1.5.12",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.addressables": "1.25.0",
"com.unity.nuget.newtonsoft-json": "3.0.2"
},
"url": "https://packages.unity.com"
},
"com.unity.mathematics": {
"version": "1.3.3",
"depth": 1,
@@ -296,6 +322,16 @@
"com.unity.render-pipelines.core": "17.0.3"
}
},
"com.unity.scriptablebuildpipeline": {
"version": "2.5.1",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.test-framework": "1.4.5",
"com.unity.modules.assetbundle": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.searcher": {
"version": "4.9.4",
"depth": 2,
@@ -303,6 +339,13 @@
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.settings-manager": {
"version": "2.1.1",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.shadergraph": {
"version": "17.3.0",
"depth": 1,
@@ -387,6 +430,14 @@
"source": "embedded",
"dependencies": {}
},
"io.continis.subassets": {
"version": "file:io.continis.subassets",
"depth": 0,
"source": "embedded",
"dependencies": {
"com.unity.settings-manager": "2.0.1"
}
},
"com.unity.modules.accessibility": {
"version": "1.0.0",
"depth": 0,