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,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