Exception Handling

In this article I'd like to tell you something about exception handling and a way how you can solve the problem of a missing global exception handler. But let me first give you an introduction.

What is an Exception?

An exception shoudl be thrown in case when your code runs into a problem and can not handle it by itself. As an example think of a method which is parsing a json-file and returns it as an object. Your workflow looks like that:


1. Find the file

2. Read the content of the file

3. Parse the file

4. Create the new object

5. Write the data to the newly created object

6. Return the object


But now something is wrong with the file. Let's say: it isn't there. So your workflow is broken and the parser isn't able to handle it on its own. That means that the parser should throw an exception and somewhere up in your hierachy one should catch it. But only in case when you really can handle the exception there.


How to NOT handle an Exception?

I often saw it that devs are using exception as a part of their workflow (so like you would use an if, switch, whatever...). If everything is fine go this way if an exception is thrown go that way. HELL NO! Don't do this! When an exception occurs that means: Your workflow ends HERE!


Also don't just catch any exception. Only catch the exceptions you want/can handle. You prefer that your game crashes instead of having an unexpected internal state which can completly mess up everything.

How to handle an Exception

The important thing is that you only catch an exception in case when you are able to handle it. Handling does not always mean something complex. In some cases it is only about logging. Sometimes handling means to start a new workflow. Think of the following scenario:


Workflow A

1. You want to send a request to a server.

2. You get a ServerConnectionException.

3.1 Log the Exception

3.2 Start Workflow B.

(Without the exception this workflow would have send the request and would do something with the respond of the server)


Workflow B

1. You try to do a reconnect to the server.

2. Reconnection was successfull.


This would be a self healing system. After Workflow B has finished the app could retry Workflow A again.


Global Exception Handler

I actually was looking for something like that. A global exception handler should be the latest place where I'd be able to catch exceptions and react on them before they make my game crash. In my case I wanted my GameManager to register to it. So that it can watch out for a given Exception which is only thrown during loading in case when one of the data-files where messed up or missing. If an exception is thrown I want to force a recreation of all those files.


To keep a long story short: There is none or I wasn't able to find it.


How I handled it

Actually it wasn't that complicated to get it working also without a global exception handler. The first thing I'd to archieve that I've a centralized place from which I trigger the loading of the game (which is my GameManager). Because I try to avoid hardcoded stuff I was using UnityEvents to keep things flexible. Let me show you with a code example.


Creating my own base exception

I like to have one base exception from which every of my other exceptions are inheriting from. That would look like that:


And next I want to have my specific exception which is thrown in case when there went something wrong during the loading:


Code
  1. public class LoadException : MyGameException {
  2. }

For this article it is enought to only have an own exception. Of course you could provide more constructors or information to the given exception if you want. But for now we will stay with the implicit default constructor.


Preparing our GameManager

I've created a new one for that article and here it is:


Very simple as you can see. We just provide two events: One for loading and one for installing our files. The inspector will look like this:




That's all for our gameManager. For those who haven't used UnityEvents: they are really awesome! And I will now show you why :-).


Creating a class which is loading / installing files

I will call this "CityManager". In my game the CityManager is taking care about the map and also about loading/creating it. Here is someting "similar" :-P:


So here is some small code snippet which is runnable and probabbly will always fail (which is totally fine for that article). The only thing which is now left to do is to register those methods to our events. Because we are using UnityEvents we're able to do this without writing any single line of code :-).


Register our Events

My current scene looks like this:



And as you can see: there are my two gameobjects and both have their manager-components attached to them. Let's select the GameManager and click on the (+) of both events. It now should look like this:




Now drag and drop the CityManager to slot on the bottom left. Do this for both events. If you've done it right your it now should be the same like this:



On the bottom left you now can see the CityManager-GameObject and on the top right the dropdown says that now function has been selected. We will change this now. Click on the dropdown and select CityManager -> LoadMap for the first one and CityManager-> CreateNewMap for the second one:



When I now run the whole thing the console has the following output:




In my opinion this is a really nice way of solving that problem. We load the game and in case of an exception (file not there, file corrupted, ...) we are able to react on it. Also we're highly flexible because the loading code is not hardcoded within the GameManager - but is triggered by it.


Also we've a proper ExceptionHandling. As soon as one component is running into trouble by loading the game the whole workflow will become interrupted and we start the "selfhealing".


Last words: For those of you who are new to UnityEvents: I really can recommend you to use them. They give you all the benefits of the C#-event-system + the ability to use the inspector.