280 lines
11 KiB
C#
280 lines
11 KiB
C#
using System.Collections.Generic;
|
||
using System.IO;
|
||
using cfg.VehicleCfg;
|
||
using Framework;
|
||
using Gameplay.Utils;
|
||
using UnityEditor;
|
||
using UnityEditor.Animations;
|
||
using UnityEngine;
|
||
namespace VehicleBuilder
|
||
{
|
||
/// <summary>
|
||
/// 所有动作都可以没有
|
||
/// body使用的animator Assets/Art/Animations/animator/Vehicle/animator_vehicle.controller
|
||
/// body需要的动作 Assets/Art/Animations/Vehicle/C00001/ani_C00001_D_dead.fbx
|
||
/// dead
|
||
/// idle
|
||
/// move
|
||
/// restart
|
||
/// stop
|
||
/// skill
|
||
/// battery使用的animator Assets/Art/Animations/animator/Battery/animator_battery.controller
|
||
/// battery需要的动作 Assets/Art/Animations/Battery/R00001/ani_R00001_attack01.fbx
|
||
/// attack01
|
||
/// idle
|
||
/// skill
|
||
/// </summary>
|
||
public class VehicleBuildData
|
||
{
|
||
public DataVehicle vehicleConfig;
|
||
|
||
public bool isChecked;
|
||
|
||
public string bodyName;
|
||
public string batteryName;
|
||
|
||
public string errorInfo;
|
||
|
||
private string _prefabPath;
|
||
|
||
private string[] _bodyAniNames = new string[]
|
||
{
|
||
"dead",
|
||
"idle",
|
||
"move",
|
||
"restart",
|
||
"stop",
|
||
// "skill",
|
||
};
|
||
|
||
public void Init()
|
||
{
|
||
var prefabPath = PathEx.GetVehicleSrcModelPath(vehicleConfig.PrefabPath);
|
||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
||
if (prefab == null)
|
||
{
|
||
errorInfo = $"载具预制体不存在:{prefabPath}";
|
||
return;
|
||
}
|
||
_prefabPath = prefabPath;
|
||
|
||
var prefabName = prefab.name;
|
||
var splits = prefabName.Split('_');
|
||
if (splits.Length != 3)
|
||
{
|
||
errorInfo = $"prefab命名错误:{prefabName}";
|
||
return;
|
||
}
|
||
bodyName = splits[1];
|
||
|
||
// 检查所有bodyanims
|
||
for (var i = 0; i < _bodyAniNames.Length; ++i)
|
||
{
|
||
var bodyAnimName = _bodyAniNames[i];
|
||
var combinePath = $"Assets/Art/Animations/Vehicle/{bodyName}/ani_{bodyName}_D_{bodyAnimName}.fbx";
|
||
var loadAnim = AssetDatabase.LoadAssetAtPath<AnimationClip>(combinePath);
|
||
if (loadAnim == null)
|
||
{
|
||
errorInfo = $"不存在需求动作: {combinePath}";
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
public void DoBuild()
|
||
{
|
||
var savePath = string.Format(Constants.VEHICLE_OUTPUT_PATH, vehicleConfig.ID);
|
||
var realPath = savePath.Replace("Assets", Application.dataPath);
|
||
if (!Directory.Exists(realPath))
|
||
{
|
||
Directory.CreateDirectory(realPath);
|
||
}
|
||
|
||
var loadPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(_prefabPath);
|
||
if (loadPrefab == null)
|
||
{
|
||
Debug.LogError($"找不到载具预制体:{_prefabPath}");
|
||
return;
|
||
}
|
||
loadPrefab = Object.Instantiate(loadPrefab);
|
||
_HandlePrefab(loadPrefab, savePath);
|
||
|
||
var savePrefabPath = $"{savePath}/vehicle_{vehicleConfig.ID}.prefab";
|
||
PrefabUtility.SaveAsPrefabAsset(loadPrefab, savePrefabPath);
|
||
|
||
// 销毁prefab
|
||
Object.DestroyImmediate(loadPrefab);
|
||
|
||
Debug.Log($"生成载具预制体:{savePrefabPath}");
|
||
}
|
||
|
||
private void _HandlePrefab(GameObject prefab, string savePath)
|
||
{
|
||
var allTrans = new List<Transform>();
|
||
_DeepSearchTrans(prefab.transform, allTrans);
|
||
var findBody = _SearchByName(allTrans, bodyName);
|
||
if (findBody == null)
|
||
{
|
||
Debug.LogError($"找不到body:{bodyName}");
|
||
return;
|
||
}
|
||
// 删除炮台
|
||
var findBattery = _SearchByName(allTrans, "Battery_point01");
|
||
if (findBattery != null && findBattery.childCount > 0)
|
||
{
|
||
var child = findBattery.GetChild(0);
|
||
if (child != null)
|
||
{
|
||
Object.DestroyImmediate(child.gameObject);
|
||
}
|
||
}
|
||
|
||
// 处理body
|
||
_HandleBody(savePath, findBody);
|
||
|
||
EditorUtility.SetDirty(prefab);
|
||
AssetDatabase.SaveAssets();
|
||
}
|
||
|
||
private void _HandleBattery(string savePath,
|
||
Transform findBattery)
|
||
{
|
||
var srcController = AssetDatabase.LoadAssetAtPath<AnimatorController>("Assets/Art/Animations/animator/Battery/animator_battery.controller");
|
||
if (srcController == null)
|
||
{
|
||
Debug.LogError($"找不到animator_battery.controller");
|
||
return;
|
||
}
|
||
// 创建一个overrideController
|
||
var overrideController = new AnimatorOverrideController();
|
||
overrideController.runtimeAnimatorController = srcController;
|
||
// 设置动作
|
||
var kvList = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
||
var oldClips = overrideController.animationClips;
|
||
for (int i = 0; i < oldClips.Length; i++)
|
||
{
|
||
var oldClip = oldClips[i];
|
||
var oldClipName = oldClip.name;
|
||
// ani_R00001_attack01
|
||
var splits = oldClipName.Split('_');
|
||
var finalName = splits[^1];
|
||
var newClipPath = $"Assets/Art/Animations/Battery/{batteryName}/ani_{batteryName}_{finalName}.fbx";
|
||
var newClip = AssetDatabase.LoadAssetAtPath<AnimationClip>(newClipPath);
|
||
if (newClip == null)
|
||
{
|
||
Debug.LogError($"找不到动作:{newClipPath}");
|
||
continue;
|
||
}
|
||
kvList.Add(new KeyValuePair<AnimationClip, AnimationClip>(oldClip, newClip));
|
||
}
|
||
overrideController.ApplyOverrides(kvList);
|
||
// 保存controller
|
||
var saveControllerPath = $"{savePath}/ov_battery_{vehicleConfig.ID}.controller";
|
||
AssetDatabase.CreateAsset(overrideController, saveControllerPath);
|
||
AssetDatabase.Refresh();
|
||
overrideController = AssetDatabase.LoadAssetAtPath<AnimatorOverrideController>(saveControllerPath);
|
||
// 设置battery的animator
|
||
var batteryAnimator = findBattery.GetComponent<Animator>();
|
||
if (batteryAnimator == null)
|
||
{
|
||
batteryAnimator = findBattery.gameObject.AddComponent<Animator>();
|
||
}
|
||
batteryAnimator.runtimeAnimatorController = overrideController;
|
||
batteryAnimator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
|
||
}
|
||
|
||
private void _HandleBody(string savePath,
|
||
Transform findBody)
|
||
{
|
||
|
||
var srcController = AssetDatabase.LoadAssetAtPath<AnimatorController>("Assets/Art/Animations/animator/Vehicle/animator_vehicle.controller");
|
||
if (srcController == null)
|
||
{
|
||
Debug.LogError($"找不到animator_vehicle.controller");
|
||
return;
|
||
}
|
||
// 创建一个overrideController
|
||
var overrideController = new AnimatorOverrideController();
|
||
overrideController.runtimeAnimatorController = srcController;
|
||
// 设置动作
|
||
var kvList = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
||
var oldClips = overrideController.animationClips;
|
||
for (int i = 0; i < oldClips.Length; i++)
|
||
{
|
||
var oldClip = oldClips[i];
|
||
var oldClipName = oldClip.name;
|
||
// ani_C00001_D_idle
|
||
var splits = oldClipName.Split('_');
|
||
var finalName = splits[^1];
|
||
var newClipPath = $"Assets/Art/Animations/Vehicle/{bodyName}/ani_{bodyName}_D_{finalName}.fbx";
|
||
var newClip = AssetDatabase.LoadAssetAtPath<AnimationClip>(newClipPath);
|
||
if (newClip == null)
|
||
{
|
||
Debug.LogError($"找不到动作:{newClipPath}");
|
||
continue;
|
||
}
|
||
kvList.Add(new KeyValuePair<AnimationClip, AnimationClip>(oldClip, newClip));
|
||
}
|
||
overrideController.ApplyOverrides(kvList);
|
||
_CompressOverrideController(overrideController);
|
||
|
||
// 保存controller
|
||
var saveControllerPath = $"{savePath}/ov_vehicle_{vehicleConfig.ID}.controller";
|
||
AssetDatabase.CreateAsset(overrideController, saveControllerPath);
|
||
AssetDatabase.Refresh();
|
||
overrideController = AssetDatabase.LoadAssetAtPath<AnimatorOverrideController>(saveControllerPath);
|
||
// 设置body的animator
|
||
var bodyAnimator = findBody.GetComponent<Animator>();
|
||
if (bodyAnimator == null)
|
||
{
|
||
bodyAnimator = findBody.gameObject.AddComponent<Animator>();
|
||
}
|
||
bodyAnimator.runtimeAnimatorController = overrideController;
|
||
bodyAnimator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
|
||
}
|
||
|
||
private void _CompressOverrideController(AnimatorOverrideController overrideController)
|
||
{
|
||
var overrideClips = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
||
overrideController.GetOverrides(overrideClips);
|
||
var newClips = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
||
foreach (var oldKV in overrideClips)
|
||
{
|
||
var srcClip = oldKV.Key;
|
||
var dstClip = oldKV.Value;
|
||
if (dstClip == null)
|
||
{
|
||
dstClip = srcClip;
|
||
}
|
||
var newClip = LTCompressor.AutoCompress(dstClip);
|
||
newClips.Add(new KeyValuePair<AnimationClip, AnimationClip>(srcClip, newClip));
|
||
}
|
||
overrideController.ApplyOverrides(newClips);
|
||
}
|
||
|
||
private static Transform _SearchByName(List<Transform> searchList, string name)
|
||
{
|
||
for (int i = 0; i < searchList.Count; i++)
|
||
{
|
||
var trans = searchList[i];
|
||
if (trans.name == name)
|
||
{
|
||
return trans;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
private static void _DeepSearchTrans(Transform searchTrans, List<Transform> result)
|
||
{
|
||
result.Add(searchTrans);
|
||
for (int i = 0; i < searchTrans.childCount; i++)
|
||
{
|
||
var child = searchTrans.GetChild(i);
|
||
_DeepSearchTrans(child, result);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|