using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
using Object=UnityEngine.Object;
/// Isolated candidate uses the ORIGINAL avatar, controller and finished clips. No animation regeneration.
public static class GreatHornStudioTrial
{
const string Original="Assets/Bundles/Characters/Enemy/GreatHorn";
const string Trial="Assets/Bundles/Characters/Enemy/GreatHornStudio";
const string ScenePath="Assets/Bundles/Scenes/Review/Enemy_GreatHornStudio_Review.unity";
static string Repo=>Path.GetFullPath(Path.Combine(Application.dataPath,"../.."));
static void Check(bool value,string message){if(!value)throw new Exception(message);}
static void Write(string name,object data){string dir=Path.Combine(Repo,"Tools/output/enemy_studio_trial/GreatHorn");Directory.CreateDirectory(dir);File.WriteAllText(Path.Combine(dir,name),JsonConvert.SerializeObject(data,Formatting.Indented));}
static Vector3[] Vertices(GameObject go)
{
return go.GetComponentsInChildren().SelectMany(s=>{
var m=s.sharedMesh;var weights=m.boneWeights;var binds=m.bindposes;var matrices=s.bones.Select((b,i)=>b.localToWorldMatrix*binds[i]).ToArray();
return m.vertices.Select((v,i)=>{var w=weights[i];return matrices[w.boneIndex0].MultiplyPoint3x4(v)*w.weight0+matrices[w.boneIndex1].MultiplyPoint3x4(v)*w.weight1+matrices[w.boneIndex2].MultiplyPoint3x4(v)*w.weight2+matrices[w.boneIndex3].MultiplyPoint3x4(v)*w.weight3;}).ToArray();
}).ToArray();
}
static Bounds Bounds(Vector3[] points){var b=new Bounds(points[0],Vector3.zero);foreach(var p in points)b.Encapsulate(p);return b;}
static AnimationClip Clip(string name)=>AssetDatabase.LoadAssetAtPath(Original+"/Clips/"+name+".anim");
public static string Inspect()
{
var prefab=AssetDatabase.LoadAssetAtPath(Original+"/GreatHorn_Enemy.prefab");var anim=prefab.GetComponentInChildren();
return JsonConvert.SerializeObject(new{model=anim.name,scale=anim.transform.localScale.ToString("F6"),position=anim.transform.localPosition.ToString("F6"),rotation=anim.transform.localEulerAngles.ToString("F6"),avatar=AssetDatabase.GetAssetPath(anim.avatar),controller=AssetDatabase.GetAssetPath(anim.runtimeAnimatorController),bones=prefab.GetComponentsInChildren().Where(t=>t.name.StartsWith("bone_")).Select(t=>new{name=t.name,path=AnimationUtility.CalculateTransformPath(t,anim.transform),position=t.localPosition.ToString("F6"),rotation=t.localRotation.ToString("F6")}).ToArray()},Formatting.Indented);
}
public static string Build()=>BuildCore(true);
public static string Prepare()=>BuildCore(false);
static string BuildCore(bool verify)
{
Check(!EditorApplication.isPlaying,"Author trial in Edit Mode");
string fbx=Trial+"/Rigged/GreatHornStudio_Rigged.fbx";
AssetDatabase.ImportAsset(fbx,ImportAssetOptions.ForceUpdate);
var imp=(ModelImporter)AssetImporter.GetAtPath(fbx);imp.animationType=ModelImporterAnimationType.Generic;imp.avatarSetup=ModelImporterAvatarSetup.CreateFromThisModel;imp.importAnimation=false;imp.globalScale=1;imp.useFileScale=false;imp.bakeAxisConversion=true;imp.materialImportMode=ModelImporterMaterialImportMode.None;imp.meshCompression=ModelImporterMeshCompression.Off;imp.SaveAndReimport();
var reference=AssetDatabase.LoadAssetAtPath(Original+"/GreatHorn_Enemy.prefab").GetComponentInChildren();
var scene=EditorSceneManager.NewPreviewScene();
try
{
var root=new GameObject("GreatHornStudio_Enemy");SceneManager.MoveGameObjectToScene(root,scene);
var model=(GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath(fbx),scene);model.transform.SetParent(root.transform,false);model.name="Model";
model.transform.localPosition=reference.transform.localPosition;model.transform.localRotation=reference.transform.localRotation;model.transform.localScale=reference.transform.localScale;
var anim=model.GetComponent();if(anim==null)anim=model.AddComponent();anim.avatar=reference.avatar;anim.runtimeAnimatorController=reference.runtimeAnimatorController;anim.applyRootMotion=false;anim.cullingMode=AnimatorCullingMode.AlwaysAnimate;
var material=AssetDatabase.LoadAssetAtPath(Trial+"/GreatHornStudio.mat");foreach(var skin in model.GetComponentsInChildren()) {skin.sharedMaterial=material;skin.updateWhenOffscreen=true;}
var expected=reference.GetComponentsInChildren().Where(t=>t.name.StartsWith("bone_")).ToDictionary(t=>AnimationUtility.CalculateTransformPath(t,reference.transform));
var actual=model.GetComponentsInChildren().Where(t=>t.name.StartsWith("bone_")).ToDictionary(t=>AnimationUtility.CalculateTransformPath(t,model.transform));
Check(expected.Count==22&&expected.Keys.OrderBy(x=>x).SequenceEqual(actual.Keys.OrderBy(x=>x)),"Original skeleton paths changed");
foreach(var entry in expected){var t=actual[entry.Key];Check(Vector3.Distance(t.localPosition,entry.Value.localPosition)<.0001f&&Quaternion.Angle(t.localRotation,entry.Value.localRotation)<.01f&&Vector3.Distance(t.localScale,entry.Value.localScale)<.0001f,"Bind transform changed "+entry.Key);}
PrefabUtility.SaveAsPrefabAsset(root,Trial+"/GreatHornStudio_Enemy.prefab");
}
finally{EditorSceneManager.ClosePreviewScene(scene);}
AssetDatabase.SaveAssets();return verify?Verify():"Prepared original skeleton/controller candidate; sole constraints pending";
}
public static string Verify()
{
var scene=EditorSceneManager.NewPreviewScene();
try
{
var go=(GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath(Trial+"/GreatHornStudio_Enemy.prefab"),scene);var anim=go.GetComponentInChildren();anim.enabled=false;
var reference=AssetDatabase.LoadAssetAtPath(Original+"/GreatHorn_Enemy.prefab").GetComponentInChildren();Check(anim.runtimeAnimatorController==reference.runtimeAnimatorController&&anim.avatar==reference.avatar,"Expected exact original controller/avatar");
var bind=Vertices(go);var bounds=Bounds(bind);int triangles=go.GetComponentsInChildren().Sum(s=>s.sharedMesh.triangles.Length/3);Check(triangles<=2600,"Studio target tolerance exceeded");Check(Mathf.Abs(bounds.size.y-.8f)<.003f&&Mathf.Abs(bounds.min.y)<.003f,"Bind ground/height changed "+bounds);
var staticGo=(GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath(Trial+"/GreatHornStudio.prefab"),scene);var staticPoints=staticGo.GetComponentsInChildren().SelectMany(m=>m.sharedMesh.vertices.Select(v=>m.transform.TransformPoint(v))).ToArray();float bindError=bind.Max(v=>staticPoints.Min(p=>Vector3.Distance(v,p)));Check(bindError<.002f,"Weight transfer changed static geometry "+bindError);
Check(go.GetComponentsInChildren().All(s=>s.sharedMesh.boneWeights.All(w=>Mathf.Abs(w.weight0+w.weight1+w.weight2+w.weight3-1)<.001f)),"Invalid weights");
var rows=new List