PATRICK MARTIN: Hi, everybody.
Firebase uses Task a lot, which I
know may be new to many Unity developers.
Let me show you some fun ways to work with them,
by asynchronously initializing Firebase, and signing
in a player anonymously.
[MUSIC PLAYING]
I have this really simple sample scene.
This Firebase logo starts invisible.
And when this Firebase init script fires, it animates in.
If I hit play now, nothing happens.
So let's initialize Firebase.
Most people will start by using continue with.
So let's start there.
First, I'll call a check and fix dependencies async,
and use continue with to execute logic when that's done.
I'll ignore error checking for now,
and just see if Firebase is available.
I'll have two branches in my logic based on whether or not
the user is logged in.
If they are, I just raise an initialized event.
And if they're not, I log in anonymously the same way,
then raise initialized.
This code looks correct.
But when I run the game, my logo still doesn't animate in.
What's happening?
Continue with fire is just fine, but in a background thread.
Because we're doing something with the Unity game engine
now by interacting with the animation graph,
I need to fire this off onto the main thread.
This is one of the easier threading related issues
to solve as well.
Basically, think of trying to keep the Zelda
timeline straight.
Yeah, it can't be that hard.
Now I'll tweak this to work on the main thread.
Firebase ships with an extension method for Tasks
called continue with on main thread.
Simply replace continue with with continue
with on main thread.
You're now thread safe.
A small note-- this is the only technique
that I'll talk about here that requires a Firebase SDK
feature to work.
Now that the action I provided to continue with
is executed on the same thread as the rest of my game,
my animation fires.
If you love technical minutiae, your code
will execute in the main update stage of Unity,
before coroutines and late update.
But code can become hard to read or edit
when it's all nested like this.
Just try matching up all those curly braces.
So the dotnet for runtime, the one
that's been Unity's default since 2018.3,
lets you use async await to clean this up a little bit.
Let's show you how that works.
I'll start with the same starting script,
but now mark void start as async.
Then I await the dependency status.
Since I'm a terrible person and not handling errors,
I'll just break out early if it fails.
I can chat for the current user and sign in anonymously
in one simple block.
And finally, I was single on initialize invocation rather
than two.
And by hitting Play, you can see that the Firebase logo appears.
This is much nicer to read, but I've given up
a little bit of control.
When you await something, you continue on the calling thread,
the main thread in this case.
But you may continue whenever in that main thread.
Usually this isn't an issue.
But if you've ever used late update,
this might make you nervous.
Also, all of the techniques I've talked about so far
have another subtle issue.
They don't take into account Unity's memory model.
The TLDR is that this code is a little like mailing
a letter to a friend.
It works fine, unless your friend has moved.
Then just some random person gets
to read your secret correspondence.
The Unity world, this might happen if you
change scenes or call destroy.
So if you don't like strangers reading your mail
or having this be known, you'll want to use coroutines.
So let's take a gander at what that code might
look like, by once again, going to my starter template.
First, I'll make start, start an initialization coroutine.
Then I'll start checking for my dependencies.
But this time, I'll save the task.
And I'll use the Unity class, wait until,
to suspend this coroutine until this task completes.
I'm going to early out of my coroutine
on failure, just like I did for async await.
If you've never tried to quit a coroutine early,
the correct way to do this is with yield break.
I'll do the same thing for off.
And finally, I'll raise the event.
And like that, I'm being both thread safe and memory safe
with my asynchronous logic.
But this also ties in super well with the rest
of Unity's infrastructure.
Do you want to wait until the end of the frame?
Or maybe wait until the next frame?
Hook into the physics update?
All of this is easier in coroutines.
But there is a downside, right?
In almost every project I've done this in,
I have at least once used the wrong task in my wait until.
I think I've always caught it, I hope.
And also, wait until checks every frame
to see if task is done.
This probably isn't noticeable.
It's never shown up in any of my profiling.
But continue with on main thread and async await
are much smarter with dispatching your logic.
But no matter how you handle Firebase's async calls,
I hope you have a better idea of why they exist and the pros
and cons of the different methods you
may have seen other programmers use to deal with them.
As always, let me know what you want
to hear me talk about next either in the comments below
or at [? Puckster ?] on the Twitter.
And definitely tell me about the cool Firebase games
you're making.
So long for now.
[MUSIC PLAYING]