Mike H
Mike H

Reputation: 407

Unity Editor detect when build fails

I'm trying to use IPreProcessBuildWithReport and IPostProcessBuildWithReport to add a game object to the scene right before build, and promptly delete it from the scene when the build finishes. The goal is to reduce all that I can from the hierarchy during the development but include these objects during the build.

My issue occurs when the build fails (due to some error), it adds the game object before the build started but never reached the code to delete the game object when it fails.

Is there a similar method to detect when the build fails without building my own build player pipeline? I really don't want to stray away from unity's default build pipeline if I don't need to.

If there was no easy way, I was trying to think if maybe there was a way to track the buildfailed exception or error and run a method if it occurs.

Thanks, let me know what you guys think.

EDIT: As requested, here is an example:

    class CustomBuildPipeline : MonoBehaviour, IPreprocessBuildWithReport, IPostprocessBuildWithReport
    {

        public int callbackOrder => 0;

        // CALLED BEFORE THE BUILD
        public void OnPreprocessBuild(BuildReport report)
        {
            // Create and add gameobjects to scene
        }


        // CALLED AFTER THE BUILD
        public void OnPostprocessBuild(BuildReport report)
        {
             // Remove gameobjects from scene once built
        }
    }
}

PreProcess Interface PostProcess Interface

I was wondering if there was a possible solution by somehow detecting when this buildexception was thrown and running code following.

EDIT 2: I found this post that has possible solutions, however, it may not be as elegant as I'd prefer. I'll try some things out and report back.

Upvotes: 3

Views: 1922

Answers (2)

v01pe
v01pe

Reputation: 1136

This approach is using a custom build handler, but still uses the default build pipeline.

Use BuildHandler.OnBuildStarted instead of (or in addition to) IPreprocessBuildWithReport for pre-processing. For post-processing use BuildHandler.OnBuildCleanup, which is called when a build completes or fails. Can also be used in conjunction with IPostprocessBuildWithReport.

[InitializeOnLoad]
public class BuildHandler : MonoBehaviour
{
    public static event Action OnBuildStarted;
    public static event Action OnBuildCleanup;

    static BuildHandler()
    {
        BuildPlayerWindow.RegisterBuildPlayerHandler(Build);
    }

    private static void Build(BuildPlayerOptions buildOptions)
    {
        try
        {
            BuildStarted();

            //now start Unity's default building procedure
            BuildPlayerWindow.DefaultBuildMethods.BuildPlayer(buildOptions);
        }
        catch (BuildPlayerWindow.BuildMethodException) { } //logged internally
        catch (Exception ex)
        {
            Exception log = ex.InnerException == null ? ex : ex.InnerException;
            Debug.LogException(log);
            Debug.LogErrorFormat("{0} in BuildHandler: '{1}'", log.GetType().Name, ex.Message);
        }
        finally
        {
            BuildCleanup();
        }
    }

    private static void BuildStarted()
    {
        try
        {
            if (OnBuildStarted != null)
                OnBuildStarted.Invoke();
        }
        catch (Exception ex)
        {
            throw new Exception("OnBuildStarted failed", ex);
        }
    }

    private static void BuildCleanup()
    {
        if (OnBuildCleanup != null)
        {
            foreach (Action cleanupBuild in OnBuildCleanup.GetInvocationList())
            {
                try
                {
                    cleanupBuild.Invoke();
                }
                catch (Exception ex)
                {
                    Object context = cleanupBuild.Target as Object;
                    Debug.LogException(ex, context);
                    Debug.LogWarning("Caught exception while BuildHandler.OnBuildCleanup... Continuing");
                }
            }
        }
    }
}

Upvotes: 0

Mike H
Mike H

Reputation: 407

I used the post in the 'EDIT 2' to come up with a decent solution. I don't know if it will work 100% of the time and I would love for someone to correct me if I have chosen a poor solution. This should allow me to run code before the build starts, and if the build fails or succeeds without changing the unity build pipeline.

    class CustomBuildPipeline : MonoBehaviour, IPreprocessBuildWithReport, IPostprocessBuildWithReport
    {

        public int callbackOrder => 0;

        // CALLED BEFORE THE BUILD
        public void OnPreprocessBuild(BuildReport report)
        {
            // Start listening for errors when build starts
            Application.logMessageReceived += OnBuildError;
        }

        // CALLED DURING BUILD TO CHECK FOR ERRORS
        private void OnBuildError(string condition, string stacktrace, LogType type)
        {
            if (type == LogType.Error)
            {
                // FAILED TO BUILD, STOP LISTENING FOR ERRORS
                Application.logMessageReceived -= OnBuildError;
            }
        }

        // CALLED AFTER THE BUILD
        public void OnPostprocessBuild(BuildReport report)
        {
            // IF BUILD FINISHED AND SUCCEEDED, STOP LOOKING FOR ERRORS
            Application.logMessageReceived -= OnBuildError;
        }
    }
}

Upvotes: 1

Related Questions