MiniGames/Assets/Editor/FixFbxClipNames.cs
2025-08-14 20:29:09 +05:00

148 lines
5.2 KiB
C#

#if UNITY_EDITOR
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
public static class FixFbxClipNames
{
// -------- Helpers --------
static string Sanitize(string s)
{
foreach (var c in Path.GetInvalidFileNameChars()) s = s.Replace(c, '_');
return s.Replace(' ', '_');
}
static string GetFBXName(string assetPath) =>
Path.GetFileNameWithoutExtension(assetPath);
static ModelImporterClipAnimation CloneClip(ModelImporterClipAnimation src)
{
return new ModelImporterClipAnimation
{
name = src.name,
firstFrame = src.firstFrame,
lastFrame = src.lastFrame,
loopTime = src.loopTime,
loopPose = src.loopPose,
lockRootRotation = src.lockRootRotation,
lockRootHeightY = src.lockRootHeightY,
lockRootPositionXZ = src.lockRootPositionXZ,
keepOriginalOrientation = src.keepOriginalOrientation,
keepOriginalPositionXZ = src.keepOriginalPositionXZ,
keepOriginalPositionY = src.keepOriginalPositionY,
heightFromFeet = src.heightFromFeet,
mirror = src.mirror,
additiveReferencePoseFrame = src.additiveReferencePoseFrame,
maskType = src.maskType,
hasAdditiveReferencePose = src.hasAdditiveReferencePose,
};
}
// -------- 1) Rename in importer --------
[MenuItem("Tools/Animations/Fix FBX Clip Names (Rename in Importer)")]
public static void FixInImporter()
{
var guids = Selection.assetGUIDs.Length > 0
? Selection.assetGUIDs
: AssetDatabase.FindAssets("t:Model");
int changedAssets = 0, changedClips = 0;
foreach (var guid in guids)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
if (!path.EndsWith(".fbx", System.StringComparison.OrdinalIgnoreCase)) continue;
var importer = AssetImporter.GetAtPath(path) as ModelImporter;
if (importer == null) continue;
var clips = importer.clipAnimations;
if (clips == null || clips.Length == 0)
clips = importer.defaultClipAnimations;
if (clips == null || clips.Length == 0) continue;
string fbxName = Sanitize(GetFBXName(path));
bool anyChange = false;
var newClips = clips.Select(c =>
{
var nc = CloneClip(c);
string old = string.IsNullOrEmpty(c.name) ? "Clip" : c.name;
string newName = (clips.Length == 1) ? fbxName : $"{fbxName}_{Sanitize(old)}";
if (nc.name != newName)
{
nc.name = newName;
anyChange = true;
changedClips++;
}
return nc;
}).ToArray();
if (anyChange)
{
importer.clipAnimations = newClips; // write custom list
try
{
importer.SaveAndReimport();
changedAssets++;
Debug.Log($"[FixFbxClipNames] Renamed clips in: {path}");
}
catch (System.Exception e)
{
Debug.LogError($"[FixFbxClipNames] Failed to reimport {path}: {e.Message}");
}
}
}
Debug.Log($"[FixFbxClipNames] Done. Assets changed: {changedAssets}, Clips renamed: {changedClips}");
}
// -------- 2) Extract .anim copies (optional) --------
[MenuItem("Tools/Animations/Extract .anim Copies With Clean Names")]
public static void ExtractAnimCopies()
{
var guids = Selection.assetGUIDs.Length > 0
? Selection.assetGUIDs
: AssetDatabase.FindAssets("t:Model");
int created = 0;
foreach (var guid in guids)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
if (!path.EndsWith(".fbx", System.StringComparison.OrdinalIgnoreCase)) continue;
string fbxName = Sanitize(GetFBXName(path));
string folder = Path.GetDirectoryName(path).Replace('\\', '/');
string outDir = folder + "/Animations_Extracted";
if (!AssetDatabase.IsValidFolder(outDir))
AssetDatabase.CreateFolder(folder, "Animations_Extracted");
var subAssets = AssetDatabase.LoadAllAssetsAtPath(path);
var clips = subAssets.OfType<AnimationClip>()
.Where(c => c != null && c.name != "__preview__")
.ToArray();
foreach (var clip in clips)
{
string baseName = (clips.Length == 1) ? fbxName : $"{fbxName}_{Sanitize(clip.name)}";
string outPath = $"{outDir}/{baseName}.anim";
if (File.Exists(outPath)) continue;
var dup = new AnimationClip();
EditorUtility.CopySerialized(clip, dup);
AssetDatabase.CreateAsset(dup, outPath);
created++;
Debug.Log($"[Extract] {outPath}");
}
}
AssetDatabase.SaveAssets();
Debug.Log($"[FixFbxClipNames] Extracted {created} .anim files.");
}
}
#endif