Asset Manager Explained | Inside Unreal

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
VICTOR: I'm your host, Victor Brodin. And my guest is Ben Zeigler-- Unreal Engine consultant. Awesome. Today we're going to talk a little bit about the Asset Manager. Ben, the floor is yours. Please go ahead. BEN: Sure, yeah. I just want to talk through the Asset Manager. This is something that's been requested a few times. It's pretty programmer focused, but also designers. And anyone that's interested, it's kind of more depths of the engine will be interested. Just a few slides I want to start out with. Just talk through the basics of it. Yeah, so the Asset Manager. Before we get too far into that, just want to do a quick intro for myself. Hi, I'm Ben Zeigler. There's my email address and my Twitter handle. I originally developed the Asset Manager when I was a full time Epic engineer a few years ago. Now I'm working as an independent contractor exclusively with Unreal Engine. And I also help out by contributing directly to the engine sometimes. My experience is kind of half gameplay and then kind of half in the more core parts of the engine. And then the relevant part for this discussion is, I worked on both Epic internal games, on the engine gameplay framework-- on Blueprint team-- and I also worked on the action RPG sample, which I was on here a few years ago to talk about. So what is the Asset Manager? So it's a single global object. It's very much like an Engine Subsystem, which is kind of a newer concept. But it's a bit older than an Engine Subsystem. But just treat it like an Engine Subsystem. It's not map or mode specific. There's only one of them even if you're in the editor or in the game. There's only one. One of the main things it does is it categorizes and queries unloaded assets using something called the Asset Registry, which I'll get into in a second. It also maintains a global asset loading state, which means it keeps track of which things are in memory and which things are not in memory. And it also integrates a bunch of existing systems that were spread out. So it talks to the cooking system. It talks to the async loading system. And Asset Registry, like I mentioned. It was also designed to be overridden and extended by individual games. So it's kind of designed with a little bit of game specific extensibility in mind. So I mentioned the Asset Registry. So the Asset Registry is used for a bunch of things not just the Asset Manager. The main thing it's used for is powering the Content Browser in the editor, which keeps track of all of your meshes, all of your textures, all of everything. It does this by storing information about assets that are saved even if they're not in memory. So it can know about all the meshes in the entire game. When you load your editor up, it actually refreshes that off of like a disk cache, which if you've ever loaded the Content Browser, you see a progress bar in the corner. That is the Asset Registry loading up all the information off of the disk. So the other thing it has, is it has a key and value map for every single asset that allows you to store kind of arbitrary data in the Asset Registry at save time, which you can then read back later on. And the Asset Manager takes advantage of that capability. Most of the data is stored in the Asset Registry is also available in a cooked or packaged game, but not all of it is. We will get into that a little bit later. And it also provides the data storage for the Asset Manager's internal systems. OK, so the Asset Manager-- why does it exist? This is actually a kind of a hard question to answer. We were talking about how to describe the Asset Manager and what the purpose of it is. It's actually a little bit complicated. Because when you're just making a prototype game or a very map based game where you go from the first map to the second map and it's very static, you don't really need an Asset Manager. You need an Asset Manager when you're going from that static prototype into a more complicated game that has a lot of different things that interact with each other or you need to know about from other places. It's especially important if you're making like a role playing game or something like a roguelike, where there's a lot of different types of things. So this came about originally because we were making a game like that with lots of things in it. We started with something called the Object Library, which is used in a few places still. But it's kind of like an older version of the Asset Manager that just keeps track of a very specific list of objects and let's you read information about them from the Asset Registry. But that was limited because we wanted to keep track a lot of different types of things like weapons and potions and all sorts of things like that. So the other problem with that is the Blueprint classes work a little differently than other assets. And they're a pain to work with sometimes, so the Asset Manager hides that complexity. It also helps deal with long load times and high memory usage. Because the other way you can avoid having an Asset Manager is if you just load everything into memory at the start-up of your game. Then you don't really need one. But also you're wasting a lot of memory and then your load times would be like minutes long at the beginning of your game. And no one wants that. The other thing is we were trying to move from a lot of cases using hard you UObject references and loading those when you need them. But that is a problem because that can often cause really bad stalls in your game. Like you might just go try to do something, and you need to wait five seconds for it to react. And players hate that. No player wants that. So we were trying to move away from that, and the Asset Manager was a tool we used to do that. Another thing we wanted to support is, when you're going from your main menu into your game or you're on a client on a server, you need to load different types of data. And that is kind of hard to track, so we wanted to have a system that can handle tracking that for us. Then the last important thing it does is it ties into the packaging and chunking system, which decides which files things end up in on your final platform-- on your console, or your mobile device, or on PC. So that was also a complicated manual system that the Asset Manager is designed to interact with. So there's a few a big components to talk through. I guess the first thing is, what is a Primary Asset? So a Primary Asset is anything you would talk about as being a top level thing. So a map, like a level, is a Primary Asset because you can talk about it anywhere in the game. But you also might have other Primary Assets like weapons or potions or up to 50 different types of Primary Assets depending on what your game needs. So there's one type for basically every single class. So there's a potion type, a weapon type, a map type. Then there's also an identifier which is called Primary Asset ID, which is one of those for every single asset that you need to categorize. There's also this concept of Rules. Rules are basically sort of like the rules you apply to different types of Primary Assets. It can be for cooking, or for chunking, or for management. I will get into those a little bit later. There's a Settings, which also is very game specific, which lets you set how you load and use each of the Primary Assets. And then, this isn't a formal type. But we talk about secondary assets because they're anything that's not a Primary Asset. So that's like textures or meshes. Because you don't normally say, load a texture. You say, oh, this texture is in a material, which is in a mesh, which is in a character. So most things in the game end up being secondary assets. Right, so to make a Primary Asset Type, the easy way to do that is you just subclass UPrimaryDataAsset, which you can do from both a native class or just in the Blueprint editor. That kind of does all the work for you. You can also prototype with any asset you want using some settings that I'll get into in a second. But you need to adjust your settings if you want to use that method because it's a little slower. It's preferred to use PrimaryDataAsset or something like it. You can set the scan options, which I'll show you. And then the default behavior is that the identifier will use the short name of your asset. So if your asset is just called WeaponAx but it's a really long path, it would just be called WeaponAx. It won't be called a huge path WeaponAx. So that allows you to keep track of things, but it also means that you're generally not allowed to use the same name in different directories for Primary Assets. And now we're going to jump over to a bit of example. This is using the action RPG sample, which is available in the launcher. This is a sample we put out a few years ago to try to illustrate how to use some of the more complicated parts of the engine like the Asset Manager. And if it's an actual small scale RPG. OK, so here is-- action RPG. Just to give you a real quick look at what it is, I'm just going to play out for a second. Oh, sorry, ignore that. So it's a simple top-down Diabolo-like game designed for both mobile and controller. So you can see we have a weapon. We have an attack. There's enemies. And then as you play this, you actually get to unlock new abilities and new weapons, and each of those weapons ends up being a Primary Asset that the Asset Manager cares about. So going over to our Content Browser, here's the assets in the game. And then, over here in items are the Primary Assets. So let's look at a weapon. Each of these directories has its own type. So like skill is a type. Tokens are a type. Weapons are a type. Here's an example, Ax-- so this has as an actor that spawns when you equip the weapon, have some inventory information. Kind of like a gameplay ability that grants, which we talked a little bit about I think last week or a few weeks ago. But the action RPG shows how you might use abilities from the Asset Manager. For this example that we're doing, I actually added a few new fields that I'll show you in code in a second. But the inventory texture is an example of something that you may want to only have in the inventory menu. You don't need it in-game. This pick up sound is the sound-- you don't need this in the menu because you only need to play that sound when you're in the game to pick it up. This is another Primary Asset that you can just pick off of a menu. And this will only give you the Primary Assets that exist in your game. So these are all the ones that you can select from. And this is an example of data registry tag field, which I'll explain later. So this is how you make a Primary Asset. But then how do you use them? So the action RPG has a few simple examples of that. The game instance has it. OK, so here we're looking at the game instance of the action RPG sample. So this is code that runs whenever you play the game. In this case, this initialised store items runs at the beginning of the game session. So what this does is it goes through a list of item slots that are set up. And the key in this map is a Primary Asset type, so like weapon, potion, et cetera. Goes through that. Gets the type out of that. And then it calls an Asset Manager function that gets every single Primary Asset that is of that type. Then it starts an asynchronous load of all those assets. So this will actually take multiple seconds in theory. Then once this is completed, that we'll hit this completed pin here. And you can see that from the clock here-- the clock means that this is a slow operation that will take multiple seconds. And once that's done, it will actually-- it iterates over all the items it loaded off disk. And then it can cast them to a type. And then it add these to the UI basically. So then the UI knows all of the items that exist in the game, and then it can show them in a list without having to hard code a bunch of paths to all of your items. The other thing this does is this calls a hacky example function I just added for this stream, which I will talk about in one second. I forgot a step. The other important part is setting up your settings. So that is just available from the project settings. There's an Asset Manager section on the left. It's a little hard to read this, so I'm going to walk through this. But let's find a weapon. Here's a weapon. So this is the type definition for the weapons we just looked at. So you pick the class that it is, save as Blueprint only. The editor only is used, in this case, for maps. I think maps are editor only. Yeah, so an editor only type is one that is not available in a cooked game. So you can categorize it, but only as far as like the cooking stuff not as far as the in-game querying. This directory is a list of where to load it from. So in this case, this was selected out of the directory where we had all the weapons stored. These Rules, I will talk about a little bit later. But this is-- I'll come back to Rules in a second. And then outside of this types array, there's a few other global options. You can actually set up some specific overrides here, which allow you to-- which I'll talk about in a second. Then down here are some options that kind of allow you to use the prototype settings. So by default, the editor will just use these settings up here and trust you know what you're doing. But in a cooked game, it actually won't work unless you hit this global option here, which says, don't listen to the items, listen to the Asset Manager when deciding what type an item is. This is a little bit slower, so we don't turn it on by default. But if you're doing a Blueprint only game, this will be a useful option. I think that's all the main options, yeah. All right, going back to the presentation. So now I'm going to get into the nitty gritty of C++. So the next, I don't know, 10 or 15 minutes will be very code heavy. So if you're a designer, you may not care about this part. But we'll get back to more general stuff in a minute. So the Asset Manager, again, is kind of like an Engine Subsystem. So you get it with a global accessor. There's a bunch of functions on the Asset Manager, which I'll go over in a second. The common one here is-- basically, this GetPrimaryAssetIDList is the equivalent of the Blueprint I showed before that gets all the different weapons in the game. This is actually querying the Asset Registry, which I'll show in a second. This does an asynchronous load like the Blueprint that I showed before. And this will, in this case, in C++, instead of using the Blueprint things, you actually pass it a delegate function. And then from your Delegate Function, you can do whatever you want because it's been loaded to memory. And then if you use the load function, this will stay in memory for the rest of the game forever, which is useful for things like items where you want to load all of them. But let's just say, you don't want to load it forever-- you want to get rid of it-- then you can call the unload, and this will let it be released on the next garbage collection. This will not immediately release it. And if something else is holding on to that asset, it will not get released either. But you need to do this if you want to switch game modes entirely and throw away all your old stuff. And then instead of using the like permanent load here, you can also use a preload and this returns a handle. And this will only keep things loaded as long as this handle is stored somewhere. And I'll show you that when we go over to the code in one second. Yeah, one big concept to talk about here is-- you see how this CurrentLoadState here-- this is a list of bundles, Asset Bundles, it is a more advanced concept. Not every game needs these, so it's totally fine just a pass in an empty array for those functions. But an Asset Bundle is what you use to support multiple game modes like menu, in game, and client and server. You can do this by like setting up metatags on the actual UProperties in your C++ asset. And that exposes it to the system. There's also a C++ function on PrimaryAssetData you can override. And then there are basically some functions in the Asset Manager that let you change the global state. So you can do a query to find all the weapons in the game. And then you can say, change all the weapons from menu mode to in game mode. And I would release the menu textures but start to load the in-game sounds. You could also do this by using another function called Change Bundle State For Everything, and then that will basically let you change the state for everything in your game. So that'll be for a very large change. Before I jump over to C++, I think now's a good time to talk through some sort of general loading best practices because it's tied to bundles and a few of those other things. And I'll show those off a little bit when we go look at the code. But like I mentioned before, synchronous loading is a bad thing to do in general. A synchronous load is when you call just like a load object call from C++. There's a few Blueprint nodes that do this. This could take a pretty long time. Like this could take seconds. And during those seconds, your user sees nothing. So it might look be the game has crashed. In some cases, it might actually fail a certification for you on console platforms. This is a pretty bad experience to do that. So the general rule that I like to use is only do this during load screens or you can sometimes get away with doing fast ones if it's in response to user input. So the user has just changed a setting, then OK if it takes like a second or to apply that setting because they know what's going on. They know that they press the button-- oh, OK, something is happening. It's probably because I changed a setting. So that's OK. But, obviously, if it's too long, it might be a problem again. You basically never want to have a random stall of more than a frame or two in the middle of your gameplay because it just feels broken to the user. I mentioned the Asset Bundles. So the Asset Bundles are a good way to handle loading screens so that's usually where you would change the bundle state and clear caches and release things. So you don't really mess with that while you're in-game unless you're doing something game specific. But in loading screens, you can do whatever you want to. The StreamableHandles like I mentioned have a bunch of utility functions on them, that I'll show you, that can be useful for just managing things going on. There's two broad ways to handle soft references when you want to load things. The first way is you can basically say, asynchronously load this thing, wait for it to finish, and then do a thing. So that's the example I showed in Blueprint where I did the multi-second load, and then it called a callback when it was done. So that's good for big things or when you know you can wait. There are sometimes, especially in the user interface, where that's not as easy to do. So sometimes you want to use what's called preload and then a fallback load. So you would start a preload when you enter a new menu. But then it may not finish on time. The user may be clicking really fast, and it may break through your preload. So in some cases, we do have a preload and then you fall back to asynchronous load. Those are the two general ways I would say it's good to do loading. Next one's kind of one that just keeps coming up whenever I contract. So a lot of programmers really like assigning lambdas to delegates. If you don't know what this means, don't worry about it. But if you do know this means, please don't do that. Or be very careful when you do that because a lot of people write lambdas that are not safe to execute a few seconds later. Be very careful when you use lambdas on anything that can happen multiple seconds later. And the last thing I'll mention is, the samples of existing systems aren't really using all these features to their best because a lot of stuff was built for internal games, and we moved it into samples later. So action RPG only uses half of the functionality of the system. Everyone knows about this, so we want to do a better job about this in the future. It's something I care about, so we're going to keep working on that. Actually no. We're going to go to C++ now. Sorry, my order is bad. OK, we're going to walk through some actual code here, and make it look nice and big. So here is the function that the Blueprint was calling. Again, this is not a real function in the sample. I just wrote this this morning. It's just kind of showing off some of the things you can do. So this gets the list of all the weapons. This does a Asset Registry query. This basically, when you call this GetPrimaryAssetData, it fills in this FAssetData structure for you. And then you can query it with a-- it's a key value map. And then this is actually the example time I added to the item Primary Asset. So this has existed in the sample, and these four fields I just added. So this example registry tag, you'll see, this has the data AssetRegistrySearchable on it. And something that's searchable, that allows you to query it later on. And then this is the ones I showed in the editor with the linked Primary Asset. And then this is how you set a bundle up. So this inventory texture is set to only be in the menu bundle. And then just pick up sound set to only be in the game bundle. OK, back to the example code. So this example code goes through all the items in the game. Grab is this example tag. This just a little helper macro that makes sure that this is really defined in the item here. So it finds a tag named this. Gives that value, throws it in this FName. And then we just print out the FName as an example. This code here is the same as the Blueprint node I showed that just loads the assets. So we declare the PrimaryAssetID of this weapon type. And this weapon type is actually defined up in the header for the RPG sample. This is a useful thing to do in general just to have these ready to go for your game because you're going often need to call these from C++. So it makes a weapon, PrimaryAssetID. Then it loads it. And then this is the callback I mentioned. So it basically just binds this function to the callback. So when that load finishes, it gives it to this code, which, in this case, just prints out the name of the thing that loaded. And then just unloads it. And then here's the streamable handle I mentioned. The preload case, like I mentioned, you need to use the handle from this because if don't use the handle, it just goes away. But this handle can be copied around or stored inside like a global object-- you want to keep things loaded. And then this also just has a lot of useful functions on it like I mentioned before. So you can see if it's still in progress. You can get a name off of it. You can cancel it ahead of time if you're like, Oh, I don't care about this-- stop loading. You can change the delegates after it's already started. And then you can also, if you wait until it complete, this will actually stall the game thread until it's done loading whatever's in the handle. Anyway, this just gives you more options in you're game specific code to do what you want. I think it's about it for the C++ side of it. Oh, one other minor thing, so this is kind of what the settings ends up looking like in the INI file. So it's actually sometimes easier to read the Asset Manager settings in the INI just because there's just so many fields. So you can use the in-game interface, or you can use the in-game interface to get you started, and then you can just go into the INI and change a few things. You would have to restart the editor if you do that, though. I think that's it for C++. We can come back to this later if they're like more coder specific questions. I'll have some water. OK, so this is the loading section of the discussion. Now, we're going to get over to cooking and packaging. So this is something that a lot of games don't even think about until very late in the process. And that can be a problem sometimes, so that's why I advise-- a good time to think about some of the stuff is when you're like turning your prototype into like a full game, and you're getting ready to figure out what platforms you want to ship on-- if you want to be on mobile, you want to be on console. And then the Asset Manager can be used to help you tweak the rules for cooking and shipping. What you can do is you can just override the modify cook function on the Asset Manager. There's a bunch of functions on the Asset Manager, which I'll go to-- at the end I'll walk through some of those. There's also a finish loading function you can override. This is a good place to just do game-specific stuff because anything that's in memory when the Asset Manager is done loading will get cooked. You don't even need to reference it. It'll get cooked if it's in memory. So this is a really easy way to make sure things get cooked. You can also set up cook rules in the INI, in the labels, or in the C++ code. And cook rules allow you to override these rules per asset. You could do some kind of complicated stuff there. And one thing we want to try to make a little better-- it's not super accessible plugin right now, at least in 4.26. And we know that something people want. So that's going to-- we're trying to figure out ways to do that better. So this is for cooking. So cooking is the process of actually getting things from editor assets into cooked assets, which is kind of like an intermediate step because you don't generally run from the cooked assets. You run from the staged assets. And then in chunking is about the transition from cooked assets to staged assets. There's a few ways to do staged assets. The older method is using dot PAK files. And there's something called IO Store which is like a newer version of PAK, but the same concepts apply for both. Basically you have individual staged files, which have a bunch of different assets in it-- thousands of assets per staged file. By default, everything goes into chunk zero. And if you don't have the generate chunk option on, everything goes into zero. It doesn't matter when you do it, it will all go into zero. But once you enable that option, you might have a chunk zero stage file. You would have your chunk one stage file and so on. You can actually make a hierarchy of chunks using an ionized called the ChunkDependencyInfo. That allows you to say that if something's in both chunk one and chunk two, don't bother putting it into chunk two because chunk one is like a higher level chunk. By default, chunk zero is the highest level chunk, so anything at zero will not get put into a lower level chunk. This can be useful if you're setting up like-- if you're setting up a platform specific feature where you want some of your stuff to be downloaded at start and some things downloaded as you play the game or in certain languages, you may need to set up these dependencies so that it doesn't like duplicate the assets into multiple chunks. And again, you would need this for platform specific features. If you're just shipping on a standard PC platform with no special downloader features, you don't actually need chunking. But if you're on a mobile platform or your game is large enough and you want to do language specific downloads or texture packs that kind of thing, then you're going to need to use chunking to split your assets up. And also it works with the new chunk of downloader plugin that was released in 4.26, which I'm not going to go into. It's a whole complicated thing on its own. But that's kind of how you would use the Asset Manager to decide which chunks things go into for the mobile downloader. Like I mentioned, you can set up chunks and cook rules per asset. So you can assign things directly in the config. So I kind of show that. We'll go back to the Asset Manager config. The Primary Asset Rules-- you could say, for the health potion, we're going to say that it's a super-high-priority potion for some reason. And it always goes in chunk two just 'cause we're saying that. So this is kind of like the most specific way you could do that. Recursively doesn't apply in this case because you're setting it to exactly one thing. But the cook rule says when you should cook it. So you could say never cook, which we actually stop it from cooking. So this is useful if you have something that you just want to make sure it never gets out, ever. Always cook just always cooks it. This is useful because you can just put anything you want to in your cook. Develop and cook-- this ties into this option where you can say that you have a prototype or development-only assets, and then you could use that with a switch to decide what kind of things go into your final cook. To use that, you need to turn on this Only Cook Production Assets rule here. So anyway, these rules here, I mentioned, are used throughout the rest of these things I'm about to talk about. So you can it directly in the config like I just showed you. You can also set up labels, and then you could also override some C++ functions to change how these rules are applied. This is a much more advanced thing that I'll talk about a little bit but some of these rules are complicated because the engine is complicated. Specifically, it's sometimes hard to tell what owns what. So it's hard to know if a map owns an item or item owns a map. So that's one of those cases where you might need to change those rules. I've go through a minor example. So going back to the example. So here is the Primary Asset Rules like I mentioned. We're actually going to get rid of that because it's not really what we want to do. Instead, I actually set up some labels in the Content Browser. Shooter Game also has some labels set up, and that's how Shooter Game does its chunk assignment. So for the action RPG, I set up a main menu and then a gameplay map label. So this case, this says that everything that is referenced by the main menu map will be assigned to chuck zero. This does apply recursively, so this says that everything under this will get to chunk zero. And then I set the priorities super high in this case, because we want everything that it uses to be the main menu. Then the gameplay map puts everything that's in chunk-- everything else into chunk one. And again, chunk one is a lower priority chunk than zero. And then I also set it up in the config already so that all of the items like weapons and stuff have a chunk ID set to two. So basically, any item or potion that's not used directly to one of the maps will end up in chunk two. Yes, so that's how you set of rules. And I'll show you how you look at those in a second. So all these things are kind of hard to get a grip on until you really understand the system. Like, it's kind of hard to do it right the first time. Don't expect anyone to do this correctly the first time. So there are some tools that I and some other people built to help you investigate what your assets are doing. First one is the Reference Viewer, which is a useful thing in general that I'll show you in a second. That allows you to see what assets refer to other assets. You can also use the Asset Audit Tool, which is just kind of like a list view of all of your assets. Kind of similar to the Content Browser. And here's some options you can do on there. And then there's also the Size Map, which allows you to get a hierarchy view of all of the assets in your game. It come's from the top down, which lets you see what's using that super big texture that you don't want to ship. And that's actually-- if you saw the announcement for this, that was the size map which I'll show you in a second. So again, these aren't really-- it's kind of hard to talk about, so we're going to go through them. I should leave that up. So to get to the Reference Viewer, the easiest way to get there is just find any assets you care about-- so let's go to one of the items. Sorry. Let's go to Reference Viewer. I could see this view here, could make it a little bigger. So this is a useful tool for all sorts of things. This let's you see that the ax is using this gameplay based class-- this is ability, this actor that spawns, this texture. So these are hard references. You can tell because they have this white line. And they stay if you disable soft references. These purple lines are soft references. These are the ones I added to the demo that you had to use bundles to look. The other thing you can do, is you can turn on management references. So this should not turn to none. That is a bug in 4.26 that should be fixed in the future. But you can still see the name above it. So this is the ax. You can see that the ax is managed by this Primary Asset-- Weapon:WeaponAx. So that lets you see that this individual on-disk asset is logically owned by this Primary Asset name over here. This is the Primary Asset identifier. So this is the actual Primary Asset identifier. Now, if we come under that, you will see that this is assigned to chunk two. And that is because of the rules we set up in the private settings where all weapons are assigned to chunk two. So you can use this interface to navigate all around and figure things out. The next tool that's useful is the Asset Audit. You can get to that two ways. You can either just go up here to Window, Developer Tools, Asset Audit-- oh, it's already open. Or you could actually select the assets you care about, right click them, go to audit assets, and that'll put it over here into your audit view. And this is basically just a version of the Content Browser that is meant for just looking at things in detail. So there's no big images in the way, there's no folders, that kind of stuff. So yeah, you can see details about using these weapons. You can actually see the Asset Registry data shows up right here. So because I have added to this example registry tag for this particular weapon, that just shows up here. You could also see what chunk it gets assigned to, the cook rule for it. This usage is a little complicated. This is just kind of like how many things are using it multiplied by their priority. So it's kind of an abstract concept. It's basically like, how important is this? Bigger numbers are more important. So if it's like a million, it's probably really important. If it's one, it's probably not important. If it's zero, it's actually just not used at all. And then this disk size is how big it is on disk. Exclusive means just how big is the actual asset on its own, which is very small because these are just like tiny little data assets. But the disk size overall is all of the things it manages. So this includes all of the textures and meshes used by it. And then here's the name of it. Yeah, from here you can right click things, and then you can get to the other tools like the Reference Viewer and the Size Map. Another very important thing you can do on this view is this dropdown over here. This is probably hard to see, but this is actually selecting which platform you want. So if you have locally cooked for a platform, it will show up here. Or if you haven't, you can actually go to custom and then you need to find basically the development asset registry file. So this part is in the documentation. So the details about this part are described in the documentation. But if you go over here and select the cooked platform, that actually switches all these sizes over here to be the cooked sizes. So these are much more accurate. So the editor sizes-- it does its best to guess how big it'll be. But it's really not that accurate. But this is how big it will actually be in your data, uncompressed. So it'll be a little bit smaller on disk usually depending on what you're doing per platform. But the point is you can use this to figure out how big things are. So you can see from this that essentially the ax is four times as big as the hammer. To see that better, we can use the Size Map. So this is-- that's not a great view actually. I'll just get all of them. OK, so this is looking at all the weapons in the game. This view is hard to understand initially. It's kind of intimidating. The important part is the bigger the box, the larger it is. So this particular texture is very large for some reason. This particular sound is very large. But these pictures over here, kind of small, who cares? So there's a shared section up here. This is all the things that are shared amongst all the weapons. And you can see that there's a lot of things that aren't shared. And you can actually see this because like the base Blueprint weapon actor has references to a bunch of other things. But you can use the mouse wheel to zoom in and out. So I could zoom in to this section of wave progression data table. And you can zoom back out. On the right here, are the individual weapons. So we saw that hammer three was really big. So hammer three happens to have these three giant textures that add up to 3.6 megabytes. So hammer one for some reason doesn't have any big textures, so this one is tiny. So hammer three is a thing you should optimize. Whereas, hammer one, you don't need to worry about it. But this is a really easy way to figure out what kind of textures and meshes should be optimized by your artist because artists tend to-- or you can go back to the Asset Audit view. Because in the Asset Audit view, in addition to having these primary types that I brought over manually, you can do clear up here. And then you can do add asset class, add all textures in the game, all 2D textures. OK, so this is every single texture in the sample. And we're just going to sort by disk size. So we can see that the barbarous character texture is very large. And you can see this because it's a pretty big normal map for this character, so that makes sense. But if you go back to the audit, some of these don't make as much sense. So here's a good example. In this case, the Speed Tree Game Wind Noise texture is five megabytes. I don't know why the Speed Tree Wind Noise Texture is five megabytes because it's this. But yeah, just for some reason using-- this is part of the speed tree importer apparently. You can see the path was in the importer. What else is there? Mostly it makes sense though. The textures is kind of a bad example because I think this game actually has been optimized pretty well. But if your game has not been optimized at all, you might find that you have some incredibly enormous like 4K textures that are plain colors. And you don't need that. So this view is a really easy way to find your low hanging fruit for optimization. Another thing you can do in here is-- clear everything out. I'm going to do, add chunks. So this just gives you all the chunks in the game. So again, zero is kind of like the main menu and everything that the game startup needs. One is all the stuff in-- actually you can just see these if I just go to be the Size Map. So one is all the stuff inside this action RPG main gameplay map. So you can see, this map has a lot of textures it uses and so forth. But this is like the lighting data, right? So the lighting data ends up being pretty big in most maps. And then chuck two is going to be all of the individual Primary Assets that are not included somewhere else. We already saw this view. Basically, it looks like all the weapons and stuff. You might notice the chunk zero is pretty big, right? And you want this zero chunk to be small. If you do Size Map on chunk zero, you can actually see what's going on. So over here, you'll see, again, here's this big Wind Noise Texture. This is not inside a label or anything else. That usually means that the engine is referencing it or it's just loaded at startup or something like that. So this might be something you need to fix in C++ code or so forth. So here's the default font. You probably need that though. The logo, I think the loading screen uses this logo, so that's why it's like big and not inside anything else. But you can also see that this-- the main menu label, this is all the things that the main menu map needs. And again, there's a lot of stuff in here. This also includes all of the base Blueprints. So this is a good way to figure out your base Blueprint is huge for some reason. The player character is 50 megabytes of total stuff, and that's probably because like the player character references-- [INAUDIBLE] you just figure it out. So why is the player character so big? You can see here that the Goblin Level One Blueprint is referenced by it for some reason. And then you can see-- we're back to the Reference Viewer. And you see there's a hard reference from the player character Blueprint to the Goblin Blueprint. So that's an example of something that you may not want in your shipping game. Because your player's loaded in every scene, but you may not have goblins at every single level. So this is the kind of thing where you might want to go back later on and use the Asset Manager to figure out if maybe you want to have an enemy Primary Asset type. And that would allow you to get rid of this like hard dependency on the Goblin. So why is the goblin referencing that? Let's see if it shows up somewhere. It does. Yeah, good example. So in this case, the goblin is in memory because of a debug function. So this is just a function that was added for debugging during development. This doesn't even work in the actual package game. This will be false, and it won't do anything. But this Blueprint node still exists in the shipping game. And this Blueprint node references this goblin. So this debug function is resulting in something like 20 megabytes of extra stuff ending up in chunk zero. So yeah, your game will have a lot of issues like this. There's a lot of things that can cause hard references. But these kind of references are again why we built the Asset Manager in the first place was to kind of try to deal with complicated use cases like this where we don't really want to load everything. Let's go back to the size map, and see if there's anything else interesting here. Not really. I mean like, here's a player character that big but that made sense. The item Blueprint has some stuff in it. Yeah, again, action RPG is pretty reasonably well optimized because we wanted to make sure it would work on mobile platform. But if you have a prototype game and you go to this view, I guarantee you you're just going to see like crazy things in it. You're going to be like, oh, our whole entire game is just one texture. So like you can get pretty far to optimizing your game by just using this view to figure out what's going on. OK, I think it's all the cool stuff I want to talk through. There's a few other options up here again. So you can add all the types if you want. You can add every single primary asset if you want. Here's all the maps and the weapons in the skills all in one place. We go back to my presentation. I don't think I have much left. Oh, I do. A few things, I'm just going to kind of mention this quickly. This is just ideas to think about for advanced programmers. This is not something you want to dive into quickly. These are things that you can build on top of the Asset Manager to do. So you may want to-- like for instance, you might have like a lot of complicated things when your game starts up. Most games just start by referencing everything and loading everything at once. But that may not be something you want to do. You may want to have a loading bar like a progress bar or something. So you could use the Asset Manager to like build a little mini state machine to give yourself a progress bar. One thing that ends up being pretty helpful is when you do a map change-- so the map change itself is going to be a hard load generally unless you're using certain things. But most of the time, it's going to be a hard load. But you can make that road a lot smaller if you do like a preload of all the assets the map uses. So you could write some custom game code to do that with bundles or just do manual stuff. It is hooked into the chunk downloading system used by the chuck downloader plugin I mentioned. So that is in the battle breakers game a mobile game that we have shipped. That's actually set up to use the Asset Manager to download chunks off of the web on demand. So you can actually say like, async load this character. And that'll start a download. And then I'll go to server and download it. And that download will finish. And then it'll load back into your game, and give you a call back saying here's your asset. It's now in memory. Again, it's not really a good example of this. It's a little complicated. But all the kind of like plumbing pieces are there. You would just have to work through those pieces on your own. There's also some kind of custom reports. That's a useful thing to do. The Asset Manager has a few built in. And actually, before I go to the Q&A. This is a good time to do one more code thing. Yeah, correct a code. This is a visual assist, which I'd recommend. OK, so the Asset Manager header file-- like I mentioned, it's kind of complicated. But I've tried to put good comments on here explaining what's going on. There's a lot of virtuals here. Basically everything is virtual. You can override pretty much everything in here. So it's kind of organized by section. So it's like general utilities for getting stuff. There's sections for async loading. There's sections for bundle changing. Again, these are very complicated, so they have very long comments. Here's some of the stuff on the chunk downloading down here. OK, there's a bunch of general utility functions here. So these are useful for pretty much every game. So, yeah, Get Asset Data For Path-- this will just give you a object path, like a soft object path, which is the same thing as a soft object reference. This just goes to the Asset Registry, just gets you the asset data for you. And this allows you to ignore like redirectors and Blueprint assets, that kind of thing. So all these utility functions are just designed to be easy to use on purpose. It's kind of the opposite. So this takes like a asset data you want to get out of the Asset Registry. It tells you like-- this gives you a pointer to the actual thing you want, which, in the Blueprint case, will be a Blueprint class. If you just create the asset register directly, you actually get back to the editor Blueprint object, which is almost never what you want. So you want the Blueprint class mostly. So that's why the Asset Manager has some wrappers to avoid that weirdness of Blueprints. Here are some of those report functions I mentioned. So one of these goes through and gives you actually like a-- this one gives a list of all the things referencing like a package. You can either call that from a script, or you could just have your own function defined in your own Asset Manager. And down here, the virtuals you want to override so here's the one that called at the end of loading. There's just a bunch of other functions. Like here's a modified cook function. Yeah, you could directly override which chunk things go into if you want to do something weird. Again, there's just a lot of functions in here. So once you are at the point where you've done the basic Asset Manager set up and you have your basic type set up, that's kind of a good time to scan through this header and see if there's anything interesting you might want to use for your set up. There's a lot of functions. I think it's all the stuff I wanted to get through. So I'm going to get some water real fast. I think it might be a good time for Victor to talk about Q&A. And I'll be back in one minute. VICTOR: For sure. Also time for me to address some of the audio issues I was having here. I was unable to speak throughout Ben's presentation, which is fine because he clearly doesn't need me helping out. While Ben is getting some water, I guess I should switch this over, and then I can let you all know that next week, we're actually going to-- We're going to do Q&A. I'm not ending the stream here. I know this is usually what I say when we end the stream, but next week we're going to cover the Chunk Downloader. Michael Prinke is coming back for another livestream, which is exciting. And yeah, I hope you're all are excited about the MetaHuman Creator. Been sitting on that for a while. And it is absolutely amazing what the team has been able to accomplish there-- super excited about that. I'm personally not very familiar with the Asset Manager, and so I don't unfortunately have anything I can share with you right then or right there about it. Anything else new, cool, and exciting? Let me take a look at the upcoming schedule for those of you who normally tune in. And I can give you a quick brief of what we have coming up on the channel in the next couple of weeks. One would think I noticed by hand, but there's a lot going on to it. So next week, we're covering the Chunk Downloader. Week after that, we are actually bringing on a team from Germany called On Point, and they're going to talk about their virtual theater setup. So there's a little bit of virtual production going on there. And then week after that, we're doing a simulation and training, which is going to be exciting. I also have Nvidia covering DLSS in the future. BEN: I cannot hear you Victor. VICTOR: That is because I am muted. And I'm going to tell Ben that. I had to go through a couple of different-- there we go. I had to go through a little bit of an audio change set up that I discovered we had a problem when we started to stream because of the shift of which PC was actually hosting the stream. I just want to verify that everyone can hear Ben now as well? BEN: Can you all hear me on the stream? VICTOR: Yes, it looks good here. And we should no longer have you double-- me streaming out twice. Thank you, chat. Good to see that everything is working as intended. Awesome. I was just covering a little bit what we were going to show on the channel in the next coming weeks. But I think it's time to cover a couple of the questions that we received so far. BEN: Yeah, absolutely and I can kind of-- one thing I will say is, I'm not going to go into detail about the specific ways that Epic has used this in the past. Sort of be more general talking about how a game would use this, or how games in general use this. VICTOR: Sounds good. Sounds good. Start from the top. matzeogh asked, is it possible to cook and build a specific chunk? For example, having a project with HTTP chunks enabled can be quite slow if you only want to update one chunk. BEN: Can you cook a single chunk? VICTOR: Cook and build a specific one, yeah. BEN: I don't think you can do that actually. No you can definitely write some custom code. So you could modify the Asset Manager to just skip everything in chunk zero. That would kind of be like never cook stage. But I don't actually know if that'll work. One thing you can do, you can use the iterative cooking feature sometimes. But I wouldn't recommend doing that for a real build. Like for real builds, you want to cook everything from scratch because sometimes we have issues where like-- the problem is that sometimes when you cook something, it actually changes it in ways that are kind of hard to predict. So it's better to do better to cook everything the same. But you can set things up so that you cook using a baseline, which is similar to a DLC cook. It uses like half the same options. That will just try to make the data you put out as similar as possible to the original data. So the download will be small, you still need to cook the whole thing, but then a download will be much smaller. VICTOR: Brainshack asked, can the Asset Manager be used to group content for DLC and similar that can be downloaded on demand to keep package size small? BEN: Yeah, basically. So yeah, that's kind of what I just talked about. So the process of doing that is hard to describe. There's kind of two ways to do this. For most games where you download things from a mobile game or so forth, you probably don't even want to use DLC. You probably just want to use the method I just talked about where you use a baseline package build and make a patch off of that. And then you would just ship your chunk zero directly in your download on Google Play Store or something. And then you're like, chunk one through 20 could be like stored on some other download server or using Google's system-- I don't know how that works. But the point is you can-- for most games you probably don't want to use DLC explicitly for things with lots of chunks. But if you are using DLC, you definitely can use chunks to set that up as well. But I've not actually done that myself. So I have not tried to combine DLC with chunk assignment. I've heard from some licensees that this does work fine. But I've not tried it because the DLC cooking makes it's own PAK file anyway, which is separate from the chunk assignment system. So I think you probably want to use either chunk assignment or DLC, but I could be wrong about that. VICTOR: Next question comes from Willowulf1. They ask, does the Asset Manager support saving slash loading per instance of item data. For example, a sword item that has a random stat range-- plus one to 10-- strength that must be saved per item instance. BEN: No, it's does not. No we don't have-- the Asset Manager is designed to be used with Editor Assets. I mean, you can definitely-- you can get pretty close with like-- a Blueprint inheritance gets you're pretty close to that. But no, it does not save the actual data. One thing you might want to look at is the action RPG save game code in the sample. So that has a really simple inventory saved in it. But that uses the Asset Manager to get the list of all the items. And it saves a inventory by pointing to the Primary Asset ID. Then it would save the random data on top of it. And then there's some code in there to reconstruct those items for you. That's generally the way to go. The engine doesn't really have a built in instant save and restore thing built into it. VICTOR: I will go ahead and add, for a simple version of that, we do have the simple UVC plugin that Chance Ivey covered on the livestream last year. That is say, an easier way to continue to push DLCs et cetera because they can essentially be loaded as a mod. And this is without the whole end user experience of being able to actually modify the game. But you can actually use that plugin to deliver content as a DLC. It will be called a mod in the back end. But for the end user, it will actually just be a DLC. I will go ahead and link that in chat. BEN: Just to mention, in general, sometimes the code refers to mods and DLCs kind of interchangeably just because of historical reasons. But also a DLC-- DLCs, mods, and plugins are kind of all the same thing depending on how you use them. So sometimes it might be a little confusing in the code. VICTOR: It's all about understanding it, right? Being able to work with it. Let's move on to the next question. ryobg asked, how to avoid pulling in references when casting in Blueprints? Soft loading usually causes return of generic objects, which needs to be casted and stored in member objects slash class references. How much is actually that nullifying the benefits of delayed and soft loading? BEN: So yes, that's a real issue. Let me construct an artificial example in the editor. Yeah, so let's go to this Goblin. OK, so we're going to add a soft reference-- I'm sorry. This is kind of on the fly so one second. VICTOR: Doing it live, folks. BEN: Yeah, here's an example. So you do the async load here, of all the items. If you have an async load that does-- so everything up to here is fine. But then if you do a cast here-- cast to goblin, range one or whatever-- yeah, the cast to goblin NPC level 1. So this is bad. So even if this object was asynchronously loaded or is this is a soft reference or whatever, every cast node just does it. You have to have a full reference to it. So the general fix to this is, you just never do that. You only ever cast to like-- what's the parent class of goblin? BPME character. So basically, you just only ever cast to your base classes. And then, usually, base classes will not have a lot of Asset References in them. So if you go-- because obviously this has a lot of functions in it. This has variables. It has components. But the class defaults are all in the component out there. Yeah, so usually they're meshed. So in the base enemy character, there's no skeletal mesh there. So you want to do as much as you can where you have an empty parent Blueprint that would have all the stuff you need. But then don't fill in things like skeletal mesh. And then in your children, then you end up setting skeletal mesh to this like actual Gruntling mesh. I go over this a little bit in the like using Blueprint and C++ documentation page, which I don't have a link for right now. But I can find one. But the point is, you want to use Blueprint based classes everywhere. The other option you could do is interfaces. So Blueprint interfaces can also be used for this. They have their own problems. I would recommend using base classes whenever you can. And then when you can't because you have-- if you want to interact with both an enemy character and like a chest, then you can't really have a base class because they're two totally different things. Then interfaces are better for that than casting to like some really low level thing. VICTOR: There's a great video that I believe Zak Parrish did a couple of years ago on Blueprint Communication. If you are unfamiliar with the different ways to communicate between Blueprints, go check that out on YouTube. It has taught me a lot back in the day. Let's go on to the next one. I just want to say, interfaces are absolutely fantastic. natnatrog32 asked, what would be the best way to deal with a massive amount of spells slash abilities, perhaps thousands? BEN: The system scales up just fine to thousands-- tens of thousands, fine. The actual problem there is you need to have the assets in the editor. There's two ways to do that. Obviously, there could literally just be 1,000 weapons there. At a certain point, you're probably going to want to write a game specific tool to create assets for you. You could use something like a-- I think the Blueprint utility widgets can do that, I think? I've never tried that with them. But I think they can do that. Or you can write game specific ones to do that. You could use that to generate a bunch of things for you. That's one option. I don't recommend doing that unless you-- I don't know. It depends on your game. The other key areas you're going to want to use Blueprint Inheritance at that point. So these are not Blueprints. Yeah, these are not Blueprints. These are just pure data assets. But if you have a really complicated hierarchy of tens of thousands of items, you probably want inheritance. The other thing you can do, you can use data tables for that, which might be a better idea at the tens of thousands level because then you could generate your data into an external tool like Excel or even just like some custom thing like custom JSON thing. Then like import it as a data table. And then a lot of games do is-- one thing you can do that works really well is like mix and match Blueprints and data tables. So you have like a generic weapon Blueprint. And then on the Blueprint, from the data asset or whatever, you would have a reference to a data table row here. And then you would pull the stacks out of the data table. And then by mixing and matching, you can then say, here's a sword. So there's all the sword animations. But it actually uses the stats out of this data table. That's a better way to get to like huge amounts of data in my experience. VICTOR: All right, next question comes from KaosSpectrum. How would you search slash query Primary Assets during runtime slash in editor using gameplay tags? I like to use gameplay tags to mark my Primary Assets. BEN: Yeah, a few ways to do that. Let's go to the code. Right, so this code here-- here is like the name example right. But you can just pull out of the raw string you. Can pull everything out as a raw string. So you could have like string, and then you pull the tags value to there. And I'm pretty sure gameplay tags have a from export text on them because this is something we actually do in some of the internal games. Yeah, here it is. Yeah, so you can just call this function, and pass them to the exports tray. I'm pretty sure that'll work. So then you have a proper gameplay tag here. This will only work if it's actually in the dictionary. But if it's in the dictionary, you can then use this time to do whatever you want to. So you can set up a runtime map from gameplay tag to PrimaryAssetID or gameplay tag to Asset Data. I'm actually working on something for 4.27 that might help a little bit with this called the Data Registry that has native tag support built into it. It does not currently interact with the asset manager in this way. But I want to do it at some point. But yeah, it's a pretty common desire to want to go from gameplay tags to assets. And I think that's probably something we're going to look at making a real feature in the future because I've had to write that in a few different times-- different projects. So it seems like a pretty common thing that we should just do once somewhere. VICTOR: All right, next question comes from flassari. Is there a way or plan to make chunks addressable by string names instead of integers? There's definitely a plan, BEN: Yeah. There's not a great way to do that just because of how we're-- chunks are stored at a very low level in the system where space is at a premium. There's not a great way to do that. I think you might end up wanting to do something that kind of generates stuff for you from some description file. Because you could name the chunks after the Primary Asset in mem or something without it being specific. So there's nothing built into the engine to do that. For some games I've worked on, we can set it up so you can have a separate description of your top level structure. And then use that to like kind of override some of the GetChunkID functions. Because on Asset Manager, all the chunk functions can just be overridden. So like-- yeah, so like this function, you can override this. So you can have this go into your game specific thing, and then figure out, oh, this is character Bob. And character Bob should go in chunk four. You could do a mapping there. So no, there's no way to do that to the engine, but that's also something that has come up a few different times. So it might be something we look at. But there's no plan for that though. VICTOR: matzeogh had another question. Extending the UPrimaryAsset label with a new class breaks instances of the new class, they get ignored by the Asset Manager. Is it possible to extend it for adding some metadata for DLCs and stuff? BEN: I would have expected that to work. As the labels are kind of treated like slightly weirdly, there might be something specific to them where that doesn't work. That works fine for everything besides labels. So I mean, that might just be a bug in the Asset Manager. I've never tried that, so it's probably just something we just doesn't work for no good reason. That should work. So and if it's a simple change, it seems like something like a pull request that we-- I would probably put the pull request if it's pretty simple. If not, maybe just describe the problem better somewhere. I'm not sure. VICTOR: Next question comes from DarknessFX. Can we use modify cook to split builds like ASTC only, textures and materials for Android, arm64-v8, and ETC2 only texture materials for Android RM-V7. BEN: I think you'd might want to use the other function in here, which is similar. So you do have some platforms that are control. You can change the chunk assignment here. So these chunk functions do pass in the target platform, so the default doesn't do anything with them. But you can definitely do that. So you can strip out certain textures if you don't need them on a certain platform. I think there's this simple override here which just lets you exclude certain assets per platform. Yes, I think the way-- yeah, I think the way you do that is-- the easy way to do that is to override the chunk assignment per platform. So then you would shove all of the whatever format you care about textures into one chunk. And then your packaging layer, you could just like say, don't package chunk five on iPhone or something. I don't know how to do that super easily. There is one file that might help a little bit with that. I forget what it's called right now. No, it's not it. I'm trying to remember-- I don't remember offhand. There's an INI file that also lets you assign nonpackaged, nonasset data to chunks, which you might need to do for shaders and stuff like that. I don't know if we have an example of doing that right now. This is another example of a thing that we should have a sample for but don't, so-- but it's definitely doable. VICTOR: Next question comes from RimaWrench. Does Primary Asset Bundles support TArray and TMaps of soft object pointers? BEN: Yes, that should all work just fine. See where that function is. So it just calls the Primary Data Asset, it just calls this generic function on the Asset Manager. So if you don't want to use Primary Data Asset for some reason, you can just like override these four functions in your base class, and that's all you need to do. But this generic function, I'm pretty sure handles arrays. Yeah, it does. So it uses a property value iterator, which actually will go to structs and arrays for you. So it doesn't matter where you put it. As long as it's inside the same UObject, it should get parsed out correctly. VICTOR: I have another question from DarknessFX. Can we use Editor Utilities plus Asset Manager or Asset Tools to automate editor tasks with edit and save assets data-- like set everything from one folder to a different chunk ID or apply new tags to Assets? BEN: Chunks, no because the chunking system right now is more rule-based. You could definitely write something to modify your INI file. But there's no way to do that from Blueprints right now. There's not super great support for Blueprint Utilities and the Asset Manager. I don't think there's much. There's some asset registry stuff, I'm pretty sure. I mean, in my experience, you're just going to have to write C++ code at some point to do that kind of thing. I feel like when it comes to things that are for packaging and shipping, you're going to be in C++ eventually. So there hasn't been a lot of effort to support packaging shipping stuff in Blueprint Editor Utilities. VICTOR: Next question comes from henrysdliu. Is that possible to hold some assets which we do not want to be unloaded during change map-- for example, a bunch of textures. BEN: Yeah, totally. So that's why the preload is useful. So actually, if you just do like this preload Primary Assets, there's also just like a function on the Asset Manager, which gives you [INAUDIBLE]. So you just pass it like a bunch of solid object paths here. If you figure out where all the textures are, you could just use this. Sorry. Start to go a little slower on this one. It's complicated. You figure out what you want to load, parse it in here, and then just hold this handle around. So put it under game instance or somewhere. And as long as it handle is around, those textures will not get garbage collected on the map transition. This is also very useful if there's anything like a reload. So like if you die and want to reload a checkpoint, this is about a very useful thing to do in that case. So it doesn't matter that we've got this already loaded. That's fine. So you can just kind of ignore the delegate. You don't have to parse on a delegate, so you just load it. I mean, just keep this handle, and then you can do exactly that. Or if you do something with bundles, that's why I was talking about bundles, where you could set up like a map Primary Asset. You have like a bundle that has all the textures it needs. That's more complicated, but it's kind of the same idea though. You figure out what textures to assign to it. And then you could override the bundle functions to assign it to it. VICTOR: Next question comes from CyberWolf755. How would you cook assets and load them from a server for a finished game? Does UD-4 support downloading natively? BEN: Per server? No, I don't think there's any support for server side downloading in anything we've shipped. Maybe you could possibly use the chunk downloader plugin. But I haven't tried to do that on the server. It may be possible. No, I don't know of a good way to do that. VICTOR: This is a long shot, but I will try to do a shout out to one of the teams in the 2019 Epic MegaJam who's actually submitted a game for the Jam that had a downloader built into it. They were very clever about that because they're trying to get around one of the special modifier category requirements. It's real clever. If you are watching or might be in the future, it would be great-- I think those folks actually wrote up something about that. And I am just not sure where that lies. But they were able to do it for the MegaJam, so I definitely know it's possible-- 100% custom though, as far as I know. ChaosSpectrum had another question for us. I have a couple of things to write for a Primary Asset-- item to world to weapon to ranged. If I have a custom asset type or ranged, I get a warning. Is this just a limitation? BEN: I don't understand that question. That might be a better one for some text later. So maybe post that on-- now's a good time for a good unplug. The Unreal Slackers Discord has some pretty good channels for like C++ and more advanced stuff. So some of these more advanced questions might be better off just doing over there. VICTOR: We can also discuss them in the forum announcement post for this live stream on our forums. And then it's a little easier to search for it once the conversation has happened. But Slackers is a great place to discuss and hash things out in more real time, which is a little different from the forums. But Ben, I'll make sure to send you the questions after the stream as well and you can go ahead and tackle them when you have some time. BEN: Yeah, so I'll make sure to check the announcement thread a few times this week. I mean, I won't check it forever. But if you do post specific things, I will definitely take a look at them. And I'll answer them if I know them if I can. VICTOR: I will check it forever because I get notifications every time someone writes there. So then if there's something that comes up, I will let you know. BEN: Sure. VICTOR: Let's see, CyberWolf had another question. Does patching a game mean swapping the changed chunks? So for example, if a game didn't make enough chunks or any, it would result in larger updates? An example being Mortal Kombat 11 that had a PC patch the size of the whole game. BEN: Yeah, there's a few things there. I'm not going to speculate about what they're patching architecture is like. But the full size downloads are often because-- if you're not building with a baseline release build, especially on older versions of the engine, it would do a pretty bad job of lining things up. I think it does a better job now by default, but it also does a much better job if you use the baseline. So that just should be better in the more recent version of the engine. But it is true that if you rearrange your chunks massively-- if you just move everything and chunk one to chunk two, move everything in chunk two to one, you're going have to redownload everything if you do that. So you want to get your chunk assignments figured out kind of before you release for real. Like if you have early access or like weight data, that kind of thing is when you want to finalize it. Because you don't really want to change it after you have a lot of people downloading it. VICTOR: saxhack asked, does this work with the GooglePAD plugin? BEN: I have no idea what that is. VICTOR: Me neither, actually. I have never heard of that plugin. BEN: There might be the DLC-E-1. There's not really native integration with this stuff. But again, this just makes the correct staged files for you. And then the staging to delivery is all very platform specific. And there's not really unified way to do that. So it's all very different depending on the platform. VICTOR: iSpamForFood asked, on a Data Asset, can we soft load them and access something like a struct? Example being, I have a data set with conditions. I want to access to conditions without fully loading the data asset. BEN: Yeah, you do something similar to what I just did for the gameplay tag example. So this FromExportString on gameplay tag basically does that for you. So if you were to tag an entire structure as AssetRegistrySearchable, pretty sure it writes out the whole structure. Yeah, it does. And then you can just kind of-- you have to use this weird import text thing. But import text basically-- this is the syntax you get when you copy paste things in the editor, basically. So uses that syntax. So you can have whatever you want you in there. So you could totally just have like a Rule structure in your Asset Registry Data, and then pull it out with this import text. This would be kind of slow though, especially if you have a lot of these. VICTOR: SniperEcho asked, I'm working on a project and currently exploring how to implement delta patching. Is this a viable replacement to delta patching? BEN: No, again, this builds into that. As long as you have your chunk set up the same before and after with the delta patch, then it'll do a delta patch for each of the chunks. So no, it's a complement to the delta patch. VICTOR: SionSheevok had a pretty good question here. Could you lend some insight into using Primary Data Assets References outside of the engine? For example, a back end service with persistent inventory. Would Storing the string like Primary Asset ID in the database be appropriate? BEN: Yes, that was actually one of the reasons we came up with that. I left it off my slides, but yes. That's absolutely what they're designed for. Because they're shorter-- so you don't want to do the full path-- you can if you want. You can override this to use a full path as the primary one if you wanted to. But in my experience, designers like to move things between directories more than they like to move things, rename them. The other thing you can do, is you can actually set up in your game so that keeps the Primary Asset consistent over time. So you could override some of these functions. There's a simple redirector in the settings, I'm pretty sure. Yeah, so these Primary Asset ID redirects, that's literally for this exact case where you have a database where you store everything as like Weapon.Ax, and then you decided to call it Weapon.Ax4. Then you could set up a remapping here. And there are some functions on the Asset Manager that let's you do that remapping. VICTOR: And this is-- we have a little bit of time-- there's a question here that's sort of on topic, but I figure we can address it. What was that? BEN: Yes, go ahead. VICTOR: sorryforthebadpuns asked, what are the kinds of problems associated with using interfaces instead of Blueprints to avoid hard Asset References? I think what they're referring to is using Blueprints, or sorry-- interfaces instead of casting in-- BEN: In base classes. Yeah. Yeah, but then it comes down to-- there's a few reasons for that. VICTOR: Load times is the big one that I came across. BEN: Well, I think he's asking more about interfaces versus base classes because those are the two options. VICTOR: Oh, yeah, yeah, I think you're right. BEN: So base classes are just a little easier to use because you don't need to expose things in both the interface and the base class if you have a base class that make sense to do it in one place. Interfaces are a little slower like performance-wise in some cases. Also, it's harder to have an interface that works in both C++ and Blueprints. So if you want to have your base classes being native of code and used from Blueprints, base classes are currently easier than interfaces for a variety of reasons that are not worth going into. But yeah, I mean, my general advice is use base classes when it makes sense. And then when it doesn't make sense, use interfaces. VICTOR: I especially like to use interfaces when I have similar functions, and I don't want different actors to have the same base class because they are vastly different but I still need to know how much health does is have or any of the other typical results. Being able to return that data and essentially call a function on a class that you don't actually have a reference to is extremely useful, especially during prototype phases when you're not sure about the entire hierarchy of all of the classes that you'll actually be shipping with the game. BEN: Yeah, totally. That's kind of the big thing, right? Basically every game should have like a base character class that's game specific. Like, I think pretty much every game ends up doing this. So that's a pretty natural place to put some of those like general functions. But yeah, I doesn't really make any sense to have like a-- vehicles and characters can't be the same base class really. So stuff like that, interfaces make way more sense for those. VICTOR: In the end, we always talk about performance and ways to manage it. But one of the most important things is that you can work with it as a human and understand what's going on. And so occasionally you can pay a little bit of the performance cost and take some of the manageability of the system over that performance cost. But always run your profilers to make sure that it's the right choice. That was our last question. I think we went through all of them. Yeah, another one about the Google plugin, which unfortunately, we're not aware. Maybe we can provide some information on that later. With that said, Ben, is there anything else you want to leave chat with before we sign off here today? BEN: Yeah, I think so, a few things. So I was thinking, I think I probably want to write up some of this in an informal form. I might throw this on the UE4 community wiki at some point. So people who don't like to read video, you know, people who don't want to watch a whole video to get some of the details out of it. So I'm probably going to write up something in the next few days, put it there. I'll link that in the forum thread if I do that. VICTOR: Yeah, I'll put it in the OP as well. BEN: In general, a lot of these systems are designed as kind of like a toolbox to be used by moderately-- these systems are mostly designed for like moderately-experienced programmers. Like if you're like a super-experience programmer, you've either already found this or you have your own way of doing this. But if you're like a brand new programmer, you might not be ready for that. But like it's a good moderate-experience programmer. So because of that, it doesn't do a lot of things all the way for you. The system is designed to do things like 95% of the way for your game. So think about that when you look into the systems and are looking at the headers and stuff. Like it's designed to be a toolbox more than it is like a all-in-one solution. I think it's really the only thing I wanted to say. I just pull my "who am I" slide I guess, and-- yeah, so you can poke me-- actually, your poke me at Twitter if you want. I think that'll work. Or obviously on the forum thread's great. And I usually think about this stuff fairly often, so there's a lot of interesting areas of combining gameplay and enginey stuff. And like I mentioned, Unreal Slackers has good discussions about that sometimes. So those are all different ways to get in contact with me if you want. I think it's everything I wanted to say from my side. VICTOR: Awesome, well, with that said, I do want to let everyone know that if you thought that it was a lot of content, and you wasn't really sure where we discuss something and you want to go back and watch the VOD, within a couple of days after the video-- we didn't stream to YouTube today unfortunately. But the VOD will go up on YouTube and we timestamp all of the Inside Unreal episodes, so that it makes it a little easier for you to find the section that you might be looking for. Within about a week of the upload on YouTube, we also provide captions for the entire stream. We also upload a link to the full transcript with timestamps on it. So that's also another way that you can go and download the transcript-- Control F and search for your key terms, and then find the timestamps where we discuss those specifically. Make sure you follow us on Twitter and all of our social media accounts. That's where all the great news will be announced first. As well as our live streams, future online events that we'll be doing this year, as well as all of the live streams. An even earlier look at the live streams coming up you can find in the events section Unreal Engine forums. If you enjoy our content, make sure you hit that follow on Twitch. And if you are streaming Unreal Engine content, there's actually an Unreal Engine tag that you can use, which makes it a little bit easier for us and others to find you and your content. I usually combine the Unreal Engine tag together with the game development tag. And then you can search for filters using those, which is pretty handy. Next week, we're going to have Michael Prinke covering the Chuck Downloader, which is somewhat relevant. Thankfully, he was nice enough to come on a little bit of last notice. So I'm excited for that. That news might go out Monday, Tuesday. But he will be on next Thursday on our regular time-- 2:00 PM, Eastern time. That said, thank you so much Ben for coming on and talking to us and explaining about the Asset Manager. And thanks to KaosSpectrum who reminded me that this was a topic that we hadn't covered yet on the live stream, so big shout out. Cool. BEN: I was very glad to talk to some of the stuff. Yeah, thank you for hosting me. It was a good experience. VICTOR: For sure. If we have any future updates to the Asset Manager, please let me know, Ben. And then we'll make sure to bring you back on the stream again. With that said, I hope you all are staying safe out there. We will see you again next week, same time. Take care everyone.
Info
Channel: Unreal Engine
Views: 27,410
Rating: undefined out of 5
Keywords: Unreal Engine, Epic Games, UE4, Unreal, Game Engine, Game Dev, Game Development
Id: 9MGHBU5eNu0
Channel Id: undefined
Length: 101min 9sec (6069 seconds)
Published: Tue Feb 16 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.