You've already forked UniversalViewer
							
							DanMachi:
-compatibility improvements Core: -simplified object and keyframe serialization -complicated assetbundle loading
This commit is contained in:
		| @@ -1,64 +1,77 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using UnityEngine; | ||||
|  | ||||
| public class DanMachiCharacterContainer : DanMachiObjectContainer, IAnimated | ||||
| public class DanMachiCharacterContainer : ObjectContainer, IAnimated | ||||
| { | ||||
|     protected override System.Type _serializeType => typeof(DanMachiCharacterSerializable); | ||||
|     protected override System.Type _keyframeType => typeof(DanMachiCharacterKeyframeData); | ||||
|  | ||||
|     public CharacterAsset Data; | ||||
|     public string AnimationSet; | ||||
|     public string Animation; | ||||
|  | ||||
|     public GameObject Body; | ||||
|     public MorphPanel MorphPanel; | ||||
|     public CharacterPanel CharacterPanel; | ||||
|     public List<AnimationClip> Animations; | ||||
|     private Animator _animator; | ||||
|     private AnimatorOverrideController _animatorController; | ||||
|     private Dictionary<HumanBodyBones, Transform> _humanBones = new Dictionary<HumanBodyBones, Transform>(); | ||||
|     public List<Transform> Bones = new List<Transform>(); | ||||
|  | ||||
|     public override void Select() | ||||
|     public void Init() | ||||
|     { | ||||
|         if(MorphPanel != null) | ||||
|         _animator = GetComponentInChildren<Animator>(); | ||||
|         if(_animator != null) | ||||
|         { | ||||
|             MorphPanel.gameObject.SetActive(true); | ||||
|             _animator.applyRootMotion = false; | ||||
|             _animator.runtimeAnimatorController = _animatorController = Instantiate(SharedResources.Instance.GenericAnimatorController); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             Error.Log(Color.red, $"{name} has no animator"); | ||||
|         } | ||||
|         CreateMorphPanel(); | ||||
|         CreateCharacterPanel(); | ||||
|         SetBones(); | ||||
|     } | ||||
|  | ||||
|     public override void Deselect() | ||||
|     public void Rebuild(CharacterAsset model) | ||||
|     { | ||||
|         if (MorphPanel != null) | ||||
|         { | ||||
|             MorphPanel.gameObject.SetActive(false); | ||||
|         } | ||||
|         DestroyImmediate(Body); | ||||
|         Build(model); | ||||
|     } | ||||
|  | ||||
|     public void Build(CharacterAsset model) | ||||
|     { | ||||
|         Data = model; | ||||
|         var characterAsset = AssetBundle.LoadFromFile(model.FilePath); | ||||
|         var animationSets = DanMachiAssetLibrary.Instance.Animations.Where(a => a.Category == model.Category && a.Id == model.Id); | ||||
|         var assetPath = Path.Combine(DanMachiAssetLibrary.Instance.LocalFilesPath, model.FilePath); | ||||
|         var characterAsset = AssetLibrary.LoadFromFile(assetPath); | ||||
|         var assetNames = characterAsset.GetAllAssetNames(); | ||||
|         var characterModel = assetNames.FirstOrDefault(a => Path.GetFileName(a).StartsWith("CP_") && a.EndsWith(".prefab")); | ||||
|  | ||||
|         foreach (var go in characterAsset.LoadAllAssets<GameObject>()) | ||||
|         if(!string.IsNullOrEmpty(characterModel)) | ||||
|         { | ||||
|             Instantiate(go, transform); | ||||
|             Body = Instantiate(characterAsset.LoadAsset(characterModel), transform) as GameObject; | ||||
|         } | ||||
|         characterAsset.Unload(false); | ||||
|         else | ||||
|         { | ||||
|             Body = new GameObject(); | ||||
|             Body.transform.SetParent(transform); | ||||
|             foreach (var go in characterAsset.LoadAllAssets<GameObject>()) | ||||
|             { | ||||
|                 Instantiate(go, Body.transform); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         LoadedAssets = new List<AssetBundleEntry>() { new AssetBundleEntry(model.AssetName, assetPath, characterAsset) }; | ||||
|         AssetLibrary.UnloadAsset(assetPath); | ||||
|  | ||||
|         SetDefaultMaterials(transform); | ||||
|  | ||||
|         Init(); | ||||
|  | ||||
|         var defaultAnimSet = animationSets.FirstOrDefault(a => a.Costume == "common"); | ||||
|         LoadAnimationSet(defaultAnimSet); | ||||
|     } | ||||
|  | ||||
|     public void Init() | ||||
|     { | ||||
|         _animator = GetComponentInChildren<Animator>(); | ||||
|         _animator.applyRootMotion = false; | ||||
|         _animator.runtimeAnimatorController = _animatorController = Instantiate(SharedResources.Instance.GenericAnimatorController); | ||||
|         CreateMorphPanel(); | ||||
|         CreateCharacterPanel(); | ||||
|         SetBones(); | ||||
|     } | ||||
|  | ||||
|     public void LoadAnimationSet(CharacterAsset animationSet) | ||||
| @@ -67,7 +80,7 @@ public class DanMachiCharacterContainer : DanMachiObjectContainer, IAnimated | ||||
|         { | ||||
|             AnimationSet = animationSet.Costume; | ||||
|             Animation = ""; | ||||
|             var animationAsset = AssetBundle.LoadFromFile(animationSet.FilePath); | ||||
|             var animationAsset = AssetBundle.LoadFromFile(Path.Combine(DanMachiAssetLibrary.Instance.LocalFilesPath, animationSet.FilePath)); | ||||
|             Animations = animationAsset.LoadAllAssets<AnimationClip>().ToList(); | ||||
|             animationAsset.Unload(false); | ||||
|         } | ||||
| @@ -81,6 +94,12 @@ public class DanMachiCharacterContainer : DanMachiObjectContainer, IAnimated | ||||
|  | ||||
|     public void PlayAnimation(AnimationClip anim) | ||||
|     { | ||||
|         if(_animator == null) | ||||
|         { | ||||
|             Error.Log(Color.red, $"{name} has no animator"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if(anim == null) | ||||
|         { | ||||
|             Animation = ""; | ||||
| @@ -110,8 +129,20 @@ public class DanMachiCharacterContainer : DanMachiObjectContainer, IAnimated | ||||
|  | ||||
|     public void SetBones() | ||||
|     { | ||||
|         _humanBones.Clear(); | ||||
|         Bones.Clear(); | ||||
|  | ||||
|         if (_animator == null) return; | ||||
|  | ||||
|         var humanBones = new Dictionary<HumanBodyBones, Transform>(); | ||||
|         var allBones = _animator.transform.GetComponentsInChildren<Transform>().ToDictionary(b=>b.name, b=>b); | ||||
|         var allBones = new Dictionary<string, Transform>(); | ||||
|         foreach(var bone in _animator.transform.GetComponentsInChildren<Transform>()) | ||||
|         { | ||||
|             if (!allBones.ContainsKey(bone.name)) | ||||
|             { | ||||
|                 allBones[bone.name] = bone; | ||||
|             } | ||||
|         } | ||||
|         humanBones.Add(HumanBodyBones.Hips,                     TryGet(allBones,"Hips")); | ||||
|         humanBones.Add(HumanBodyBones.Spine,                    TryGet(allBones,"Spine")); | ||||
|         humanBones.Add(HumanBodyBones.RightUpperLeg,            TryGet(allBones,"RightUpLeg")); | ||||
| @@ -186,6 +217,7 @@ public class DanMachiCharacterContainer : DanMachiObjectContainer, IAnimated | ||||
|         } | ||||
|  | ||||
|         _humanBones = humanBones; | ||||
|         Bones = allBones.Values.ToList(); | ||||
|     } | ||||
|  | ||||
|     public T TryGet<T>(Dictionary<string, T> dict, string key) | ||||
| @@ -199,11 +231,6 @@ public class DanMachiCharacterContainer : DanMachiObjectContainer, IAnimated | ||||
|  | ||||
|     public void CreateMorphPanel() | ||||
|     { | ||||
|         if(MorphPanel != null) | ||||
|         { | ||||
|             Destroy(MorphPanel.gameObject); | ||||
|         } | ||||
|  | ||||
|         var morphRenderers = new Dictionary<SkinnedMeshRenderer, List<MorphHelper>>(); | ||||
|         foreach (var rend in gameObject.GetComponentsInChildren<SkinnedMeshRenderer>()) | ||||
|         { | ||||
| @@ -213,29 +240,59 @@ public class DanMachiCharacterContainer : DanMachiObjectContainer, IAnimated | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (morphRenderers.Count == 0) return; | ||||
|         if (morphRenderers.Count == 0) | ||||
|         { | ||||
|             if(MorphPanel != null) | ||||
|             { | ||||
|                 Destroy(MorphPanel.gameObject); | ||||
|                 MorphPanel = null; | ||||
|                 InstantiatedObjects.Remove(MorphPanel.gameObject); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         MorphPanel = MorphPanel.Create(morphRenderers.Select(mr=>mr.Key.sharedMesh.name).ToList()); | ||||
|         MorphPanel.name = $"Chr_{Data.Id} Morphs"; | ||||
|         if(MorphPanel != null) | ||||
|         { | ||||
|             MorphPanel.Init(morphRenderers.Select(mr => mr.Key.sharedMesh.name).ToList()); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             MorphPanel = MorphPanel.Create(morphRenderers.Select(mr => mr.Key.sharedMesh.name).ToList()); | ||||
|             MorphPanel.name = $"Chr_{Data.Id} Morphs"; | ||||
|             InstantiatedObjects.Add(MorphPanel.gameObject); | ||||
|             DanMachiInterface.Instance.SelectedObjectToolbar.AttachToThis(MorphPanel.GetComponent<UIElementDragger>()); | ||||
|         } | ||||
|  | ||||
|         foreach(var rend in morphRenderers) | ||||
|         foreach (var rend in morphRenderers) | ||||
|         { | ||||
|             var mesh = rend.Key.sharedMesh; | ||||
|             for(int i = 0; i < mesh.blendShapeCount; i++) | ||||
|             { | ||||
|                 MorphPanel.CreateMorph(mesh.name, this, rend.Key, i, mesh.GetBlendShapeName(i).Replace("blendShape1.","")); | ||||
|                 var panel = MorphPanel.CreateMorph(mesh.name, this, rend.Key, i, mesh.GetBlendShapeName(i).Replace("blendShape1.","")); | ||||
|                 var helper = panel.MorphHelper;  | ||||
|                 if (morphRenderers.ContainsKey(rend.Key)) | ||||
|                     morphRenderers[rend.Key].Add(helper); | ||||
|                 else | ||||
|                     morphRenderers.Add(rend.Key, new List<MorphHelper>() { helper }); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Morphs = morphRenderers; | ||||
|         DanMachiModelViewerInterface.Instance.SelectedObjectToolbar.AttachToThis(MorphPanel.GetComponent<UIElementDragger>()); | ||||
|     } | ||||
|  | ||||
|     public void CreateCharacterPanel() | ||||
|     { | ||||
|         CharacterPanel = CharacterPanel.Create(this); | ||||
|         CharacterPanel.name = $"Chr_{Data.Id} Settings"; | ||||
|         DanMachiModelViewerInterface.Instance.SelectedObjectToolbar.AttachToThis(CharacterPanel.GetComponent<UIElementDragger>()); | ||||
|         if(CharacterPanel != null) | ||||
|         { | ||||
|             CharacterPanel.Init(this); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             CharacterPanel = CharacterPanel.Create(this); | ||||
|             CharacterPanel.name = $"Chr_{Data.Id} Settings"; | ||||
|             InstantiatedObjects.Add(CharacterPanel.gameObject); | ||||
|             DanMachiInterface.Instance.SelectedObjectToolbar.AttachToThis(CharacterPanel.GetComponent<UIElementDragger>()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public override Vector3 GetCenter() | ||||
| @@ -247,19 +304,45 @@ public class DanMachiCharacterContainer : DanMachiObjectContainer, IAnimated | ||||
|         return base.GetCenter(); | ||||
|     } | ||||
|  | ||||
|     protected override void OnDestroy() | ||||
|     { | ||||
|         if (_applicationQuitting) return; | ||||
|         if(MorphPanel != null) | ||||
|         { | ||||
|             Destroy(MorphPanel.gameObject); | ||||
|         } | ||||
|         Destroy(CharacterPanel.gameObject); | ||||
|         base.OnDestroy(); | ||||
|     } | ||||
|  | ||||
|     public Animator GetAnimator() | ||||
|     { | ||||
|         return _animator; | ||||
|     } | ||||
|  | ||||
|     public override void PastePose(KeyframeData frame, PoseLoadOptions pasteParams) | ||||
|     { | ||||
|         PlayAnimation(""); | ||||
|  | ||||
|         if (pasteParams.Root) | ||||
|         { | ||||
|             transform.SetTransform(frame.Root); | ||||
|         } | ||||
|  | ||||
|         var frameData = frame as DanMachiCharacterKeyframeData; | ||||
|         if (frameData == null) return; | ||||
|  | ||||
|         foreach (var bone in frameData.Bones.Bones) | ||||
|         { | ||||
|             var targetBone = Bones.FirstOrDefault(b => b.name == bone.Name); | ||||
|             if (targetBone == null) continue; | ||||
|  | ||||
|             bone.Transform.ApplyTo(targetBone.transform); | ||||
|         } | ||||
|  | ||||
|         foreach(var morph in frameData.Morphs) | ||||
|         { | ||||
|             var renderer = Morphs.Keys.FirstOrDefault(k => k.name == morph.Key); | ||||
|             if (renderer == null) continue; | ||||
|  | ||||
|             foreach(var value in morph.Value) | ||||
|             { | ||||
|                 var helper = Morphs[renderer].FirstOrDefault(h => h.Name == value.Name); | ||||
|                 if (helper == null) continue; | ||||
|                 helper.Value = value.Value; | ||||
|                 helper.UpdateMorph(value.Strength); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         SetKeyframe(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,29 @@ | ||||
|  | ||||
| using System.Collections.Generic; | ||||
| using System.ComponentModel; | ||||
| using System.Linq; | ||||
| using UnityEngine; | ||||
|  | ||||
| public class DanMachiCharacterKeyframeData : KeyframeData | ||||
| { | ||||
|     public BoneList Bones = new BoneList(); | ||||
|     public Dictionary<string, List<MorphHelper>> Morphs = new Dictionary<string, List<MorphHelper>>(); | ||||
|  | ||||
|     public DanMachiCharacterKeyframeData() { } | ||||
|  | ||||
|     public DanMachiCharacterKeyframeData(DanMachiCharacterContainer container) | ||||
|     { | ||||
|         this.Root = new SerializableTransform(container.transform); | ||||
|         this.Bones = new BoneList() { Name = "", Bones = container.Bones.Select(b => new SerializableBone(b)).ToArray() }; | ||||
|         this.Morphs = container.Morphs.ToDictionary(m => m.Key.name, m => m.Value); | ||||
|     } | ||||
|  | ||||
|     public override KeyframeData Clone() | ||||
|     { | ||||
|         var keyframe = new DanMachiCharacterKeyframeData(); | ||||
|         keyframe.Root = new SerializableTransform(this.Root); | ||||
|         keyframe.Bones = new BoneList() { Name = Bones.Name, Bones = Bones.Bones.Select(b=> new SerializableBone(b)).ToArray() }; | ||||
|         keyframe.Morphs = Morphs.ToDictionary(m => m.Key, m => m.Value.Select(v=>new MorphHelper(v.ParentName, v.Name, v.Strength, v.Value)).ToList()); | ||||
|         return keyframe; | ||||
|     } | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| fileFormatVersion: 2 | ||||
| guid: 6ce5c34b04160214b935e3dcefed9ffc | ||||
| guid: d096ac3a0685dd54a836bc35192a0522 | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
| @@ -0,0 +1,12 @@ | ||||
|  | ||||
| public class DanMachiCharacterSerializable : ObjectContainerSerializable | ||||
| { | ||||
|     public string AssetName; | ||||
|  | ||||
|     public DanMachiCharacterSerializable() { } | ||||
|  | ||||
|     public DanMachiCharacterSerializable(DanMachiCharacterContainer container) : base(container) | ||||
|     { | ||||
|         AssetName = container.Data.AssetName; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| fileFormatVersion: 2 | ||||
| guid: 90e549cfb34f0cc47ac51d28cf4a6d9a | ||||
| MonoImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|   defaultReferences: [] | ||||
|   executionOrder: 0 | ||||
|   icon: {instanceID: 0} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
| @@ -1,42 +0,0 @@ | ||||
| public class DanMachiObjectContainer : ObjectContainer | ||||
| { | ||||
|     protected static DanMachiModelViewerMain Main => DanMachiModelViewerMain.Instance; | ||||
|  | ||||
|     protected override void Start() | ||||
|     { | ||||
|         if (DoNotSave) return; | ||||
|  | ||||
|         if(Frames.Count == 0) | ||||
|         { | ||||
|             SetKeyframe(); | ||||
|         } | ||||
|  | ||||
|         DanMachiModelViewerMain.RegisterObject(this); | ||||
|         var selector = UITimelineObjectEntry.Create(this); | ||||
|         InstantiatedObjects.Add(selector.gameObject); | ||||
|  | ||||
|         ModelViewerMain.GetInstance<DanMachiModelViewerMain>().SelectObject(this); | ||||
|     } | ||||
|  | ||||
|     public override void Select() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public override void Deselect() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     protected override void OnDestroy() | ||||
|     { | ||||
|         if(_applicationQuitting) return; | ||||
|  | ||||
|         if (Main.SelectedObject == this) | ||||
|         { | ||||
|             Main.SelectObject(null); | ||||
|         } | ||||
|  | ||||
|         ModelViewerMain.UnregisterObject(this); | ||||
|  | ||||
|         base.OnDestroy(); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user