>>Amanda: Hello everyone! If you haven’t yet, take your
first look at Unreal Engine 5! In the new demo, see two new core
technologies: Lumen, a fully dynamic global illumination
solution that immediately reacts to scene
and light changes, and Nanite virtualized micropolygon
geometry, which empowers you to directly import film-quality
source art comprising hundreds of millions or billions of polygons
into Unreal Engine—and it just works. Unreal Engine 5 will be available for
preview in early 2021—watch the full demo with commentary from Epic’s
Technical Director of Graphics, Brian Karis, and Special Projects
Art Director, Jerome Platteaux. And we hope you’re ready for more big
news—starting today you can download and use Unreal Engine to build
games for free as you always have, except now royalties
are waived on your first $1 million in gross revenue,
retroactive to January 1. Head over to the unrealengine.com
blog for all the details! We are also thrilled to announce
that Epic Online Services are now available to all developers across
PlayStation, Xbox, Nintendo Switch, PC, and Mac, with support
coming soon to iOS and Android. From player identity and friends,
cross-play, and achievements, these services empower you to create
the best experiences for players with complete freedom of engine, store,
and platform integration choice. Want to see what Epic Online
Services can do for your game? Head over to the Developer
Portal to download the SDK and get started today. With a near five-star user rating, Lies Beneath is one of the
most highly-rated VR games designed for the Oculus Quest. The title exemplifies how
a AAA quality experience can be tailor-made for
Oculus’ mobile VR headset. The game was developed by
VR veteran studio Drifter, the studio behind Gunheart and Robo
Recall: Unplugged for the Oculus Quest. Read our interview
with Drifter’s team to discover their inspirations
and how they executed on the game’s stylized
comic-book aesthetic. In a new hands-on presentation,
Epic's Sjoerd De Jong breaks down how to render a beautiful and fully
dynamic sky utilizing the robust Sky Atmosphere system that’s now
available in Unreal Engine 4.25, with the added help of
Quixel Megascans. Check out his full presentation
on our blog, then learn more about Quixel’s mission and the future of
the Sky Atmosphere system in a short video from Quixel
Director, Teddy Bergsman, and Epic Games' Senior Rendering
Programmer, Sebastien Hillaire. Thanks to this week’s top karma
earners, doing a lovely job helping others on AnswerHub: ClockworkOcean, Everynone,
Xyah_, Detach789, T_Sumisaki, BamaGame, QUANDINI, EvilCleric,
mrteuy, and GoldenYoann3D, Heading over to our community spotlights,
here you see THE INVITATION, a PvX MMO shooter about the joy of
adventure, tough decision making, and harsh consequences. In the Invitation,
the players and the environment dynamically create quests. Find out more about The
Invitation on their website. Storyteller, VFX artist, and animator
Samuel Walsh began learning Unreal Engine to explore new
ways of telling stories. Dogfight was designed to tell a story
in the most filmic way possible, not focusing on realistic
movement, but on composition. Go behind the scenes of Dogfight
and learn more about the project on Walsh’s website. After four years of development,
Nifty Llama Games revealed "Ruth's Journey," a preview of their upcoming interactive
story game, The Long Way Home. Set in the same universe,
Ruth’s Journey follows Ruth as she sets out to photograph
the rare Golden Finch. Watch the full trailer
at niftyllamagames.com. Thanks for watching our News
and Community Spotlight! >>Victor: Hi, everyone, and
welcome to Inside Unreal, a weekly show where we
learn, explore, and celebrate everything Unreal. I'm your host, Victor Brodin and my guest today is our
Evangelist, Christian Allen. >>Christian: Hello, hello! >>Victor: Thanks for
coming on the show. We are going to
cover, or demystify, soft object references today. But I did want it to
take just a little moment to talk about the announce
of Unreal Engine 5. Difficult not to be
excited and to mention it. As you saw as part
of the news, there is plenty of information
available online. If you have not yet checked out
the Lumen in the Land of Nanite tech demo that's running
on a Playstation 5, you definitely should
go and do that. But for Indies, I think one
of the bigger announcements that we made is that we
are now waiving the royalty fee for the first million
dollars that your game makes. How do you think this
is going to change how indies approach the
use of the Engine, as well as shipping their games? >>Christian: Well, I hope it's
going to be a game changer. My focus at Epic is on
Indies in North America. And so, I interact
with them a lot. And previously, we've waived
the first $12,000 a year before we started
calculating royalties. And now with this move
from that $12,000 a year to a million dollars
for the entire lifecycle of the product, ideally
what it's going to do is just allow Indies to
do what we want them to do is really focus on the game. So they're not worried about
royalties and calculating that in the first few
months as projects come out. They can just really
focus on their product, and their customers,
and the quality level. And then once they start
generating significant revenue for themselves, then we can
talk about collecting royalties. So I think it really just
reinforces our company wide goals across Epic,
both for Unreal Engine and our other
services, to try to get this content and these
tools distributed as broadly as possible and
try to lower as many barriers as we can to allow new content. And that content
is king, so that's what we want to focus on. >>Victor: Yeah. Empower everyone to be able
to be as creative as possible and then worry about the
financial details later. >>Christian: Yeah, exactly. >>Victor: If you get there. >>Christian: Yeah, exactly. And again, just taking that
off the table with developers, we started-- we've gone through a lot of
permutations of royalties. We had fee structures
over the years and we've just found that
just allowing developers to focus on
development first, not worry about having different
tiers of subscriptions and things like that when
it comes to the technology. If your game is hugely
successful, then awesome. That's where we want you to be
because we are royalty-based. That allows us to
share in the success. And really, the
thing I like about it as Evangelist is it really
helps to align our goals. While I'm helping a
developer, I don't have to worry about well
let me check and see if there are a silver
member or a gold member. Let me-- oh, you just launched
your game a month ago. Let me make sure and check
it that you've paid royalties until I can help you. It just aligns
everybody together. So, again, focusing on high
quality content, good content and gameplay for the
consumer because that's what's going to help make
the product successful. And so, it aligns
our business goals with all our other goals, too. >>Victor: I also want to make
sure if you haven't noticed that or in case you just joined
and you missed the intro, we just did a huge
public release of Epic Online Services,
which will allow you to-- and it's just to mention
that it is completely free, which is just huge. It's like a whole back
end of online services that you're now able
to use for your game. And that's going to empower
a lot more developers to implement what
previously could have been a rather expensive
or a rather difficult thing. Any comments on EOS? >>Christian: Yeah. I mean, the big thing about
EOS, Epic Online Services, is that one, it is free which
is kind of a running theme. But the big thing about it
is it's engine agnostic. So obviously, we want
Unreal Engine developers to check it out. But regardless what kind of
core technology you're using, you should look into it. I mean, one of the
big focuses on it is to break down the
walls in the garden, to open it up to
things like cross-play. Obviously, cross-play we feel
is hugely important as you've seen with the
development of Fortnite, to allow developers to have
that access to online services that aren't specific
to the platform that they're launching
on and aren't specific to a certain
storefront, whether it be Epic Game Store
or other stores. Again, give that power
to the developers. So it is a standalone SDK
compatible with major engines. So regardless of
whether using Unreal, I encourage you to
go check it out. And we're going to be
continuing to launch additional services with that. Additional support. There'll be roadmaps
published of those as they come online, as well. >>Victor: There's a
lot more to come. This is just the
initial announcement. And as we work our
way towards release, there will be a
lot more to come. And on that topic, I'd like to
mention that tomorrow if you have more technical details
regarding the technology that we announced
yesterday, there will be tech talks
released on YouTube. Two of them, specifically. And so, make sure you tune
into our social media channels and you can see
when they are live. Moving on, we are
also-- we will of course be covering UE5 on the
livestreams in the future. So stay tuned for that, as well. Moving on, I think it's time
to get onto to today's topic. >>Christian: Yes! Exciting times. The exciting stuff
that everybody wants to talk about, besides
Unreal 5 and Epic Online Services. >>Victor: Memory management! >>Christian: Memory management! Hard object loading and
soft object references. >>Victor: Well, it's a good topic
to cover because it's something that affects pretty much every
single game and something that you should always keep in
mind from the moment you start. And the more practice you
get to do this workflow, the easier it's
going to get for you to spend less time in
the end refactoring and looking at some of the
problems that you have. >>Christian: Yes, definitely. And it's something
that has come up a lot. As an Evangelist, I travel
around to our various Unreal Engine meetups that
are community run groups all around North America. And obviously, there are other
Evangelists around the world. And when I'm doing
my presentations of the various demos
that I've done, I've referenced this
every once in a while. And every time I bring it up, a
lot of hands shoot in the air. And a lot of people
start asking questions because it's not a super
complicated concept, but I think there's just
a lot of misconceptions. And it's not necessarily
readily apparent, especially when you're
just getting started and you're using a lot
of the default settings and just rolling forward. And generally, it doesn't
become an issue or a problem until one, you get very
far along in development and you've got a lot
of content or you're trying to optimize for a
platform, such as mobile or low end PC where users might have
not as much memory available. Memory management can be a
relatively complicated aspect. But as a game designer, which
is my specialty, game design and Blueprint
scripting, there are a lot of things in
the planning phase as you're setting
up your Blueprints and structuring your objects. And so, I've got some just
simple tips and tricks to get started with that today. >>Victor: Awesome. Well, let's get started. >>Christian: Cool. Cool. So I'll just jump
and talk a little bit before I get into
the demonstration. I actually made a
video version of what I'm showing today that I
released a couple of weeks ago. And the popularity
and the response to it is really, I think, what got
you to invite me here today. >>Victor: Sure was. >>Christian: So
that's really good. The general idea
is that when you think about memory management
and object oriented design, you're thinking
about controlling when and where you are
loading objects into memory. And really, in Blueprints
specifically where that comes down to is
hard objects references and soft object references. And the key concept
to get your head around that is essentially,
a hard object reference is you're essentially attaching
the object to your Blueprint. So when you have a hard object
reference, that Uobject, that actor or
whatever it may be is going to be attached
to the Blueprint. And then, it's going to be
loaded into memory whenever the Blueprint is
accessed, whenever the Blueprint is loaded. And that's a hierarchical
cascading effect. So if you have a hard object
reference in a Blueprint, you open that Blueprint, that's going to open the
Blueprint of that hard object reference. If that object also has
additional references, those are going to be loaded
and so on, and so on, and so on. So you can see the
cascading effect. A soft object reference
is basically-- I like to think
about it as the web. A soft object reference
is essentially a web link to the object
on the user's hard drive or on your hard drive. And so, it's storing the
location of that object and then, you're going to
control when it is actually loaded into memory. So that's the way
to think about it. When it's a soft
object reference, it's just sitting there
on your hard drive until you reach out and
tell the game or the Engine to actually load it up. So the demonstration, I'm going
to go and share my screen. So the demonstration
I've got here is a very simple project
that I built. This is just-- >>Victor: One second, Christian. >>Christian: OK. >>Victor: I have a little
delay in OBS here. Just went completely black. Trying to figure out
what happened there. >>Christian: It's live, baby. >>Victor: It is live. All right. We're good. >>Christian: OK, cool. So what I have here is
just a very simple project that's set up. We've got a scene
just with some static-- some various different mesh
objects in the background. But the key for
this demonstrator is this Blueprint object
that I have represented by the Shinbi
skeletal mesh, obviously available for
free on our Marketplace. And so, I've got a
very basic Blueprint that contains two references
to skeletal meshes. One is the one
that you see here, the default skeletal mesh
of Shinbi and another is a variant of
her skeletal mesh with the different
materials set. And what I'd like to do
to demonstrate this is a fresh version of the
editor that I've opened. And I'm going to use a console
command to show my object list. This is console command
is object list class. And in this example, I'm
just using skeletal mesh. Object list class
basically displays all of that type of class that
you have loaded into memory or open in this scene
at any one time. So you can see, if I span this
upward, down at the bottom here you can see that basically,
it's showing that I have one skeletal mesh in memory. And that's the Shinbi.Shinbi object. It shows memory usage,
things like that. Obviously in a larger
project, this list is going to be much bigger. But for this example,
I just have the one. Now something to consider
when you're looking at this is that this is going
to display anything that the editor currently
has loaded into memory. So if I go and go into
my content directory and start opening up a bunch of
different skeletal meshes out of the content
directory, the editor is going to load
those into memory. And if I then run
that console command, it's going to show
all of those objects. So generally when you
want to test this, you either want to be in a
fresh version of the editor that you've just opened up,
that you're not opening up of various bunch
of things, or you want to run these tests
in a cooked build. There are various
different console commands that you can use to
display memory dumps. You can do dumps [INAUDIBLE]
the text and things like that. There's lots of information
about that online. So I'll jump over to
the actual Blueprint here and talk a little bit
about what I've got going on. So when I say hard object
reference and soft object reference, essentially in your
variable in your component. So here's the
components that I have. Basically again, super simple. Up on the upper
left, it's basically just this skeletal mesh. It's a skeletal mesh component. And on the right,
you can see that it's set to the one that's
being displayed. So that is, by default, that
component and that reference is a hard reference. That means every time this
Blueprint is accessed, that's going to be
loaded into memory. Obviously, it needs to be
loaded into memory because it's displaying it here and it's
going to be displaying it in the game. And then in our components,
we've got variables. And if I go down over here, I've
got another variable reference to a different skeletal mesh. This is this Shinbi
Dynasty skeletal mesh. The difference here between these two
is that one is a hard object reference and one is a soft
object reference. And if you see if
you mouse over it, I'm showing that it's a skeletal
mesh soft object reference. And the way that
you control that-- the basic way you control it
is when you create a variable-- I'll create a new one here. I'll just call it
dummy variable. And I'm just going
to move my Zoom display, which is in the way. OK. And I go over to variable
type in the upper right. Move that a little bit more. And I'll bring up skeletal mesh. And so, sometimes it
gets a little hard to see because the pop-ups
are jumping up and giving me the information, but we've got
the different reference here. So we've got object reference,
class reference, soft object reference, and soft
class reference. By default, everything's going
to be an object reference. Again, that's a hard reference. Generally, it just
says object reference. That's defaulting to
being a hard reference. Same with the class reference. That's going to be a hard
reference that's going to load that class into memory. Now these selections down here
are the soft object references. So basically when you
create a variable, the basic easy way to
do this is just you click onto soft
object reference. When I compile it, now it's
a soft object reference. So you interact in this
phase with everything almost exactly the same. You can go through
your content browser. You can choose various
different selections. However you want to do it. And so, that's how you
do the basic setup. Now because soft object
references are essentially just web links to
materials, there is a little bit of a difference
in how you access them. The first thing that you're
going to want to think about is how they're actually
loaded into memory. And let me just
move display again. So what I've got
here is very simple-- in the event graph, a
very simple Blueprint that's essentially loading
the reference that I created earlier, the soft
object reference of the other skeletal match. Pulling some information
out of it-- i.e. the string, the name-- casting it and then setting
it as a hard variable so that I can
continue to interact with it beyond that point. So async load asset. Asynchronous loading nodes. This works both for loading
individual asset or the one for an entire class is, I believe called
async load class-- is essentially your
way through Blueprints of loading the class up. And there's a few key terms. One, asynchronous. Asynchronous means that it
loads the object asynchronously while the rest of the game
simulation continues to run. So when you activate
a async load, it's not going to pause
everything and wait for you. It's just going to
start loading it. And then when it's done,
it'll be available. So you want to keep that in
mind either having delays-- or you can use just the
nodes right off of this. The completed node will only
fire once the objects actually loaded into memory. Sometimes if you want
to string right off, that's the best way to do it. Or if you have a bunch
of assets that you want to load to
stage things out, you can do your time
control through that. It's kind of up to you. >>Victor: Something
that's good to mention is that that timer indicates that
that Blueprint function is an asynchronous function and
that is across the board. If you see that timer, it
means that the function is asynchronous. >>Christian: That's a great point. Yeah. I have these delays
that I just put in. These delays aren't necessary to
the actual functioning of this. They're just so that when I
actually show the demonstration here in a minute, there's
enough time for your brain to actually process
what's happening because it'll run too fast. And you'll see they have
that same pop-up just to let you know that that's
running asynchronously. So that's a great point. So the next thing to think about
or to get your brain wrapped around is that essentially
because this is just a link to a location
of an object, the Engine and the
Blueprint don't actually know the data that's
contained in it. It doesn't have all
the information. That's one of the
reasons why when you make a default, a
hard object reference, the object is by default loaded
into memory because the Engine is assuming that
when you're placing a hard variable
into your Blueprint that you're going to be
referencing that, you're going to be using it for something. Either loading into
memory and activating it or you're going to want to
be pulling data out of it. So it needs to have all
that information loaded. So the first thing
that we need to do if we want to interact
with it in this case once it's loaded into memory
is actually cast to it as the class that it is. And so, what that's doing
is telling the Engine hey, this link to this object
is a skeletal mesh actor. And so, we're going to cast to
it as a skeletal mesh actor. And then, that allows
you to reference the various different
things, whether it be materials, variables
that you have, and public variables that
you want to interact with. So once this is
loaded into memory, I'm casting to it
as a skeletal mash. I have another delay
built in again. That's just for viewing after
the print string is delayed. And then, I set the actual
skeletal mesh component to that new skeletal mash that
I have loaded into memory. After that, I am actually
setting it to a hard variable. So I have an empty variable
that I've created here. You can see nothing's
referenced in here. And now, I'm actually
setting it to that variable. So after this is done, if I
want to reference that variable like I normally
would, I can just go out and start referencing
it and interacting with it. So once you do that, then
later on in your Blueprints you can just treat them however
you would a normal variable. You don't actually have to
worry about it at that point. Another thing I
get asked usually about this point
in the presentation is about unloading the assets. Well, here's how. I've showed you how to manually
load the assets in a memory. What about unloading them? There's not a Blueprint node
to manually unload the objects. Once they're loaded
into memory, they're going to be treated
like any other Uobject. So once the actor is destroyed
and it's no longer referenced by anything else, then
your garbage collection will come and remove it out of
memory when that's appropriate. So once it's loaded
into memory again, you can treat it
like any other Uobject when it comes to memory
management and garbage collection. >>Victor: We did have some
questions about garbage collection and when
it gets collected. Could you go into detail
a little bit about when-- how would I go about it? When would garbage collection
come in and actually nuke that from memory? >>Christian: Well,
the memory manager is going to control that. I don't have a lot
of specific details. You can force
garbage collection. That is a Blueprint node. So if you know, for
example, that you're going to be doing something
very specific where maybe you want to stay in the
same level, but you've had a bunch of objects that
have just been destroyed. And you want to have
a new set of objects. You can force
garbage collection. Generally when you
open up a new level, that's obviously a point
where garbage collection is automatically going to happen. And also as the memory manager
that runs in the background is keeping an eye on the memory
and recognizing the things that garbage
collection can be run. It's going to be handling that. Obviously, if you're
getting into C++ there's a lot finer control
on garbage collection. And there's a lot of
documentation on that side of things on our documentation. So yes. Does that answer your question? >>Victor: Yeah. And then, I think to
add to that I believe if you were to, say,
destroy this Blueprint that was actually the Blueprint
that loaded the soft object reference and then, you stored
it in the empty skel mesh variable. If you were to destroy
this Blueprint, that would eventually get
garbage collected as well, right? And if you were to
spot that again, you would have to
asynchronously load the asset from the soft
object reference again, right? >>Christian: Correct. Correct. Although, that does touch on one
thing that I should talk about. And that's the hierarchical
nature of Blueprints. And let me go ahead and
show the demonstration and then, I can get into
the class parts of things and the hierarchical part. So basically, I walk
through the Blueprint. It's nice and simple. Essentially on
begin play, you're going to see it
waits a few seconds. Once the asset is
actually loaded, it's going to pop up a string
in the upper left and say hey, this has been
loaded into memory. And then, there's going
to be another delay and then you'll see the
actual character swap over. So you'll see that I'm going
to run this console command one more time. If I can click on
the right button. So there's my skeletal-- the list of the skeleton meshes. Again, even though
you saw me interacting with those variables,
placing the variable, creating new ones. Even though I created that
new skeletal mesh variable as a soft object reference, it's
still not loaded into memory. So you can see it's
still right there. Now when I hit play, you're
going to see essentially what I described and then
we'll come back and see what's loaded into memory after that. It's going to be a
pretty exciting surprise. So here, we have
the demonstration. On the upper left, you're
going to see a text pop-up. There she is. She's loaded into memory. And then a few
seconds later, she switches over to
the Dynasty model. Whoops. I'll run that one more time. >>Victor: Get to see it again. >>Christian: Yeah, you
can see it again. There it is loaded in memory
and now it's popped up. You notice the second time it
went a lot faster because it was already loaded into memory. So the only thing slowing that
down was that actual delay. That's why I had to put
it in because otherwise, it just happens like that. So now when I run that
object console command, you'll see now boom. Now there's two. Pretty exciting stuff. So we have the
Shinbi and Dynasty. So now again, the
editor by default pretty much keeps most
things loaded in the memory that it's ever had
open because that's just-- it assumes
that you're going to be working with that again. So again, something to consider. If I just keep adding objects
and keep opening objects, this list is just going
to grow, and grow, and grow while I'm
in this editor session. So again, the easiest
way when you're working doing tests like this
would just be close the editor, reopen a fresh setting,
and then start from there. So let's go back
to the Blueprint while I'm talking about
the hierarchical stuff. So again, where this
really comes into play is both the amount
of memory that you're taking up with various objects. And where you start
to get into trouble is related to what
you were talking about earlier about destroying
this specific actor, this Blueprint, and then it
not being loaded into memory. The thing that you
have to remember is in object oriented design,
everything is hierarchical. So if you create a base
class of an actor with just a default skeletal
mesh in it that then has say 10 materials
and a bunch of textures and a bunch of various
different things, and that's a dummy that
you're never going to use. And then, you start creating
child classes of that actor. So you start creating
children and you start setting them to different
skeletal meshes, which have their own set of materials,
their own set of textures, things like that. Every time you load
one of those children, that parent's going
to be loaded as well because the child inherits
things from that parent. It needs to have that in memory. So if you put a bunch of
variable, bunch of content, into that parent and
then start loading multiple different
children, that just gets bigger and bigger
and bigger and more and more objects. So even if you
destroy the children, the parent might necessarily
not be referenced. The other thing that
people forget a lot is when it comes to
things like casting. So I mentioned casting
earlier that you need to cast the soft
object reference. But a lot of people
don't understand that when you cast to an
object, you cast to a Blueprint, it also gets loaded into memory. Just because you're casting
to it from one Blueprint, it's not only loading
that very specific thing. It's loading the entire
Blueprint into memory because it again, needs to
have all that information to pull out whatever
you're trying to reference. So again, thinking about
things hierarchically, if I have that
parent class, then I have all those children classes. And then that goes from there. And I cast to those. That whole chain is going
to be loaded into memory. And where this
comes into play when it comes to memory management
is not just the total amount of memory you're using,
which can affect things like load time. So if in your scene you've
got a bunch of Blueprints that cast to other Blueprints
that have a bunch of references themselves and you
wonder why you're load times take a
really long time, it's because the
game's not actually doing that until you
open the scene, until you open the level. So if you open the level,
it has a bunch of Blueprints and referencing a bunch
of other Blueprints, all that stuff has to
be loaded into memory. So that's increasing
your load time. So you can, of course then, you
can use soft object references in and stage that
loading ahead of time to smooth that out or just
reduce all those references so that you're not having
that giant load time. The other thing when
it comes to performance is the memory manager is
keeping track of those objects. It's clumping them together
into different chunks of memory. And especially if you
have a lot of little-- I'd say like small objects in
the course of like thousands of various different
small objects, those are constantly being
arranged and clumped together to be the most efficient
use of your memory. But that takes that
takes performance in CPU to do that. That generally doesn't
hurt you too bad. But again, if you start getting
into thousands and thousands of these objects being
constantly managed in the background, that
can affect performance. So let's see. Lost my train of thought there. So one of the ways to
reduce this overhead is when you're setting
up your dummy objects, you can reference
lower impact objects. One of the things
that I do is when I'm setting up a
lot of my classes, I'll use the mannequin. The Unreal mannequin
for most of my skeletal mesh references as
just the default. And if you're always using that
one thing is a default and then you just budget in that OK,
I'm going to use the mannequin or whatever default
character you may have-- if you're always using
those references then especially something
that's just always going to be loaded in memory
anyway, then you can reduce your overhead
just right there. And then, you can use your
soft object references to then load up the very
specific information that you want to have. For example in ParaChess, which
is the game demo that actually brought me to this,
I had the entire set of Paragon characters
from the Marketplace available in that game. And when I started
out, it's a chess game. So there's only, I think,
14 possible characters on screen at once. And I had all that set up just
using hard object references. And that was totally fine that
with the scope of the game that I was making. All the characters were loaded
up in front because it's chess. You don't get more characters
as the game goes on. You get less characters. So performance just improves
the longer you played. But as soon as I went
in and said oh OK. Well, I'm going to have all
of the Paragon characters as well as all of
the variants, that's upwards of 70 AAA
level characters loaded into memory at any one time. And so if I in my
basic Blueprints had all of those characters and
all of their variants listed as hard references
default references, every single one
of those is going to be loaded into memory
when I open that up. Now eventually, if
those aren't ever-- if I destroyed that
actor and it wasn't used, then garbage collection
would clean that up. But if I'm not actually using
those, I don't want all 70 of those characters
loaded into memory just to choose 14 of them to
actually use for the game. That's just super
inefficient for the player to sit to wait for all
those to be loaded up. And then, I might run into
memory management issues. So instead of that,
what I did is just have all the characters listed
as soft object references. And then as the game
loads and the player actually chooses the set
that they're going to have, that's when I actually
asynchronous load them and continue on from there. And of course with
clever management, you could maybe always
load the default that they're going to have. And then as the players
open up widgets and doing different things, you could
start to asynchronously load the things that you
think the player might possibly going to be choosing. So you can just make smart
decisions around there. >>Victor: And we did do a stream
on ParaChess earlier last year. >>Christian: Yes. Yes. And I'm still working on that,
getting through the chess rules. But I did a lot of work. A lot of the actual delay
in releasing ParaChess has been through going back. I didn't do it initially. I just ran with it
and until I started getting into 70 plus
characters at high resolution. That's when I started
realizing-- especially when I said oh I'm going
to make this on the Switch or on mobile. It's like oh, I really
need to start thinking about memory management. And that's where thinking
about this ahead of time and starting to plan out how organizing your content
in smart and efficient ways really comes into play. The earlier you do it-- even if you don't
think that you're going to have a lot of these
objects in a year or two, it's a lot easier to set
it up smart and efficiently in the beginning than it is
when you're in beta testing and you have to go back
and realize that hey, when I first set up the
system for weapon pickups, I was only going to have
12 different weapons. But we decided to add weapon
skins and the weapon skins-- >>Victor: That happens
all the time. >>Christian: --now attached. So now, you had one
weapon with one skin. Now, you have 10
skins per weapon. And now instead of 10 weapon
skeletal meshes being loaded, you have a hundred. And then you add
another variant. Now you have 1,000. And now you have 10,000. And so, thinking about
that ahead of time and structuring it,
doesn't take a lot of time in the beginning when
you're setting things up. But when you haven't touched
a Blueprint in six months and you're having to
go back and go, OK, now I need to
restructure everything to do asynchronous
loading and think about how these are going to-- how these are going
to affect the player. It can become a real hurdle. So setting up the object
oriented hierarchy, separating Blueprints, looking
into things like Blueprint interfaces. A lot of people choose to
use Blueprint interfaces for this type of management. And a Blueprint
interface is something that just contains
variables that sit in alongside your Blueprint. Some people use other methods. I personally like the
soft object references because I can basically
treat them just like any other variable
within my Blueprint. I can organize them
within my Blueprint. I can have everything there
on the variable viewer. I can organize them that way. So thinking about memory
management ahead of time-- It's interesting, I was reading an article
by a developer that was doing a VR development. And working on
desktop, everything was fine until they
got to actual testing with actual hardware. And they were having like
seven minute load times. And when they said this
doesn't make sense-- the levels are taking
seven minutes to load, but the levels
aren't that heavy. What's going on? And then, they opened
up a blank empty space, started doing memory dumps. And here, they have 1,000-1,200
objects loaded in an empty scene and they're
like what's going on. And then, they start
digging in and it's like oh. It was the hard
object reference. They've got class-- they
passed to other classes. They've got references to
ponds that that then have-- or characters that have
things like pickups that are referenced. And then, if you think
about an RPG where-- It's really easy like in a
player character file to say, well, I'm just going to have
the 5 classes of weapons inside the character. And then when the player
walks over a weapon pick up, it's already there and
I can reference it. It's great. But again, you start
expanding that in it in an RPG and now, you've got
thousands of combinations with dozens of different
materials for each object. And it just
exponentially explodes. >>Victor: I'll say it's difficult
to manage at that point. And if you're already
prepared for that, then you will have a
little bit of an easier time getting there. Yeah, I'm glad you mentioned
Blueprint interfaces because they're definitely
a good way because they're agnostic. They don't care
what kind of object that you're trying to
call this function on. They just care if the interface
has been implemented or not. And even if it hasn't
been implemented, you won't get an
error because it's just a call that you're doing. And if it's not there, it
will be perfectly fine, but that's also something
you do need to think of. It won't tell you if you
haven't implemented it. So definitely need
to think about it. Something else
that I tend to do. We talked a little bit
about this earlier, is that if it's
possible for you-- if you're only looking
to access a piece of data inside the Blueprint that
you're talking to that exists in the base level
of actor, you don't need to declare that variable
as the specific class of object that you're trying to talk to
to save a little bit of memory. Because if you just
instead say you need to-- you need a reference to that
actor to destroy it later or something. That destroy function already
exists as the base class actor. And so therefore,
you don't need-- and it's easy to do
because you drag out like from the cast or something. And you promote to variable. And if it's aware of
which class that is and it was just not a cast to
an actor or something low level, then it will actually
create a piece or declare a variable that
is now that specific class. And so therefore, it
will be loaded once to the initial actor is loaded. And so, keeping
those things in mind can help you keep
the costs down. And once they become-- once you get used to it, you
don't think about it anymore and it's just part
of your workflow. >>Christian: Yeah. And I think that brings
up another point. And that's a great one is-- yeah. By saying I need to cast
to this actor class that is five levels down
from a base actor, it has to step through
each one of those children or each one of those references. Load all that stuff
in a memory just to do a simple destroy function. And so, if you're casting
to it, especially if you built a lot of hierarchy in with
a lot of different references-- but the other thing is if I pop
back over to do share screen again, a lot of people don't-- they don't really get the
idea that any reference in the Blueprint where you're
telling the Blueprint you need to know this
information, it's going to be loaded into memory. So it doesn't matter. Let me stop my simulation. It doesn't matter if it's
an actual variable over here on your variable list
or your components. It matters that it's referenced. So if I do spawn
actor from class and then I do a dropdown of the
actor class and pick one here, let's say here's a default
one that I created. If this is sitting
in your Blueprint, that class is going to
be loaded into memory. It doesn't matter whether
it's been spawned yet. That's loaded in memory now
because the editor is assuming that if you've got this
object in, when you spawn it you want it to spawn instantly. So in order for
it to be spawned, it's already going to
be loaded in memory. Otherwise, you would
have to wait for it to load for it to
actually spawn. So a way around this,
or the way to not have this loaded into
memory-- and that's fine if that's what
you want to do. But this class,
this reference, is going to be loaded into memory. So if I wanted to not do
that, then what I could do is come back over here. Create a new dummy var. And then if I go into
the variable type, change that over. I just use skeletal
meshes just because I'm using two soft class reference. And now when I place that
in and link that up, whoops. Oh, let's see because I
am just doing an actor. Let's just change
that back to actor. >>Victor: Yeah. The data types are
context sensitive, which is really nice when you
start out but can sometimes confuse you when you
haven't done it right. >>Christian: Yeah,
but it stops you from doing things that
are wrong, which is great. So I'll do that drop down. Soft class reference. Change the variable type. So it's going to convert
the soft object to a class. Now, what I would want to do
is actually do async load class. And then, I could
run off of that. So the key is that
any time you've got a reference, whether it's
a placed variable over here or just basically any
kind of reference. I'm casting to it. Casting is a class. Again, if I cast
like you mentioned-- if I cast as an actor or
if I cast a skeleton mesh, I go down that hierarchy. That information and all
those references ahead of that are going to be
loaded into memory. >>Victor: That's great. Are you ready for a
couple of questions? See if we can-- see if we can tackle them. >>Christian: Yeah. I think so. I'm sure I will be
dumbfounded on a couple, but I will take it as far as I can. >>Victor: Well, it is a
rather complex subject if you go all the way down
to the low level of what's actually happening. And so, it can be tricky. Let's see. One of the main questions
I'll repeat a few times. You might have tackled this, but
maybe we can just dive into it. What happens when you tried
loading a soft reference asset that's already loaded? >>Christian: That's
a great question. Essentially, the async is just
going to immediately complete. >>Victor: OK. >>Christian: So
actually, you saw it on that second time I
ran through a round. I didn't get any
errors or anything. It just said loading
complete because it's already loaded into memory. So except for a wasted call,
which is super minimal, essentially you're not going
to get any error messages or anything like that. The completed is just going
to fire off immediately. >>Victor: And so, even if
you for some reason, you had two different functions. They both individually
need to reference something that you have a soft
object reference to. You are not sure
which of the functions will be called first,
so they both need to implement the asynchronous
loading function. If one of them has
already executed and the other one
gets called later, even if you have two separate
paths of that asynchronous loading, it will know that
it's already loaded and just immediately execute, yes? >>Christian: I believe so, yes. You should definitely
double test it, double check it, in your project. But, yeah. I believe that's the
functionality that I've seen. And the other thing to keep
in mind just on that note is that completed node
is the important part because the default execution
pin is going to fire as soon as that block goes by. It's going to assume that
you want to just keep going. And so for example, if you
run, not off the completed, just on the default pin and then
immediately try to cast to it and it's not loaded
yet, your cast is going to fail because
it's not loaded into memory. So if you're trying to
do a race condition, you could also have
logic to double check that your cast has failed
and then continue to cast. But you're going to need
to have that logic in, just like anytime you're
dealing with a delay. Anything that's asynchronous,
the time management is really on your shoulders. >>Victor: We did have a question. If you could give a quick
example of where the delay load technique would be useful. And I think you specified
that it was specifically just for the purpose of the
presentation of us being able to see the difference
of the hard one being loaded and then the soft one
actually asynchronous loading in and replacing it. >>Christian: Yeah, correct. In this example, I
just put the delays in to have some time to process
because my computer's too fast and it would be instantaneous. Where you would possibly
want to use time delays in is, I guess, if you wanted
to have a set of assets that you loaded up. Started loading
first to make sure they're first in the queue. And then, you wanted to
put it a delay in where before you started
loading other assets that might be a time frame. But one of the good reasons for
it or thing to think about it is when you're debugging stuff. And you want to put
those delays in so that your brain can--
when you're debugging, you can put it in text pop-ups. Because if you just run text
strings off of everything telling you when things are
and then don't put delays in, you're just going to
get a massive text dump. So I use delays a lot
like that for debugging into personal things. So yeah. >>Victor: Someone was wondering
if you can share any best practices to handle
race conditions with asynchronous
loading to make sure everything is loaded on
clients before spawning players. >>Christian: Essentially,
you can use logic in your Blueprint interfaces
to put in stage gates. So for example, if I
had 10 different objects that I wanted to make sure
it was going into loaded into memory before I
started doing anything else, I could essentially
build a Boolean logic and have a set of
variables, whether it be in increments or Booleans
that check to see essentially, start the asynchronous loaded, when number one is complete,
set to true or ink or increment an integer variable. And then when all 10 are
true, then continue on. So just basic logic that you
would use in any other case. >>Victor: Someone is
wondering when will we use an actor soft
reference versus an actor class soft reference? >>Christian: Essentially,
when you want to reference a very specific thing. So the class is going
to load up is also going to load up its children. An actor is going to load
up the child and the parent. So the classes is going
to load the entire thing and the actor is just going
to load a specific object that you need. I tend to-- generally when
I'm setting up the variables, I tend to work in references to
the specific actors rather than the class. That's just how my brain works. >>Victor: It also depends a
little bit on what kind of logic you're trying to execute
there and what type of data those functions expect. >>Christian: Exactly. Exactly. The system is set up to be
malleable and versatile, depending on how you're
trying to set up your project. So there can be a lot
of personalization based on what you're trying
to do in specific cases. >>Victor: This question might be
a little tricky, but let's see. Would you recommend digging
into the asset registry and try and combine that
with soft object references for asset streaming? Can you even do that? >>Christian: Well, yes I would
encourage people to look into the asset registry. It's good information to have.
As far as combining them, it's so dependent on what
exactly you're trying to do. There's a lot of-- one of the nice things about
the Blueprint system and object oriented design in
general is that you can come at things different ways. Again, you can have this exact
same effect using soft object references in your Blueprint
or creating a Blueprint interface that only contains
those references that you need to have. And then, attach that to
the appropriate Blueprints that you reference. And asset registries are another
way to do management that way. So I don't have a
perfect like, yes, in this specific case, you should definitely do that. But the more knowledge you have
about the system in general, the better equipped that
you're going to have to be able to organize things. Again, with the
logic that you want to use to build your project. >>Victor: I think that
applies to a lot of things. Having a little bit of a
computer science understanding of what you're
actually doing has helped me a lot and
that's something that came after I was
even making things. It just makes you
understand why am I going through this
convoluted way of getting it to work like this? Why is this best practice? It's like oh, it's
zeros and ones on a CPU that actually need to
execute all of this and here are the
reasons why it needs to do what it needs to
do, which then leads us to when we do the abstraction
of all the way up to Blueprints. That's far up the chain, as
far as the abstractions go. Always good to know a little
bit of what's actually going on behind the scenes. >>Christian: Yeah. And a lot of it comes
down to again the logic that you're building and
having it work with the logic that you're building. And there's not
always necessarily one right way to do it. If you're making a
mobile game, a space invaders game that's
only going to have 32 actors variance
at any one time, then you may never need to
worry about this at all. But having the knowledge base
and knowing the general way that it works can
save you down the line when you decide to
add those things. And I've never-- I don't think I've ever
had a case where I thought, man I wish I hadn't
spent that extra couple hours in the beginning
researching this and learning about it and setting
it up in a good way. Gosh, I wish that I had
that two hours back. I have had a lot of
times where oh, gosh. I have to go back
and change this and I went in a direction that
was incredibly challenging and now I have to spend
days working on this. But again, there's not
necessarily one right way to do everything. And that's what
makes it challenging. And that's what makes
game development hard is there's a lot of
different ways a lot of times to accomplish
the same goal. >>Victor: Please listen to
another question I saw here. Is there a good use case
not to use soft references wherever you can? I think you touched
on it a little bit with sort of the small scale
example of the space invaders project. >>Christian: Yeah. But also, it was funny
because just yesterday, I think my tutorial might have
made some impact-- because it was funny because yesterday, I
was at the Facebook Unreal help desk. And I go through
that every couple of days and to see if there's
questions I can quickly answer. And someone was asking
a general question about using construction script
to build a roadside generator. And someone's first response
was make sure you soft object references. Don't have all these
references in there. And I'm like, wow that's-- that's a beginner having a
better beginning question trying to set up a-- basically, learn
the fundamentals of construction script. It can-- it does
add complication to your Blueprints. And if every single time
you create any variable, you're creating a
soft object reference and then you're
asynchronously loading that, and then you're
going through there, that's a lot of complication. That's going to
increase the actual load times on your Blueprints when
you open them up in the editor. That's one of the
reasons why you generally try to compress things and
have things to be simpler. It's going to add
complication to the logic when you're debugging things. And it can get quite
complicated quite quickly. So again, if you
know that if you know that this is
going to be referenced and it's going to be used,
there's not generally a-- Say for example, if I
was making Super Mario Brothers, the first level. I wouldn't go and set
each of those enemies as a soft object reference,
and then try to-- right before he runs
into a mushroom, go OK, well now, I need to load
them up mushroom into memory. And later, OK, here's the turtle
two minutes later. Now, I'm going to load
the turtle into memory. I would probably just add all
those enemies into the level, have them loaded into memory
and not worry about it because I know I know there's
only going to be 10 of them. I've budgeted for that. You don't want to
get too caught up into like trying to
constantly go OK, well there's no more mushrooms,
now OK, you know let's get that out of the way. So I guess that's thinking
about where am I going to go. So if you're budgets take
into account that hey, we're budgeted for
20 enemies per level. We're good to go. We've got bandwidth there. We're never going to-- we know that as long as we stay
below that, we're 100% good, then yeah. You don't have to
worry about it. When it comes to
those enemies, you can just have them all
loaded up on load time. You're front loading that time
onto the player to make sure that everything's in memory. And that way,
everything's instantaneous as you're rolling through
because everything's loaded into memory. >>Victor: So we had a
specific question. So if you're doing
an actor spawner, would you place the
spawner in the level or have a soft reference
to spawn the spawner, then soft references to spawn
the assets as well? >>Christian: That's
a great question. So assuming that your spawner
is relatively lightweight, I would place the
spawner in the level. I mean, that's the
whole point of having a spawner is that
it's lightweight compared to what it spawning. However, the thing to think
about if that spawner actor-- And I actually have another-- I did a talk a couple
of weeks ago at Vector where I did a really rapid
prototype on an arcade style game that I built
super simple spawners. And I actually have
a video of that that I'll probably put out-- >>Victor: Yeah. Let's put that in the
forum announcement post under resources. >>Christian: Yes. So I put spawners in there,
even though they were basically just empty actors that
spawned another actor, with the idea that later
I would have more actors. So if your spawner has-- say you want a
randomize enemy spawner and so, you have a Blueprint. And it basically says,
hey when I'm activated, spawn an actor of this class. And then, you have
10 different classes as variables in that spawner. All 10 of those are going
to be loaded into memory. And that might be fine. But in that case
if you only want to have the spawner load
the actor that's actually going to be spawned
into memory, again going back to Super
Mario Brothers as an example, what you
could do is, I hit level 2, I know the types
of enemies that are going to be spawned
in and either I might have a special spawner
that only contains those actor references or in that spawner,
I could say OK, spawners in the level, here's the type of actors
that we could have go into your soft references,
load those specific actors into memory. That way, you're
spawners ready to go, has those loaded on begin play. Only load those and then spawn
from those specific classes. Does that make sense-- >>Victor: Yeah. >>Christian: --as an example? >>Victor: I think so. I think so. And we had a few more
questions related to-- let's see here. That I think relates
a little bit. How would one go about using
soft references for assets referenced in data tables? >>Christian: Data tables get
brought up a lot in reference to this. And I have to apologize
because I'm not super familiar with data tables. I don't actually use them a lot. So, yeah. So I would have to
pass on that one. I'd want to do a
little bit of follow up on how specifically to
reference those assets from data tables as variables. Unless you know, Victor. >>Victor: No, I don't actually. I was going to mention that
on the first games I shipped, not a single soft
object reference at all. >>Christian: Yes. >>Victor: Just entirely in
Blueprints. Just all references
to everything and-- >>Christian: Again, data
tables are something-- Data tables, to me,
are a little old school and I try to stay away from them
personally just because I've had so many-- anytime something gives it a
spreadsheet form and manual text entry form, I get scared. When it comes to QA, I've had-- If any designers dealt
with localization tables in the past, I'm sure they
had terrible horror stories about trying to track down bugs
and things like that in there. So I like to minimize data
entry by game designers because I know how
ADD we are and how we have a tendency to screw
things up in very little ways. So I like to have
stuff in my Blueprints so that I can make sure
that they're actually referencing an object and not
using a text stream to reference objects. And that's a personal thing. >>Victor: Right. I was going to say that. And it's always important
to sometimes consider your personal preferences over
the possibility of a very, very, very minor optimization. You need to remember that
we are all humans that need to work with these projects. And if you try to do
to the best practice every single time
everywhere, the amount of time you'll spend on that,
the amount of complexity you might add to this
for you as a human to actually work with this-- The production part of the
game is sometimes as important, especially if you have a budget
limitation or a time limitation sometimes. And there's 1,000
ways to do everything. But sometimes, take
your personal preference into the plan for
development as well. That can be important. As always, balance that versus
the performance optimization and try to learn
as much as possible about that so that you can
make a qualified decision whether this is the
right choice or not. Should it go personal? Should I go best practice,
in terms of optimization? >>Christian: And think about the
effect on things like test, as well. I actually shot myself
in the foot a little bit in trying to do an optimization
on ParaChess where right now, I'm working on some of
the king threat logic to stop the king from being able
to move to places where they're not supposed to be able to move. They're threatened
by another piece. And I was running a
check on the entire board to check every tile. So that was 64
checks every tick. And I said well, it'd be much
more efficient to only check from the pieces that are
actually occupied by the enemy because that would
only be maximum 16. So that's 64 versus
16 checks per tick. That's going to
be more efficient. I should do that. Meanwhile in trying to do
that, I blew up my logic and essentially broke the
game because the logic, really, was built around
checking every tile. And then I went
down this rabbit hole where then I had to go back
and compensate for that and I'm adding much more
logic to double check. But I don't think
that in the end, I ended up with necessarily
a more optimized project because yes, I was only
doing 16 checks here instead of 64 checks here. But then, I had to add
a bunch more check logic to compensate for
that and it probably would have just been
better, especially because I wasn't actually
seeing a performance hit on it. My game designer brain went
this will be more efficient. >>Victor: Yeah. >>Christian: And so, that can
be a natural thing, especially with programmers and game
designers where you can you can cross over
that threshold of adding inefficiency while
trying to do optimization. >>Victor: Let's see. We have a little bit more time. See if we get some
new questions in. I think that's a good one. What's a one sentence summary of
why soft object references are used? Now, we have to put
the wordsmith hats on. >>Christian: Soft
object references are used to put
the control of when the object is loaded into memory
into the designer's hands. >>Victor: I think that works. >>Christian: Boom. >>Victor: Next question. Do we need to unload the
assets that we're not going to use anymore? I think I'd follow up with how
would you specifically do that? >>Christian: Yeah, that
that tags into something I mentioned in the beginning. Generally, there is no manual-- In Blueprint, there's no manual
like async unload this object. That's because in general
case, your garbage collection is going to handle that. So once you load it
into memory manually through asynchronous loading,
it gets to a certain point where the object is no longer
needed in memory where it's not referenced by anything. It's been destroyed. Nothing else is referencing it. The garbage collection system
is going to unload that at a certain point. It could be on a new
level load, whenever garbage collection runs. So in general, this system
should take care of that automatically. There are ways to
create a specific functions for that in C+. I think Alex Stevens recently
did a tweet storm on that. But that information
is there, if you need to get into the
really fine detail. But in general, your
garbage collection is going to handle
it exactly the same as it would for a destroyed
actor that you spawn in and is not referenced. >>Victor: And that's another
portion of memory management. Say for an example, if you
have an automatic weapon of some sort that is
firing x bullets a second. If you never destroy
those projectiles, you're quickly going to
run out of memory, right? And if they're all
being somewhere drawn, maybe they're sitting
on a wall or something. You're going to run
into other issues. But if you do have a max
lifespan which is a way that I like to not have to worry
about manually calling destroy to just to make sure that, hey. After 30 seconds,
this projectile has traveled five times the
length of the size of my map. There is no way that this actor
is being used in any way, shape or form. I'll add a 30 second data
to the lifespan variable that exists in every actor. And so, making sure
that you destroy them. And then once you
destroy that actor, garbage collection
will come in and remove all of that from memory. And so, that initial
step could be all you need to think
about and then manage what garbage collection
is actually being done. >>Christian: Exactly. Exactly. So, yeah. Lifespan of various
different objects. Yeah. And again, multiple versions
of the same instances of the same actor,
obviously, it's not a linear scale
on memory usage. And yeah. So just building
in smart things. Again, a lot of it
comes into account when you have an object
that references something that references something else
that references something else. We've all built-- I think the first thing
most game designers do is build an actor that spawns
another actor that spawns another actor and then go, oh. That was not a good idea. Now, I have infinite number-- And most of the time, the
Engine will try to stop you. Like, stop! You're doing an infinite loop. Stop it. But once you start
creating things that create other
things, that can help you visualize what it
can do to memory management. If you have an actor that's
randomly spawning an actor that has another reference to
another 100 actors in it, you can very quickly get into
the millions and billions of things loading into memory. Or your game just crashes. >>Victor: There's a lot to think
about in game development. [LAUGHS] Think that's a good question. Let's see-- excuse me. If we can tackle this. If one were to stay
away from data tables-- I'm sorry bringing
data tables up again, but it's a good point. And it can be very useful. If one were to stay
away from data tables, what's the best way
to manage thousands of objects for a
character customizer and you need to group
specific objects by category? Hats, pants... >>Christian: I would think the
interfaces would be a good way to do this. You can also do
them in function. You can utilize your functions
for your organization of your hierarchy. It's really, at
that point it's-- outside of data
management tables, it's you know,
layering the things in, having a class of pants
that has all your information for the various different
pants, either as an interface or a function where
you're going to access it. It's really about--
at that point, it goes into how you want
to organize and manage that information. So you know, you can you set up
your variables how you want it. You can organize them
into different categories. And yeah, just build that
to access the information. I don't know if that
answered the question. >>Victor: I think there's
a balance there as well. If you know you have
thousands of actors, you know, it might be good to
actually do it at a data table in terms of management. You might even have--
if that's the case, then you say you have-- RPG is a good example, right,
because there's usually a lot of different pieces
of equipment, skills, you name it-- what it could be. At some point, it does get
easier to manage all of that. You know, you might even have
a complete dedicated like, QA person just dedicated
to making sure that all of the names in
the data table are correct. You know, and at that point,
it's easier for that person to actually manage CSV
files, other than having to go in and open
every Blueprint and possibly check them out,
prevent the designer from being able to work on them. And so there's-- >>Christian: Yeah,
and that's where you start getting into
good source control management, right? Like, one of those stories
related to this that came up was-- it was in a different
engine, but they were using a data
table-type information-- and they were actually
getting ready for gold. And when they were building
the final version of the game, at a certain point,
the person that was managing one of the
data tables did a check in, changed some of the data tables. And so half of the
information was current and half the information
wasn't current, because the source control
didn't differentiate when it was checked in. So yeah, you know, you start
getting into your source control, how do you want to
manage that information, what works best for your team, you
know, how many people you have, whether those people
are onside or remote, all those kinds of things
start to come into play. It really-- you
know, it's funny, because I mentioned
localization earlier. You know, when you
start managing loc, if you think that RPG item
management is complicated, you know, managing loc from
multiple different languages for 10,000 lines of dialogue-- that can be a good thing. Any game designer
should go read up on managing localization,
because there's a lot of great
information on there how to manage a lot of data,
and especially a lot of data that you don't necessarily
know what it is, right? >>Victor: Right. >>Christian: If you're managing
localization in German, you might not actually be able
to just inherently look at it and go like oh,
yeah, that's right. So you need to set up
systems within your team to make sure that you
understand whether it's tags or how you do it, how you
organize that information. And that can apply into
the game systems as well. >>Victor: We did have Paulo
Souza on the live stream a couple of weeks ago
talking about localization. So if you're curious
about that, and he did mention briefly sort of how
to deal with contractors that-- because essentially,
you're not going to have-- well, you probably won't
have 12 people on your team that all speak
different languages and know specifically
how everything is spelled and the correct grammar
and ways to change-- you know, whether they're pawns
or possibly saying in one language have to translate them. You are going to have
to use a contractor to manage all of that. And we did do a
string where Paulo goes through how to do
that in Unreal Engine and which tools exist for
you to help with that. Good question about
garbage collection that I think we can tackle. Following the
projectile lifespan that we talked about, is
the garbage collector run for every bullet destroyed,
or will it batch them? >>Christian: I believe-- I mean, the garbage collection
doesn't constantly run. Garbage collection gets
to a certain point, and again, you can
control some of that. So it's going to go through-- and as I understand it,
it's going to go through and essentially say, hey,
here's all the objects right now that I can get rid of. And it's essentially
basically-- you know, so if you had 50 different
types of projectiles coming out of your weapon, and they
all lifespan expired, basically, the next time
the garbage collection came through it would
say, OK, all of these are ready to go, boom,
dump them all at once. That's how I understand it. >>Victor: Yeah, when you do
call to destroy actor node, it actually puts it in a list, and when the garbage
collector does its tick, it will actually go and nuke
everything that's in that list. >>Christian: Exactly. >>Victor: There are a few
questions about sort of network relevancy and how you deal
with soft object references when it relates to that. I'm not too familiar
with that myself. Not sure if you've had a
chance to tackle that yet. >>Christian: Not really, no. You know, once the object
is loaded into memory, as I understand it, you're going
to do your relevancy the same as you would anything else. But I would want to do-- if you're working in a
multiplayer environment-- I'd want to do a little
bit more research that maybe something
I can follow up on is whether I need to treat
those objects a little bit differently on you know, making
sure whether they're loaded on clients and servers as well. >>Victor: Yeah,
there could be some form of prediction there that you might want to
implement based on that. So you can set the tick rate
for the garbage collector to fire off? Yes, I believe that's
in project settings. >>Christian: Yeah, I think so. And you can manually force
garbage collection as well. >>Victor: Yes. There's a question about if we
can give any prominent examples from any well-known
games if they were using Unreal Engine,
of when soft object references should be used. I think we tackled a couple
of those use cases in general. I have no specific information
about whether game A or game B used that particular method. >>Christian: No, I
don't, not offhand. >>Victor: All right, well, this
has been a really, really good and informational stream. I appreciate you coming on
and doing the presentation. And for everyone,
if you're curious and you want to share sort
of a quick version of this, Christian did present-- or upload a video, which
it's like 10 minutes long? >>Christian: 10 minutes, yeah. >>Victor: Yeah, on Vimeo. And I've gone ahead and linked
it in the form announcement post already. So if you're curious and
you want sort of this stream but in a quick format,
and it's something you can share to
someone who's like, what's soft object references? You can send that video. And then if they're like, I
would like to work on this, you can go ahead and link
them the live stream. Which by the way, I did see a
question that usually comes up. All of our live streams
get uploaded to YouTube once we're finished. Once Twitch is done
processing and then YouTube is done processing,
they will exist there. And usually every weekend we
tweet a link to that as well. And you can find it archived. So if you're going
through our forums, in the event section
of the forum where we post all of the announcements
for the live streams, whenever the stream is done and
it's up on YouTube, we go ahead and we add that link
to the livestream. And so if you see a topic
that we've already done live, and you would like
to check it out, the embedded version
of the YouTube video should be there in the
forum announcement post. I think with that, I think
it's time to wrap up for today. Like I said, it's been great. Next week we're going to
have Wyeth Johnson on talking about Niagara in 4.25. So yeah, it's gonna be cool. He's sort of our
Niagara wizard here on the team, so all
kinds of exciting things. Yeah, once again thanks,
Christian, for coming on. I do want to mention for all of
you who actually stream Unreal Engine development on Twitch
that there is now a new tag. And you can see it as part
of this stream, actually. You can now tag your
stream with Unreal Engine, which is kind of cool. So that means that you can
stream in whichever category that you feel entails most to
you, whether you're doing art, or you want to be in science
and technology or just creative, you can go ahead and add the
Unreal Engine tag to make sure that if someone just
searched for Unreal Engine, they'll be able to find all
the current livestreams and streamers that are using
the tag, which is a pretty neat little thing for them. So thanks, Twitch. As always, we are still looking
for more countdown videos. If you've been here from
the beginning of the stream, we appreciate you watching and
staying with us for this long. If you saw that little
countdown video, it is 30 minutes of development
that you record, and then speed it up to five minutes. Send that to
community@unrealengine.com, and we will put the
little countdown. Don't composite or add
anything to the video itself. Send that with your
logo, and we'll add a little countdown to it,
add some nice little intro music track. And you might be
one of the people that we showcase at the
beginning of the stream. Make sure you follow
us on social media for all news related to
whether it's Unreal 4 or Unreal Engine 5, which you can see-- also, I should mention that
Christian's virtual background is actually available
if you would like to use that in Zoom,
which is kind of fancy. I like it a lot. I think you did a good choice. >>Christian: Yeah, I like it. >>Victor: Yeah, it's
almost like Stargate. >>Christian: So awesome. >>Victor: Yeah, I think
that's it for this week. I appreciate everyone
for coming on. Everyone in chat, say
goodbye to Christian. And I hope to see you at some point. Oh, I'll make sure to add the
link to the stream that you did on ParaChess if anyone is
interested in watching that as well. A little project Christian's
been working on there. I think it's pretty cool. >>Christian: Awesome,
thanks very much. Thanks for having me on
and yeah, see you online. >>Victor: Yeah, we'll
see you all online. Have a good rest of your
week, everyone, bye.