#if UNITY_EDITOR using System; using UnityEditor; using UnityEngine.Animations.Rigging; #endif using UnityEngine; using System.Linq; [AddComponentMenu("KFAttachments/RigAdaptors/Rig Converter")] public class RigConverter : MonoBehaviour { public Transform targetRoot; #if UNITY_EDITOR [ContextMenu("Convert Rig Constraints to Adaptors")] private void Convert() { foreach (var constraint in GetComponentsInChildren(true)) { if (constraint.component.TryGetComponent(out var role) && role.role == RigConverterRole.Role.Ignore) { continue; } var adaptorName = constraint.GetType().Name; if (role && role.role == RigConverterRole.Role.Reverse) { adaptorName += "Reverse"; } adaptorName += "Adaptor,KFCommonUtilityLib"; var adaptorType = Type.GetType(adaptorName); var adaptor = (RigAdaptorAbs)constraint.component.transform.AddMissingComponent(adaptorType); adaptor.ReadRigData(); adaptor.hideFlags = HideFlags.NotEditable; EditorUtility.SetDirty(adaptor); } Save(); } [ContextMenu("Read Adaptor Value to Constraints")] private void Read() { Rebind(); Save(); } [ContextMenu("Remove All Adaptors")] private void RemoveAll() { var constraints = GetComponentsInChildren(true); foreach (var constraint in constraints) { DestroyImmediate(constraint); } Save(); } [ContextMenu("Fix A22 Constraints")] private void Fix() { Rebind(); foreach (var constraint in GetComponentsInChildren()) { string name = constraint.component.transform.name; if (char.IsDigit(name[^1])) { if (name.Contains("ArmRollCorrections") && constraint.component is MultiRotationConstraint mrcArm) { int index = int.Parse(name.Substring(name.Length - 1, 1)); var source = mrcArm.data.sourceObjects; source.SetWeight(0, index * 0.25f); mrcArm.data.sourceObjects = source; mrcArm.data.constrainedXAxis = true; mrcArm.data.constrainedYAxis = false; mrcArm.data.constrainedZAxis = false; } else if (name.Contains("FingerTarget") && name.Length == 13 && constraint.component is TwoBoneIKConstraint tbc) { int index = int.Parse(name.Substring(name.Length - 1, 1)); string targetNameBase = tbc.data.root.transform.name[..^1]; tbc.data.root = targetRoot.FindInAllChildren($"{targetNameBase}1"); tbc.data.mid = targetRoot.FindInAllChildren($"{targetNameBase}{(index == 5 ? 3 : 2)}"); tbc.data.tip = targetRoot.FindInAllChildren($"{targetNameBase}4"); } else if (name.Contains("FingerTargetRollCorrection") && constraint.component is MultiRotationConstraint mrcFinger) { int index = int.Parse(name.Substring(name.Length - 1, 1)); mrcFinger.data.constrainedXAxis = true; mrcFinger.data.constrainedYAxis = false; mrcFinger.data.constrainedZAxis = index == 1; } } } Convert(); } [ContextMenu("Convert To New Rig Setup")] private void Renew() { Rebind(); string leftHandTransName = null, rightHandTransName = null; foreach (var tbik in GetComponentsInChildren()) { if(tbik.data.tip.name.Contains("hand", StringComparison.OrdinalIgnoreCase)) { Transform target = tbik.data.target; if(target.name.Contains("target", StringComparison.OrdinalIgnoreCase)) { target = target.parent; } if (tbik.data.tip.name.StartsWith("Left", StringComparison.OrdinalIgnoreCase)) { leftHandTransName = target.name; } else { rightHandTransName = target.name; } } } if(leftHandTransName == null || rightHandTransName == null) { Log.Error("Left/Right hand transform not found on weapon skeleton!"); return; } foreach (var constraint in GetComponentsInChildren()) { Transform trans = constraint.component.transform; string name = trans.name; if (char.IsDigit(name[^1]) && name.StartsWith("FingerTarget") && !trans.parent.name.StartsWith("FingerTarget") && constraint is TwoBoneIKConstraint tbik) { int index = int.Parse(name.Substring(name.Length - 1, 1)); if(index > 4) { continue; } GameObject newConstraint = new(name); newConstraint.transform.SetParent(trans, true); newConstraint.transform.SetAsFirstSibling(); newConstraint.transform.position = trans.position; EditorUtility.CopySerialized(tbik, newConstraint.AddComponent()); DestroyImmediate(tbik); if (trans.GetComponent() is TwoBoneIKConstraintAdaptor adaptor) { DestroyImmediate(adaptor); } string targetNameBase = tbik.data.root.transform.name[..^1]; bool isLeft = targetNameBase.StartsWith("Left"); GameObject metacarpal = new($"MetacarpalAiming{index}"); var aimConstraint = metacarpal.AddComponent(); aimConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{targetNameBase}0"); aimConstraint.data.aimAxis = isLeft ? MultiAimConstraintData.Axis.X_NEG : MultiAimConstraintData.Axis.X; aimConstraint.data.upAxis = isLeft ? MultiAimConstraintData.Axis.Y : MultiAimConstraintData.Axis.Y_NEG; aimConstraint.data.worldUpType = MultiAimConstraintData.WorldUpType.None; aimConstraint.data.constrainedXAxis = false; aimConstraint.data.constrainedYAxis = false; aimConstraint.data.constrainedZAxis = true; Transform curSource = tbik.data.target; while(((isLeft && curSource.parent.parent.name != leftHandTransName) || (!isLeft && curSource.parent.parent.name != rightHandTransName)) && !curSource.parent.name.Contains("1")) { curSource = curSource.parent; } var sourceArr = aimConstraint.data.sourceObjects; var source = new WeightedTransform(curSource.parent.name.Contains("1") ? curSource.parent : curSource, 1); sourceArr.Add(source); aimConstraint.data.sourceObjects = sourceArr; metacarpal.transform.SetParent(trans.transform); metacarpal.transform.SetAsFirstSibling(); } } Convert(); } public void CreateEmpty() { CreateEmptyForSide("Left"); CreateEmptyForSide("Right"); } private static string[] PhalangeBoneNames = new[] { "Thumb", "Index", "Middle", "Pinky", "Ring" }; private void CreateEmptyForSide(string side) { WeightedTransformArray sourceObjects = new(); Transform shoulderReposition = new GameObject($"{side}ShoulderReposition").transform; shoulderReposition.parent = transform; MultiPositionConstraint shoulderRepositionConstraint = shoulderReposition.gameObject.AddComponent(); shoulderRepositionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}Shoulder"); shoulderRepositionConstraint.data.constrainedXAxis = shoulderRepositionConstraint.data.constrainedYAxis = shoulderRepositionConstraint.data.constrainedZAxis = true; Transform armRollCorrection = new GameObject($"{side}ArmRollCorrections").transform; armRollCorrection.parent = transform; for (int i = 1; i <= 4; i++) { Transform child = new GameObject($"{armRollCorrection.name}{i}").transform; child.parent = armRollCorrection; MultiRotationConstraint armRollCorrectionConstraint = child.gameObject.AddComponent(); armRollCorrectionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}ForeArmRoll{i}"); armRollCorrectionConstraint.data.constrainedXAxis = true; armRollCorrectionConstraint.data.constrainedYAxis = false; armRollCorrectionConstraint.data.constrainedZAxis = false; sourceObjects.Add(new WeightedTransform(null, i * .25f)); armRollCorrectionConstraint.data.sourceObjects = sourceObjects; sourceObjects.Clear(); } Transform armTarget = new GameObject($"{side}ArmTarget").transform; armTarget.parent = transform; TwoBoneIKConstraint armTargetConstraint = armTarget.gameObject.AddComponent(); armTargetConstraint.data.root = targetRoot.FindInAllChildren($"{side}Arm"); armTargetConstraint.data.mid = targetRoot.FindInAllChildren($"{side}ForeArm"); armTargetConstraint.data.tip = targetRoot.FindInAllChildren($"{side}Hand"); bool isLeft = side == "Left"; Transform handTargets = new GameObject($"{side}HandTargets").transform; handTargets.parent = transform; for (int i = 1; i <= 4; i++) { string fingerTargetName = $"FingerTarget{i}"; Transform fingerTargetParent = new GameObject(fingerTargetName).transform; fingerTargetParent.parent = handTargets; Transform metacarpalAiming = new GameObject($"MetacarpalAiming{i}").transform; metacarpalAiming.parent = fingerTargetParent; MultiAimConstraint metacarpalAimingConstraint = metacarpalAiming.gameObject.AddComponent(); metacarpalAimingConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}Hand{PhalangeBoneNames[i]}0"); metacarpalAimingConstraint.data.aimAxis = isLeft ? MultiAimConstraintData.Axis.X_NEG : MultiAimConstraintData.Axis.X; metacarpalAimingConstraint.data.upAxis = isLeft ? MultiAimConstraintData.Axis.Y : MultiAimConstraintData.Axis.Y_NEG; metacarpalAimingConstraint.data.worldUpType = MultiAimConstraintData.WorldUpType.None; metacarpalAimingConstraint.data.constrainedXAxis = false; metacarpalAimingConstraint.data.constrainedYAxis = false; metacarpalAimingConstraint.data.constrainedZAxis = true; Transform fingerTarget = new GameObject(fingerTargetName).transform; fingerTarget.parent = fingerTargetParent; TwoBoneIKConstraint fingerTargetConstraint = fingerTarget.gameObject.AddComponent(); fingerTargetConstraint.data.root = targetRoot.FindInAllChildren($"{side}Hand{PhalangeBoneNames[i]}1"); fingerTargetConstraint.data.mid = targetRoot.FindInAllChildren($"{side}Hand{PhalangeBoneNames[i]}2"); fingerTargetConstraint.data.tip = targetRoot.FindInAllChildren($"{side}Hand{PhalangeBoneNames[i]}4"); } Transform thumbTargetParent = new GameObject("FingerTarget5").transform; thumbTargetParent.parent = handTargets; Transform thumbTargetRollCorrection1 = new GameObject("FingerTargetRollCorrection1").transform; thumbTargetRollCorrection1.parent = thumbTargetParent; MultiRotationConstraint thumbTargetRollCorrectionConstraint = thumbTargetRollCorrection1.gameObject.AddComponent(); thumbTargetRollCorrectionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}HandThumb1"); thumbTargetRollCorrectionConstraint.data.constrainedXAxis = thumbTargetRollCorrectionConstraint.data.constrainedYAxis = thumbTargetRollCorrectionConstraint.data.constrainedZAxis = true; sourceObjects.Add(new WeightedTransform(null, .5f)); thumbTargetRollCorrectionConstraint.data.sourceObjects = sourceObjects; sourceObjects.Clear(); Transform thumbTargetRollCorrection2 = new GameObject("FingerTargetRollCorrection2").transform; thumbTargetRollCorrection2.parent = thumbTargetParent; thumbTargetRollCorrectionConstraint = thumbTargetRollCorrection2.gameObject.AddComponent(); thumbTargetRollCorrectionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}HandThumb2"); thumbTargetRollCorrectionConstraint.data.constrainedXAxis = true; thumbTargetRollCorrectionConstraint.data.constrainedYAxis = false; thumbTargetRollCorrectionConstraint.data.constrainedZAxis = false; sourceObjects.Add(new WeightedTransform(null, .3f)); thumbTargetRollCorrectionConstraint.data.sourceObjects = sourceObjects; sourceObjects.Clear(); Transform thumbTargetRollCorrection3 = new GameObject("FingerTargetRollCorrection3").transform; thumbTargetRollCorrection3.parent = thumbTargetParent; thumbTargetRollCorrectionConstraint = thumbTargetRollCorrection3.gameObject.AddComponent(); thumbTargetRollCorrectionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}HandThumb3"); thumbTargetRollCorrectionConstraint.data.constrainedXAxis = true; thumbTargetRollCorrectionConstraint.data.constrainedYAxis = false; thumbTargetRollCorrectionConstraint.data.constrainedZAxis = false; sourceObjects.Add(new WeightedTransform(null, .2f)); thumbTargetRollCorrectionConstraint.data.sourceObjects = sourceObjects; sourceObjects.Clear(); Transform thumbTarget = new GameObject("FingerTarget5").transform; thumbTarget.parent = thumbTargetParent; TwoBoneIKConstraint thumbTargetConstraint = thumbTarget.gameObject.AddComponent(); thumbTargetConstraint.data.root = targetRoot.FindInAllChildren($"{side}HandThumb1"); thumbTargetConstraint.data.mid = targetRoot.FindInAllChildren($"{side}HandThumb3"); thumbTargetConstraint.data.tip = targetRoot.FindInAllChildren($"{side}HandThumb4"); thumbTargetConstraint.data.targetRotationWeight = 0; } private void Save() { var root = GetComponentInParent(true).gameObject; if(PrefabUtility.IsOutermostPrefabInstanceRoot(root)) PrefabUtility.ApplyPrefabInstance(root, InteractionMode.AutomatedAction); } #endif public void Rebind() { foreach (var adaptor in GetComponentsInChildren(true)) { adaptor.targetRoot = targetRoot; adaptor.FindRigTargets(); } } }