Understanding Asset Dependencies in Unreal Engine 5 with Mike Seese

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
well thanks everyone for showing up uh to understanding asset dependencies and Unreal Engine 5 hard reps and you so today we are covering uh what asset dependencies are why they exist when you don't want to have them what you can do to try to avoid them and when they're okay to use and you should be using them it's not something to be scared about it's just something you should be cautious about and then if you're down the road you're about to release and you everything hits the fan how do you fix those problems what are the tools available and resources for you to actually systemically try to make that better and I have some links to some additional great resources and talks and then we'll have some q a and then later if you're interested we're going to go over to 10 Barrel Brewing for some food and drinks what is an asset dependency well it's when another asset references another asset an asset is anything in the engine a material a blueprint a data table or um a widget which is kind of like a blueprint but with the did the the UI and stuff like that it's those things that you see in the content browser in unreal and many times those things will reference other things whether that's in variables and things like that we'll go at what makes a hard reference but references can be hard and soft or soft that means hard references they load immediately when you load asset a and it refer references acid B it has to load asset B before it loads asset a it's this way of you're telling the engine look like I can't do anything unless this thing is loaded into memory and so that's what a hard reference is a soft reference is I have this reference but you know the class this asset can function without it loaded into memory and we'll load that sometime during runtime whenever that may be uh oh and as it depends chain just means I'll use that term a couple of times it's when it's the whole chain of dependencies that you make when acid a refers to B and B refers to C anything that refers to B will also load C when it's a hard reference and so you get this really dangerous uh exponentiation issue where if you asset a refers to 10 different assets and then each of those refers to 10 different assets and then some of them Circle back and then they come back now you have this like real nightmare of a problem I call those asset dependency chains and you try to keep those as small as possible to prevent issues some examples of hard references are variable types that is either you're making a blueprint in the details panel you have local variables for functions or the variables for the blueprint inputs and outputs to functions all of those the types of that variable and I'll have some pictures I think a little bit later those will make hard references if you say the type is of this blueprint actor my character now you have a hard reference to my character anytime you cast to a thing even if you don't use the result of the cast that still is a hard reference uh any input pins to functions that you specify which class you want to do like spawn actor those are hard references components so skeletal mesh meshes the materials that there are you say that you want to use for the skeletal missions anything that are in the components of uh like a blueprint and then inheritance so child classes that have a hard reference to the parent classes we have to load the parent class for the child class to work so why is this any important a lot of times you can just completely ignore this and ship a game no problems usually it's because your game is a little bit on the smaller scale you have less assets maybe less complexity and it's not a really big problem you don't get you don't have a game that has a gigabyte worth of textures and all these other things so you know long loading times don't really affect you because you could load the whole game and still not be an issue but generally speaking if you load one thing let's say the splash screen and it refers to the game mode that has a reference to your controller and then that starts this whole chain loading your splash screen could load the entire game into RAM just by clicking on the exe or launch app on Steam so we try to minimize our loading times for the specific assets to prevent these kinds of issues later down the road if you're doing updates and things like that and you're focused on like optimizing your chunk size for when you package uh you can't separate packages across different chunks they all go into the same chunk because that whole chunks got to get loaded because it has all the dependencies so you're going to end up with larger chunks with larger asset dependency chains seemingly innocent references end up loading half the game we already talked about that symptoms will creep up slowly you will not notice this is a problem until it is well not really too late you can fix it but man it's going to be a lot of work and there's a talk that I reference multiple times from Mark Craig from Lucid games and I kind of I I'm not quite there yet but eventually we'll be there but pretty much every gray on his head is caused by a hard reference in an asset somewhere and it is one of those things where either you're the person asking to have hard references fixed or you're the person fixing them I tend to be the one fixing them so here's an example from a game uh that I work on and you can see here this is the UI player it is the interface the HUD of the player and you can see here by loading it it loads 4 900 assets it's like it's probably not the entire game but it is pretty close and that means that you're loading almost well it says at least 657 megabytes because I had to like make the window bigger and scroll in to like find more assets so I don't know if it really got the whole size there but uh it's very similar like and the problems with this specific game it's a couple of key references that are really hard for us to remove because of our later in production we don't want to change a bunch of things because it's going to break things or we don't have the time to do it because we're like strapped on cash so ultimately gets to this point where all these things end up referring to this one problem child and then that just does this huge circular dependency with the entire game same game release day at 8 pm Foo told me this is yeah like I've been able to package this entire time and getting this weird error that says could not clear async delete root directory we have no idea what that means but all of a sudden couldn't package and another person bars was like what got it to work last time I just deleted my save folder and it seemed to work uh and that's why we were like well maybe it's the order and the references are being loaded remind you Foo has been packaging this game for years and never having an issue and then all of a sudden when it was already late uh we had these issues Barr called me in to call on the calvary and then many hours later uh oh this was an interesting one we found out that if you opened up unreal and they loaded a specific asset before loading anything else in the editor by opening it up the editor would crash specifically due to a very very long circular dependency like multiple circular dependencies like I went around and then I went around and then I did it so many times that I couldn't defer that circular dependency because unreal does handle it it'll say it's circular I'll handle that later when I get a chance it wouldn't get a chance with this one specific asset and it would crash the engine so we basically just deferred it into acid X we said just don't open asset why because that's less of a problem and we were able to package and ship the game not a problem right so this is really important that when you are time crunched and all these things I guess it depends on the scale of your project but it is good to understand uh uh why these are problems and how to prevent them so there are many ways uh and this is probably not all of them but the ones that I uh are more and more familiar with for avoiding dependencies that you don't need uh casting to a higher and sister class creating the logic of we'll go over each of these in detail um creating a logic only parent class that could be in Blueprint or C plus plus don't put asset loads in a c plus Constructor uh the class default object uh that's for really for C plus plus people uh use soft class references when you can and use blueprint interfaces but don't do it incorrectly very very important we'll go over that uh using proxy actors for multiplayer and messaging bus 4 events so casting to the highest ancestor ancestor class let's say you've implemented be my character this is your character uh that you're loaded into the game it's got a uh your skeletal mesh and your animation blueprint and a bunch of materials that have really high textures and all these other things defined in the defaults for that character well if you need to do things like jump and move the pawn don't cast to be my character when you need to cast cast to a character only cast to the things that are needed in this specific exams example I I'm using this jump function which is you can see see here that it says Target is character that's telling you the class that that function is belonged to so if I'm saying okay I'm casting it to do this jump and then like oh wait I could I could cast higher up in the ancestor chain let me do that and then do the bottom here where you cast to character instead and now you don't you just prevented that hard reference to be my character that's loading all of these textures all of these other things you probably have references to some widget and some other thing maybe you have a reference to a level or you don't want to load a whole other level just because you want to load the character um so that's one it's an easy thing to do uh it's just about being more um patient when you prototype your code and uh try to only do the stuff that's necessary create a logic only blueprint class that's used for casting so similar here where uh we had be my character we we went to higher up sometimes there isn't a higher up so you need to create a higher up and this can be in C plus plus or blueprint a lot of people out there say oh you got to create C plus plus classes for every blueprint class and that's because of this main thing is they put all the logic in the C plus class which is very hard to load other Assets in and so you usually don't but you could do it in Blueprint where you have a blueprint that only has functions it only has logic it doesn't have any textures or anything like that you can Define the components or the default variables and then you create a sub-child a child class of that class where you actually say it's this skeletal mesh it's this material it's these things in the default in the defaults panel you can then change those things so now you can cast to be my character instead of be my character child where it's all defined um all those visual assets uh yeah go in the child class you still can have asset dependency change don't get me wrong you can this all this can still have them but now instead of loading 500 megabytes you're loading maybe a hundred megabytes so here I have this example uh uh everyone can see that all right cool so we have be my character here and it inherits from the parent class character I got a couple of events here where I'll begin play we're going to Loop on tick apparently uh we're gonna jump and this is just going to keep happening and uh I want to be able to tell it to to stop jumping and I call this end jumping there is a stop jump function but for the purpose of this demo where we created our own where we stop we stopped that timer so it won't call this event anymore so you can see here in my character I have I I didn't Define anything in my skeletal mesh or my anim my anim class for the animation blueprint it's completely empty and then I create I right clicked on the be my character in the content browser and I said create child class you could also say right click blueprint and then in the drop down you could say you could type in be my character to find it but right click create child class is the best way to do is easy way to do it and in this child class it doesn't have any logic all the logic that is in my character but I Define the skeletal mesh and the anim class and I created hard references to those in be my character child whose parent is be my character but now I can cast to be my character instead of being my character child wow tongue twister so I have in this other uh uh I just put in the game state for no reason but it's there we can say get player pawn and now I can cast that to be my character and I can call the end jumping function so this becomes a very tedious thing to do because now for everything you want now you're going to have at least two of them uh and now you have an organizational Nightmare and things and I don't know what the best practices are you know I think that's going to be what works for you and your team um but generally speaking for some of these things that are going to have um a lot of textures a lot of other kinds of references and things like that try to create that like if you're going to create a shop a merchant in an RPG game and it's got 10 different meshes because you kit bashed it and you created into a child actor and each of those smashes have all these high you know 4K textures I maybe try to go to like a 1K texture or less but if they had all 4K textures because it's really high def now you could create a child the the logic only for doing the shock which is interacting with it purchasing goods and things like that and then you have the child class that actually says I want these uh actors to be or those meshes to be part of the shop any questions there before we move on oh and another thing is to like double check if you if this worked out you can close the child class and then reopen it and it will say hey if you ever seen this it doesn't show like the event graph it says this is a data only blueprint because it realized that it hasn't defined any functions or any logic in it you're like oh okay good we only defined like uh the skeletal mesh and things like that there's no logic in here that's kind of what uh I was going for so if you're a c plus user um you can there's a function for you to override what the class default object is um and then blueprints this happens just in the nature of them you have all these variables and they all have default values for them well if you're trying to uh I'll try not to explain we can talk more about it later but the tldr is uh if C plus plus classes they all load when the engine starts up when the editor starts up when the game starts up because it's just kind of like I got all these C plus modules and those are super lightweight the code is so lightweight and it loads up but the engine itself will say hey let's go call this class default object because I kind of need to like know what's up and it will if you have a load this asset into memory in there now you're loading that asset when the engine just starts up before you load a level or game mode or any other those things just starting things up will load all of the stuff in the cdos for C plus not a great practice probably in general but that's kind of one thing to keep out for so using soft class references so we got all these hard references but can we like use soft class and references and we can for things like spawning an actor or checking whether or not an actor is a class so for spawning an actor I couldn't find a like okay so you might be able to see that the soft class references like a pink and then a hard reference for a class is purple so very slight change but when you call a spawn an actor it's a drop down and usually would like select it unless you had it in a variable but usually you would just like drop down type it in and say yeah that's the class I want to be able to spawn well what you can do instead is you can say async load class asset or load class asset blocking the top one will be asynchronous it'll load it and whenever comes around it'll go ahead and spawn it it's a great one to use but in some cases you need to block the actual execution path and you this can be problematic if it's a law a lot to load you could cause some hangs in your game but if it's nice and small or if you know it's already loaded into RAM because by the time you got to this level that well sure is you know loaded like you know 30 minutes ago so if it's already loaded into RAM this will be immediate it'll just say yep I already got it here you go otherwise it will fetch it from disk and load it into RAM and then from there you can take this is just going to be like a object class so you have to cast it to an actor class to be able to put it in here but and then I right click and say change cast to Pure cast so then I didn't have an extra line but it'll it'll it'll error if it's not an actor class but uh yeah so that's how you use a nice little drop down you could also put the soft act soft class reference as a variable type in your blueprint because you're like oh this is something I'm going to use in several different functions and I want to just put it in one place and you could do that too and then you could still um drag it here there's another node for loading a class and it's called resolve resolve soft reference and it looks like this it's not very uh definitive and tell you anything other than it goes from pink to purple but when you put it in the uh right click menu it's called resolve soft reference but before we get to there another common practice is casting to figure out is this actor of this type of class because I want to do something if it's a I know it's a weapon but what if it's a melee weapon then I'm going to apply different type of damage than I would if it was a ranged weapon well don't class don't cast to weapon melee because now you just created a hard reference we don't really need to where you could put uh make this it's not a built-in function you would have to make this function put in like a little function library and um is actor of class and you can provide a the actor object and a soft class reference that you can select in this little drop down menu to weapon melee and what it will do is it will say hey resolve the soft reference that's going to load it into memory and then check to see if those classes are equal and now we just totally didn't need that hard reference for just checking Class Type very useful uh especially if you got like a lot of different types of logic like kind of like in the weapon you have all these types of weapons in the each of those weapons go are going to trigger off different types of logic you could also have like a different way of doing it is to have an enume in your master weapon class that says what type of weapon it is and then in your child classes you say oh this is a range weapon this is a melee weapon and things like that and then you can check off that yeah and or would that create a hard reference in the template but it has to reference in the other part of the what do you mean by a template you to check check if it's this thing it will if you do the cast to that yes it will create a hard reference to the template but if your template doesn't hard reference other things that's okay you just create an asset dependency chain of one is that's okay it's not a problem um hard and we'll get to this hard references are okay as long as what's behind it is is under control so that that's totally fine if in your specific game that doesn't have a bunch of a big asset dependency chain behind it so so to repeat the question I believe you're asking well let me try to rephrase to see if I can answer your question at the same time uh the async load doesn't mean it's loaded it might be loaded but it may not let's say we had like four of these async load class Assets in the same blueprint uh and one of them got triggered already and it loaded it into RAM later down the road five minutes later a different thing maybe the same event got triggered because you wanted to say shoot rocket and the first time it loaded it in but the second time we're going to go to async load give me the rocket and it's already loaded into RAM because we didn't get rid of it and doesn't load it again that's correct that's correct in both cases these functions would return in this case the completed for the async and then the other output pin those would happen just immediately be like I already got it here you go and that could be loaded somewhere else from another class too it's not just in that one class it's kind of a global did this class at all get loaded yes does that answer your question cool any other questions about soft class references cool this thing should be put in the engine I oh I got this specifically from Mark Craig's talk this is a great talk you should check it out it's going to be a little bit repetitive but there's some nuggets of good information in there and there'll be a link at the end of the presentation okay so that was soft class objects and if you ever go into uh create you know specifying uh the type of a variable you'll see you have two different soft references you have the soft class which we just talked about and they have soft object reference and so my first thought was like okay well maybe like we're it's kind of like a soft class we won't load the class and it's just like a a pointer in like a c plus term of this random thing and eventually will load it and it will be a soft reference that is not true soft and and the internet there are a couple of like first Five results on Google they sell you that a soft object reference is a soft reference that is not it is a hard reference it will still load it into memory what they are specifically for and uh epic day to talk about it was kind of confusing and you had to like decipher the video but here is what a soft object reference is for it's the values of that soft object reference whatever you set that soft object reference for those values are not loaded into memory immediately on the app the asset being loaded and you still have to manually load that value so it's a little unintuitive but here's uh in the Epic talk they had like a skeletal mesh but I think what's even better is textures and materials so let's um before I guess we talk about for this yeah what not gonna look at slight so what the soft object reference is really useful for is let's say you have a building that is in a war zone but the war the battle hasn't come yet so you have this texture loaded of all of the pristineness of that building but then later in the game some bomb blows up or something and you've got all this dirt the the texture totally changes and that's a big 4K or multiple 4K textures of this building and the rubble around that you don't want to have all that loaded into moram beforehand because you're just doubling your loaded space for no reason that's only for the second half of the game why would you want that So Soft object references allow you to specify what those textures are going to be for that one actor but they're not loaded until you tell them to load and so it's a great one for like textures and materials you load those in when an event happens and you say set the material now to these things that I have loaded otherwise you would say you would have two materials uh one for pre pre pre-explosion and one post-expl explosion and if you did just a soft object reference or not a normal object reference the the they're both teal the darker teal uh one which is like kind of the default you would make a hard reference to both materials and both materials would get loaded immediately um whereas a soft object means you can defer it so I would almost like there is a set of blueprint notes for you to it's always going to stay a soft object uh reference at the type you just say it's very similar to these functions is you say loaded into RAM and it returns a object reference for you to then use you can say set material from there so cleared up the air about soft object references probably less useful uh the misnomer is very confusing uh I don't really use them very often but I could see with uh more High Fidelity games or experiences that have lots of four and 8K textures it can be very important for you to only load the ones that actually matter and could it happen with skeletal meshes too let's say you have the same character and you have this like backpack that has like a robotic arm that's coming out well that has all these extra skeletal meshes and things but you only get it when you get the the the power up or something like that you only want to load that later in the game okay interfaces is like the clear this is this thing that people have been saying to use to avoid this but people use it wrong all the time blueprint interfaces are great for avoiding hard references they allow you to call functions inside of any actor that implements that interface and if they don't it's ignored so it's pretty cool you can check to see if some actor implements interface by saying does implement interface but that interface which looks like this you have a list of functions and those functions have inputs and outputs that's it that's what a blueprint interface is you're defining the things that you can call to this thing and then the specific actors themselves will Implement those interfaces actually put the logic in them now the problem is with using blueprint interfaces incorrectly is don't put hard references that you don't want in those blueprint interfaces because now you're like oh I'm doing all this great stuff I'm avoiding all these hard references and you're just like oh go get the actor reference and then you return of type B actor and you're like oh you know I didn't cast or anything like that but it's very easy to do that now you have an interface of that and every single place in your project that you say call this interface of any type it doesn't even have to be this function you could have like 30 functions in this and you could call a function that only returns a Boolean it will load the entire interface and you have a hard reference to that other actor in this other function foreign if you do this all over the place and then you say okay I've got a couple of interfaces that are like core to my game because from an art organization perspective it makes a lot of sense you say oh I have a BPI character and that way we can do a handful of things and those characters can jump and they can drive or they can do these things and you implement them but if one function has this one hard reference that goes and loads half the game because it ignored the rest of the rules for that one specific case I guess then you would load it for every single time you called any function from the interface because it is a beautiful tool if you do use it properly so if you use the other techniques like don't you have the if you can return a character instead of returning your character like the engine built-in character that doesn't have any hard references then you can return that there and you now recruit decrease the hard reference the higher ancestor class logic only classes so that you can create that higher ancestor class if you need it and if you use it in that way and you look at the references for the interface itself and those are very little now you can use it throughout your entire code without actually creating a hard reference to the class so instead of saying be my character uh end jumping that custom event that we added you can create an interface function that says in jumping and you could just say call this interface function if it implements it then run it otherwise do nothing and you totally you know remove the idea of making a hard reference to it because you're only making a hard reference to the interface and not the actual class itself interfaces are also helpful for classes that don't have inheritance unless you probably the main reason for it is um let's say we have a vehicle class and there are two child functions of vehicle there's a car and a motorcycle or a bicycle two-wheeler and their versions of Drive are completely different and so you would Implement an you could have the drive function in the parent and then override them in the children as one way to implement inheritance another way is to use interfaces it's like one of those there's multiple tools to be able to solve the same problems uh and interfaces is one of them for being able to have generic functions that either don't share an ancestor a clap parent class or so my example is really bad in that case because they did share an ancestor class or in this case to to to avoid using hard references is another really good use use case but the what it comes down to is people then put hard references in it and then it kind of defeats the whole point so use them but be careful tread carefully follow the other steps with them uh uh you could try to keep to Primitives but eventually you're not gonna you're gonna have to return actor references to you can cast outside of the interface call instead of having the type you could say I want to return an actor and then and the result you could cast but then you have casts everywhere as could be cluji anyways [Music] um we could talk more about interfaces if you've got further questions so if you're in multiplayer uh I gotta give credit to Zach Burke he's error 454 on the Discord server he's not here today uh I had this problem when I was doing multiplayer where my player controller class had references to everything because the way you communicate from the client to the server is this thing called an RPC it's just a message but to do it you must be the owner the client must be the owner of that class and only one one client can be the owner of a specific actor in unreal and so I had this like um it was a potion station that anyone could use and anyone could run up to it start using the potion station and put ingredients in and make potions and things like that and that had a widget and they were pushing buttons on the widget and that was sending messages to the server for the station to start brewing some potions well what I did is I did this where I would put all of my client to server logic and the player controller because that's the default class that is owned by the player and it wasn't just the potion station it was also the arena bulletin board and insert like 20 different things and so I had to have all these different things and it was all going to player controller and that was having all these hard references everywhere and then if I ever reference player controller they now have to reference the potion station for whatever reason right anyway so what you can do is add a proxy actor and so that what the the idea of this I'll just go through the workflow and maybe it'll make sense so if your player is running up to like a merchant or a potion station or whatever it is maybe it's a vehicle to get into the vehicle to start driving it uh and the server says oh a player has entered this uh compounding box and you can say I'm going to spawn a proxy for this specific client I'm only going to tell the clients about it and I'm going to set that client as the owner no one else is going to know about this client so you keep your networking pretty down pretty low and then on the client says oh I got this proxy just spawned for me and I'm the owner great so I'm going to spawn a widget to be able to then interact with it and purchase some goods and then I since I'm the owner of the proxy I can now say hey uh I would like to purchase this good without even touching the player controller at all and so now I don't my hard reference is B Merchant proxy has a hard reference to Merchant maybe the other way around maybe both ways and um that's really it oh and B Merchant the actual logic of the what's the inventory in the store and things like that to be able to decrease and increase and things like that and apply the inventory changes to the player um so this is a nice little cool little tip I don't know if uh we covered all that yeah I have an intro to multiplayer talk that covers more PCS and things like that it is found on the unreal PDX YouTube channel uh and if you scroll up in the announcements far enough you will find it it might be pinned and okay and then a messaging bus this is a cool one so I use event dispatchers all the time and if you're not familiar event dispatcher is a thing in the blueprint I don't have a picture for this but we can talk more about it uh it's a thing in a blueprint that says this thing has happened this event has happened in anyone's listening for when this event happens we'll be told about this event and then they can process it however they want it's a typical Paradigm in programming called Pub sub for publish And subscribe and the problem with event dispatchers is you have to bind to them so you have to say uh Hey Merchant I want to know when an item is purchased well you have to say Merchant hard reference to the merchant right there bind to event and then you can get it back so now you have a hard reference to the merchant when you just want to know that like uh that a player's currency went down or I I maybe not a great example to use a merchant but you know you're going to create these hard references to every time you want to buy into an event well you can use a messaging bus Which anonymizes this thing where you're saying hey message bus uh uh I want to know when this thing happens and uh it's the thing is defined by either like a gameplay tag which is what I recommend uh or maybe like a string the name of it which is operationally difficult you can make typos I don't recommend it um and so you say hey this gameplay tag whenever it goes off you're not creating a hard reference because that gameplay tag is like one of 20 things or 300 whatever whatever your number of gameplay tags are defined in unreal it's an unreal thing we can talk more about that later and when it happens it's going to return a struct and the struct can have variables in it with certain types and maybe they do have a hard reference to some actor class and that might be okay because instead of like littering the entire message bus with creating those hard references is only when you have bound to that specific message of that type you created the hard reference to that struct um and now you've decreased the chance of you cluttering your space for that unreal doesn't have uh something built in they do have a plug-in in the Lyra example called the gameplay message router that's the name of the folder under the plugins folder when you download it now in the editor plugins it's called something else like game message subsystem why it's a misnomer don't ask me but uh there is a link at the end of the presentation that has a GitHub page that's not mine which does a pretty good job about how to pull it out of the library You Know download Lyra pull it out and how to use it and all you really have to do is Define a bunch of structs and gameplay tags and you're up and running and you can listen to anything anywhere in the game is I want this event whenever it happens uh so it's great for like if you have day night cycles and you want to know when dusk happens uh without creating a hard reference to your time manager uh that's for some reason might have a reference to something it shouldn't and now everything has references to it so if you follow all these tips you end up having a really clean project but the idea is you're going to mess up and you're trying to just reduce the amount of references you have and this is just another great tip that I've enjoyed I've actually enjoyed the act the process of using a message bus more than the event dispatchers anyways [Music] we don't use dispatchers and you're subscribed to them correct and so you create a hard reference to the bus uh but it's a plug-in so yeah and you create hard references to the structs uh and but yes and so it's it is the true nature of a pub sub interface public or publish subscribe where it's I want to know when it happens I don't care when or who it comes from that could be part of your payload that you send is where it came from so it's less useful if you've got like a thousand of a certain type of actor and they're all publishing events uh because maybe you want to know for like a specific actor it happened but even then if you said for loop on an array of actors subscribe to this event you still have to pass who called that event in the event itself you have to say a publisher or something and pass the self-reference through so regardless it's the same kind of interface I guess so for sure correct uh it's the probably the most ideal way to do Pub sub uh in all all the cases uh now that I'm thinking about it there might be one specific instance where event dispatcher is going to be more useful the problem is is it just doesn't come included so you have to like extra plugin to be added and it's not something that's maintained by epic because they kind of just threw it in the live template that gets updates someone's watching this video and they're not happy about it but uh uh but it I've been using it and I haven't had to change it for a year now uh I can pull up the link for that when we get to the end to show you kind of like what that Pub the message bus looks like when to use hard references then the tldr is whenever you need while being cautious about following the above tips because ultimately uh you're going to need to make hard references and you shouldn't be you're trying to ship a game you have limited time limited budget move fast just one thing to consider is every time you make a hard reference by remembering the things that make a hard reference do you need to call functions on this class if not do you really need can you use the is actor of this class if you do need to make fun call functions you're going to need a hard reference because you have to call the function but can it be put in an interface is adding an interface like too much time am I cluttering an interface that's like already too much cluttered and you know you got to like judge that constantly and I don't have the recipe for success um yet but uh can should it be loaded so asynchronously at runtime does it can it be a soft class reference or something along those lines and can you refer to a parent class uh to do the same thing just questions in the form of the things that we've already talked about and each time you'll decide later is another semi-permanent asset dependency because decide later never happens okay tools for reducing your asset dependency chains so there are we will not cover this too much for the interest in time we talk more these are the tools that I use size map is a great one size map I I don't have a picture of it right now it's okay well before we do that right click on an asset and you can find reference viewer and size map and then from there size map is this picture that I showed earlier where it shows you uh uh how many assets get loaded when you load this asset roughly how big it is and I blurred it out for anonymous anonymity wow okay uh oh yeah I mean that's where the money's at right uh so from here it's kind of like a better graphic when you have less dependencies in this case it's kind of like hard to see things uh but it can show you like oh I've got this one class and it's like much larger than I thought it was going to be oh maybe I need to move this texture to like a child class or something like that so this is a great thing for one look seeing how big a level is or a sub level that you're going to stream in later or other kinds of things but also um how many assets are loaded and you can see that you iPlayer loads this thing on the top which loads the thing in the bottom it's like one thing that's contained in another so it's a great way to look at a large amount of information all at once and um the reference viewer is is this I use the reference viewer a lot and ue5 0.0 and really 5.1 kind of like fix all the bugs that went into 50 is so much better than the ue4 reference viewer I highly recommend it but you can still I still use an ue4 what the reference viewer is it shows you all the types of heart references and the order and you can say hey uh I want to search 20 uh you know I I want to limit how many assets like if you got 5 000 references it's going to take a long time for this thing to load so you can limit the uh the breadth limit or you could uncheck that and then load them all and then you then you'll see there's like really large graph which I can probably pull up an image I just didn't include it but um by default it shows hard references which are the gray lines and the magenta pinkish fuchsia lines are soft references and you can specify um whether or not you want to see hard and soft references by going up to the eyeglass thing here I think it's part of this menu in ue4 but in ue5 they moved it to this little menu and you can say uncheck soft references if you only want to look at the Hard references but you can also look at the color of this and you can also specify depth so like right now I'm only going one layer deep I'm looking at my character I don't know why I went two layers but uh when so you can see from my character there's game State and then things like that and then going right is the dependency chain so child Arrow to to my character child references my character depends on stuff so the that's the direction of the reference it does not show circular dependencies really well um but I have another tool for that there is a plug-in I believe it's free I will have to double check and like like 95 sure it's free on the marketplace and this is a kind of a little widget editor utility thing for you to be able to find circular dependencies into traditional programming sense circular dependencies are like a big no no you don't do them because you got to load one thing to load another thing that loads the thing that you're trying to load and you just never load uh unreal has a nice smart way of being able to defer the circular dependency but it can become problematic if it's too big too long or I don't know why but in one specific case the game crashed because of a circular depend many circular dependencies like 5 000 circular dependencies so if length of like 300 chains it's very very bad anyways that's a cool tool it's okay uh it's a great free tool if it is free I'm pretty sure it's free uh check that one out then there's a hard reference finder it's a free plug-in it's not on the marketplace so you have to go download it from GitHub this is a cool let me open this guy they both have this kind of uh feature so a hard reference thing is I want to find my hard references in the specific class and it am I gonna have to like load this two times okay that's good enough so it has this little um widget utility in the editor and you can see this has makes two references to other packages it's kind of like the reference viewer but in the blueprint utility itself and you can double click on this and it will highlight the place where that hard reference is sometimes it's very hard you're like there's a hard reference to this class but I have no idea where it is and you can try using the find utility but that only goes so far so it's nice to be able to double click on on the thing below and it will highlight exactly where the reference is and a circular dependency tool does something similar where if you click on like this button it finds it goes and scans all of your uh dependencies I it's a blueprint utility like most of the logic is in blueprints I was able to like edit the blueprint that came with it and say I only want to scan this directory it doesn't have an input field for it should but uh it doesn't so I could only scan like something but it'll scan the entire slash the game the whole entire project for circular dependencies can take a long time if you've got a lot of assets and a lot of circular dependencies but if you click on the button it will bring up that reference for that dependency you can create uh custom C plus plus Comm commandlets and use the asset registry to be able to like scan your own project and make custom tools and custom reports I'm not going to cover that here uh I would check out Mark's talk and he covers it like just a little bit more um kind of more of an advanced way but if you need to solve your problems Uh custom C plus tools are going to become necessary at some point I've got these additional resources uh you there is a there's a link to the slides that you can scan and get these links uh hard references and reasons to avoid them that's from a an article from Phil his last name isn't anywhere so I put out wushu Studios uh I got a lot of the content from here there so that's also a good one to kind of like do a refresher as a written kind of article a asset dependency change in the hidden danger is a talk from unreal Fest 2022 from Mark that's the one I've been referencing a bunch uh it's a great talk uh you can go and check that out and guide on setting up the gameplay message router that is the thing I was talking about the messaging bus uh which will open up in a second and then you can always hit up unreal Slackers for like a huge source of people that know how to do stuff or the unreal PDX community and get a couple of us that more of a tight-knit group so before we go on to further this is that message router so I don't know if he made he pushed the source of the thing here but you can't get it from the Lyra example and if we scroll down says go and get the Lyra game project here oh I didn't know they pushed push it to GitHub you can download from GitHub or you can get it from the marketplace Lyra starter project or template or something like that and download that and then go into the plugins project folder in that and then get the gameplay message router download that and then if you're using it in C plus plus then you can follow these tools and things like that they made a struct in C plus but you can make your struct in blueprints you don't have to use the C plus struct where they just created these things this is kind of like the payload of the message that's going to be sent and here let's just skip over this and go to the blueprint stuff and so part of the message subsystem because they the naming is hard for epic uh you do the broadcast message and here they specify the channel is a gameplay tag and you can specify you can make new gameplay tags I think through this little editor you can drop down and say new gameplay tag you can also go to the project settings and add gameplay tags there and uh so tags are kind of like hierarchical in the sense that player can have multiple tags underneath it and player Pawn can have multiple tags underneath it so the player is the pawn part of the player Is possessing a thing so we want to know an event when a player is possessed the pawns for the players possessed probably and they pass in the payload and this is a broadcast and that's it they you know specify the values and then later you can listen for gameplay messages where you can specify that channel as well you specify the payload type by selecting that struct and um then when it on message received is called you can get those details that's it and now you can like use this one plugin to do events for your entire project so I think it's a pretty useful tool so there's this common thing around the internet programming it's broken gets fixed and it shitty lasts forever but I would like to add something or until your project decides it's time to break and on release day after you're already late in a way that takes days if not weeks to fix so you know keep in mind that even though it doesn't feel like your Project's broken you might be setting yourself up for failure but the project that I showed you that's years of development that's thousands and thousands of assets with several different programmers coming on and off the project with different mindsets so you know not every case is that bad but uh if you take Mark's experience from a triple A programmer that works on sea of Thieves and all these other cool games they have problems too and so and their problems are also severe you can scan this uh to get the access to these slides and um thank you will be time for questions and answers [Applause] anyone have any questions player this talk here it's it's an awareness so questions come when it when when you're you're in the weeds and the problems came up right yeah for sure um it is definitely like an awareness thing and it's one of those things that people don't even uh the that project the person told me I didn't know Cass make hard references I thought that like sir I was like that's okay uh it's just people don't know because it's not part of the educational pipeline of learning unreal is learning this part because it's it's the publishing the game it's the putting it out to Market it's these things that are learned over time uh usually through the hard way and yeah question is the ancestor chain a common term uh I don't think ancestor chain is but asset dependency chain uh is used by Mark I don't know if it's a really common term yeah any other questions yes uh I I can't I can't you can um I think that if you have a object reference the darker teal uh I don't think you can control when it gets unloaded but that soft object reference that we're talking about can be unloaded that just like how there's a loaded into memory there is an unload um otherwise you're up to garbage collection to uh unload it and you know what happens when it happens yeah so does the destroy actor unload it or does it just delete it from the player's interaction great question uh destroy actor cues it up for garbage collection it immediately just you know removes it from the player's uh HUD and things like that but it doesn't get destroyed immediately it kind of says I'm pending kill and uh the Garbage Collection comes every so often and says if it's pending kill it'll then delete it from RAM and then it'll say okay for each things that were loaded because of that actor uh can we destroy can we unload the whole class can we unload these different things and it will try to smartly detect when to load and unload things but usually it tries to keep things loaded um more often than not um because you're trying to have like a a more smooth experience and so unless you're using the tools to load and unload stuff manually it won't load everything at once but if you unload a level if you load a different level that other load level does get unloaded but buy a garbage collection at some point in the future you can there I think there are C plus plus endpoints functions for you to tell the garbage collection to run like explicitly if you need to like hey I'm loading this level and I had like three gigabytes loaded in this last level and like we really need to like cut down now before I load this next level so let's go into an intermediary loading screen level before so I can force garbage collection to do it because your platform requirements are telling you like look you only get so much gigabytes of RAM don't think there's a tool for that in blueprints you can expose it you got an OC plus to do it any other questions yeah I don't understand that because you said you said they do still they're not loaded immediately when the answer is loaded so how is that still a hard reference what does heart mean in that context great question so the question is I said soft object references are still hard references um but they're not loaded immediately so if we have this B actor is my class or or here and we say soft object reference I'm creating a hard reference to be actor okay to the class B actor by doing this so everything in B actor does get loaded the class gets loaded but the value of this variable which is a we can specify some instance of B actor say a child class inherits from B actor and I want to say the default value of B actor is be a big boss that's got a bunch of stuff on it that inherits from actor but I don't want to load boss yet I will load B actor but I won't load the boss even though the boss is set as the value in the default in the details panel under default the boss won't get loaded so the values themselves don't get loaded but the class that you are specifying does so it uh be after yeah it would load all the heart it will load everything that's in B actor that has a hard reference so if B actor has textures and all those things that will get loaded let me um yes uh I'll try to start up unreal so maybe we can I can show you like a real example but specifically B actor gets loaded but if you have like a child class of be actor that you want to use for the value of that variable that actor won't get loaded whereas normally it would it would create a hard reference records think of that as telling you which part of it is an instance of it in the world that's the object that's the part that doesn't get loaded correct so for the recording's sake Nick just said that the soft class the class itself is not being loaded uh uh right and the soft and for soft object the value of the odd it's it's not intuitive because the soft object reference has a class the class is hard but the saw the object the value of the variable is soft correct and then even though soft class references both have the class of the soft class and a value that you can set it to like a child can you we're about to find out yeah we'll we'll find out it's confusing so while epics games launcher decides to let me load the engine uh any other questions so the question is uh does the profiler tool help you with determining uh hard references and things like this my follow-up question would be which profile or tool there's unreal insights there's the session front end and one could say that size map is a profiling tool but it's a stretch but um you're probably thinking on insights but session front end also has colorful graphs too but they're phasing that one out uh I believe the answer is no I don't think it's their like yeah I think the answer is no it's just it's not meant for that kind of profiling it's more for CPU usage GPU usage uh Network usage RAM usage a bit less about uh class hierarchical and when things are getting loaded or not loaded you can see the profiler that like wow it took like a lot of time for this one frame to load because we were loading this asset and that might be like the first note that something's wrong that you now need to go look into to this specific asset when it got loaded so yes it's a good first thing of my player is telling me the game's not is taking a really long time to load and then from there you can drill down like oh it's trying to load this asset and that took a really long time now you use the other tools to drill down further okay so hard references are going like the thing that hard reference the the device that hard references effect are going to be both CPU and your disk so because because you have this hard reference you're spending actual CPU time to load it that's the processing of reading from disk so you're waiting for disk to tell you here's the asset and then you're loading that into RAM and that's gonna all of that kind of is like this autonomous Atomic transfer of thing from disk to RAM and the CPU is not it's obviously super uh heavy uh for the CPU you're going to be disc bound uh more than anything else yeah okay so we have uh we're in B bomb right now this is a uh a class that we're going to make a ref we we want to load be child in it at some point in time so we're going to make this variable called um the child coincidental and we're going to change this type to not to be child because we don't want to load be child we just want the logic and be parent because from a logic perspective that's all we need from bum because we're going to run functions in bomb to like do stuff for for the child but we'll type in parent instead of child here and we'll create a soft object reference and then we're going to compile it and then over in the details panel for the child we're going to specify an instance of it that we don't have okay okay okay so I don't use this very often but we're gonna like you know work with what we've got here it's wanting like a real live thing that's like instantiated so we're gonna just drag be child in here now the level has a hard reference to be child it's going to load B child this is so confusing yeah so like oh but I don't want beat this is there's a talk called understanding soft object references inside unreal uh and Chris Christian Allen takes like an hour and a half video you can skip the first half hour and it's a he covers the use cases it and I just didn't look into it too much further I'm sorry I'm guessing it is not meant for actors but maybe for like he used it for like skeletal mesh components and loading a skeletal mesh maybe a so yeah sorry maybe maybe that's because we're using it as a variable and not as a as a so if we created a blueprint and it's actor component PC parent and then we say add AC component or a c b a c parent and parent had some material and we change this to a material soft object reference okay so we could we can pick a material now so I created a material and be parent a type soft object reference so it's maybe not useful for actors but for assets specifically and so we could create our own material M expensive and get this to go away and now material it has a hard reference to material the class material but it doesn't have a hard reference to M expensive and M expensive gets loaded dynamically whenever you tell it to load which you can do some material load async load asset on uh you know we could say like delay so it'll load it in a quarter second later after the B parent loads so material has hard reference to material and I can show you that has a soft reference to M expensive so if we go to here to be parent and we go to the reference viewer I don't know why it has a soft reference to none that's odd oh so um I don't know why it it's probably not showing you a hard reference to material because it's a c plus class but you can see here now we have a soft reference to M expensive uh because I'm expensive is still a reference but it will get loaded later but if material was like material is really a bad example because child classes don't really exist because they're like material instances but um this selection right here is a hard reference but this is a soft reference does that help explain it a little bit better something's in there okay right kind the hard references to the type of the material the type of the variable and the soft references the value of that variable that you set in the details panel like another way to do it would be if we created uh uh so they said a skeletal mesh can we create one of those without all the fancy stuff I think we need like a an actual skeleton to do that anyways that's the intro go watch uh Christian Allen's from the inside real to really understand it more but generally that's the principle is the variable type itself is still a hard reference but the value of the variable is a soft reference okay any other questions cool well thanks for coming I really appreciate it and uh hit us up on unreal PDX got any more questions and I think we'll go and head over to 10 Barrel Brewing now to get some drinks and food
Info
Channel: UnrealPDX
Views: 238
Rating: undefined out of 5
Keywords:
Id: AVSZOEHy3_I
Channel Id: undefined
Length: 77min 10sec (4630 seconds)
Published: Sat Jul 15 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.