I’m wondering if there is any way to verify all EventRefs in a pre-build script?
If you change the path of an event in FMOD studio and don’t update the references in editor these events obviously wont play so I’m hoping for a way to find all the EventRefs and check that they are valid before doing a build.
Unless there’s already a way to do this I’m guessing this would require reflection to find all strings that have the [EventRef] attribute but I’m not really sure how to use reflection to do this. Hooking into the prebuild script I’m good with.
There isn’t currently a feature for this built in to the integration, you would have to do it manually. The [EventRef] objects are created in memory and attached to the FMODStudioCache object in the integration.
I have created a task to look into this further and see if it is something we can add.
I managed to create a bit of a solution using reflection. It’s not able to check every possible reference but it should work for our needs.
Basically I created a editor menu option to get every monobehaviour in the scene and check if it has a field with the [EventRef] attribute using reflection. Currently it only will find string or any IEnumerable of string (i.e. string[] or List<string>) with the attribute. Custom classes that have an [EventRef] attribute field wont be found. This could be done recursively but I didn’t want to deal with checking for cycles in the recursion and it wasn’t needed for our project currently. Once all the field with that attribute are found I use EventManager.EventFromPath(ref) to verify if it’s a valid reference.
Here’s a rough copy of the code:
foreach (GameObject gameObject in rootObjects)
{
MonoBehaviour[] allBehvaiours = gameObject.GetComponentsInChildren<MonoBehaviour>();
for (int i = 0; i < allBehvaiours.Length; i++)
{
Type componentType = allBehvaiours[i].GetType();
FieldInfo[] fields = componentType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo item in fields)
{
if (HasAttribute(item, typeof(EventRefAttribute)))
{
if (item.FieldType == typeof(string))
{
string output = item.GetValue(allBehvaiours[i]) as string;
if (!IsValidEventRef(output))
{
Debug.LogError($"Unable to find FMOD Event {output} on object of type {componentType.ToString()} from gameobject {allBehvaiours[i].gameObject.name}");
allValid = false;
}
}
else if (typeof(IEnumerable).IsAssignableFrom(item.FieldType))
{
foreach (var listItem in (IEnumerable)item.GetValue(allBehvaiours[i]))
{
if (listItem.GetType() == typeof(string))
{
string listOutput = listItem as string;
if (!IsValidEventRef(listOutput))
{
Debug.LogError($"Unable to find FMOD Event {listOutput} on object
{valueObject.ToString()}");
}
}
}
}
}
}
}
}
}
I hope that makes sense, it’s a lot of code to paste into this form. Not sure if it’s the best way but seems to work for finding event references that are not valid. (In the code I ignore empty event reference strings but that can be changed easily). I also have a method that takes a list of scriptable objects and does a similar check. The code is basically the same.
Let me know if you can think of an better way but maybe this will help anyone else looking for a similar solution.