private bool HasAudioSource(AnimatorTriggeredSpecialFX fx) { if (fx.m_AudioSources == null) { return(false); } foreach (var audioSource in fx.m_AudioSources) { if (audioSource != null) { return(true); } } return(false); }
private void ValidateNodeNames(AnimatorTriggeredSpecialFX fx) { Animator animator = fx.GetComponent <Animator>(); if (!animator) { // should be impossible because we explicitly RequireComponent the Animator EditorUtility.DisplayDialog("Error", "No Animator found on this GameObject!?", "OK"); return; } if (animator.runtimeAnimatorController == null) { // perfectly normal user error: they haven't plugged a controller into the Animator EditorUtility.DisplayDialog("Error", "The Animator does not have an AnimatorController in it!", "OK"); return; } // make sure there aren't any duplicated event entries! int totalErrors = 0; for (int i = 0; i < fx.m_EventsOnNodeEntry.Length; ++i) { for (int j = i + 1; j < fx.m_EventsOnNodeEntry.Length; ++j) { if (fx.m_EventsOnNodeEntry[i].m_AnimatorNodeNameHash == fx.m_EventsOnNodeEntry[j].m_AnimatorNodeNameHash && fx.m_EventsOnNodeEntry[i].m_AnimatorNodeNameHash != 0) { ++totalErrors; Debug.LogError($"Entries {i} and {j} in EventsOnNodeEntry refer to the same node name ({fx.m_EventsOnNodeEntry[i].m_AnimatorNodeName})! This is probably a copy-paste error. (But if it isn't and you intend to play two effects, remove this error-check!)"); } } } for (int i = 0; i < fx.m_EventsOnNodeExit.Length; ++i) { for (int j = i + 1; j < fx.m_EventsOnNodeExit.Length; ++j) { if (fx.m_EventsOnNodeExit[i].m_AnimatorNodeNameHash == fx.m_EventsOnNodeExit[j].m_AnimatorNodeNameHash && fx.m_EventsOnNodeExit[i].m_AnimatorNodeNameHash != 0) { ++totalErrors; Debug.LogError($"Entries {i} and {j} in EventsOnNodeExit refer to the same node name ({fx.m_EventsOnNodeExit[i].m_AnimatorNodeName})! This is probably a copy-paste error. (But if it isn't and you intend to play two effects, remove this error-check!)"); } } } // create a map of nameHash -> useful debugging information (which we display in the log if there's a problem) Dictionary <int, string> usedNames = new Dictionary <int, string>(); for (int i = 0; i < fx.m_EventsOnNodeEntry.Length; ++i) { usedNames[fx.m_EventsOnNodeEntry[i].m_AnimatorNodeNameHash] = $"{fx.m_EventsOnNodeEntry[i].m_AnimatorNodeName} (EventsOnNodeEntry index {i})"; } for (int i = 0; i < fx.m_EventsOnNodeExit.Length; ++i) { usedNames[fx.m_EventsOnNodeExit[i].m_AnimatorNodeNameHash] = $"{fx.m_EventsOnNodeExit[i].m_AnimatorNodeName} (EventsOnNodeExit index {i})"; } int totalUsedNames = usedNames.Count; // now remove all the hashes that are actually used by the controller AnimatorController controller = GetAnimatorController(animator); foreach (var layer in controller.layers) { foreach (var state in layer.stateMachine.states) { usedNames.Remove(state.state.nameHash); } } // anything that hasn't gotten removed from usedNames isn't actually valid! foreach (var hash in usedNames.Keys) { Debug.LogError("Could not find Animation node named " + usedNames[hash]); } totalErrors += usedNames.Keys.Count; if (totalErrors == 0) { EditorUtility.DisplayDialog("Success", $"All {totalUsedNames} referenced node names were found in the Animator. No errors found!", "OK!"); } else { EditorUtility.DisplayDialog("Errors", $"Found {totalErrors} errors. See the log in the Console tab for more information.", "OK"); } }