少年修仙传客户端基础资源
hch
2024-12-10 650351d224145cc692715571fc2178378bff393a
Assets/Editor/Actor/ResourcesBuilder.cs
@@ -1,657 +1,746 @@
using UnityEngine;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Animations;
using System.IO;
public class ResourcesBuilder
{
    protected const byte param_NoExist = 1;
    protected const byte param_Prefab = 2;
    protected const byte param_Clip = 4;
    protected const byte param_AnimatorController = 8;
    protected class MountPointInfo
    {
        public string path;
        public string name;
        public Vector3 localPosition;
        public Quaternion localRotation;
        public Vector3 localScale;
    }
    protected class ColliderInfo
    {
        public Vector3 center;
        public float radius;
        public float height;
    }
    public static int buildParams = 0;
    public static bool OnlyBuildNoExist
    {
        get
        {
            return (buildParams & param_NoExist) != 0;
        }
        set
        {
            if (value)
            {
                buildParams |= param_NoExist;
            }
            else
            {
                buildParams &= ~param_NoExist;
            }
        }
    }
    public static bool IsBuildPrefab
    {
        get
        {
            return (buildParams & param_Prefab) != 0;
        }
        set
        {
            if (value)
            {
                buildParams |= param_Prefab;
            }
            else
            {
                buildParams &= ~param_Prefab;
            }
        }
    }
    public static bool IsBuildAnimationClip
    {
        get
        {
            return (buildParams & param_Clip) != 0;
        }
        set
        {
            if (value)
            {
                buildParams |= param_Clip;
            }
            else
            {
                buildParams &= ~param_Clip;
            }
        }
    }
    public static bool IsBuildAnimatorController
    {
        get
        {
            return (buildParams & param_AnimatorController) != 0;
        }
        set
        {
            if (value)
            {
                buildParams |= param_AnimatorController;
            }
            else
            {
                buildParams &= ~param_AnimatorController;
            }
        }
    }
    protected static List<MountPointInfo> m_MountPointInfoList = new List<MountPointInfo>();
    public void BuildPrefab(string path, string resName, string suffix)
    {
        string _absOriginalePath = string.Format("{0}/ART/Role/{1}/{2}.FBX", Application.dataPath, path, resName);
        string _originalAssetPath = string.Format("Assets/ART/Role/{0}/{1}.FBX", path, resName);
        string _absAssetPath = string.Format("{0}Mob/{1}{2}.prefab", ResourcesPath.ResourcesOutPath, suffix, resName);
        string _assetPath = string.Format("{0}Mob/{1}{2}.prefab", ResourcesPath.ResourcesOutAssetPath, suffix, resName);
        string _acAbsAssetPath = string.Format("{0}Mob/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutPath, path, AnimatorControllerLoader.controllerSuffix, path);
        string _acAssetPath = string.Format("{0}Mob/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutAssetPath, path, AnimatorControllerLoader.controllerSuffix, path);
        if (string.IsNullOrEmpty(_absOriginalePath))
        {
            return;
        }
        // 指定动画控制器
        if (!File.Exists(_acAbsAssetPath))
        {
            Debug.LogWarningFormat("检测到此prefab资源: {0} 的AnimatorContorller(动画控制器)资源尚未生成, 这里需要注意啊此资源是否需要先生成AnimatorContorller(动画控制器), 再生成prefab资源.", path);
        }
        ColliderInfo _colliderInfo = null;
        if (File.Exists(_absAssetPath))
        {
            if (OnlyBuildNoExist)
            {
                //Debug.LogFormat("当前为只生成不存在的资源模式, 这里检测到 {0} 已经存在, 不进行生成.");
                return;
            }
            GameObject _originalAssetRes = null;
            _originalAssetRes = AssetDatabase.LoadAssetAtPath<GameObject>(_assetPath);
            if (_originalAssetRes)
            {
                Transform _mpNode;
                // 这里需要记录旧的对象身上的绑点信息, 然后给新的prefab设置绑点
                m_MountPointInfoList.Clear();
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Down");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Name");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Name2");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Hit");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Stun");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                CapsuleCollider _collider = _originalAssetRes.GetComponent<CapsuleCollider>();
                if (_collider)
                {
                    _colliderInfo = new ColliderInfo();
                    _colliderInfo.center = _collider.center;
                    _colliderInfo.height = _collider.height;
                    _colliderInfo.radius = _collider.radius;
                }
            }
        }
        GameObject _fbxRes = AssetDatabase.LoadAssetAtPath<GameObject>(_originalAssetPath);
        if (_fbxRes == null)
        {
            _originalAssetPath = _originalAssetPath.Remove(_originalAssetPath.LastIndexOf(".")) + ".prefab";
            _fbxRes = AssetDatabase.LoadAssetAtPath<GameObject>(_originalAssetPath);
            if (_fbxRes == null)
            {
                Debug.LogFormat("无法读取 {0}, 地址: {1}", resName, _originalAssetPath);
                return;
            }
        }
        // 为了防止fbx本身就带有材质, 这里去掉fbx上的Import material属性
        ModelImporter _modelImport = AssetImporter.GetAtPath(_originalAssetPath) as ModelImporter;
        if (_modelImport != null)
        {
            if (_modelImport.importMaterials)
            {
                _modelImport.importMaterials = false;
                _modelImport.SaveAndReimport();
            }
        }
        GameObject _prefab = Object.Instantiate(_fbxRes);
        // 设置绑点
        if (m_MountPointInfoList.Count > 0)
        {
            MountPointInfo _mpInfo = null;
            for (int i = 0; i < m_MountPointInfoList.Count; ++i)
            {
                _mpInfo = m_MountPointInfoList[i];
                GameObject _mp = new GameObject(_mpInfo.name);
                Transform _parent = null;
                if (string.IsNullOrEmpty(_mpInfo.path))
                {
                    _parent = _prefab.transform;
                }
                else
                {
                    _parent = _prefab.transform.Find(_mpInfo.path);
                }
                if (_parent != null)
                {
                    _mp.transform.SetParent(_parent);
                    _mp.transform.localPosition = _mpInfo.localPosition;
                    _mp.transform.localRotation = _mpInfo.localRotation;
                    _mp.transform.localScale = _mpInfo.localScale;
                }
            }
        }
        // 加载特效
        if (InstanceResourcesLoader.horseSuffix.Equals(suffix)
         || resName.Contains("B_Cw"))
        {
            HandlerModelEffect("horseEffectConfig", null, resName, ref _prefab);
        }
        else if (InstanceResourcesLoader.raceSuffix.Equals(suffix))
        {
            HandlerModelEffect("clothesEffectConfig", path, resName, ref _prefab);
        }
        if (_colliderInfo != null)
        {
            CapsuleCollider _collider = _prefab.AddMissingComponent<CapsuleCollider>();
            _collider.center = _colliderInfo.center;
            _collider.radius = _colliderInfo.radius;
            _collider.height = _colliderInfo.height;
        }
        Transform _rendererNode = _prefab.transform.Find(resName);
        if (!_rendererNode)
        {
            _rendererNode = _prefab.transform;
        }
        Renderer _renderer = _rendererNode.GetComponent<Renderer>();
        if (_renderer)
        {
            OnSetupRenderer(path, resName, ref _renderer);
        }
        Animation _animation = _prefab.GetComponent<Animation>();
        if (_animation)
        {
            Object.DestroyImmediate(_animation);
        }
        Animator _animator = _prefab.GetComponent<Animator>();
        if (!_animator)
        {
            _animator = _prefab.AddComponent<Animator>();
        }
        // 绑定动画控制器
        RuntimeAnimatorController _runtimeAnimatorContorller = AssetDatabase.LoadAssetAtPath<RuntimeAnimatorController>(_acAssetPath);
        if (_runtimeAnimatorContorller)
        {
            _animator.runtimeAnimatorController = _runtimeAnimatorContorller;
        }
        PrefabUtility.CreatePrefab(_assetPath, _prefab, ReplacePrefabOptions.Default);
        // 设置打包路径
        AssetImporter _assetImport = AssetImporter.GetAtPath(_assetPath);
        _assetImport.assetBundleName = ResourcesPath.MOB_FOLDER_NAME
            + (InstanceResourcesLoader.raceSuffix + resName).ToLower();
        EditorUtility.SetDirty(_prefab);
        AssetDatabase.Refresh();
        Object.DestroyImmediate(_prefab);
        AssetDatabase.SaveAssets();
    }
    private void HandlerModelEffect(string configName, string path, string modelName, ref GameObject _go)
    {
        if (_go == null)
        {
            return;
        }
        string _configPath = ResourcesPath.ResourcesOutAssetPath + "Mob/" + configName + ".asset";
        HorseEffectConfig _horseEffectConfig = AssetDatabase.LoadAssetAtPath<HorseEffectConfig>(_configPath);
        if (_horseEffectConfig == null
         || _horseEffectConfig.effectConfigList == null
         || _horseEffectConfig.effectConfigList.Count == 0)
        {
            return;
        }
        HorseEffectConfig.EffectConfig _effectConfig;
        int _index = -1;
        for (int i = 0; i < _horseEffectConfig.effectConfigList.Count; ++i)
        {
            _effectConfig = _horseEffectConfig.effectConfigList[i];
            if (_effectConfig.modelName.Equals(modelName))
            {
                _index = i;
                break;
            }
        }
        if (_index == -1)
        {
            Debug.LogFormat("HandlerModelEffect() => 模型 {0} 没有配置任何特效", modelName);
            return;
        }
        _effectConfig = _horseEffectConfig.effectConfigList[_index];
        Transform _parent;
        GameObject _effect;
        string _bonePath;
        string _effectName;
        for (int i = 0; i < _effectConfig.boneNameList.Count; ++i)
        {
            _bonePath = _effectConfig.boneNameList[i];
            _parent = _go.transform.GetChildTransformDeeply(_bonePath);
            if (_parent == null)
            {
                Debug.LogWarningFormat("HandlerModelEffect() => 坐骑 {0} 配置的骨骼名称: {1} 找不到", modelName, _bonePath);
                continue;
            }
            _effectName = _effectConfig.effectNameList[i];
            if (string.IsNullOrEmpty(path))
            {
                _configPath = string.Format("Assets/Art/Role/{0}/Effects/{1}.prefab", modelName, _effectName);
            }
            else
            {
                _configPath = string.Format("Assets/Art/Role/{0}/Effects/{1}.prefab", path, _effectName);
            }
            _effect = AssetDatabase.LoadAssetAtPath<GameObject>(_configPath);
            if (_effect == null)
            {
                Debug.LogWarningFormat("HandlerModelEffect() => 坐骑 {0} 配置的特效资源: {1} 找不到", modelName, _configPath);
                continue;
            }
            _effect = Object.Instantiate(_effect);
            _effect.name = _effect.name.Replace("(Clone)", "");
            _effect.transform.SetParentEx(_parent, Vector3.zero, Quaternion.identity, Vector3.one);
            _effect.SetLayer(LayerUtility.BattleEffect, true);
        }
    }
    protected static void CreateMountPointInfo(Transform t)
    {
        MountPointInfo _info = new MountPointInfo();
        _info.path = SampleEditorTool.PrintHierarchyPath(t);
        if (!string.IsNullOrEmpty(_info.path))
        {
            if (_info.path.Contains("/"))
            {
                _info.path = _info.path.Replace("/" + t.name, "");
            }
            else
            {
                _info.path = _info.path.Replace(t.name, "");
            }
        }
        _info.name = t.name;
        _info.localPosition = t.localPosition;
        _info.localRotation = t.localRotation;
        _info.localScale = t.localScale;
        m_MountPointInfoList.Add(_info);
    }
    public static void BuildAnimationClip(string path)
    {
        string _absOriginaleDirectory = string.Format("{0}/ART/Role/{1}", Application.dataPath, path);
        string _assetOriginalDirectory = string.Format("Assets/ART/Role/{0}", path);
        string _absAssetDirectory = string.Format("{0}/ResourcesOut/Mob/{1}/AnimationClips", Application.dataPath, path);
        string _assetDirectory = string.Format("Assets/ResourcesOut/Mob/{0}/AnimationClips", path);
        if (!Directory.Exists(_absOriginaleDirectory))
        {
            return;
        }
        // 生成目标文件夹是否存在, 不存在则创建
        if (!Directory.Exists(_absAssetDirectory))
        {
            Directory.CreateDirectory(_absAssetDirectory);
        }
        DirectoryInfo _dInfo = new DirectoryInfo(_absOriginaleDirectory);
        FileInfo[] _fInfos = _dInfo.GetFiles("*.fbx");
        FileInfo _fInfo = null;
        Object _animationClip = null;
        AssetImporter _assetImport = null;
        int _count = _fInfos.Length;
        string _newName = string.Empty;
        string _assetDestPath = string.Empty;
        string _originalPath = string.Empty;
        List<AnimationClip> clips = new List<AnimationClip>();
        for (int i = 0; i < _fInfos.Length; ++i)
        {
            _fInfo = _fInfos[i];
            if (!_fInfo.Name.Contains("@"))
            {
                continue;
            }
            _newName = _fInfo.Name.Substring(_fInfo.Name.IndexOf("@") + 1);
            _newName = _newName.Substring(0, _newName.Length - 4);
            _assetDestPath = string.Format("{0}/{1}.anim", _absAssetDirectory, _newName);
            EditorUtility.DisplayProgressBar(string.Format("正在生成 {0} 的动画中...", path),
                                             string.Format("{0} => {1}.", _fInfo.Name, _assetDestPath),
                                             i * 1f / _count);
            if (File.Exists(_assetDestPath))
            {
                if (OnlyBuildNoExist)
                {
                    continue;
                }
            }
            _assetDestPath = string.Format("{0}/{1}.anim", _assetDirectory, _newName);
            _originalPath = _fInfo.FullName.Substring(Application.dataPath.Length + 1);
            _originalPath = Path.Combine("Assets/", _originalPath);
            _originalPath = _originalPath.Replace("\\", "/");
            _animationClip = AssetDatabase.LoadAssetAtPath(_originalPath, typeof(AnimationClip));
            AnimationClip _newClip = new AnimationClip();
            EditorUtility.CopySerialized(_animationClip, _newClip);
            _newClip.legacy = false;
            if (_newClip.name.Contains("Idle") || _newClip.name.Contains("Run") || _newClip.name.Contains("Stun"))
            {
                if (_newClip.isLooping == false)
                {
                    AnimationClipSettings _clipSetting = AnimationUtility.GetAnimationClipSettings(_newClip);
                    _clipSetting.loopTime = true;
                    AnimationUtility.SetAnimationClipSettings(_newClip, _clipSetting);
                }
            }
            AssetDatabase.CreateAsset(_newClip, _assetDestPath);
            _assetImport = AssetImporter.GetAtPath(_assetDestPath);
            _assetImport.assetBundleName = ResourcesPath.MOB_FOLDER_NAME + ResourcesPath.MOB_SUFFIX + path.ToLower();
            clips.Add(_newClip);
            EditorUtility.SetDirty(_newClip);
        }
        EditorUtility.ClearProgressBar();
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
    public static void BuildAnimatorController(string resName, string templeName, string configName)
    {
        string _absAssetPath = string.Format("{0}Mob/{1}", ResourcesPath.ResourcesOutPath, resName);
        if (!Directory.Exists(_absAssetPath))
        {
            Directory.CreateDirectory(_absAssetPath);
        }
        _absAssetPath = string.Format("{0}Mob/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutPath, resName, AnimatorControllerLoader.controllerSuffix, resName);
        string _assetPath = string.Format("{0}Mob/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutAssetPath, resName, AnimatorControllerLoader.controllerSuffix, resName);
        if (templeName.Equals("Temple_AnimatorController_BossShow"))
        {
            _absAssetPath = string.Format("{0}Mob/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutPath, resName, AnimatorControllerLoader.controllerShowSuffix, resName);
            _assetPath = string.Format("{0}Mob/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutAssetPath, resName, AnimatorControllerLoader.controllerShowSuffix, resName);
        }
        string _templePath = string.Format("{0}Mob/{1}.controller", ResourcesPath.ResourcesOutPath, templeName);
        if (File.Exists(_absAssetPath))
        {
            if (OnlyBuildNoExist)
            {
                return;
            }
            else
            {
                File.Delete(_absAssetPath);
            }
        }
        File.Copy(_templePath, _absAssetPath);
        AssetDatabase.Refresh();
        AnimatorController _animatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(_assetPath);
        if (!_animatorController)
        {
            Debug.LogErrorFormat("找不到所需要的动画状态机, 地址为: {0}", _assetPath);
            return;
        }
        AnimatorControllerLayer _layer = _animatorController.layers[0];
        AnimatorStateMachine _stateMachine = _layer.stateMachine;
        // 读取配置文件
        string _configPath = StringUtility.Contact(ResourcesPath.ResourcesOutAssetPath,
                                                  "mob/",
                                                  configName,
                                                  ".asset");
        AnimatorBuildConfig _buildConfig = AssetDatabase.LoadAssetAtPath<AnimatorBuildConfig>(_configPath);
        HandleStateMachine(resName, _stateMachine, _buildConfig);
        EditorUtility.SetDirty(_animatorController);
        AssetImporter _assetImport = AssetImporter.GetAtPath(_assetPath);
        _assetImport.assetBundleName = ResourcesPath.MOB_FOLDER_NAME + ResourcesPath.MOB_SUFFIX + resName;
        EditorUtility.ClearProgressBar();
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
    protected static void HandleStateMachine(string modelName, AnimatorStateMachine stateMachine, AnimatorBuildConfig _buildConfig)
    {
        if (stateMachine.states == null || stateMachine.states.Length == 0)
        {
            return;
        }
        AnimatorState _animatorState = null;
        Motion _motion = null;
        int _configStateIndex = -1;
        for (int i = 0; i < stateMachine.states.Length; ++i)
        {
            _animatorState = stateMachine.states[i].state;
            _motion = _animatorState.motion;
            foreach (var _clipInfo in _buildConfig.clipConfigs)
            {
                if (_clipInfo.stateName.Equals(_animatorState.name))
                {
                    _configStateIndex = _buildConfig.clipConfigs.IndexOf(_clipInfo);
                }
            }
            if (_configStateIndex == -1)
            {
                Debug.LogWarningFormat("没有找到状态机上名称为: {0}在animatorBuildConfig里的对应配置. ", _animatorState.name);
                continue;
            }
            //  处理融合树类型
            if (_motion is BlendTree)
            { }
            else
            {// 非融合树类型处理
                if (_configStateIndex < 0 || _configStateIndex >= _buildConfig.clipConfigs.Count)
                {
                    Debug.LogWarningFormat("state的名称{0}在配置表 animatorBuildConfig 找到索引{1} 找不到它对应的 clipConfigs 动画配置. ",
                                            _animatorState.name,
                                            _configStateIndex);
                    continue;
                }
                // 读取配置上的动画片段
                List<string> _configClipNames = _buildConfig.clipConfigs[_configStateIndex].clipNames;
                if (_configClipNames == null || _configClipNames.Count == 0)
                {
                    continue;
                }
                AnimationClip _configClip;
                for (int j = 0; j < _configClipNames.Count; ++j)
                {
                    _configClip = LoadModelAnimationClip(modelName, _configClipNames[j]);
                    if (_configClip != null)
                    {
                        _animatorState.motion = _configClip;
                        break;
                    }
                }
                if (_animatorState.motion == null)
                {
                    Debug.LogWarningFormat("为{0}状态设置动画失败!!!", _animatorState.name);
                }
            }
        }
        for (int i = 0; i < stateMachine.stateMachines.Length; ++i)
        {
            HandleStateMachine(modelName, stateMachine.stateMachines[i].stateMachine, _buildConfig);
        }
    }
    protected static AnimationClip LoadModelAnimationClip(string modelName, string clipName)
    {
        string _assetPath = StringUtility.Contact(ResourcesPath.ResourcesOutAssetPath,
                                                 "mob/",
                                                  modelName,
                                                 "/AnimationClips/",
                                                 clipName,
                                                 ".anim");
        AnimationClip _animationClip = AssetDatabase.LoadAssetAtPath<AnimationClip>(_assetPath);
        return _animationClip;
    }
    protected virtual void OnSetupRenderer(string path, string resName, ref Renderer renderer)
    {
    }
using UnityEngine;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Animations;
using System.IO;
public class ResourcesBuilder
{
    protected const byte param_NoExist = 1;
    protected const byte param_Prefab = 2;
    protected const byte param_Clip = 4;
    protected const byte param_AnimatorController = 8;
    protected const byte param_AnimatorUIController = 16;
    protected class MountPointInfo
    {
        public string path;
        public string name;
        public Vector3 localPosition;
        public Quaternion localRotation;
        public Vector3 localScale;
    }
    protected class ColliderInfo
    {
        public Vector3 center;
        public float radius;
        public float height;
    }
    public static int buildParams = 0;
    public static bool OnlyBuildNoExist
    {
        get
        {
            return (buildParams & param_NoExist) != 0;
        }
        set
        {
            if (value)
            {
                buildParams |= param_NoExist;
            }
            else
            {
                buildParams &= ~param_NoExist;
            }
        }
    }
    public static bool IsBuildPrefab
    {
        get
        {
            return (buildParams & param_Prefab) != 0;
        }
        set
        {
            if (value)
            {
                buildParams |= param_Prefab;
            }
            else
            {
                buildParams &= ~param_Prefab;
            }
        }
    }
    public static bool IsBuildAnimationClip
    {
        get
        {
            return (buildParams & param_Clip) != 0;
        }
        set
        {
            if (value)
            {
                buildParams |= param_Clip;
            }
            else
            {
                buildParams &= ~param_Clip;
            }
        }
    }
    public static bool IsBuildAnimatorController
    {
        get
        {
            return (buildParams & param_AnimatorController) != 0;
        }
        set
        {
            if (value)
            {
                buildParams |= param_AnimatorController;
            }
            else
            {
                buildParams &= ~param_AnimatorController;
            }
        }
    }
    public static bool IsBuildAnimatorUIController
    {
        get
        {
            return (buildParams & param_AnimatorUIController) != 0;
        }
        set
        {
            if (value)
            {
                buildParams |= param_AnimatorUIController;
            }
            else
            {
                buildParams &= ~param_AnimatorUIController;
            }
        }
    }
    protected static List<MountPointInfo> m_MountPointInfoList = new List<MountPointInfo>();
    public void BuildPrefab(string path, string resName, string suffix, string outName = null, bool isHighMesh = false)
    {
        if (string.IsNullOrEmpty(outName))
        {
            outName = resName;
        }
        string _absOriginalePath = string.Format("{0}/ART/Role/{1}/{2}.FBX", Application.dataPath, path, resName);
        string _originalAssetPath = string.Format("Assets/ART/Role/{0}/{1}.FBX", path, resName);
        if ((resName.StartsWith("A_Zs") || resName.StartsWith("A_Fs"))
         && !isHighMesh
         && (suffix.Equals(InstanceResourcesLoader.raceSuffix) || suffix.Equals(InstanceResourcesLoader.handSuffix)))
        {
            _absOriginalePath = string.Format("{0}/ART/Role/{1}/{2}_Dm.FBX", Application.dataPath, path, resName);
            _originalAssetPath = string.Format("Assets/ART/Role/{0}/{1}_Dm.FBX", path, resName);
        }
        string _tempPrefabName = outName;
        if (isHighMesh
        && ((resName.StartsWith("A_Zs") || resName.StartsWith("A_Fs"))
        && (suffix.Equals(InstanceResourcesLoader.raceSuffix) || suffix.Equals(InstanceResourcesLoader.handSuffix))))
        {
            _tempPrefabName += "_UI";
            _absOriginalePath = string.Format("{0}/ART/Role/{1}/{2}.FBX", Application.dataPath, path, resName);
            _originalAssetPath = string.Format("Assets/ART/Role/{0}/{1}.FBX", path, resName);
        }
        string _absAssetPath = string.Format("{0}Gmodels/{1}{2}.prefab", ResourcesPath.ResourcesOutPath, suffix, _tempPrefabName);
        string _assetPath = string.Format("{0}Gmodels/{1}{2}.prefab", ResourcesPath.ResourcesOutAssetPath, suffix, _tempPrefabName);
        string _acAbsAssetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutPath, path, AnimatorControllerLoader.controllerSuffix, path);
        string _acAssetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutAssetPath, path, AnimatorControllerLoader.controllerSuffix, path);
        if (!outName.Equals(resName))
        {
            _acAbsAssetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutPath, path, AnimatorControllerLoader.controllerSuffix, outName);
            _acAssetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutAssetPath, path, AnimatorControllerLoader.controllerSuffix, outName);
        }
        if (string.IsNullOrEmpty(_absOriginalePath))
        {
            return;
        }
        // 指定动画控制器
        if (!File.Exists(_acAbsAssetPath))
        {
            Debug.LogWarningFormat("检测到此prefab资源: {0} 的AnimatorContorller(动画控制器)资源尚未生成, 这里需要注意啊此资源是否需要先生成AnimatorContorller(动画控制器), 再生成prefab资源.", _acAssetPath);
        }
        ColliderInfo _colliderInfo = null;
        if (File.Exists(_absAssetPath))
        {
            if (OnlyBuildNoExist)
            {
                //Debug.LogFormat("当前为只生成不存在的资源模式, 这里检测到 {0} 已经存在, 不进行生成.");
                return;
            }
            GameObject _originalAssetRes = null;
            _originalAssetRes = AssetDatabase.LoadAssetAtPath<GameObject>(_assetPath);
            if (_originalAssetRes)
            {
                Transform _mpNode;
                // 这里需要记录旧的对象身上的绑点信息, 然后给新的prefab设置绑点
                m_MountPointInfoList.Clear();
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Down");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Name");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Name2");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Hit");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                _mpNode = _originalAssetRes.transform.GetChildTransformDeeply("A_Stun");
                if (_mpNode)
                {
                    CreateMountPointInfo(_mpNode);
                }
                CapsuleCollider _collider = _originalAssetRes.GetComponent<CapsuleCollider>();
                if (_collider)
                {
                    _colliderInfo = new ColliderInfo();
                    _colliderInfo.center = _collider.center;
                    _colliderInfo.height = _collider.height;
                    _colliderInfo.radius = _collider.radius;
                }
            }
        }
        GameObject _fbxRes = AssetDatabase.LoadAssetAtPath<GameObject>(_originalAssetPath);
        if (_fbxRes == null)
        {
            _originalAssetPath = _originalAssetPath.Remove(_originalAssetPath.LastIndexOf(".")) + ".prefab";
            _fbxRes = AssetDatabase.LoadAssetAtPath<GameObject>(_originalAssetPath);
            if (_fbxRes == null)
            {
                Debug.LogFormat("无法读取 {0}, 地址: {1}", resName, _originalAssetPath);
                return;
            }
        }
        // 为了防止fbx本身就带有材质, 这里去掉fbx上的Import material属性
        //ModelImporter _modelImport = AssetImporter.GetAtPath(_originalAssetPath) as ModelImporter;
        //if (_modelImport != null)
        //{
        //    if (_modelImport.importMaterials)
        //    {
        //        _modelImport.importMaterials = false;
        //        _modelImport.SaveAndReimport();
        //    }
        //}
        GameObject _prefab = Object.Instantiate(_fbxRes);
        // 设置绑点
        if (m_MountPointInfoList.Count > 0)
        {
            MountPointInfo _mpInfo = null;
            for (int i = 0; i < m_MountPointInfoList.Count; ++i)
            {
                _mpInfo = m_MountPointInfoList[i];
                GameObject _mp = new GameObject(_mpInfo.name);
                Transform _parent = null;
                if (string.IsNullOrEmpty(_mpInfo.path))
                {
                    _parent = _prefab.transform;
                }
                else
                {
                    _parent = _prefab.transform.Find(_mpInfo.path);
                }
                if (_parent != null)
                {
                    _mp.transform.SetParent(_parent);
                    _mp.transform.localPosition = _mpInfo.localPosition;
                    _mp.transform.localRotation = _mpInfo.localRotation;
                    _mp.transform.localScale = _mpInfo.localScale;
                }
            }
        }
        // 加载特效
        //if (outName.StartsWith("M")
        // || outName.StartsWith("N")
        // || outName.StartsWith("B_")
        // || outName.StartsWith("Zq"))
        //{
        //    HandlerModelEffect("horseEffectConfig", null, outName, ref _prefab);
        //}
        //else if (InstanceResourcesLoader.raceSuffix.Equals(suffix))
        //{
        //    HandlerModelEffect("clothesEffectConfig", path, resName, ref _prefab);
        //}
        if (_colliderInfo != null)
        {
            CapsuleCollider _collider = _prefab.AddMissingComponent<CapsuleCollider>();
            _collider.center = _colliderInfo.center;
            _collider.radius = _colliderInfo.radius;
            _collider.height = _colliderInfo.height;
        }
        string _tempName = resName;
        if ((resName.StartsWith("A_Zs") || resName.StartsWith("A_Fs"))
            && (suffix.Equals(InstanceResourcesLoader.raceSuffix)
             || suffix.Equals(InstanceResourcesLoader.handSuffix))
            && !isHighMesh)
        {
            _tempName += "_Dm";
        }
        Transform _rendererNode = _prefab.transform.Find(_tempName);
        if (!_rendererNode)
        {
            _rendererNode = _prefab.transform;
        }
        Renderer _renderer = _rendererNode.GetComponent<Renderer>();
        if (_renderer)
        {
            OnSetupRenderer(path, _tempName, ref _renderer);
        }
        Animation _animation = _prefab.GetComponent<Animation>();
        if (_animation)
        {
            Object.DestroyImmediate(_animation);
        }
        if (suffix.Equals(InstanceResourcesLoader.raceSuffix)
         || suffix.Equals(InstanceResourcesLoader.horseSuffix)
         || suffix.Equals(InstanceResourcesLoader.wingSuffix))
        {
            Animator _animator = _prefab.GetComponent<Animator>();
            if (!_animator)
            {
                _animator = _prefab.AddComponent<Animator>();
            }
            if (suffix.Equals(InstanceResourcesLoader.wingSuffix))
            {
                // 绑定动画控制器
                RuntimeAnimatorController _runtimeAnimatorContorller = AssetDatabase.LoadAssetAtPath<RuntimeAnimatorController>(_acAssetPath);
                if (_runtimeAnimatorContorller)
                {
                    _animator.runtimeAnimatorController = _runtimeAnimatorContorller;
                }
            }
        }
        PrefabUtility.CreatePrefab(_assetPath, _prefab, ReplacePrefabOptions.Default);
        // 设置打包路径
        AssetImporter _assetImport = AssetImporter.GetAtPath(_assetPath);
        _assetImport.assetBundleName = ResourcesPath.MOB_FOLDER_NAME
            + (InstanceResourcesLoader.raceSuffix + resName).ToLower();
        EditorUtility.SetDirty(_prefab);
        AssetDatabase.Refresh();
        Object.DestroyImmediate(_prefab);
        AssetDatabase.SaveAssets();
    }
    private void HandlerModelEffect(string configName, string path, string modelName, ref GameObject _go)
    {
        if (_go == null)
        {
            return;
        }
        string _configPath = ResourcesPath.ResourcesOutAssetPath + "Gmodels/" + configName + ".asset";
        HorseEffectConfig _horseEffectConfig = AssetDatabase.LoadAssetAtPath<HorseEffectConfig>(_configPath);
        if (_horseEffectConfig == null
         || _horseEffectConfig.effectConfigList == null
         || _horseEffectConfig.effectConfigList.Count == 0)
        {
            return;
        }
        HorseEffectConfig.EffectConfig _effectConfig;
        int _index = -1;
        for (int i = 0; i < _horseEffectConfig.effectConfigList.Count; ++i)
        {
            _effectConfig = _horseEffectConfig.effectConfigList[i];
            if (_effectConfig.modelName.Equals(modelName))
            {
                _index = i;
                break;
            }
        }
        if (_index == -1)
        {
            Debug.LogFormat("HandlerModelEffect() => 模型 {0} 没有配置任何特效", modelName);
            return;
        }
        _effectConfig = _horseEffectConfig.effectConfigList[_index];
        Transform _parent;
        GameObject _effect;
        string _bonePath;
        string _effectName;
        for (int i = 0; i < _effectConfig.boneNameList.Count; ++i)
        {
            _bonePath = _effectConfig.boneNameList[i];
            _parent = _go.transform.GetChildTransformDeeply(_bonePath);
            if (_parent == null)
            {
                Debug.LogWarningFormat("HandlerModelEffect() => 坐骑 {0} 配置的骨骼名称: {1} 找不到", modelName, _bonePath);
                continue;
            }
            _effectName = _effectConfig.effectNameList[i];
            if (string.IsNullOrEmpty(path))
            {
                _configPath = string.Format("Assets/Art/Role/{0}/Effects/{1}.prefab", modelName, _effectName);
            }
            else
            {
                _configPath = string.Format("Assets/Art/Role/{0}/Effects/{1}.prefab", path, _effectName);
            }
            _effect = AssetDatabase.LoadAssetAtPath<GameObject>(_configPath);
            if (_effect == null)
            {
                Debug.LogWarningFormat("HandlerModelEffect() => 坐骑 {0} 配置的特效资源: {1} 找不到", modelName, _configPath);
                continue;
            }
            _effect = Object.Instantiate(_effect);
            _effect.name = _effect.name.Replace("(Clone)", "");
            _effect.transform.SetParentEx(_parent, Vector3.zero, Quaternion.identity, Vector3.one);
            _effect.SetLayer(LayerUtility.BattleEffectLow, true);
        }
    }
    protected static void CreateMountPointInfo(Transform t)
    {
        MountPointInfo _info = new MountPointInfo();
        _info.path = SampleEditorTool.PrintHierarchyPath(t);
        if (!string.IsNullOrEmpty(_info.path))
        {
            if (_info.path.Contains("/"))
            {
                _info.path = _info.path.Replace("/" + t.name, "");
            }
            else
            {
                _info.path = _info.path.Replace(t.name, "");
            }
        }
        _info.name = t.name;
        _info.localPosition = t.localPosition;
        _info.localRotation = t.localRotation;
        _info.localScale = t.localScale;
        m_MountPointInfoList.Add(_info);
    }
    public static void BuildAnimationClip(string path)
    {
        string _absOriginaleDirectory = string.Format("{0}/ART/Role/{1}", Application.dataPath, path);
        string _assetOriginalDirectory = string.Format("Assets/ART/Role/{0}", path);
        string _absAssetDirectory = string.Format("{0}/ResourcesOut/Gmodels/{1}/AnimationClips", Application.dataPath, path);
        string _assetDirectory = string.Format("Assets/ResourcesOut/Gmodels/{0}/AnimationClips", path);
        if (!Directory.Exists(_absOriginaleDirectory))
        {
            return;
        }
        // 生成目标文件夹是否存在, 不存在则创建
        if (!Directory.Exists(_absAssetDirectory))
        {
            Directory.CreateDirectory(_absAssetDirectory);
        }
        DirectoryInfo _dInfo = new DirectoryInfo(_absOriginaleDirectory);
        FileInfo[] _fInfos = _dInfo.GetFiles("*.fbx");
        FileInfo _fInfo = null;
        Object _animationClip = null;
        AssetImporter _assetImport = null;
        int _count = _fInfos.Length;
        string _newName = string.Empty;
        string _assetDestPath = string.Empty;
        string _originalPath = string.Empty;
        List<AnimationClip> clips = new List<AnimationClip>();
        for (int i = 0; i < _fInfos.Length; ++i)
        {
            _fInfo = _fInfos[i];
            if (!_fInfo.Name.Contains("@"))
            {
                continue;
            }
            _newName = _fInfo.Name.Substring(_fInfo.Name.IndexOf("@") + 1);
            _newName = _newName.Substring(0, _newName.Length - 4);
            _assetDestPath = string.Format("{0}/{1}.anim", _absAssetDirectory, _newName);
            EditorUtility.DisplayProgressBar(string.Format("正在生成 {0} 的动画中...", path),
                                             string.Format("{0} => {1}.", _fInfo.Name, _assetDestPath),
                                             i * 1f / _count);
            if (File.Exists(_assetDestPath))
            {
                if (OnlyBuildNoExist)
                {
                    continue;
                }
            }
            _assetDestPath = string.Format("{0}/{1}.anim", _assetDirectory, _newName);
            _originalPath = _fInfo.FullName.Substring(Application.dataPath.Length + 1);
            _originalPath = Path.Combine("Assets/", _originalPath);
            _originalPath = _originalPath.Replace("\\", "/");
            _animationClip = AssetDatabase.LoadAssetAtPath(_originalPath, typeof(AnimationClip));
            AnimationClip _newClip = new AnimationClip();
            EditorUtility.CopySerialized(_animationClip, _newClip);
            _newClip.legacy = false;
            if (_newClip.name.Contains("Idle") || _newClip.name.Contains("Run") || _newClip.name.Contains("Stun"))
            {
                if (_newClip.isLooping == false)
                {
                    AnimationClipSettings _clipSetting = AnimationUtility.GetAnimationClipSettings(_newClip);
                    _clipSetting.loopTime = true;
                    AnimationUtility.SetAnimationClipSettings(_newClip, _clipSetting);
                }
            }
            AssetDatabase.CreateAsset(_newClip, _assetDestPath);
            _assetImport = AssetImporter.GetAtPath(_assetDestPath);
            _assetImport.assetBundleName = ResourcesPath.MOB_FOLDER_NAME + ResourcesPath.MOB_SUFFIX + path.ToLower();
            clips.Add(_newClip);
            EditorUtility.SetDirty(_newClip);
        }
        EditorUtility.ClearProgressBar();
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
    public static void BuildAnimatorController(string resName, string templeName, string configName, string outName = null)
    {
        if (string.IsNullOrEmpty(outName))
        {
            outName = resName;
        }
        string _absAssetPath = string.Format("{0}Gmodels/{1}", ResourcesPath.ResourcesOutPath, outName);
        if (!Directory.Exists(_absAssetPath))
        {
            Directory.CreateDirectory(_absAssetPath);
        }
        _absAssetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutPath, outName, AnimatorControllerLoader.controllerSuffix, outName);
        string _assetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutAssetPath, outName, AnimatorControllerLoader.controllerSuffix, outName);
        if (templeName.Equals("Temple_AnimatorController_BossShow"))
        {
            _absAssetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutPath, resName, AnimatorControllerLoader.controllerShowSuffix, resName);
            _assetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutAssetPath, resName, AnimatorControllerLoader.controllerShowSuffix, resName);
        }
        if (templeName.Equals("Temple_AnimatorController_Realm"))
        {
            _absAssetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutPath, resName, AnimatorControllerLoader.controllerRealmSuffix, resName);
            _assetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutAssetPath, resName, AnimatorControllerLoader.controllerRealmSuffix, resName);
        }
        if (templeName.Equals("Temple_AnimatorController_UI"))
        {
            _absAssetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutPath, outName, AnimatorControllerLoader.controllerUISuffix, outName);
            _assetPath = string.Format("{0}Gmodels/{1}/{2}{3}.controller", ResourcesPath.ResourcesOutAssetPath, outName, AnimatorControllerLoader.controllerUISuffix, outName);
        }
        string _templePath = string.Format("{0}Gmodels/{1}.controller", ResourcesPath.ResourcesOutPath, templeName);
        if (File.Exists(_absAssetPath))
        {
            if (OnlyBuildNoExist)
            {
                return;
            }
            else
            {
                File.Delete(_absAssetPath);
            }
        }
        File.Copy(_templePath, _absAssetPath);
        AssetDatabase.Refresh();
        AnimatorController _animatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(_assetPath);
        if (!_animatorController)
        {
            Debug.LogErrorFormat("找不到所需要的动画状态机, 地址为: {0}", _assetPath);
            return;
        }
        AnimatorControllerLayer _layer = _animatorController.layers[0];
        AnimatorStateMachine _stateMachine = _layer.stateMachine;
        // 读取配置文件
        string _configPath = StringUtility.Contact(ResourcesPath.ResourcesOutAssetPath,
                                                  "gmodels/",
                                                  configName,
                                                  ".asset");
        AnimatorBuildConfig _buildConfig = AssetDatabase.LoadAssetAtPath<AnimatorBuildConfig>(_configPath);
        HandleStateMachine(resName, _stateMachine, _buildConfig);
        EditorUtility.SetDirty(_animatorController);
        AssetImporter _assetImport = AssetImporter.GetAtPath(_assetPath);
        _assetImport.assetBundleName = ResourcesPath.MOB_FOLDER_NAME + ResourcesPath.MOB_SUFFIX + outName;
        EditorUtility.ClearProgressBar();
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
    protected static void HandleStateMachine(string modelName, AnimatorStateMachine stateMachine, AnimatorBuildConfig _buildConfig)
    {
        if (stateMachine.states == null || stateMachine.states.Length == 0)
        {
            return;
        }
        AnimatorState _animatorState = null;
        Motion _motion = null;
        int _configStateIndex = -1;
        for (int i = 0; i < stateMachine.states.Length; ++i)
        {
            _animatorState = stateMachine.states[i].state;
            _motion = _animatorState.motion;
            foreach (var _clipInfo in _buildConfig.clipConfigs)
            {
                if (_clipInfo.stateName.Equals(_animatorState.name))
                {
                    _configStateIndex = _buildConfig.clipConfigs.IndexOf(_clipInfo);
                }
            }
            if (_configStateIndex == -1)
            {
                Debug.LogWarningFormat("没有找到状态机上名称为: {0}在animatorBuildConfig里的对应配置. ", _animatorState.name);
                continue;
            }
            //  处理融合树类型
            if (_motion is BlendTree)
            { }
            else
            {// 非融合树类型处理
                if (_configStateIndex < 0 || _configStateIndex >= _buildConfig.clipConfigs.Count)
                {
                    Debug.LogWarningFormat("state的名称{0}在配置表 animatorBuildConfig 找到索引{1} 找不到它对应的 clipConfigs 动画配置. ",
                                            _animatorState.name,
                                            _configStateIndex);
                    continue;
                }
                // 读取配置上的动画片段
                List<string> _configClipNames = _buildConfig.clipConfigs[_configStateIndex].clipNames;
                if (_configClipNames == null || _configClipNames.Count == 0)
                {
                    continue;
                }
                AnimationClip _configClip;
                for (int j = 0; j < _configClipNames.Count; ++j)
                {
                    _configClip = LoadModelAnimationClip(modelName, _configClipNames[j]);
                    if (_configClip != null)
                    {
                        _animatorState.motion = _configClip;
                        break;
                    }
                }
                if (_animatorState.motion == null)
                {
                    Debug.LogWarningFormat("为{0}状态设置动画失败!!!", _animatorState.name);
                }
            }
        }
        for (int i = 0; i < stateMachine.stateMachines.Length; ++i)
        {
            HandleStateMachine(modelName, stateMachine.stateMachines[i].stateMachine, _buildConfig);
        }
    }
    protected static AnimationClip LoadModelAnimationClip(string modelName, string clipName)
    {
        string _assetPath = StringUtility.Contact(ResourcesPath.ResourcesOutAssetPath,
                                                 "gmodels/",
                                                  modelName,
                                                 "/AnimationClips/",
                                                 clipName,
                                                 ".anim");
        AnimationClip _animationClip = AssetDatabase.LoadAssetAtPath<AnimationClip>(_assetPath);
        return _animationClip;
    }
    protected virtual void OnSetupRenderer(string path, string resName, ref Renderer renderer)
    {
    }
}