live2D (sdk가 6.5 미지원으로 sprite로 대응)

This commit is contained in:
2026-08-08 22:13:54 +09:00
parent 9ce6930772
commit 8a4a001fe0
4278 changed files with 287426 additions and 18 deletions

View File

@@ -0,0 +1,50 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
using Live2D.Cubism.Framework;
using System;
using System.Linq;
using UnityEngine;
namespace Live2D.Cubism.Editor.Importers
{
/// <summary>
/// Extensions for <see cref="MonoBehaviour"/>s.
/// </summary>
internal static class ComponentExtensionMethods
{
public static Component GetOrAddComponent(this Component self, Type type)
{
var component = self.GetComponent(type);
if (component != null)
{
return component;
}
return self.gameObject.AddComponent(type);
}
/// <summary>
/// Checks whether a component should be moved on reimport.
/// </summary>
/// <param name="self">Component to check against.</param>
/// <returns>True if component should be moved; false otherwise.</returns>
public static bool MoveOnCubismReimport(this Component self, bool componentsOnly)
{
return self
.GetType()
.GetCustomAttributes(false)
.FirstOrDefault(a => (a.GetType() == typeof(CubismDontMoveOnReimportAttribute)) || (a.GetType() == typeof(CubismMoveOnReimportCopyComponentsOnly) && !componentsOnly)) == null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 87405b60b59ea2746b508ef63aba402c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,300 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
using Live2D.Cubism.Core;
using Live2D.Cubism.Framework.Json;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Live2D.Cubism.Editor.Importers
{
/// <summary>
/// Helper functionality for <see cref="ICubismImporter"/>s.
/// </summary>
public static class CubismImporter
{
#region Delegates
/// <summary>
/// Callback on <see cref="CubismModel"/> import.
/// </summary>
/// <param name="importer">Importer.</param>
/// <param name="model">Imported model.</param>
public delegate void ModelImportListener(CubismModel3JsonImporter importer, CubismModel model);
/// <summary>
/// Callback for textures used by Cubism model on <see cref="CubismModel"/> import.
/// </summary>
public delegate void TextureImportHandler(CubismModel3JsonImporter importer, CubismModel model, Texture2D texture);
/// <summary>
/// Callback on Cubism motions import as<see cref="AnimationClip"/>.
/// </summary>
/// <param name="importer">Importer.</param>
/// <param name="animationClip">Generated animation.</param>
public delegate void MotionImportHandler(CubismMotion3JsonImporter importer, AnimationClip animationClip);
#endregion
#region Events
/// <summary>
/// Allows getting called back whenever a model is imported (and before it is saved).
/// </summary>
public static event ModelImportListener OnDidImportModel;
/// <summary>
/// Allows customizing import of textures used by a Cubism model.
/// </summary>
/// <remarks>
/// Set <see langword="null"/> in case you don't want Cubism model texture importing to be customized from script.
/// </remarks>
public static TextureImportHandler OnDidImportTexture = BuiltinTextureImportHandler;
/// <summary>
/// Material picker to use when importing models.
/// </summary>
public static CubismModel3Json.DrawableMaterialPicker OnPickDrawableMaterial = CubismBuiltinPickers.DrawableMaterialPicker;
/// <summary>
/// Texture picker to use when importing models.
/// </summary>
public static CubismModel3Json.TexturePicker OnPickTexture = CubismBuiltinPickers.TexturePicker;
/// <summary>
/// Offscreen material picker to use when importing models.
/// </summary>
public static CubismModel3Json.OffscreenMaterialPicker OnPickOffscreenMaterial = CubismBuiltinPickers.OffscreenMaterialPicker;
/// <summary>
/// Allows getting called back whenever a Cubism motions is imported (and before it is saved).
/// </summary>
public static event MotionImportHandler OnDidImportMotion;
#endregion
/// <summary>
/// Enables logging of import events.
/// </summary>
public static bool LogImportEvents = true;
/// <summary>
/// Tries to get an importer for a Cubism asset.
/// </summary>
/// <typeparam name="T">Importer type.</typeparam>
/// <param name="assetPath">Path to the asset.</param>
/// <returns>The importer on success; <see langword="null"/> otherwise.</returns>
public static T GetImporterAtPath<T>(string assetPath) where T : class, ICubismImporter
{
return GetImporterAtPath(assetPath) as T;
}
/// <summary>
/// Tries to deserialize an importer from <see cref="AssetImporter.userData"/>.
/// </summary>
/// <param name="assetPath">Path to the asset.</param>
/// <returns>The importer on success; <see langword="null"/> otherwise.</returns>
public static ICubismImporter GetImporterAtPath(string assetPath)
{
var importerEntry = _registry.Find(e => assetPath.EndsWith(e.FileExtension));
// Return early in case no valid importer is registered.
if (importerEntry.ImporterType == null)
{
return null;
}
var userData = AssetImporter
.GetAtPath(assetPath)
.userData;
// Try to deserialize a importer from the user data.
var importer = JsonUtility.FromJson(userData, importerEntry.ImporterType) as ICubismImporter;
// Activate an instance in case Json deserialization magically fails...
if (importer == null)
{
importer = Activator.CreateInstance(importerEntry.ImporterType) as ICubismImporter;
}
// Finalize importer initialization.
if (importer != null)
{
importer.SetAssetPath(assetPath);
}
return importer;
}
/// <summary>
/// Safely triggers <see cref="OnDidImportModel"/>.
/// </summary>
/// <param name="importer">Importer.</param>
/// <param name="model">Imported model.</param>
internal static void SendModelImportEvent(CubismModel3JsonImporter importer, CubismModel model)
{
if (OnDidImportModel == null)
{
return;
}
OnDidImportModel(importer, model);
}
/// <summary>
/// Safely triggers <see cref="OnDidImportModelTexture"/>
/// </summary>
/// <param name="importer">Importer.</param>
/// <param name="model">Imported model.</param>
/// <param name="texture">Imported texture.</param>
internal static void SendModelTextureImportEvent(CubismModel3JsonImporter importer, CubismModel model, Texture2D texture)
{
if (OnDidImportTexture == null)
{
return;
}
OnDidImportTexture(importer, model, texture);
}
/// <summary>
/// Safely triggers <see cref="OnDidImportMotion"/>.
/// </summary>
/// <param name="importer">Importer.</param>
/// <param name="animationClip">Generated animation.</param>
internal static void SendMotionImportEvent(CubismMotion3JsonImporter importer, AnimationClip animationClip)
{
if (OnDidImportMotion == null)
{
return;
}
OnDidImportMotion(importer, animationClip);
}
/// <summary>
/// Logs a reimport event.
/// </summary>
/// <param name="sourceName">Source asset reimported.</param>
/// <param name="destinationName">Destination asset updated.</param>
internal static void LogReimport(string sourceName, string destinationName)
{
if (!LogImportEvents)
{
return;
}
Debug.LogFormat("[Cubism] Reimport: \"{0}\" was synced with \"{1}\".", destinationName, sourceName);
}
#region Builtin Texture Import Handler
/// <summary>
/// Makes sure textures used by Cubism models have the <see cref="TextureImporter.alphaIsTransparency"/> option enabled.
/// </summary>
/// <param name="importer">Importer.</param>
/// <param name="model">Imported model.</param>
/// <param name="texture">Imported texture.</param>
private static void BuiltinTextureImportHandler(CubismModel3JsonImporter importer, CubismModel model, Texture2D texture)
{
var textureImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture)) as TextureImporter;
if (!textureImporter)
{
Debug.LogError("[Texture Importer] Could not get TextureImporter for texture used by Cubism model.");
return;
}
// Return early if texture already seems to be set up.
if (!textureImporter.mipmapEnabled
&& textureImporter.alphaIsTransparency
&& textureImporter.textureType == TextureImporterType.Default
&& textureImporter.textureCompression == TextureImporterCompression.Uncompressed
&& textureImporter.wrapMode == TextureWrapMode.Repeat
&& textureImporter.filterMode == FilterMode.Bilinear)
{
return;
}
// Set up texture importing.
textureImporter.mipmapEnabled = false;
textureImporter.alphaIsTransparency = true;
textureImporter.textureType = TextureImporterType.Default;
textureImporter.textureCompression = TextureImporterCompression.Uncompressed;
textureImporter.wrapMode = TextureWrapMode.Repeat;
textureImporter.filterMode = FilterMode.Bilinear;
EditorUtility.SetDirty(texture);
textureImporter.SaveAndReimport();
}
#endregion
#region Registry
/// <summary>
/// Registry entry.
/// </summary>
private struct ImporterEntry
{
/// <summary>
/// Importer type.
/// </summary>
public Type ImporterType;
/// <summary>
/// File extension valid for the importer.
/// </summary>
public string FileExtension;
}
/// <summary>
/// List of registered <see cref="ICubismImporter"/>s.
/// </summary>
private static List<ImporterEntry> _registry = new List<ImporterEntry>();
/// <summary>
/// Registers an importer type.
/// </summary>
/// <typeparam name="T">The type of importer to register.</typeparam>
/// <param name="fileExtension">The file extension the importer supports.</param>
internal static void RegisterImporter<T>(string fileExtension) where T : ICubismImporter
{
_registry.Add(new ImporterEntry
{
ImporterType = typeof(T),
FileExtension = fileExtension
});
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9a5211838ab488047b05c5806016ed5b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
using System;
using UnityEditor;
using UnityEngine;
namespace Live2D.Cubism.Editor.Importers
{
/// <summary>
/// Base class for Cubism asset importers.
/// </summary>
[Serializable]
public abstract class CubismImporterBase : ICubismImporter
{
/// <summary>
/// Gets the path to the imported asset.
/// </summary>
public string AssetPath { get; private set; }
/// <summary>
/// Imports the corresponding asset.
/// </summary>
public abstract void Import();
/// <summary>
/// Saves the importer state and reimports the asset.
/// </summary>
public void Save()
{
var assetImporter = AssetImporter.GetAtPath(AssetPath);
assetImporter.userData = JsonUtility.ToJson(this);
AssetDatabase.WriteImportSettingsIfDirty(AssetPath);
}
#region ICubismImporter
/// <summary>
/// Sets the asset path.
/// </summary>
void ICubismImporter.SetAssetPath(string value)
{
AssetPath = value;
}
/// <summary>
/// Imports the corresponding asset.
/// </summary>
void ICubismImporter.Import()
{
Import();
}
/// <summary>
/// Saves the importer state and reimports the asset.
/// </summary>
void ICubismImporter.Save()
{
Save();
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d72a86459d505cb4ebc7c52a389e9c00
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,416 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
using Live2D.Cubism.Core;
using Live2D.Cubism.Framework;
using Live2D.Cubism.Framework.Expression;
using Live2D.Cubism.Framework.Json;
using Live2D.Cubism.Framework.MotionFade;
using Live2D.Cubism.Framework.MouthMovement;
using Live2D.Cubism.Framework.Pose;
using Live2D.Cubism.Rendering;
using System;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Live2D.Cubism.Editor.Importers
{
/// <summary>
/// Handles importing of Cubism models.
/// </summary>
[Serializable]
public sealed class CubismModel3JsonImporter : CubismImporterBase
{
/// <summary>
/// <see cref="Model3Json"/> backing field.
/// </summary>
[NonSerialized] private CubismModel3Json _model3Json;
/// <summary>
///<see cref="CubismModel3Json"/> asset.
/// </summary>
public CubismModel3Json Model3Json
{
get
{
if (_model3Json == null)
{
_model3Json = CubismModel3Json.LoadAtPath(AssetPath);
}
#if UNITY_2018_3_OR_NEWER
if (_modelPrefab == null)
{
_modelPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(AssetPath.Replace(".model3.json", ".prefab"));
if(_modelPrefab != null)
{
_modelPrefabGuid = AssetGuid.GetGuid(_modelPrefab);
}
}
#endif
return _model3Json;
}
}
/// <summary>
/// Guid of model prefab.
/// </summary>
[SerializeField] private string _modelPrefabGuid;
/// <summary>
/// <see cref="ModelPrefab"/> backing field.
/// </summary>
[NonSerialized] private GameObject _modelPrefab;
/// <summary>
/// Prefab of model.
/// </summary>
private GameObject ModelPrefab
{
get
{
if (_modelPrefab == null)
{
_modelPrefab = AssetGuid.LoadAsset<GameObject>(_modelPrefabGuid);
}
return _modelPrefab;
}
set
{
_modelPrefab = value;
_modelPrefabGuid = AssetGuid.GetGuid(value);
}
}
/// <summary>
/// Guid of moc.
/// </summary>
[SerializeField]
private string _mocAssetGuid;
/// <summary>
/// <see cref="MocAsset"/> backing field.
/// </summary>
[NonSerialized]
private CubismMoc _mocAsset;
/// <summary>
/// Moc asset.
/// </summary>
private CubismMoc MocAsset
{
get
{
if (_mocAsset == null)
{
_mocAsset = AssetGuid.LoadAsset<CubismMoc>(_mocAssetGuid);
}
return _mocAsset;
}
set
{
_mocAsset = value;
_mocAssetGuid = AssetGuid.GetGuid(value);
}
}
/// <summary>
/// Should import as original workflow.
/// </summary>
private bool ShouldImportAsOriginalWorkflow
{
get
{
return CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow;
}
}
#region Unity Event Handling
/// <summary>
/// Registers importer.
/// </summary>
[InitializeOnLoadMethod]
// ReSharper disable once UnusedMember.Local
private static void RegisterImporter()
{
CubismImporter.RegisterImporter<CubismModel3JsonImporter>(".model3.json");
}
#endregion
#region CubismImporterBase
/// <summary>
/// Imports the corresponding asset.
/// </summary>
public override void Import()
{
var isImporterDirty = false;
// Instantiate model source and model.
var model = Model3Json.ToModel(CubismImporter.OnPickDrawableMaterial, CubismImporter.OnPickTexture, CubismImporter.OnPickOffscreenMaterial, ShouldImportAsOriginalWorkflow);
if (model == null)
{
return;
}
var assetPath = AssetPath.Replace(".model3.json", "");
var modelName = Path.GetFileName(assetPath).Replace(".model3.json", "");
var moc = model.Moc;
moc.name = modelName;
// Create moc asset.
if (MocAsset == null)
{
AssetDatabase.CreateAsset(moc, $"{assetPath}.asset");
MocAsset = moc;
isImporterDirty = true;
}
// Create model prefab.
if (ModelPrefab == null)
{
// Trigger event.
CubismImporter.SendModelImportEvent(this, model);
foreach (var texture in Model3Json.Textures)
{
CubismImporter.SendModelTextureImportEvent(this, model, texture);
}
// Create prefab and trigger saving of changes.
#if UNITY_2018_3_OR_NEWER
ModelPrefab = PrefabUtility.SaveAsPrefabAsset(model.gameObject, $"{assetPath}.prefab");
#else
ModelPrefab = PrefabUtility.CreatePrefab($"{assetPath}.prefab", model.gameObject);
#endif
isImporterDirty = true;
}
// Update model prefab.
else
{
var cubismModel = ModelPrefab.FindCubismModel();
if (cubismModel.Moc == null)
{
CubismModel.ResetMocReference(cubismModel,
AssetDatabase.LoadAssetAtPath<CubismMoc>(
$"{assetPath}.asset"));
}
// Copy all user data over from previous model.
var source = Object.Instantiate(ModelPrefab).FindCubismModel();
CopyUserData(source, model);
Object.DestroyImmediate(source.gameObject, true);
// Trigger events.
CubismImporter.SendModelImportEvent(this, model);
foreach (var texture in Model3Json.Textures)
{
CubismImporter.SendModelTextureImportEvent(this, model, texture);
}
var renderController = model.gameObject.GetComponent<CubismRenderController>();
if (renderController)
{
// HACK: Re-assign textures to avoid lost references due to Unity prefab optimization.
foreach (var cubismRenderer in renderController.DrawableRenderers)
{
// Reset texture references.
cubismRenderer.MainTexture =
CubismBuiltinPickers.TexturePicker(Model3Json, cubismRenderer.Drawable);
}
}
// Reset moc reference.
CubismModel.ResetMocReference(model, MocAsset);
// Update moc asset before saving prefab to avoid IndexOutOfRangeException
// when Inspector loads the prefab and calls Revive() with stale moc data.
if (MocAsset != null)
{
EditorUtility.CopySerialized(moc, MocAsset);
// Revive by force to make instance using the new Moc.
CubismMoc.ResetUnmanagedMoc(MocAsset);
EditorUtility.SetDirty(MocAsset);
}
// Keep layer value.
model.gameObject.layer = ModelPrefab.layer;
// Replace prefab.
#if UNITY_2018_3_OR_NEWER
ModelPrefab = PrefabUtility.SaveAsPrefabAsset(model.gameObject, $"{assetPath}.prefab");
// Clear stale non-serialized state cached during prefab replacement.
var savedModel = ModelPrefab.FindCubismModel();
if (savedModel != null)
{
CubismModel.ResetNonSerializedFields(savedModel);
}
#else
ModelPrefab = PrefabUtility.ReplacePrefab(model.gameObject, ModelPrefab, ReplacePrefabOptions.ConnectToPrefab);
#endif
// Log event.
CubismImporter.LogReimport(AssetPath, AssetDatabase.GUIDToAssetPath(_modelPrefabGuid));
}
// Clean up.
Object.DestroyImmediate(model.gameObject, true);
// Save state and assets.
if (isImporterDirty)
{
Save();
}
else
{
AssetDatabase.SaveAssets();
}
}
#endregion
private static void CopyUserData(CubismModel source, CubismModel destination, bool copyComponentsOnly = false)
{
// Give parameters, parts, and drawables special treatment.
CopyUserData(source.Parameters, destination.Parameters, copyComponentsOnly);
CopyUserData(source.Parts, destination.Parts, copyComponentsOnly);
CopyUserData(source.Drawables, destination.Drawables, copyComponentsOnly);
// Copy components.
foreach (var sourceComponent in source.GetComponents(typeof(Component)))
{
// Skip non-movable components.
if (!sourceComponent.MoveOnCubismReimport(copyComponentsOnly))
{
continue;
}
// skip copy original workflow component.
if(sourceComponent.GetType() == typeof(CubismUpdateController)
|| sourceComponent.GetType() == typeof(CubismFadeController)
|| sourceComponent.GetType() == typeof(CubismExpressionController)
|| sourceComponent.GetType() == typeof(CubismPoseController)
|| sourceComponent.GetType() == typeof(CubismParameterStore)
|| sourceComponent.GetType() == typeof(CubismDisplayInfoCombinedParameterInfo))
{
continue;
}
// Copy component.
var destinationComponent = destination.GetOrAddComponent(sourceComponent.GetType());
EditorUtility.CopySerialized(sourceComponent, destinationComponent);
}
}
private static void CopyUserData<T>(T[] source, T[] destination, bool copyComponentsOnly) where T : MonoBehaviour
{
foreach (var destinationT in destination)
{
var sourceT = source.FirstOrDefault(p => p.name == destinationT.name);
// Skip removed parameters.
if (sourceT == null)
{
continue;
}
// Copy any children.
foreach (var child in sourceT.transform
.GetComponentsInChildren<Transform>()
.Where(t => t != sourceT.transform)
.Select(t => t.gameObject))
{
Object.Instantiate(child, destinationT.transform);
}
// Copy components.
foreach (var sourceComponent in sourceT.GetComponents(typeof(Component)))
{
// Skip non-movable components.
if (!sourceComponent.MoveOnCubismReimport(copyComponentsOnly))
{
continue;
}
// Skip import-managed components that should not be inherited from the old prefab.
if (sourceComponent.GetType() == typeof(CubismEyeBlinkParameter)
|| sourceComponent.GetType() == typeof(CubismMouthParameter))
{
continue;
}
// Copy component.
var destinationComponent = destinationT.GetOrAddComponent(sourceComponent.GetType());
if (destinationComponent is CubismDisplayInfoParameterName cdiParameterName && !string.IsNullOrEmpty(cdiParameterName.Name))
{
var name = cdiParameterName.Name;
EditorUtility.CopySerialized(sourceComponent, destinationComponent);
cdiParameterName.Name = name;
EditorUtility.SetDirty(cdiParameterName);
}
else if (destinationComponent is CubismDisplayInfoPartName cdiPartName && !string.IsNullOrEmpty(cdiPartName.Name))
{
var name = cdiPartName.Name;
EditorUtility.CopySerialized(sourceComponent, destinationComponent);
cdiPartName.Name = name;
EditorUtility.SetDirty(cdiPartName);
}
else
{
EditorUtility.CopySerialized(sourceComponent, destinationComponent);
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c2b5f5eae05433546b6801c35df937b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,276 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
using Live2D.Cubism.Framework.Json;
using System;
using System.IO;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
namespace Live2D.Cubism.Editor.Importers
{
/// <summary>
/// Handles importing of Cubism motions.
/// </summary>
[Serializable]
public sealed class CubismMotion3JsonImporter : CubismImporterBase
{
/// <summary>
/// <see cref="Motion3Json"/> backing field.
/// </summary>
[NonSerialized]
private CubismMotion3Json _motion3Json;
/// <summary>
///<see cref="CubismMotion3Json"/> asset.
/// </summary>
public CubismMotion3Json Motion3Json
{
get
{
if (_motion3Json == null)
{
_motion3Json = CubismMotion3Json.LoadFrom(AssetDatabase.LoadAssetAtPath<TextAsset>((AssetPath)));
}
return _motion3Json;
}
}
/// <summary>
/// GUID of generated clip.
/// </summary>
[SerializeField] private string _animationClipGuid;
/// <summary>
/// <see cref="AnimationClip"/> backing field.
/// </summary>
[NonSerialized] private AnimationClip _animationClip;
/// <summary>
/// Gets the moc3 importer.
/// </summary>
private AnimationClip AnimationClip
{
get
{
if (_animationClip != null)
{
return _animationClip;
}
AnimationClip clip;
var directoryName = Path.GetDirectoryName(AssetPath);
var motionName = Path.GetFileName(AssetPath.Replace(".motion3.json", ".anim"));
var motionPath = $"{directoryName}/{motionName}";
motionPath = motionPath.Replace("\\", "/");
var assetList = CubismCreatedAssetList.GetInstance();
var assetListIndex = assetList.AssetPaths.Contains(motionPath)
? assetList.AssetPaths.IndexOf(motionPath)
: -1;
// When the AnimationClip has already been registered in CubismCreatedAssetList.Assets.
if (assetListIndex >= 0)
{
clip = (AnimationClip)assetList.Assets[assetListIndex];
_animationClip = clip;
_animationClipGuid = AssetGuid.GetGuid(_animationClip);
return _animationClip;
}
clip = AssetGuid.LoadAsset<AnimationClip>(_animationClipGuid);
_animationClip = clip;
_animationClipGuid = AssetGuid.GetGuid(_animationClip);
// When the AnimationClip can be retrieved from a GUID.
if (_animationClip != null)
{
return _animationClip;
}
clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(AssetPath.Replace(".motion3.json", ".anim"));
_animationClip = clip;
_animationClipGuid = AssetGuid.GetGuid(clip);
return _animationClip;
}
set
{
_animationClip = value;
_animationClipGuid = AssetGuid.GetGuid(value);
}
}
/// <summary>
/// Should import as original workflow.
/// </summary>
private bool ShouldImportAsOriginalWorkflow
{
get
{
return CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow;
}
}
/// <summary>
/// Should clear animation clip curves.
/// </summary>
private bool ShouldClearAnimationCurves
{
get
{
return CubismUnityEditorMenu.ShouldClearAnimationCurves;
}
}
#region Unity Event Handling
/// <summary>
/// Registers importer.
/// </summary>
[InitializeOnLoadMethod]
// ReSharper disable once UnusedMember.Local
private static void RegisterImporter()
{
CubismImporter.RegisterImporter<CubismMotion3JsonImporter>(".motion3.json");
}
#endregion
#region CubismImporterBase
/// <summary>
/// Imports the corresponding asset.
/// </summary>
public override void Import()
{
if (Motion3Json == null)
{
return;
}
var isImporterDirty = false;
// Add reference of motion to list.
var directoryName = Path.GetDirectoryName(AssetPath);
var motionName = Path.GetFileName(AssetPath.Replace(".motion3.json", ""));
var motionPath = $"{directoryName}/{motionName}.anim";
var assetList = CubismCreatedAssetList.GetInstance();
var assetListIndex = assetList.AssetPaths.Contains(motionPath)
? assetList.AssetPaths.IndexOf(motionPath)
: -1;
AnimationClip clip;
if (assetListIndex < 0)
{
clip = (ShouldImportAsOriginalWorkflow)
? AssetDatabase.LoadAssetAtPath<AnimationClip>(motionPath)
: null;
// Convert motion.
var animationClip = (clip == null)
? Motion3Json.ToAnimationClip(ShouldImportAsOriginalWorkflow, ShouldClearAnimationCurves)
: Motion3Json.ToAnimationClip(clip, ShouldImportAsOriginalWorkflow, ShouldClearAnimationCurves);
if (animationClip == null)
{
return;
}
animationClip.name = motionName;
// Create animation clip.
if (AnimationClip == null)
{
AssetDatabase.CreateAsset(animationClip, AssetPath.Replace(".motion3.json", ".anim"));
AnimationClip = animationClip;
}
isImporterDirty = true;
clip = AnimationClip;
assetList.Assets.Add(AnimationClip);
assetList.AssetPaths.Add(motionPath);
assetList.IsImporterDirties.Add(false);
}
else
{
// Update animation clip.
clip = (AnimationClip)assetList.Assets[assetListIndex];
// Convert motion.
var animationClip = (clip == null)
? Motion3Json.ToAnimationClip(ShouldImportAsOriginalWorkflow, ShouldClearAnimationCurves)
: Motion3Json.ToAnimationClip(clip, ShouldImportAsOriginalWorkflow, ShouldClearAnimationCurves);
if (animationClip == null)
{
return;
}
animationClip.name = motionName;
// Create animation clip.
if (AnimationClip == null)
{
AssetDatabase.CreateAsset(animationClip, AssetPath.Replace(".motion3.json", ".anim"));
AnimationClip = animationClip;
}
EditorUtility.CopySerialized(animationClip, AnimationClip);
EditorUtility.SetDirty(AnimationClip);
// Log event.
CubismImporter.LogReimport(AssetPath, AssetDatabase.GUIDToAssetPath(_animationClipGuid));
}
if (clip == null)
{
Debug.LogError("CubismFadeMotionImporter : Can not create Motion.");
return;
}
// Trigger event.
CubismImporter.SendMotionImportEvent(this, AnimationClip);
// Apply changes.
if (isImporterDirty)
{
Save();
}
else
{
while (assetList.onPostImporting)
{
Task.Delay(1);
}
assetListIndex = assetList.AssetPaths.Contains(motionPath)
? assetList.AssetPaths.IndexOf(motionPath)
: -1;
if (assetListIndex >= 0)
{
assetList.Remove(assetListIndex);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 90c8795cd29fb0047bec2755fcd35661
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
namespace Live2D.Cubism.Editor.Importers
{
/// <summary>
/// Common interface for Cubism asset importers.
/// </summary>
public interface ICubismImporter
{
/// <summary>
/// Sets the asset path.
/// </summary>
void SetAssetPath(string value);
/// <summary>
/// Imports the corresponding asset.
/// </summary>
void Import();
/// <summary>
/// Saves the importer.
/// </summary>
void Save();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c2374b8a6a81af94394cfac68832b35d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: