﻿using ProtoBuf;
using ProtoBuf.Meta;
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;

class BuildNettedPrefabs:MonoBehaviour
{
    [MenuItem("Netted/BuildPrefabs")]
    public static void BuildNettesd()
    {
        string dir = @"Assets\NettedsAssets";
        if (Directory.Exists(dir) == false)
        {
            Directory.CreateDirectory(dir);
        }
        string[] paths = AssetDatabase.GetAllAssetPaths();
        List<string> fbxPaths = new List<string>();
        foreach (var i in paths)
        {
            if ((i.ToLower().EndsWith(".obj") || i.ToLower().EndsWith(".fbx")) && i.StartsWith(@"Assets/NettedsAssets"))
            {
                fbxPaths.Add(i);
            }
        }
        paths = fbxPaths.ToArray();
        foreach (var i in paths)
        {
            string dPath= Path.GetDirectoryName(i) + @"\"+ Path.GetFileNameWithoutExtension(i);
            if (File.Exists(dPath+@".prefab")) continue;
            if (!Directory.Exists(dPath))
            {   
                Directory.CreateDirectory(dPath);
            }
            UnityEngine.Object[] objs = AssetDatabase.LoadAllAssetsAtPath(i);
            foreach (var n in objs)
            {
                Type t = n.GetType();
                //Debug.Log(n.name + "|" + n.GetType());
                
                if (t == typeof(Mesh) || t == typeof(Texture) || t == typeof(Material) || t == typeof(AnimationClip))
                {
                    FileInfo fi = new FileInfo(dPath + @"\" + n.name + ".asset");
                    if(!fi.Exists)
                        AssetDatabase.CreateAsset(GameObject.Instantiate(n),dPath+@"\"+n.name+".asset");
                    
                }
                
            }
            //Create prefabs
            GameObject o = AssetDatabase.LoadAssetAtPath(i, typeof(GameObject)) as GameObject;
            GameObject root = new GameObject();//GameObject.Instantiate(o);
            /*for (int n = 0; n < root.transform.childCount; n++)
            {
                Debug.Log(n);
                DestroyImmediate(root.transform.GetChild(n).gameObject);
            }*/
            root.name = o.name;
            bool success;
            //List<GameObject> gobjpool = new List<GameObject>();
            for (int n = 0; n < o.transform.childCount; n++)
            {
                GameObject duplicatee = o.transform.GetChild(n).gameObject;
                GameObject g = GameObject.Instantiate(duplicatee,root.transform);
                g.name = duplicatee.name;
                g.transform.parent = root.transform;
                ChangeAssets(dPath+@"\",g);
                //PrefabUtility.SaveAsPrefabAsset(g, dPath + @"\" + g.name + ".prefab",out success);
                //AssetDatabase.CreateAsset(g,dPath + @"\" + g.name + ".prefab");
                //gobjpool.Add(g);
                //DestroyImmediate(g);
                //Debug.Log(success);
            }
            FixBones(root);
            PrefabUtility.SaveAsPrefabAsset(root,Path.GetDirectoryName(i) +@"/"+ Path.GetFileNameWithoutExtension(i)+".prefab", out success);
            DestroyImmediate(root);
            
        }
        //GameObject.Find();
    }
    static void ChangeAssets(string dPath,GameObject g)
    {
        MeshFilter mf = g.GetComponent<MeshFilter>();
        MeshRenderer mr = g.GetComponent<MeshRenderer>();
        SkinnedMeshRenderer smr = g.GetComponent<SkinnedMeshRenderer>();
        if (mf != null)
        {
            FileInfo fi = new FileInfo(dPath + mf.sharedMesh.name + ".asset");
            if (fi.Exists)
            {
                mf.sharedMesh = AssetDatabase.LoadAssetAtPath(dPath + mf.sharedMesh.name + ".asset", typeof(Mesh)) as Mesh;
            }
            else
            {
                Debug.LogError(dPath + mf.sharedMesh.name + ".asset");
            }
        }
        if (mr != null)
        {
            Material[] orimat = mr.sharedMaterials;
            Material[] newmat = new Material[orimat.Length];
            for (int j = 0; j < mr.sharedMaterials.Length; j++)
            {
                FileInfo fi = new FileInfo(dPath + orimat[j].name + ".asset");
                if (fi.Exists)
                {
                    newmat[j] = AssetDatabase.LoadAssetAtPath<UnityEngine.Material>(dPath + orimat[j].name + ".asset");
                }
                else
                {
                    newmat[j] = orimat[j];
                }

            }
            mr.sharedMaterials = newmat;
        }
        if (smr != null)
        {
            FileInfo fi = new FileInfo(dPath + smr.sharedMesh.name + ".asset");
            if (fi.Exists)
            {
                smr.sharedMesh = AssetDatabase.LoadAssetAtPath(dPath + smr.sharedMesh.name + ".asset", typeof(Mesh)) as Mesh;
            }

            /*Transform sknd = smr.rootBone,secd=null;
            while (sknd.parent != null)
            {
                secd = sknd;
                sknd = sknd.parent;
            }
            //ShareSkeletonInstanceWith(smr, AssetDatabase.LoadAssetAtPath<GameObject>(dPath + secd.name + ".prefab"));
            */

            Material[] orimat = smr.sharedMaterials;
            Material[] newmat = new Material[orimat.Length];
            for (int j = 0; j < smr.sharedMaterials.Length; j++)
            {
                fi = new FileInfo(dPath + orimat[j].name + ".asset");
                if (fi.Exists)
                {
                    newmat[j] = AssetDatabase.LoadAssetAtPath<UnityEngine.Material>(dPath + orimat[j].name + ".asset");
                }
                else
                {
                    newmat[j] = orimat[j];
                    //Debug.LogError(dPath + orimat[j].name + ".asset");
                }

            }
            smr.sharedMaterials = newmat;
        }
        for (int n = 0; n < g.transform.childCount; n++)
        {
            GameObject child = g.transform.GetChild(n).gameObject;
            ChangeAssets(dPath, child);
        }
    }
    public static void ShareSkeletonInstanceWith(SkinnedMeshRenderer selfSkin, GameObject target)
    {
        Transform[] newBones = new Transform[selfSkin.bones.Length];
        for (int i = 0; i < selfSkin.bones.GetLength(0); ++i)
        {
            GameObject bone = selfSkin.bones[i].gameObject;
            // 目标的SkinnedMeshRenderer.bones保存的只是目标mesh相关的骨骼,要获得目标全部骨骼,可以通过查找的方式.
            newBones[i] = FindChildRecursion(target.transform, bone.name);
        }
        selfSkin.bones = newBones;
        selfSkin.rootBone = FindChildRecursion(target.transform, selfSkin.rootBone.name);
    }

    public static void FixBones(GameObject g)
    {
        FindSkinnedMeshRenderer(g,g);
    }
    public static void FindSkinnedMeshRenderer(GameObject g,GameObject target)
    {
        SkinnedMeshRenderer smr = g.GetComponent<SkinnedMeshRenderer>();
        if (smr != null)
        {
            ShareSkeletonInstanceWith(smr,target);
        }
        for (int n = 0; n < g.transform.childCount; n++)
        {
            GameObject child = g.transform.GetChild(n).gameObject;
            FindSkinnedMeshRenderer(child,target);
        }

    }
    // 递归查找
    public static Transform FindChildRecursion(Transform t, string name)
    {
        foreach (Transform child in t)
        {
            if (child.name == name)
            {
                return child;
            }
            else
            {
                Transform ret = FindChildRecursion(child, name);
                if (ret != null)
                    return ret;
            }
        }
        return null;
    }
}
