Files
MinFt/Client/Assets/Editor/CampTool/CampToolBobo.cs
Liubing\LB 3d8d4d18f3 first commit
先修复一下,错误的场景

删除不必要的钓场资产

修复into场景

update:更新meta文件,修复报错

update:修复资源

修复第一章节建造

修复建造第三章

update:删除多余内容

update:更新README.md

update:还原图标

update:更新README

update:更新配置
2026-04-28 02:17:22 +08:00

268 lines
9.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Serialization;
using UnityEditor.Timeline;
using UnityEngine.Playables;
using UnityEngine.Timeline;
public class CampToolBobo : EditorWindow
{
[MenuItem("Window/CampTool/Refactor Build Process")]
public static void RefactorBuildProcess()
{
var selectedObjects = Selection.objects;
if (selectedObjects.Length != 1)
Debug.LogError($"Expect only one target, got {selectedObjects.Length}");
var targetGo = selectedObjects[0] as GameObject;
if (targetGo is null)
{
Debug.LogError($"Target {selectedObjects[0].name} not a game object.");
return;
}
foreach (Transform child in targetGo.transform)
{
RefactorStep(child);
}
}
private static void RefactorStep(Transform step)
{
Debug.Log($"<color=white>咱瞅瞅步骤{step.name}有没有重复的...</color>");
bool hasRepeat = false;
foreach (Transform miniStep in step)
{
if (miniStep.childCount > 0)
continue;
var goAnimRoot = new GameObject
{
name = "AnimRoot",
transform =
{
parent = miniStep,
}
};
goAnimRoot.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
goAnimRoot.transform.localScale = Vector3.one;
var newMiniStep = Instantiate(miniStep.gameObject, goAnimRoot.transform);
newMiniStep.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
newMiniStep.transform.localScale = Vector3.one;
newMiniStep.name = "obj";
DestroyImmediate(miniStep.GetComponent<MeshFilter>());
DestroyImmediate(miniStep.GetComponent<MeshRenderer>());
DestroyImmediate(newMiniStep.transform.GetChild(0).gameObject);
}
var children = step.Cast<Transform>().ToList();
children.Sort((Transform t1, Transform t2) =>
{
var a = int.Parse(t1.name);
var b = int.Parse(t2.name);
if (a != b) return a.CompareTo(b);
Debug.Log($"<color=red> 旭哥我跟你讲啊,{a}有重复的啊!</color>");
hasRepeat = true;
return a.CompareTo(b);
});
for (int i = 0; i < step.childCount; i++)
{
Undo.SetTransformParent(children[i], children[i].parent, "SortChildren");
children[i].SetSiblingIndex(i);
}
if (!hasRepeat)
Debug.Log($"<color=white>哦,好像没有。</color>");
}
[MenuItem("Window/CampTool/Rename Child of AnimRoot")]
public static void RenameChildOfAnimRoot()
{
var selectedObjects = Selection.objects;
foreach (var selectedObject in selectedObjects)
{
var go = selectedObject as GameObject;
Assert.IsTrue(go);
foreach (var stepTransform in go.transform.Cast<Transform>())
{
foreach (var miniStep in stepTransform.Cast<Transform>())
{
var animRoot = miniStep.GetChild(0);
if (animRoot.name == "AnimRoot")
{
animRoot.GetChild(0).name = "obj";
}
}
}
}
}
[MenuItem("Window/CampTool/Scale Animation Clips")]
public static void OpenScaleAnimationClipsWindow()
{
GetWindow<CampToolBobo>("Rescale Animation Clips");
}
[SerializeField] private AnimationClip[] animationClips;
private float _targetLength = 5f;
private void OnGUI()
{
GUILayout.Label("Animation Clip Rescaler", EditorStyles.boldLabel);
// Field for selecting animation clips
var serializedObject = new SerializedObject(this);
var clipsProperty = serializedObject.FindProperty("animationClips");
if (clipsProperty != null)
EditorGUILayout.PropertyField(clipsProperty, true);
else
{
Debug.Log("Bad...");
}
serializedObject.ApplyModifiedProperties();
// Target duration field
_targetLength = EditorGUILayout.FloatField("Target Length (seconds):", _targetLength);
// Button to scale animation clips
if (GUILayout.Button("Scale Animation Clips"))
{
ScaleAnimationClips();
}
}
private void ScaleAnimationClips()
{
if (animationClips == null || animationClips.Length == 0)
{
Debug.LogWarning("No animation clips selected.");
return;
}
foreach (var clip in animationClips)
{
if (!clip) continue;
// Get the original length of the clip
float originalLength = clip.length;
if (originalLength <= 0)
{
Debug.LogWarning($"Clip '{clip.name}' has no length to scale.");
continue;
}
// Calculate the new speed to scale the animation
float scaleFactor = originalLength / _targetLength;
// Scale the animation clip speed by adjusting its frame rates
ScaleClip(clip, scaleFactor);
EditorUtility.SetDirty(clip); // Mark as modified
}
// AssetDatabase.SaveAssets(); // Save the modified asset
// AssetDatabase.Refresh();
Debug.Log("Animation clips scaled successfully.");
}
private void ScaleClip(AnimationClip clip, float scaleFactor)
{
// Debug.Log($"<color=red>{scaleFactor} for {clip}</color>");
// Scale all curves in the clip
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
{
var curve = AnimationUtility.GetEditorCurve(clip, binding);
var curveKeyFrames = curve.keys;
// Adjust keyframe times
for (int i = 0; i < curveKeyFrames.Length; i++)
{
// Debug.Log($" before: {curveKeyFrames[i].time}");
// var t = curveKeyFrames[i].time / scaleFactor;
// curve.keys[i].time = t;
curveKeyFrames[i].time /= scaleFactor;
// Debug.Log($" after: {curveKeyFrames[i].time}");
// Debug.Log($" after t: {t}");
}
curve.keys = curveKeyFrames;
AnimationUtility.SetEditorCurve(clip, binding, curve);
}
foreach (var binding in AnimationUtility.GetObjectReferenceCurveBindings(clip))
{
var curve = AnimationUtility.GetEditorCurve(clip, binding);
for (int i = 0; i < curve.keys.Length; i++)
{
curve.keys[i].time /= scaleFactor;
}
AnimationUtility.SetEditorCurve(clip, binding, curve);
}
// Scale events
foreach (var animEvent in AnimationUtility.GetAnimationEvents(clip))
{
animEvent.time /= scaleFactor;
}
// Apply changes back to the clip
AnimationUtility.SetAnimationEvents(clip, AnimationUtility.GetAnimationEvents(clip));
Debug.Log($"Scaled clip '{clip.name}' to {clip.length / scaleFactor} seconds.");
}
#region Duplicate Timeline
[MenuItem("Window/CampTool/CreateTimelineSteps")]
public static void ShowDuplicateTimelineWindow()
{
GetWindow<DuplicateTimeline>("复制Timeline轨道");
}
#endregion
}
public class DuplicateTimeline : EditorWindow
{
private PlayableDirector _playableDirector;
private Animator _animator;
private void OnGUI()
{
GUILayout.Label("复制Timeline轨道", EditorStyles.boldLabel);
_playableDirector = (PlayableDirector)EditorGUILayout.ObjectField("PlayableDirector",
_playableDirector, typeof(PlayableDirector), true);
_animator = (Animator)EditorGUILayout.ObjectField("Dynamic", _animator, typeof(Animator), true);
if (!GUILayout.Button("走你"))
return;
try
{
var asset = _playableDirector?.playableAsset as TimelineAsset;
DuplicateTracks(asset, _playableDirector, _animator);
}
catch (Exception e)
{
Debug.Log($"<color=red>{e.Message}</color>");
}
}
private static void DuplicateTracks(TimelineAsset timeline, PlayableDirector director, Animator animator)
{
Undo.RecordObject(timeline, "Duplicate Timeline Track");
var originTrack = timeline.GetOutputTracks().ToList()[0];
var clips = originTrack.GetClips().ToList();
foreach (var clip in clips)
{
var newTrack = timeline.CreateTrack(originTrack.GetType(), null,
originTrack.name + ": " + clip.displayName);
director.SetGenericBinding(newTrack, animator);
Debug.Log(clip.TryMoveToTrack(newTrack)
? $"{clip.displayName} 完成。"
: $"{clip.displayName} 失败。");
}
timeline.DeleteTrack(originTrack);
AssetDatabase.SaveAssets();
EditorUtility.SetDirty(timeline);
Debug.Log("处理完成!");
}
}