1319 lines
55 KiB
C#
1319 lines
55 KiB
C#
using System.Collections.Generic;
|
|
using System.Data;
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using cfg;
|
|
using SimpleJSON;
|
|
using UnityEditor.Animations;
|
|
using Path = System.IO.Path;
|
|
using RootMotion.FinalIK;
|
|
|
|
public class ArtActorPrefabModifyWindow : EditorWindow
|
|
{
|
|
public static string assetSrcFolderPath = "Assets/AssetsPackage/art/fishsetting/mesh";
|
|
|
|
public static string assetDstFolderPath = "Assets/ABPackage/pkgDownloads/Fish"; //"Assets/AssetsPackage/Prefabs/Fishing/Fish";
|
|
public static string assetRodDstFolderPath = "Assets/ABPackage/pkgDownloads/Rod";
|
|
|
|
public static string fishMaterialFolderPath = "Assets/AssetsPackage/art/fishsetting/materials/";
|
|
public static string reelMaterialFolderPath = "Assets/AssetsPackage/art/fishingrod/reel/materials/";
|
|
public static string rodMaterialFolderPath = "Assets/AssetsPackage/art/fishingrod/rod/materials/";
|
|
|
|
public static string baseFishOverrideControllerPath = "Assets/AssetsPackage/Animation/Fishing/Fish/";
|
|
public static string baseRodOverrideControllerPath = "Assets/AssetsPackage/Animation/Fishing/Rod/";
|
|
public static UnityEditor.Animations.AnimatorController animatorController;
|
|
public static string animatorOverrideControllerPath = "Assets/AssetsPackage/art/fishsetting/animations/";
|
|
public static UnityEditor.Animations.AnimatorController animatorRodController;
|
|
public static string animatorRodControllerPath = "Assets/AssetsPackage/art/fishingrod/rod/animations/";
|
|
private Object jsonFile;
|
|
private string folderPath = "Assets/ABPackage/pkgDownloads/Fish";
|
|
private int startLine;
|
|
private int endLine;
|
|
|
|
static string crossbowPrefabPath = "Assets/ABPackage/pkgDownloads/Aquarium/AquariumCommon/Crossbow/";
|
|
public static string baseCrossbowOverrideControllerPath = "Assets/AssetsPackage/art/fishingcrossbow/animations/";
|
|
static UnityEditor.Animations.AnimatorController animatorCrossbowController;
|
|
public static string animatorCrossbowControllerPath = "Assets/AssetsPackage/art/fishingcrossbow/animations/";
|
|
|
|
[MenuItem("Window/自动化构建工具", false, 1)]
|
|
public static void ShowWindow()
|
|
{
|
|
EditorWindow thisWindow = EditorWindow.GetWindow(typeof(ArtActorPrefabModifyWindow));
|
|
thisWindow.titleContent = new GUIContent("创建Prefab");
|
|
thisWindow.position = new Rect(Screen.width / 2, Screen.height / 2, 600, 800);
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
// 设置默认的json文件
|
|
string defaultJsonPath = "Assets/ABPackage/pkgData/Export/tbfishdata.json";
|
|
jsonFile = AssetDatabase.LoadAssetAtPath(defaultJsonPath, typeof(TextAsset));
|
|
}
|
|
|
|
void OnGUI()
|
|
{
|
|
//分一个组
|
|
EditorGUILayout.BeginVertical("box");
|
|
EditorGUILayout.LabelField("批量创建鱼的Prefab", EditorStyles.boldLabel);
|
|
EditorGUILayout.Space(10);
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField("选择源文件夹");
|
|
assetSrcFolderPath = EditorGUILayout.TextField(assetSrcFolderPath);
|
|
if (GUILayout.Button("选择"))
|
|
{
|
|
assetSrcFolderPath = EditorUtility.OpenFolderPanel("选择文件夹", assetSrcFolderPath, "");
|
|
}
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField("选择保存文件夹");
|
|
assetDstFolderPath = EditorGUILayout.TextField(assetDstFolderPath);
|
|
if (GUILayout.Button("选择"))
|
|
{
|
|
assetDstFolderPath = EditorUtility.OpenFolderPanel("选择文件夹", assetDstFolderPath, "");
|
|
}
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.EndHorizontal();
|
|
EditorGUILayout.BeginHorizontal();
|
|
animatorController = (AnimatorController)EditorGUILayout.ObjectField("animatorController", animatorController, typeof(AnimatorController), false);
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
if (GUILayout.Button("开始创建") && assetSrcFolderPath != null && assetDstFolderPath != null)
|
|
{
|
|
Seperate(GetAbsolutePath(assetSrcFolderPath));
|
|
}
|
|
|
|
EditorGUILayout.Space(10);
|
|
//分组结束
|
|
EditorGUILayout.EndVertical();
|
|
EditorGUILayout.BeginVertical("box");
|
|
|
|
EditorGUILayout.EndVertical();
|
|
EditorGUILayout.BeginVertical("box");
|
|
EditorGUILayout.LabelField("CheckFishFilesInFolder", EditorStyles.boldLabel);
|
|
// 创建可以拖拽Excel表的字段
|
|
jsonFile = EditorGUILayout.ObjectField("Json File tbfishdata", jsonFile, typeof(TextAsset), false);
|
|
|
|
// 获取拖进去的文件夹路径
|
|
if (Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform)
|
|
{
|
|
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
|
|
if (Event.current.type == EventType.DragPerform)
|
|
{
|
|
DragAndDrop.AcceptDrag();
|
|
foreach (string path in DragAndDrop.paths)
|
|
{
|
|
if (Directory.Exists(path))
|
|
{
|
|
folderPath = path;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 显示文件夹路径
|
|
EditorGUILayout.LabelField("Folder Path: " + folderPath);
|
|
|
|
// 输入起始行和结束行
|
|
startLine = EditorGUILayout.IntField("Start Line", startLine);
|
|
endLine = EditorGUILayout.IntField("End Line", endLine);
|
|
// 检查文件夹中是否存在指定文件
|
|
if (GUILayout.Button("Check Files"))
|
|
{
|
|
CheckFiles();
|
|
}
|
|
|
|
//分组结束
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
|
|
void CheckFiles()
|
|
{
|
|
// 读取json文件
|
|
string jsonString = (jsonFile as TextAsset).ToString();
|
|
var jsonData = new TbFishData(JSON.Parse(jsonString));
|
|
|
|
// 获取指定区间的数据
|
|
List<string> fileNames = new List<string>();
|
|
if (startLine < 1)
|
|
{
|
|
startLine = 1;
|
|
}
|
|
|
|
if (endLine > jsonData.DataList.Count)
|
|
{
|
|
endLine = jsonData.DataList.Count;
|
|
}
|
|
|
|
for (int i = startLine - 1; i < endLine; i++)
|
|
{
|
|
fileNames.Add(jsonData.DataList[i].Fbx);
|
|
}
|
|
|
|
// 检查文件夹中是否存在指定文件
|
|
List<string> missingFiles = new List<string>();
|
|
foreach (string fileName in fileNames)
|
|
{
|
|
string filePath = System.IO.Path.Combine(folderPath, fileName + ".prefab");
|
|
if (!File.Exists(filePath))
|
|
{
|
|
missingFiles.Add(fileName);
|
|
}
|
|
}
|
|
|
|
// 打印缺失文件名
|
|
if (missingFiles.Count > 0)
|
|
{
|
|
Debug.Log("The following files are missing:");
|
|
foreach (string missingFile in missingFiles)
|
|
{
|
|
Debug.Log(missingFile);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("All files are present.");
|
|
}
|
|
}
|
|
|
|
private static void Seperate(string folderPath)
|
|
{
|
|
//*.prefab或*.Fbx
|
|
var folders = Directory.GetDirectories(folderPath, "F_*", SearchOption.TopDirectoryOnly);
|
|
foreach (var folder in folders)
|
|
{
|
|
var files = Directory.GetFiles(folder, "*.*")
|
|
.Where(file => file.EndsWith(".prefab") || file.EndsWith(".fbx") || file.EndsWith(".FBX")).ToArray();
|
|
string srcPath = GetRelativePath(files[0]);
|
|
GameObject prefab = AssetDatabase.LoadAssetAtPath(srcPath, typeof(GameObject)) as GameObject;
|
|
if (prefab == null)
|
|
continue;
|
|
string fileName = Path.GetFileNameWithoutExtension(srcPath);
|
|
string directory = Path.GetDirectoryName(srcPath);
|
|
string newPath = Path.Combine(directory, fileName);
|
|
AssetsFish(prefab, newPath);
|
|
}
|
|
}
|
|
|
|
public static string GetRelativePath(string path)
|
|
{
|
|
string srcPath = path.Replace("\\", "/");
|
|
var retPath = Regex.Replace(srcPath, @"^(.*?/)Assets/", "Assets/");
|
|
return retPath;
|
|
}
|
|
|
|
public static string GetAbsolutePath(string path)
|
|
{
|
|
string srcPath = path.Replace("\\", "/");
|
|
//替换第一个Assets之前的路径
|
|
var retPath = Regex.Replace(srcPath, @"^(.*?/)Assets", Application.dataPath);
|
|
return retPath;
|
|
}
|
|
#region 鱼相关工具
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab查找节点")]
|
|
static void MenuAssetsFinFishNodes()
|
|
{
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
var files = Directory.GetFiles(path, "*.prefab");
|
|
foreach (var file in files)
|
|
{
|
|
string srcPath = GetRelativePath(file);
|
|
GameObject prefab = AssetDatabase.LoadAssetAtPath(srcPath, typeof(GameObject)) as GameObject;
|
|
if (prefab == null)
|
|
continue;
|
|
Fish fish = prefab.GetComponent<Fish>();
|
|
if (fish == null)
|
|
{
|
|
Debug.LogError($"{prefab.name}不是可钓的鱼");
|
|
continue;
|
|
}
|
|
FindFishNode(fish, prefab.transform);
|
|
LogNullNode(prefab.name, fish);
|
|
EditorUtility.SetDirty(prefab);
|
|
}
|
|
AssetDatabase.SaveAssets();
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab查找节点", true)]
|
|
private static bool MenuAssetsFinFishNodesValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
return AssetDatabase.IsValidFolder(path);
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab检查偏移")]
|
|
static void MenuAssetsCheckFishPos()
|
|
{
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
var files = Directory.GetFiles(path, "*.prefab");
|
|
foreach (var file in files)
|
|
{
|
|
string srcPath = GetRelativePath(file);
|
|
GameObject prefab = AssetDatabase.LoadAssetAtPath(srcPath, typeof(GameObject)) as GameObject;
|
|
if (prefab == null)
|
|
continue;
|
|
Fish fish = prefab.GetComponent<Fish>();
|
|
if (fish == null)
|
|
{
|
|
Debug.LogError($"{prefab.name}不是可钓的鱼");
|
|
continue;
|
|
}
|
|
//FindFishNode(fish, prefab.transform);
|
|
//LogNullNode(prefab.name, fish);
|
|
//EditorUtility.SetDirty(prefab);
|
|
if (fish.animator != null)
|
|
{
|
|
if (fish.animator.transform.localPosition != Vector3.zero)
|
|
{
|
|
Debug.LogError($"{prefab.name}的animator有偏移{fish.animator.transform.localPosition}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError($"{prefab.name}缺少animator节点");
|
|
}
|
|
}
|
|
AssetDatabase.SaveAssets();
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab检查偏移", true)]
|
|
private static bool MenuAssetsCheckFishPosValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
return AssetDatabase.IsValidFolder(path);
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab设置动画")]
|
|
static void MenuAssetsFinFishAni()
|
|
{
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
var files = Directory.GetFiles(path, "*.prefab");
|
|
foreach (var file in files)
|
|
{
|
|
string srcPath = GetRelativePath(file);
|
|
GameObject prefab = AssetDatabase.LoadAssetAtPath(srcPath, typeof(GameObject)) as GameObject;
|
|
if (prefab == null)
|
|
continue;
|
|
Fish fish = prefab.GetComponent<Fish>();
|
|
if (fish == null)
|
|
{
|
|
Debug.LogError($"{prefab.name}不是可钓的鱼");
|
|
continue;
|
|
}
|
|
srcPath = $"{GetRelativePath(assetSrcFolderPath)}/{prefab.name}/{prefab.name}";
|
|
SetFishAni(fish, srcPath);
|
|
}
|
|
AssetDatabase.SaveAssets();
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab设置动画", true)]
|
|
private static bool MenuAssetsFinFishAniValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
return AssetDatabase.IsValidFolder(path);
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab检查节点")]
|
|
static void MenuAssetsCheckFishNodes()
|
|
{
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
var files = Directory.GetFiles(path, "*.prefab");
|
|
foreach (var file in files)
|
|
{
|
|
string srcPath = GetRelativePath(file);
|
|
GameObject prefab = AssetDatabase.LoadAssetAtPath(srcPath, typeof(GameObject)) as GameObject;
|
|
if (prefab == null)
|
|
continue;
|
|
Fish fish = prefab.GetComponent<Fish>();
|
|
if (fish == null)
|
|
{
|
|
Debug.LogError($"{prefab.name}不是可钓的鱼");
|
|
continue;
|
|
}
|
|
LogNullNode(prefab.name, fish);
|
|
}
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab检查节点", true)]
|
|
private static bool MenuAssetsCheckFishNodesValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
return AssetDatabase.IsValidFolder(path);
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab检查Layer")]
|
|
static void MenuAssetsCheckFishLayer()
|
|
{
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
var files = Directory.GetFiles(path, "*.prefab");
|
|
foreach (var file in files)
|
|
{
|
|
string srcPath = GetRelativePath(file);
|
|
GameObject prefab = AssetDatabase.LoadAssetAtPath(srcPath, typeof(GameObject)) as GameObject;
|
|
if (prefab == null)
|
|
continue;
|
|
|
|
LogRendererLayer(prefab);
|
|
}
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/遍历文件夹下的鱼prefab检查Layer", true)]
|
|
private static bool MenuAssetsCheckFishLayerValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
return AssetDatabase.IsValidFolder(path);
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/文件夹下创建鱼Prefab", true)]
|
|
private static bool MenuAssetsFishFValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
return Directory.Exists(path);
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/文件夹下创建鱼Prefab")]
|
|
static void MenuAssetsFishF()
|
|
{
|
|
if (Selection.activeObject == null)
|
|
{
|
|
Debug.Log("Assets choose null");
|
|
}
|
|
else
|
|
{
|
|
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
Seperate(path);
|
|
}
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/创建鱼Prefab", true)]
|
|
private static bool MenuAssetsFishValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
return path.EndsWith(".fbx") || path.EndsWith(".FBX") || path.EndsWith(".prefab");
|
|
}
|
|
[MenuItem("Assets/FISH_Tools/创建鱼Prefab")]
|
|
static void MenuAssetsFish()
|
|
{
|
|
if (Selection.activeObject == null)
|
|
{
|
|
Debug.Log("Assets choose null");
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("Assets name = " + Selection.activeObject.name);
|
|
GameObject prefab = Selection.activeObject as GameObject;
|
|
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
string fileName = Path.GetFileNameWithoutExtension(path);
|
|
string directory = Path.GetDirectoryName(path);
|
|
string newPath = Path.Combine(directory, fileName);
|
|
AssetsFish(prefab, newPath);
|
|
}
|
|
}
|
|
static void AssetsFish(GameObject prefab, string srcPath)
|
|
{
|
|
string dstPath = GetRelativePath(assetDstFolderPath);
|
|
|
|
GameObject dstObj = new GameObject(prefab.name, typeof(Fish), typeof(BoxCollider));
|
|
|
|
GameObject srcObj = Instantiate(prefab, dstObj.transform, false);
|
|
srcObj.transform.localPosition = Vector3.zero;
|
|
srcObj.transform.localEulerAngles = Vector3.up * 180;
|
|
srcObj.transform.localScale = Vector3.one;
|
|
srcObj.name = prefab.name;
|
|
ConvertToPrefabInstanceSettings settings = new ConvertToPrefabInstanceSettings();
|
|
PrefabUtility.ConvertToPrefabInstance(srcObj, prefab, settings, InteractionMode.AutomatedAction);
|
|
Fish fish = dstObj.GetComponent<Fish>();
|
|
Renderer skinnedMeshRenderer = srcObj.GetComponentInChildren<Renderer>();
|
|
//Add Material
|
|
var fishMaterial = AssetDatabase.LoadAssetAtPath($"{fishMaterialFolderPath}/{prefab.name}.mat", typeof(Material)) as Material;
|
|
if (skinnedMeshRenderer != null && fishMaterial != null)
|
|
{
|
|
skinnedMeshRenderer.material = fishMaterial;
|
|
}
|
|
else if (skinnedMeshRenderer == null)
|
|
{
|
|
Debug.LogError($"{prefab.name} :没有 Renderer");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError($"{prefab.name} :没有名为 {prefab.name} 的 fishMaterial");
|
|
}
|
|
|
|
FindFishNode(fish, srcObj.transform);
|
|
fish.animator = srcObj.AddComponent<Animator>();
|
|
SetFishAni(fish, srcPath);
|
|
//dstObj下的layer都变成fish
|
|
SetLayerRecursively(dstObj, LayerMask.NameToLayer("fish"));
|
|
//设置脏数据
|
|
LogNullNode(srcObj.name, fish);
|
|
|
|
EditorUtility.SetDirty(dstObj);
|
|
PrefabUtility.SaveAsPrefabAsset(dstObj, dstPath + "/" + prefab.name + ".prefab");
|
|
Debug.Log($"创建{prefab.name}成功");
|
|
DestroyImmediate(dstObj);
|
|
}
|
|
static void SetFishAni(Fish fish, string srcPath)
|
|
{
|
|
//创建新的 Animator Override Controller并设置到fish.animator上
|
|
AnimatorOverrideController animatorOverrideController = new AnimatorOverrideController();
|
|
if (animatorController == null)
|
|
{
|
|
animatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(baseFishOverrideControllerPath + "fishGeneralAnimator.controller");
|
|
}
|
|
animatorOverrideController.runtimeAnimatorController = animatorController;
|
|
if (!string.IsNullOrEmpty(srcPath))
|
|
{
|
|
srcPath = srcPath.Replace(@"\", "/");
|
|
AnimationClip clip;
|
|
List<KeyValuePair<AnimationClip, AnimationClip>> overrides = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
|
animatorOverrideController.GetOverrides(overrides);
|
|
string clipName;
|
|
bool isHasClip = false;
|
|
bool isHasDash01 = false;
|
|
bool isHasShow01 = false;
|
|
foreach (var pair in overrides)
|
|
{
|
|
clipName = pair.Key.name;
|
|
string clipPath = $"{srcPath}@{clipName}.fbx";
|
|
clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(clipPath);
|
|
if (clip)
|
|
{
|
|
if (clipName.Equals("Dash01"))
|
|
{
|
|
isHasDash01 = true;
|
|
}
|
|
if (clipName.Equals("Show01"))
|
|
{
|
|
isHasShow01 = true;
|
|
}
|
|
isHasClip = true;
|
|
if (clipName.Equals("Idle01") || clipName.Equals("Swim01") || clipName.Equals("Show01"))
|
|
{
|
|
AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip);
|
|
clipSettings.loopTime = true;
|
|
AnimationUtility.SetAnimationClipSettings(clip, clipSettings);
|
|
//修改FBX的Animation的ModelImporter的循环属性
|
|
|
|
ModelImporter importer = AssetImporter.GetAtPath(clipPath) as ModelImporter;
|
|
ModelImporterClipAnimation modelImporterClipAnimation = importer.defaultClipAnimations[0];
|
|
modelImporterClipAnimation.loopTime = true;
|
|
importer.clipAnimations = new[] { modelImporterClipAnimation };
|
|
AssetDatabase.ImportAsset(clipPath);
|
|
}
|
|
animatorOverrideController[clipName] = clip;
|
|
}
|
|
}
|
|
if (!isHasClip)
|
|
{
|
|
return;
|
|
}
|
|
if (!isHasDash01)
|
|
{
|
|
animatorOverrideController["Dash01"] = animatorOverrideController["Swim01"];
|
|
}
|
|
if (!isHasShow01)
|
|
{
|
|
animatorOverrideController["Show01"] = animatorOverrideController["Swim01"];
|
|
}
|
|
//保存animatorOverrideController到指定文件夹
|
|
AssetDatabase.CreateAsset(animatorOverrideController, animatorOverrideControllerPath + fish.name + ".overrideController");
|
|
AssetDatabase.SaveAssets();
|
|
fish.animator.runtimeAnimatorController = animatorOverrideController;
|
|
}
|
|
}
|
|
static void FindFishNode(Fish fish, Transform root)
|
|
{
|
|
if (root.name.Equals("Mouth"))
|
|
{
|
|
fish.mouthPos = root;
|
|
}
|
|
else if (root.name.Equals("Head"))
|
|
{
|
|
fish.Head = root;
|
|
}
|
|
else if (root.name.Equals("Left_Eye"))
|
|
{
|
|
fish.LeftEye = root;
|
|
}
|
|
else if (root.name.Equals("Right_Eye"))
|
|
{
|
|
fish.RightEye = root;
|
|
}
|
|
else if (root.name.Equals("Fin"))
|
|
{
|
|
fish.Fin = root;
|
|
}
|
|
else if (root.name.Equals("Tail"))
|
|
{
|
|
fish.Tail = root;
|
|
}
|
|
else if (root.name.Equals("Neck"))
|
|
{
|
|
fish.Neck = root;
|
|
}
|
|
else if (root.name.Equals("Root"))
|
|
{
|
|
fish.Root = root;
|
|
}
|
|
|
|
foreach (Transform child in root)
|
|
{
|
|
FindFishNode(fish, child);
|
|
}
|
|
}
|
|
static void LogNullNode(string objName, Fish fish)
|
|
{
|
|
string nullNode = $"{objName}: 缺少";
|
|
bool isLog = false;
|
|
if (fish.mouthPos == null)
|
|
{
|
|
nullNode += "-|-Mouth";
|
|
isLog = true;
|
|
}
|
|
if (fish.Head == null)
|
|
{
|
|
nullNode += "-|-Head"; isLog = true;
|
|
}
|
|
if (fish.LeftEye == null)
|
|
{
|
|
nullNode += "-|-Left_Eye"; isLog = true;
|
|
}
|
|
if (fish.RightEye == null)
|
|
{
|
|
nullNode += "-|-Right_Eye"; isLog = true;
|
|
}
|
|
if (fish.Fin == null)
|
|
{
|
|
nullNode += "-|-Fin"; isLog = true;
|
|
}
|
|
if (fish.Tail == null)
|
|
{
|
|
nullNode += "-|-Tail"; isLog = true;
|
|
}
|
|
if (fish.Neck == null)
|
|
{
|
|
nullNode += "-|-Neck"; isLog = true;
|
|
}
|
|
if (isLog)
|
|
{
|
|
Debug.LogError(nullNode);
|
|
}
|
|
}
|
|
static void LogRendererLayer(GameObject obj)
|
|
{
|
|
Renderer skinnedMeshRenderer = obj.GetComponentInChildren<Renderer>();
|
|
if (skinnedMeshRenderer == null)
|
|
{
|
|
Debug.LogError($"{obj.name}: 缺少SkinnedMeshRenderer");
|
|
}
|
|
else
|
|
{
|
|
//skinnedMeshRenderer.renderingLayerMask 是包含 //fish = 1 << 0 //rod = 1 << 1 = 2
|
|
if ((skinnedMeshRenderer.renderingLayerMask & 1) == 0)
|
|
{
|
|
Debug.LogError($"{obj.name}: skinnedMeshRenderer.renderingLayerMask 不包含 fish");
|
|
}
|
|
if (skinnedMeshRenderer.gameObject.layer != LayerMask.NameToLayer("fish"))
|
|
{
|
|
Debug.LogError($"{obj.name}: skinnedMeshRenderer.Layer 不是 fish");
|
|
}
|
|
}
|
|
}
|
|
static void SetLayerRecursively(GameObject obj, int layer)
|
|
{
|
|
obj.layer = layer;
|
|
foreach (Transform child in obj.transform)
|
|
{
|
|
SetLayerRecursively(child.gameObject, layer);
|
|
}
|
|
}
|
|
|
|
|
|
[MenuItem("Assets/FISH_Tools/Fish_改名")]
|
|
static void GenerateFish()
|
|
{
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
string[] filePaths = Directory.GetFiles(path, "*.prefab", SearchOption.AllDirectories);
|
|
|
|
foreach (string filePath in filePaths)
|
|
{
|
|
string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath);
|
|
if (!fileName.StartsWith("Fish_"))
|
|
{
|
|
string[] nameParts = Regex.Split(fileName, @"\s+");
|
|
nameParts = nameParts.Where(part => !part.Equals("Variant")).ToArray();
|
|
nameParts = nameParts.Select(part => char.ToUpper(part[0]) + part.Substring(1)).ToArray();
|
|
string fishName = "Fish_" + string.Join("", nameParts);
|
|
// string newFilePath = Path.Combine(path, fishName + Path.GetExtension(filePath));
|
|
AssetDatabase.RenameAsset(filePath, fishName);
|
|
// AssetDatabase.ImportAsset(newFilePath);
|
|
Debug.Log(fishName);
|
|
}
|
|
}
|
|
}
|
|
|
|
[MenuItem("Assets/FISH_Tools/Fish_改名", true)]
|
|
static bool GenerateFishValidation()
|
|
{
|
|
//选中的是文件夹
|
|
return AssetDatabase.IsValidFolder(AssetDatabase.GetAssetPath(Selection.activeObject));
|
|
}
|
|
#endregion
|
|
|
|
#region 鱼杆相关工具
|
|
[MenuItem("Assets/Rod_Tools/遍历文件夹下的杆prefab查找动画")]
|
|
static void MenuAssetsFinRodAnimator()
|
|
{
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
var files = Directory.GetFiles(path, "*.prefab");
|
|
foreach (var file in files)
|
|
{
|
|
string srcPath = GetRelativePath(file);
|
|
GameObject prefab = AssetDatabase.LoadAssetAtPath(srcPath, typeof(GameObject)) as GameObject;
|
|
if (prefab == null)
|
|
continue;
|
|
string prefabName = prefab.name;
|
|
var animator = prefab.transform.Find(prefabName).GetComponent<Animator>();
|
|
List<KeyValuePair<AnimationClip, AnimationClip>> overrides = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
|
var animatorOverrideController = animator.runtimeAnimatorController as AnimatorOverrideController;
|
|
animatorOverrideController.GetOverrides(overrides);
|
|
string clipName;
|
|
AnimationClip clip;
|
|
foreach (var pair in overrides)
|
|
{
|
|
clipName = pair.Key.name;
|
|
string clipPath = $"Assets/AssetsPackage/art/fishingrod/rod/mesh/{prefabName}/{prefabName}@{clipName}.fbx";
|
|
ModelImporter modelImporter = AssetImporter.GetAtPath(clipPath) as ModelImporter;
|
|
if (modelImporter != null)
|
|
{
|
|
clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(clipPath);
|
|
if (clipName.Equals("Idle01")
|
|
|| clipName.Contains("Drawing")
|
|
|| clipName.Contains("Reeling")
|
|
|| clipName.Contains("Waiting01")
|
|
|| clipName.Contains("Waiting02")
|
|
|| clipName.Contains("MaxCombo01")
|
|
|| clipName.Contains("Show01")
|
|
&& !clipName.Equals("Drawing00"))
|
|
{
|
|
AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip);
|
|
clipSettings.loopTime = true;
|
|
AnimationUtility.SetAnimationClipSettings(clip, clipSettings);
|
|
//修改FBX的Animation的ModelImporter的循环属性
|
|
ModelImporterClipAnimation modelImporterClipAnimation = modelImporter.defaultClipAnimations[0];
|
|
modelImporterClipAnimation.loopTime = true;
|
|
modelImporter.clipAnimations = new[] { modelImporterClipAnimation };
|
|
AssetDatabase.ImportAsset(clipPath);
|
|
}
|
|
|
|
animatorOverrideController[clipName] = clip;
|
|
}
|
|
}
|
|
}
|
|
AssetDatabase.SaveAssets();
|
|
}
|
|
[MenuItem("Assets/Rod_Tools/遍历文件夹下的杆prefab查找动画", true)]
|
|
private static bool MenuAssetsFinRodAnimatorValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
return AssetDatabase.IsValidFolder(path);
|
|
}
|
|
[MenuItem("Assets/Rod_Tools/创建鱼竿Prefab")]
|
|
static void MenuAssetsRod()
|
|
{
|
|
if (Selection.activeObject == null)
|
|
{
|
|
Debug.Log("Assets choose null");
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("Assets name = " + Selection.activeObject.name);
|
|
GameObject prefab = Selection.activeObject as GameObject;
|
|
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
string fileName = Path.GetFileNameWithoutExtension(path);
|
|
string directory = Path.GetDirectoryName(path);
|
|
string newPath = Path.Combine(directory, fileName);
|
|
if (fileName.StartsWith("Rod_"))
|
|
{
|
|
AssetsRod(prefab, newPath);
|
|
}
|
|
|
|
}
|
|
}
|
|
[MenuItem("Assets/Rod_Tools/创建鱼竿Prefab", true)]
|
|
private static bool MenuAssetssRodValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
string fileName = Path.GetFileNameWithoutExtension(path);
|
|
return fileName.StartsWith("Rod_") && (path.EndsWith(".FBX") || path.EndsWith(".fbx") || path.EndsWith(".prefab"));
|
|
}
|
|
|
|
static void AssetsRod(GameObject prefab, string srcPath = "")
|
|
{
|
|
string dstPath = GetRelativePath(assetRodDstFolderPath);
|
|
GameObject dstObj = new GameObject(prefab.name, typeof(Rod), typeof(CCDIK));
|
|
GameObject srcObj = Instantiate(prefab, dstObj.transform, false);
|
|
ConvertToPrefabInstanceSettings settings = new ConvertToPrefabInstanceSettings();
|
|
PrefabUtility.ConvertToPrefabInstance(srcObj, prefab, settings, InteractionMode.AutomatedAction);
|
|
Rod rod = dstObj.GetComponent<Rod>();
|
|
rod.cCDIK = dstObj.GetComponent<CCDIK>();
|
|
rod.rod = srcObj;
|
|
rod.LineList = new List<Transform>();
|
|
FindRodNode(rod, srcObj.transform);
|
|
//rod.LineList.Reverse();
|
|
rod.LineList = rod.LineList.OrderByDescending(t => t.name).ToList();
|
|
|
|
//========================================Line===========================================//
|
|
var FishingLinePrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/AssetsPackage/Prefabs/Fishing/Component/FishingLine.prefab");
|
|
var fishingLine = Instantiate(FishingLinePrefab, dstObj.transform, false);
|
|
PrefabUtility.ConvertToPrefabInstance(fishingLine, FishingLinePrefab, settings, InteractionMode.AutomatedAction);
|
|
rod.fishingLineRenderer = fishingLine.GetComponent<LineRenderer>();
|
|
//========================================================================================//
|
|
|
|
SetRodAndReelMaterial(srcObj.transform);
|
|
|
|
var animator = srcObj.AddComponent<Animator>();
|
|
|
|
//创建新的 Animator Override Controller
|
|
if (animatorRodController == null)
|
|
{
|
|
animatorRodController = AssetDatabase.LoadAssetAtPath<AnimatorController>(baseRodOverrideControllerPath + "RodAnimatorController.controller");
|
|
}
|
|
AnimatorOverrideController animatorOverrideController = new AnimatorOverrideController();
|
|
animatorOverrideController.runtimeAnimatorController = animatorRodController;
|
|
if (!string.IsNullOrEmpty(srcPath))
|
|
{
|
|
string clipName;
|
|
srcPath = srcPath.Replace(@"\", "/");
|
|
AnimationClip clip;
|
|
List<KeyValuePair<AnimationClip, AnimationClip>> overrides = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
|
animatorOverrideController.GetOverrides(overrides);
|
|
foreach (var pair in overrides)
|
|
{
|
|
clipName = pair.Key.name;
|
|
string clipPath = $"{srcPath}@{clipName}.fbx";
|
|
ModelImporter modelImporter = AssetImporter.GetAtPath(clipPath) as ModelImporter;
|
|
if (modelImporter != null)
|
|
{
|
|
modelImporter.resampleCurves = false;
|
|
modelImporter.animationCompression = ModelImporterAnimationCompression.Optimal;
|
|
|
|
clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(clipPath);
|
|
|
|
if (clipName.Equals("Idle01")
|
|
|| clipName.Contains("Drawing")
|
|
|| clipName.Contains("Reeling")
|
|
|| clipName.Contains("Waiting01")
|
|
|| clipName.Contains("Waiting02")
|
|
|| clipName.Contains("MaxCombo01")
|
|
|| clipName.Contains("Show01")
|
|
&& !clipName.Equals("Drawing00"))
|
|
{
|
|
AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip);
|
|
clipSettings.loopTime = true;
|
|
AnimationUtility.SetAnimationClipSettings(clip, clipSettings);
|
|
//修改FBX的Animation的ModelImporter的循环属性
|
|
|
|
ModelImporter importer = AssetImporter.GetAtPath(clipPath) as ModelImporter;
|
|
ModelImporterClipAnimation modelImporterClipAnimation = importer.defaultClipAnimations[0];
|
|
modelImporterClipAnimation.loopTime = true;
|
|
importer.clipAnimations = new[] { modelImporterClipAnimation };
|
|
AssetDatabase.ImportAsset(clipPath);
|
|
}
|
|
|
|
animatorOverrideController[clipName] = clip;
|
|
}
|
|
}
|
|
}
|
|
//保存animatorOverrideController到指定文件夹
|
|
AssetDatabase.CreateAsset(animatorOverrideController, animatorRodControllerPath + prefab.name + ".overrideController");
|
|
animator.runtimeAnimatorController = animatorOverrideController;
|
|
AssetDatabase.SaveAssets();
|
|
|
|
//设置脏数据
|
|
EditorUtility.SetDirty(dstObj);
|
|
PrefabUtility.SaveAsPrefabAsset(dstObj, dstPath + "/" + prefab.name + ".prefab");
|
|
Debug.Log($"创建{prefab.name}成功");
|
|
DestroyImmediate(dstObj);
|
|
|
|
}
|
|
static void FindRodNode(Rod rod, Transform root)
|
|
{
|
|
if (root.name.Equals("Rod_Joint"))
|
|
{
|
|
rod.Rod_Joint = root;
|
|
}
|
|
else if (root.name.Equals("Bait"))
|
|
{
|
|
rod.Bait = root;
|
|
}
|
|
else if (root.name.Equals("TopLine"))
|
|
{
|
|
rod.TopLine = root; //TopLine;
|
|
}
|
|
else if (root.name.Equals("EndLine"))
|
|
{
|
|
rod.EndLine = root; //EndLine;
|
|
}
|
|
else if (Regex.IsMatch(root.name, @"^Line\d+$"))
|
|
{
|
|
rod.LineList.Add(root);
|
|
}
|
|
else if (root.name.Equals("LineHole"))
|
|
{
|
|
rod.LineHole = root;
|
|
}
|
|
else if (root.name.Equals("Bip001 L Hand"))
|
|
{
|
|
//========================================HandleLeft===========================================//
|
|
// var HandleLeft = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/ABPackage/pkgDownloads/Hand/HandleLeft.prefab");
|
|
// var handleLeft = Instantiate(HandleLeft, root.transform, false);
|
|
// ConvertToPrefabInstanceSettings settings = new ConvertToPrefabInstanceSettings();
|
|
// PrefabUtility.ConvertToPrefabInstance(handleLeft, HandleLeft, settings, InteractionMode.AutomatedAction);
|
|
rod.LeftHandTargets = root;
|
|
//========================================================================================//
|
|
}
|
|
else if (root.name.Equals("Bip001 R Hand"))
|
|
{
|
|
// //========================================HandleRight===========================================//
|
|
// var HandleLeft = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/ABPackage/pkgDownloads/Hand/HandleRight.prefab");
|
|
// var handleLeft = Instantiate(HandleLeft, root.transform, false);
|
|
// ConvertToPrefabInstanceSettings settings = new ConvertToPrefabInstanceSettings();
|
|
// PrefabUtility.ConvertToPrefabInstance(handleLeft, HandleLeft, settings, InteractionMode.AutomatedAction);
|
|
rod.RightHandTargets = root;
|
|
//========================================================================================//
|
|
}
|
|
else if (root.name.Equals("Bip001 Spine"))
|
|
{
|
|
rod.BodyTargets = root;
|
|
//========================================================================================//
|
|
}
|
|
foreach (Transform child in root)
|
|
{
|
|
FindRodNode(rod, child);
|
|
}
|
|
}
|
|
|
|
static Transform FindChildTransform(Transform root, string childName, bool isRoot)
|
|
{
|
|
if (root.name.Replace(" ", "").Equals(childName) && !isRoot)
|
|
{
|
|
return root;
|
|
}
|
|
|
|
for (int i = 0; i < root.childCount; i++)
|
|
{
|
|
var result = FindChildTransform(root.GetChild(i), childName, false);
|
|
if (result != null)
|
|
return result;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
static Transform FindChildTransformStartWithName(Transform root, string pattern, bool isRoot)
|
|
{
|
|
if (root.name.StartsWith(pattern) && !isRoot)
|
|
return root;
|
|
for (int i = 0; i < root.childCount; i++)
|
|
{
|
|
var result = FindChildTransformStartWithName(root.GetChild(i), pattern, false);
|
|
if (result != null)
|
|
return result;
|
|
}
|
|
return null;
|
|
}
|
|
static void SetRodAndReelMaterial(Transform root)
|
|
{
|
|
// 检查root是否为空
|
|
if (root == null)
|
|
{
|
|
Debug.LogError("SetRodAndReelMaterial: root parameter is null!");
|
|
return;
|
|
}
|
|
|
|
// 检查root名称格式是否正确
|
|
if (!root.name.Contains("_"))
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: root name '{root.name}' does not contain '_' character!");
|
|
return;
|
|
}
|
|
|
|
var name = root.name.Split('_')[1];
|
|
|
|
var rodName = $"Rod_{name}";
|
|
var reelName = $"Reel_{name}";
|
|
var reellineName = $"Reelline_{name}";
|
|
var fishingLineName = "Fishing_line";
|
|
|
|
var rawRod = FindChildTransform(root, rodName, true);
|
|
var rawReel = FindChildTransform(root, reelName, true);
|
|
var rawReelline = FindChildTransform(root, reellineName, true);
|
|
|
|
var rawLine = FindChildTransformStartWithName(root, fishingLineName, true);
|
|
|
|
// 分别检查每个节点是否找到,并单独报错
|
|
if (rawRod == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: Cannot find rod node '{rodName}' in root '{root.name}'");
|
|
}
|
|
if (rawReel == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: Cannot find reel node '{reelName}' in root '{root.name}'");
|
|
}
|
|
if (rawReelline == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: Cannot find reelline node '{reellineName}' in root '{root.name}'");
|
|
}
|
|
if (rawLine == null)
|
|
{
|
|
Debug.LogWarning($"SetRodAndReelMaterial: Cannot find fishing line node '{fishingLineName}' in root '{root.name}' (this is optional)");
|
|
}
|
|
|
|
// 如果关键节点缺失,直接返回
|
|
if (rawRod == null || rawReel == null || rawReelline == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: Critical nodes missing in root '{root.name}'. Please check the prefab structure.");
|
|
return;
|
|
}
|
|
|
|
var rodRender = rawRod.GetComponent<SkinnedMeshRenderer>();
|
|
var reelRender = rawReel.GetComponent<SkinnedMeshRenderer>();
|
|
var reellineRender = rawReelline.GetComponent<SkinnedMeshRenderer>();
|
|
|
|
// 检查Renderer组件
|
|
if (rodRender == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: SkinnedMeshRenderer component not found on rod node '{rodName}'");
|
|
return;
|
|
}
|
|
if (reelRender == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: SkinnedMeshRenderer component not found on reel node '{reelName}'");
|
|
return;
|
|
}
|
|
if (reellineRender == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: SkinnedMeshRenderer component not found on reelline node '{reellineName}'");
|
|
return;
|
|
}
|
|
|
|
//Add Material
|
|
var RodMaterial = AssetDatabase.LoadAssetAtPath($"{rodMaterialFolderPath}/{rodName}.mat", typeof(Material)) as Material;
|
|
var ReelMaterial = AssetDatabase.LoadAssetAtPath($"{reelMaterialFolderPath}/{reelName}.mat", typeof(Material)) as Material;
|
|
var ReellineMaterial = AssetDatabase.LoadAssetAtPath($"{reelMaterialFolderPath}/{reellineName}.mat", typeof(Material)) as Material;
|
|
|
|
// 检查材质是否加载成功
|
|
if (RodMaterial == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: Failed to load rod material from path '{rodMaterialFolderPath}/{rodName}.mat'");
|
|
}
|
|
if (ReelMaterial == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: Failed to load reel material from path '{reelMaterialFolderPath}/{reelName}.mat'");
|
|
}
|
|
if (ReellineMaterial == null)
|
|
{
|
|
Debug.LogError($"SetRodAndReelMaterial: Failed to load reelline material from path '{reelMaterialFolderPath}/{reellineName}.mat'");
|
|
}
|
|
|
|
Debug.Log($"SetRodAndReelMaterial: Loaded materials - Rod: {RodMaterial}, Reel: {ReelMaterial}, Reelline: {ReellineMaterial}");
|
|
|
|
// 应用材质
|
|
rodRender.material = RodMaterial;
|
|
reelRender.material = ReelMaterial;
|
|
reellineRender.material = ReellineMaterial;
|
|
|
|
//Change MeshRender
|
|
//layer
|
|
int layerIndex = LayerMask.NameToLayer("rod");
|
|
rodRender.renderingLayerMask = (uint)(1 << 1);
|
|
reelRender.renderingLayerMask = (uint)(1 << 1);
|
|
reellineRender.renderingLayerMask = (uint)(1 << 1);
|
|
|
|
if (rawLine != null)
|
|
{
|
|
var fishLineRender = rawLine.GetComponent<SkinnedMeshRenderer>();
|
|
if (fishLineRender != null)
|
|
{
|
|
fishLineRender.renderingLayerMask = (uint)(1 << 1);
|
|
fishLineRender.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
|
rawLine.gameObject.layer = layerIndex;
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"SetRodAndReelMaterial: SkinnedMeshRenderer component not found on fishing line node '{fishingLineName}'");
|
|
}
|
|
}
|
|
|
|
//Cast Shadows
|
|
rodRender.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
|
reelRender.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
|
reellineRender.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
|
|
|
//Change Layer
|
|
rawReel.gameObject.layer = layerIndex;
|
|
rawRod.gameObject.layer = layerIndex;
|
|
rawReelline.gameObject.layer = layerIndex;
|
|
|
|
Debug.Log($"SetRodAndReelMaterial: Successfully processed rod, reel, and reelline for '{root.name}'");
|
|
}
|
|
#endregion
|
|
|
|
|
|
#region Crossbow相关工具
|
|
[MenuItem("Assets/Crossbow_Tools/创建弩Prefab")]
|
|
private static void MenuAssetsCrossbow()
|
|
{
|
|
if (Selection.activeObject == null)
|
|
{
|
|
Debug.Log("Assets choose null");
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("Assets name = " + Selection.activeObject.name);
|
|
GameObject prefab = Selection.activeObject as GameObject;
|
|
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
string fileName = Path.GetFileNameWithoutExtension(path);
|
|
string directory = Path.GetDirectoryName(path);
|
|
string newPath = Path.Combine(directory, fileName);
|
|
if (fileName.Contains("prop_crossbow_"))
|
|
{
|
|
AssetsCrossbow(prefab, newPath);
|
|
}
|
|
|
|
}
|
|
}
|
|
[MenuItem("Assets/Crossbow_Tools/创建弩Prefab", true)]
|
|
private static bool MenuAssetsCrossbowValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
string fileName = Path.GetFileNameWithoutExtension(path);
|
|
return fileName.Contains("prop_crossbow_") && (path.EndsWith(".FBX") || path.EndsWith(".fbx"));
|
|
}
|
|
|
|
|
|
static void FindCrossbowNode(Crossbow crossbow, Transform root)
|
|
{
|
|
if (root.name.Equals("Root"))
|
|
{
|
|
crossbow.root = root.gameObject;
|
|
}
|
|
else if (root.name.Equals("crosshair_P"))
|
|
{
|
|
crossbow.crosshair_P = root;
|
|
}
|
|
else if (root.name.Equals("TopLine"))
|
|
{
|
|
crossbow.TopLine = root; //TopLine;
|
|
}
|
|
else if (root.name.Equals("EndLine"))
|
|
{
|
|
crossbow.EndLine = root; //EndLine;
|
|
}
|
|
else if (Regex.IsMatch(root.name, @"^Line\d+$"))
|
|
{
|
|
crossbow.LineList.Add(root);
|
|
}
|
|
else if (root.name.Equals("Bip001 L Hand"))
|
|
{
|
|
crossbow.LeftHandTargets = root;
|
|
}
|
|
else if (root.name.Equals("Bip001 R Hand"))
|
|
{
|
|
crossbow.RightHandTargets = root;
|
|
}
|
|
|
|
//LeftHandTargets
|
|
|
|
foreach (Transform child in root)
|
|
{
|
|
FindCrossbowNode(crossbow, child);
|
|
}
|
|
}
|
|
static void AssetsCrossbow(GameObject prefab, string srcPath = "")
|
|
{
|
|
string dstPath = GetRelativePath(crossbowPrefabPath);
|
|
GameObject dstObj = new GameObject(prefab.name, typeof(Crossbow));
|
|
GameObject srcObj = Instantiate(prefab, dstObj.transform, false);
|
|
ConvertToPrefabInstanceSettings settings = new ConvertToPrefabInstanceSettings();
|
|
PrefabUtility.ConvertToPrefabInstance(srcObj, prefab, settings, InteractionMode.AutomatedAction);
|
|
Crossbow crossbow = dstObj.GetComponent<Crossbow>();
|
|
crossbow.animator = srcObj.AddComponent<Animator>();
|
|
crossbow.LineList = new List<Transform>();
|
|
FindCrossbowNode(crossbow, srcObj.transform);
|
|
crossbow.LineList.Reverse();
|
|
|
|
|
|
//========================================Line===========================================//
|
|
var FishingLinePrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/AssetsPackage/Prefabs/Fishing/Component/FishingLine.prefab");
|
|
var fishingLine = Instantiate(FishingLinePrefab, dstObj.transform, false);
|
|
PrefabUtility.ConvertToPrefabInstance(fishingLine, FishingLinePrefab, settings, InteractionMode.AutomatedAction);
|
|
crossbow.fishingLineRenderer = fishingLine.GetComponent<LineRenderer>();
|
|
//========================================================================================//
|
|
|
|
//========================================C_Crosshair===========================================//
|
|
var C_CrosshairPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(crossbowPrefabPath + "C_Crosshair.prefab");
|
|
var crosshair = Instantiate(C_CrosshairPrefab, crossbow.crosshair_P, false);
|
|
PrefabUtility.ConvertToPrefabInstance(crosshair, C_CrosshairPrefab, settings, InteractionMode.AutomatedAction);
|
|
crossbow.icon_nml = crossbow.crosshair_P.Find("C_Crosshair/icon_nml").gameObject;
|
|
crossbow.icon_notarget = crossbow.crosshair_P.Find("C_Crosshair/icon_notarget").gameObject;
|
|
//========================================================================================//
|
|
|
|
|
|
//创建新的 Animator Override Controller
|
|
SetCrossbowAni(crossbow, srcPath);
|
|
//dstObj下的layer都变成rod
|
|
SetLayerRecursively(dstObj, LayerMask.NameToLayer("rod"));
|
|
//设置脏数据
|
|
EditorUtility.SetDirty(dstObj);
|
|
PrefabUtility.SaveAsPrefabAsset(dstObj, dstPath + "/" + prefab.name + ".prefab");
|
|
Debug.Log($"创建{prefab.name}成功");
|
|
DestroyImmediate(dstObj);
|
|
}
|
|
static void SetCrossbowAni(Crossbow crossbow, string srcPath)
|
|
{
|
|
//创建新的 Animator Override Controller并设置到fish.animator上
|
|
SetCrossbow(crossbow.animator, crossbow.name, srcPath, "CrossbowAnimatorController.controller");
|
|
}
|
|
|
|
[MenuItem("Assets/Crossbow_Tools/创建弩箭Prefab")]
|
|
private static void MenuAssetsCrossbowArrow()
|
|
{
|
|
if (Selection.activeObject == null)
|
|
{
|
|
Debug.Log("Assets choose null");
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("Assets name = " + Selection.activeObject.name);
|
|
GameObject prefab = Selection.activeObject as GameObject;
|
|
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
string fileName = Path.GetFileNameWithoutExtension(path);
|
|
string directory = Path.GetDirectoryName(path);
|
|
string newPath = Path.Combine(directory, fileName);
|
|
if (fileName.Contains("prop_crossbowarrow_"))
|
|
{
|
|
AssetsCrossbowArrow(prefab, newPath);
|
|
}
|
|
|
|
}
|
|
}
|
|
[MenuItem("Assets/Crossbow_Tools/创建弩箭Prefab", true)]
|
|
private static bool MenuAssetsCrossbowArrowValidation()
|
|
{
|
|
// 设置什么情况下消失/显现(the menu item will be disabled otherwise).
|
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|
string fileName = Path.GetFileNameWithoutExtension(path);
|
|
return fileName.Contains("prop_crossbowarrow_") && (path.EndsWith(".FBX") || path.EndsWith(".fbx"));
|
|
}
|
|
|
|
|
|
static void FindCrossbowArrowNode(CrossbowArrow crossbowArrow, Transform root)
|
|
{
|
|
if (root.name.Equals("TopLine"))
|
|
{
|
|
crossbowArrow.TopLine = root; //TopLine;
|
|
}
|
|
else if (root.name.Equals("EndLine"))
|
|
{
|
|
crossbowArrow.EndLine = root; //EndLine;
|
|
}
|
|
else if (Regex.IsMatch(root.name, @"^Line\d+$"))
|
|
{
|
|
crossbowArrow.LineList.Add(root);
|
|
}
|
|
foreach (Transform child in root)
|
|
{
|
|
FindCrossbowArrowNode(crossbowArrow, child);
|
|
}
|
|
}
|
|
static void AssetsCrossbowArrow(GameObject prefab, string srcPath = "")
|
|
{
|
|
string dstPath = GetRelativePath(crossbowPrefabPath);
|
|
GameObject dstObj = new GameObject(prefab.name, typeof(CrossbowArrow));
|
|
GameObject srcObj = Instantiate(prefab, dstObj.transform, false);
|
|
ConvertToPrefabInstanceSettings settings = new ConvertToPrefabInstanceSettings();
|
|
PrefabUtility.ConvertToPrefabInstance(srcObj, prefab, settings, InteractionMode.AutomatedAction);
|
|
CrossbowArrow crossbowArrow = dstObj.GetComponent<CrossbowArrow>();
|
|
crossbowArrow.animator = srcObj.AddComponent<Animator>();
|
|
crossbowArrow.crossbow = srcObj;
|
|
crossbowArrow.LineList = new List<Transform>();
|
|
FindCrossbowArrowNode(crossbowArrow, srcObj.transform);
|
|
crossbowArrow.LineList.Reverse();
|
|
|
|
//创建新的 Animator Override Controller
|
|
SetCrossbowArrowAni(crossbowArrow, srcPath);
|
|
//dstObj下的layer都变成rod
|
|
SetLayerRecursively(dstObj, LayerMask.NameToLayer("rod"));
|
|
//设置脏数据
|
|
EditorUtility.SetDirty(dstObj);
|
|
PrefabUtility.SaveAsPrefabAsset(dstObj, dstPath + "/" + prefab.name + ".prefab");
|
|
Debug.Log($"创建{prefab.name}成功");
|
|
DestroyImmediate(dstObj);
|
|
}
|
|
static void SetCrossbowArrowAni(CrossbowArrow crossbowArrow, string srcPath)
|
|
{
|
|
//创建新的 Animator Override Controller并设置到fish.animator上
|
|
SetCrossbow(crossbowArrow.animator, crossbowArrow.name, srcPath, "CrossbowArrowAnimatorController.controller");
|
|
}
|
|
static void SetCrossbow(Animator animator, string nameStr, string srcPath, string animatorController)
|
|
{
|
|
//创建新的 Animator Override Controller并设置到fish.animator上
|
|
AnimatorOverrideController animatorOverrideController = new AnimatorOverrideController();
|
|
if (animatorCrossbowController == null)
|
|
{
|
|
animatorCrossbowController = AssetDatabase.LoadAssetAtPath<AnimatorController>(baseCrossbowOverrideControllerPath + animatorController);
|
|
}
|
|
animatorOverrideController.runtimeAnimatorController = animatorCrossbowController;
|
|
if (!string.IsNullOrEmpty(srcPath))
|
|
{
|
|
srcPath = srcPath.Replace(@"\", "/");
|
|
AnimationClip clip;
|
|
List<KeyValuePair<AnimationClip, AnimationClip>> overrides = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
|
animatorOverrideController.GetOverrides(overrides);
|
|
string clipName;
|
|
bool isHasClip = false;
|
|
foreach (var pair in overrides)
|
|
{
|
|
clipName = pair.Key.name;
|
|
string clipPath = $"{srcPath}@{clipName}.fbx";
|
|
clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(clipPath);
|
|
if (clip)
|
|
{
|
|
isHasClip = true;
|
|
ModelImporter importer = AssetImporter.GetAtPath(clipPath) as ModelImporter;
|
|
importer.animationCompression = ModelImporterAnimationCompression.Optimal;
|
|
importer.resampleCurves = false;
|
|
if (clipName.Equals("Idle01"))
|
|
{
|
|
AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip);
|
|
clipSettings.loopTime = true;
|
|
AnimationUtility.SetAnimationClipSettings(clip, clipSettings);
|
|
//修改FBX的Animation的ModelImporter的循环属性
|
|
ModelImporterClipAnimation modelImporterClipAnimation = importer.defaultClipAnimations[0];
|
|
modelImporterClipAnimation.loopTime = true;
|
|
importer.clipAnimations = new[] { modelImporterClipAnimation };
|
|
}
|
|
AssetDatabase.ImportAsset(clipPath);
|
|
animatorOverrideController[clipName] = clip;
|
|
}
|
|
}
|
|
if (!isHasClip)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//保存animatorOverrideController到指定文件夹
|
|
AssetDatabase.CreateAsset(animatorOverrideController, animatorCrossbowControllerPath + nameStr + ".overrideController");
|
|
AssetDatabase.SaveAssets();
|
|
animator.runtimeAnimatorController = animatorOverrideController;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
} |