ChunkDownloader Explained | Inside Unreal

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
AMANDA: Hey, folks! Hundreds of Arabian Nights-themed environment assets and hand-painted 2D textures are now available to all Unreal creators--for free. Join us in welcoming Uppercut Games City of Brass and OTK Games The Vagrant to The Marketplace Collection, an initiative which brings high-quality content from Unreal Engine games to the Marketplace and download them all. And while you're snagging those new free assets, check out the deals of the future, today, during the Unreal Engine Marketplace February Sale! You can save big on a plethora of cyberpunk-themed products--including a killer robot samurai--in addition to amazing environments, effects, and more! The sale ends Friday at 11:59 PM EST, so don't miss out! Last week, we shared a sneak peek at the MetaHuman Creator, our new cloud-streamed app for creating high-fidelity real-time humans--and you met the MetaHumans! But did you know they're equipped with a complete facial rig to create a full range of human expressions? Cubic Motion's Adam Walton created a presentation to walk you through each and every control, so you can create everything from the most subtle smirk to the broadest grin. Watch the video on our YouTube channel and download the MetaHuman sample via the Marketplace to get started. Explore the afterlife in the puzzle-adventure I Am Dead, in which you assume the role of the recently deceased Morris Lupton--he is the island of Shelmerston's only hope against an impending volcanic eruption. Uncover how Richard Hogg and Hollow Ponds crafted I Am Dead's whimsical visuals, charming world, and inventive gameplay in our interview: NVIDIA has now released the DLSS Plugin for 4.26--DLSS is a deep learning neural network that uses the power of the NVIDIA RTX Tensor Cores to boost frame rates and generate sharp images in-game, while getting performance headroom to maximize ray tracing settings and increase output resolution. Find out more details on the NVIDIA DLSS plugin on the Marketplace. And wrapping up this week's news, we are proud to share that Epic Games Lead Virtual Production Engineer Alejandro Arango has been recognized with a Sci-Tech Award by The Academy of Motion Picture Arts and Sciences for his significant contributions to the widely adopted Technoprops head-mounted camera system. Congratulations Alejandro! Now over to this week's top karma earners! Many thanks to: Detach789, Everynone, ClockworkOcean, Kehel18, Shadowriver, chrudimer, LunaNelis, BenVlodgi, AnotherZach, and nofxboy1234 Diving into our Spotlights, French indie studio ASM Games is working on their turn-based RPG Oaths of Light, which tells the story of Eden, a young girl who stumbles into a journey of fate much bigger than she could have ever imagined. Learn more about Oaths of Light and support the small team on Kickstarter. And next up is Project Depto 478, a gorgeous--and stylish--modern apartment by Miguel Rueda built using Substance Painter, 3DS Max and Unreal. Head over to their YouTube page to watch the full cinematic on apartment 478 and see even more incredible abodes. The final spotlight this week is a series of scenes built to explore ray tracing and global illumination. These absolutely stunning pieces were created by Saga Alayyoubi, with inspiration from classic paintings, the Speed of Light demo, and others. Head to ArtStation and take a closer look at these great works! Thanks for watching this week's News and Community Spotlight! VICTOR: Hi, everyone. And welcome to another episode of Inside Unreal, a weekly show where we learn, explore, and celebrate everything Unreal. I'm your host Victor Brodin. And my guest today is technical writer Michael Prinke. Welcome back. MICHAEL: Hello, Victor. I'm glad to be back. And this week, we have an episode on the Chunk Downloader patching solution. Now, to start out, I want to outline what exactly the Chunk Downloader solution is and what it is designed to accomplish for you in your projects. So if you are building a live service game or if you're building a game that has to take frequent updates, like an MMORPG, or if you are running a mobile game that has to get patched very frequently, especially a mobile game, in fact, one of the major problems that you can encounter is large file sizes for your base executable on the storefront that you're shipping your game on. So, basically, if you have a really, really big executable, it just creates a whole lot of problems. A lot of store fronts will have either hard limits, where they won't let you put an executable of a certain size on the storefront at all. Or they will have a soft limit, where they will say, OK, after a certain size, you can use Wi-Fi to download this, but you can't use cellular data to do it. And even if you could do it, then large file sizes are really inconvenient on cellular data anyway. If you have a multi-gigabyte sized file, it could take a lot of time to download. It could start and stop a whole lot of times throughout the day. And that's just the kind of thing that makes users look at the file size on the storefront and say, mm, no, I'm going to pass on this application, I'd rather pick up something that I can play right now. That's a fairly typical kind of reaction. And while this seems a really trivial, petty kind of criteria for whether or not people are going to download your game, believe it or not, it makes a really, really big difference. That aside, if you are running just a general like live service type of product, like an MMO or something more on a modest scale than that even but that has to get patched very frequently, updating very frequently can be very painful and difficult to sustain if every update requires you to push a new version of the base executable to the user every single time. It is the kind of thing that users get fed up with very, very quickly. It takes longer and longer as the project grows in size. It's just not really sustainable. So the common solution to both of these problems is to separate out most of your games assets, like the textures, sounds, models, even maps, and things like that, and use a content delivery system to add or remove them at runtime as you need them instead of putting them all in the base executable and making the user install all of it all at the same time. Then you can reduce the base executable size down to something very small, something that you could measure maybe in the megabytes instead of the gigabytes. And then they can start that up almost immediately no matter what kind of connection they're on. And then the patching solution can grab files, basically, as the user needs them or as the application needs them in order to deliver the full user experience. And that is basically what Chunk Downloader does. Chunk Downloader is a patching system for delivering external files and mounting them to your running executable at runtime. So we're going to show you how to implement it in a project and all of the stuff that you need to do to prepare your assets to work with it. So to begin, let's hop on over to the Unreal Editor here for a second. The very first thing that you need to do, obviously, is make sure that the Chunk Downloader Plugin is enabled. And you can see, we have it enabled. I think that it's actually enabled by default in 4.26. This was added in 4.26, by the way, as a relatively new feature. To give a little background on where Chunk Downloader comes from, it's actually the patching solution that we used in Battle Breakers. It was built specifically for Battle Breakers, which has a large number of small files that it has to deliver for all the different puzzles and characters, and things. And so it wound up being a very clean solution for this type of thing. And it was good enough to document and good enough to put into the engine instead basically as a replacement of HTTP Chunk Installer, which is the older solution. We definitely recommend going forward using Chunk Downloader instead of HTTP Chunk Installer simply because it requires, I think, as you'll see, a little bit less setup. And it's a bit more user-friendly and easy to deal with. But, anyway, once you've got the plugin for Chunk Downloader enabled, we hop over to Visual Studio. And we go to the build.cs file for your project. And you just have to add to the private dependency module names the Chunk Downloader module name. And then it will be available for you to use in your C++ project. I've also added the HTTP module here so that we can make a basic HTTP request. I'll go over what that's for in a minute. Shout out real quick to Sebastian Hernandez, who is actually the Evangelist who helped prepare this sample project that we are showing you today and that we will be able to make available for you to download once this presentation is all complete. Sebastian has been very helpful with both this and the game playability system stuff that I showed of a couple of weeks ago. So I want to give credit where it's due. But, anyway. So once you've got all of that stuff ready to roll, the dependency module name setup and the plugin enabled, you are ready to start implementing. But before we go into actually implementing Chunk Downloader in code, I'm going to talk about the cooking and chunking process. So chunking. Chunks are basically groups of files that are packaged up into external dot PAK files when you cook the content for your game. What you do in order to separate things into chunks-- we might have gone over this during last week's stream. But I'll go over it again anyway. Last week was all about the Asset Manager. And this is all fairly related stuff. What you do is you either go into your Project Settings and go to the Asset Manager. And you set up your primary asset types there. But you can also set up primary asset rules, which are a lot of the information that you need in order to assign chunk IDs to groups of assets. Doing it through the Asset Manager in the Project Settings is a little bit clunky. So it's not the way that I prefer to do this. But you can do it that way if you have some universal rules that you always want to institute here. What, instead, I would recommend doing is using primary asset labels. So to make a primary asset label, all you have to do is right click in the Content Browser, go to Miscellaneous, pick Data Asset because it is a type of data asset. And then you pick Primary Asset Label as your type. I've already got a primary asset label in this folder for the bear character here. And this has all of the information necessary to separate your asset into a different chunk. By default, all assets inside of the Assets folder are going to be grouped into chunk 0, which is the chunk that is packaged with the base executable. If you set the chunk ID to something else, then the assets that belong to this primary asset label will be assigned that chunk ID instead. And they will be put into a pack file corresponding to this chunk ID. This is set to Label assets inside of this directory. And so everything that is just inside of this folder for the bear here is going to be put inside of chunk 2004. Another important thing to note here is the Priority. The Priority actually relates to the prioritization of secondary assets for this primary asset label. So the primary assets are going to decide who gets precedence of ownership based on this Priority. If it is a higher priority value for this, then it should take precedence. And if it has equal priority, then both assets will actually-- both of them will take ownership over the secondary assets that are assigned here. There are a couple of neat things you can do with primary asset labels, which I will talk about later in terms of extending this functionality and adding more information and metadata to this that you can use for managing assets. But for right now, we are just going to stick with the basic application of a default primary asset label. And the way that we have divided it up here, we have each of these characters with a primary asset label, it is a unique ID for each one. So for 2005, we have greystone for 2003-- wait, no, I think 2003. Yeah, 2003 is greystone. Sorry, misspoke. 2005 is this troll character. Decker is 2002 and so on and so forth. And they don't have to all be unique. You can absolutely take more than one primary asset label and give them the same chunk ID. And they will all contribute to the same PAK file, basically. But this is an easy way to make sure that each character is its own chunk and its own PAK file in the end. There are also a couple of other primary asset labels of note in this project. We have the Loader Primary Asset label, which is explicitly assigned chunk 0. That's kind of like a safety measure to make sure that all of the core files that we need to start up the application at all are all contained inside of chunk 0. And then we have two different variations of the user interface that's going to show up when we load into our game. And they are in 5001 for variant A and 5002 for variant B. And just so you know what they look like, variant B looks like this, where it's red and in the lower left corner with the text. And then variant A is blue. And it has the text in the upper right so they are easy to distinguish. I'll go over what exactly we're using those to demonstrate later. But that in a nutshell is how you organize things into chunks. You want to think ahead when you consider your chunking scheme. Basically, you want to make sure that all of your files are reasonably digestible and that they are all within a certain size range and that if you need an asset from inside of that PAK, you're not depending on something outside of that PAK file. Battle Breakers has an interesting scheme where they extended the primary asset label class and made, basically, a custom primary asset label class that has a concept of a parent chunk. So it designates not only the chunk ID for that primary asset label but another chunk ID that that chunk depends on in order to load. And so what they would do is chunk 1000 would be the basic stuff for characters. Chunk 1100 would be like a specific character. And then chunk 1110 would be a specific character with a specific skin and stuff like that. And they wrote the asset manager in such a way that it could look at the parent chunk ID when they were trying to load up that chunk and say, if I don't already have this chunk, let's load the parent trunk as well. And it would walk all the way up the ladder to get all of the chunks that was dependent on right back to the basic stuff that makes up the base of the game. There's actually a really cool tech blog that you can find, I'll see if I can dig up the link to it later, that describes the system in detail. And it's a really, really cool way of doing things if you have these kinds of interdependencies for your chunks. But by default, all the PAKs will be fairly independent files. And in order to generate your PAKs, you go to a Package Project, you pick whichever platform you are going to package. In this instance, I would hit Windows 64-bit. I'm not going to make you sit here and wait for me to package it. And then I would go to my Builds folder, where I have output the packaged project, go into the game folder, under Saved. And it will be-- no, it's not under Saved. It's under Content. Under Content, Paks. And this is the directory that it outputs to. In fact, let me see if I can hop up to one that I haven't modified-- Builds, Android18, nope, nope, nope. Heck with it, I will just go ahead and package it. Why not? Why not show you that? VICTOR: Easy enough. MICHAEL: Give it a second, doesn't take very long. So there's a step after this that I forgot about that where you actually take the PAKs out of the folder. So we need to see the PAKs in the folder first. But if you can't find it in there, there is another resource that you can look at. In the Project folder, there is a save directory. And you can go to-- where is it? StagedBuilds. And then that will have the Content, Paks folder in it as well. And you can see all of the PAK files located in here. That is the place you would look if you don't know where else to find it. For Windows, you should actually see it inside of your Final Build folder, like so. And if you are using a different platform, it will probably be under the StagedBuilds folder inside of the saved directory here. So if I go into the Android one, you can see that I have the Android version of all these PAKs lined up inside of this directory. And that is the other place where you can find those files. Now, just to make a quick point about the file size, here is chunk zero inside of the version of the project we just packaged. It is 108 megabytes in size. Earlier, I made a different version of this that does not have chunking enabled. And you can see that this is a file that is over 2 gigabytes in size. It is a much larger file. And that is what I would be asking the user to download to their device all at once if I were delivering that version of the project. It is just that easy to separate things into PAK files. The hard part is not making it output chunks. It is designing your chunking scheme in a way that makes sense for the final delivery of your content and that is sustainable and organized so you know what is in each of these files. And that's actually a worthwhile thing to talk about in the project settings. Make sure Generate Chunks is turned on under Packaging. This is something that you can turn off and on depending on the builds that you're outputting and then things like that. But that is basically-- that is something a prerequisite that you have to make sure that you have set. Otherwise, you are not going to get any chunks at all. But now that we have our PAK files generated, we need to build a manifest file. So what chunk downloader does, the first thing that it does is it grabs a manifest file that is basically a list of all of the PAKs that you expect to find on the user's device, all the ones that are valid for a current build of the game and that you want users to be able to download. And this manifest file must contain the following information. It is just a text file. And it contains the number of PAK files that you need that you are listing inside of this file so that it knows how many entries to read through. And then it needs a build ID, which is, basically, going to be either like a deployment ID or a sandbox ID. So as an example, Patcher Demo Live or Patcher Demo Testing or Patcher Demo Development. I'll call this one Development and set it to eight PAK files because we have 1, 2, 3, 4, 5 6, 7, 8 PAKs that we've divided this game up into. And then we need to make an entry for each PAK consisting of the name of the PAK file. VICTOR: Is pakchunk0 not considered one of the entries? MICHAEL: Correct pakchunk0 is shipped with the base executable. It is always available to your initial executable to access. It is not something that you need to concern yourself with in Chunk Downloader. But for the entries that we do need to concern ourselves with, we put in the file name. Then we put in the size of the file in bytes. And to do that, you can just look at the properties. It will be the size, not the size on disk. And we break that down without any of the commas or anything, just like that, this big ugly looking number. Then we have a version stream. This is an arbitrary string. This is something where you come up with your own convention for how you want to designate the version name of all these different PAK files. And whatever convention you use, it can just go into this arbitrary string for what the version is. Then you need the chunk ID. And then you need the relative path where this is going to exist on the web host, which is something that I'm going to get into in a minute. But I will just, for the sake of argument, call this Windows. And I will put the name of the PAK file here. And that is what's going to be appended to a URL that Chunk Downloader is going to use to try to fetch this file. It is relative to the location of the build manifest. So whatever folder this build manifest exists in, it has to be inside of the folder relative to this. So what I will actually go ahead and do is hop back up to this base folder. And I've got a PatchStaging folder here, where I have kind of pre-built the directory structure for the website where we're going to host this. And I've got a couple of extra things that I put together. So I've got a built manifest set up here with all the entries for all these different PAK files. And then I have a VariantA folder that contains all of the files that are relevant for variant A and a VariantB folder that contains all of the files that are relevant for variant B. You probably don't necessarily need to duplicate all of this. I could just as easily take and have a universal folder here or a universal Windows folder or something like that for all the ones that they share. But, basically, you remember that user interface thing where there was a variant A user interface and a variant B user interface, this is how I am separating them. So chunk 5001 is variant A. And that is going to be the blue interface. And variant B with the red interface uses chunk 5002. And these two manifests do not include each other's exclusive files. I hope that is clear to explain. The usual use case for something like this is if you had separate platforms. So if this were Windows and this were Mac or something or if one of these were going to be on Android and one of them was iOS, that would be a use case where you would set them up this way. But as it is-- I believe this is variant B. Yes, it is. As it is, these are just arbitrary for the sake of the demonstration at hand. So now we've got that all set up, the last thing that we've got set up in this Staging folder is this file called ContentBuildID.txt. And all of this has in it is the name of the build that we are going to get. It is PatcherLive. It corresponds to this folder here that contains the build that we are going to get. You'll understand why this file exists in a minute. There are lots of different ways you could approach what this is going to do. But this is one way of doing it so that the user doesn't have control over it. The idea is that you have this file that the user is accessing through the internet to check what version you want to put on their device. So if I wanted to make a Patcher Live Holiday for Christmas or something like that, then I could just edit this file. And that would be what eventually tells Chuck Downloader to grab this folder instead of this folder. And that's something that you could do. I think that's probably crazy off label use that I would get yelled at for. But that is a way to use it and a simple demonstration of how powerful it can be to control things with this remotely hosted file instead of hard coding it in the user's application. So now that that's all set up, we have to actually put together a locally hosted website where users will be able to access this. So first thing that you need to do is go to Turn Windows features on or off. It brings up this window here. And you need to turn on Internet Information Services. This gives you the ability to put together a website locally on this machine. And once you activate that and hit OK, it will take a minute before it finishes updating your machine and getting everything set up. Once it's done, you can open up Internet information Services Manager. And this will give you the ability to look at your locally hosted website, which, you can see, I've already got set up here. The first thing that you will have to do in order to make sure this works is go to this top level thing here for the local host. And you will need to open up your MIME Types. And in the MIME Types, you need to add-- let's see where it is-- dot PAK. That will tell it to recognize PAK files. And you need to give it a MIME type of application slash octet stream, just like that. And then once you have added that MIME type to your list, you can-- I didn't actually mean to close that. Then it will recognize that type of file. And you'll be able to download those from your website just fine. And then all you have to do is right click on the default website home, hit Explore, and then you can create a folder for your project. In this case, I've called it PatcherDemo. And all I had to do for this was take the stuff in my Staging folder-- darn it, I keep clicking the wrong-- so much white space on the screen to click on. All I had to do was take all of the stuff from this PatchStaging folder that I prepared with the variance, the PAK files, the build manifests and everything, and this ContentBuildID text file and copy it over into this PatcherDemo folder. And then it is available for me to use. It is on a website that is running on this computer locally and that I can access with the default refer to self IP address, the 127.0.0.1 IP address, which is just how to access yourself. Make sure that it is all running, that it is not stopped and everything. And then you should be good to go on the website side of this. And then, finally, the last bit of prep before we go into the C++ code and everything, we need to go to-- it's showing Explorer. I'm really lazy about opening my project folder. We need to go to Config, go to DefaultGame.ini. And we need to add this section here Script Plugins dot Chunk Downloader and then the deployment name that you're going to use for this build, which I've called Patcher-Live, Patcher dash Live. This is specifically a deployment ID that you are going to feed to Chunk Downloader. It is not necessarily the same as the build ID for the folder that you've got here. I just made it the same as the build ID name for the sake of not having as many names to keep track of. But you need to add CDN Base URL is equals 127.0.0.1 PatcherDemo. And then it will look for this website on your own computer and fetch that URL. And it will be able to access that website for download. This is a piece of information that Chunk Downloader will use internally in order to access all of those files when you make patch requests and, in fact, when you look for the manifest file, I believe. Are there any questions so far before I get into the implementation phase? I'll see if I can answer them. VICTOR: We have a couple. Yeah, if you want to go through it, we can do it now. MICHAEL: This is a good point to take a couple of them. VICTOR: Cool. MICHAEL: I'll see if I can answer them. VICTOR: I'm sure you'll do your best. Someone with a Cyrillic name that I unfortunately can't read is asking, "Is there any difference from mobile patching system plug-in-- which is available in UE4-- that you can use to download chunk files as well?" MICHAEL: This is a separate patching system from that one. In fact, this is the one that we would recommend over all the other patching solutions we've engineered with the possible exception of using Google Pad if you're doing Android app bundles. Google Pad is specific to Android app bundles and has a lot of automated features for fast follow and on-demand delivery of pack files as well. But yeah, the mobile patcher is a separate system that you don't need to use in order to use Chunk Downloader. VICTOR: ekiander asked, "How do you do versioning? Let's say, Chunk 200 is released in version 1.0, and then data is changed in 1.1. Do you just re-upload a chunk to your server, or do you make a patch?" MICHAEL: So what you do is you just-- depending on how you want to keep track of that, typically you would upload the new version of the pack file to your serve, and that is eventually what you're going to need to do. Where that lives and how you are keeping track of versioning is kind of up to you, at least that's as far as I understand it. You can kind of use the manifest in order to control what chunks are available to the user and keep track of a version string for your own purposes, but that's obviously not the same as passing differently versioned copies of pack files around. But the idea is that you replace things one pack at a time, as needed. And those are relatively small downloads to ask users to do. When Chunk Downloader looks at the manifest, it actually compares it against a cached copy of the manifest to see which one is the newer version and if they match. And it's using this bite size here to determine if the file that you're putting up is the same expected file size. So if it's not this file size, then it's going to want to replace it. I hope that makes sense. VICTOR: I think so. Yeah, let's continue with the questions. And then if we get into the next part-- MICHAEL: One or two more, yeah. VICTOR: OK, two more. We'll do two more. Epgenix asked, "Can you manage an entire game over the internet with a Chunk Downloader?" MICHAEL: Yeah. That's the idea. The idea is, you strip out most of your game's content into pack files like this, which is an extensive thing to do. If you do this for an entire project, you could have hundreds and hundreds of lines of chunks with all kinds of different-- that's the reason why we're not using Chunk001 or Chunk002. We're using 2,001 2,002 2,003 and so on. 2000 we have set aside for characters here. And then the end number is different characters. And then 5,000 is these different UIs. And then 10,000 here we have set aside for the level file, actually, the map that you load into when you start up the game. That is the convention we are using for this demonstration. You can decide to use whatever convention you want. But however you set this up, the manifest file relative to everything else in your game is going to be a really, really small file. If it measures in the megabytes, it'll be kind of surprising. Sorry, I thought I heard something. But yeah, that's basically the idea, is that the base executable you're giving the user is this minimalistic start-up flow kind of executable. And then everything else that you have is kind of delivered on demand or in packages depending on what phase of the application you're in. So you might make a chunk that is dedicated to a specific character, and be that granular about it. Or you might make a chunk that is dedicated specifically to the first time user experience and all the stuff that you would expect the user to experience then, like the tutorials and the first level of gameplay, and all that kind of stuff that they would basically play in the first 15 minutes. In fact, it is a very common convention to have an asset package like that for the first time user experience in many of these different types of games, and very quickly load it up as one of the first things that you deliver during the patching process in-game. VICTOR: Cool, let's do one more. Giulio Dionisi asks, "Can we use the Chunk Downloader to update config files or is it content only?" MICHAEL: This is for assets. This is for anything that you would put into a pack file. Config files are a completely different-- I'm not actually completely sure if there is a way you could do that, but I don't think so. I will get back to you if I turn up any information that says otherwise. But I think if you're changing the configs, then you're stuck updating the base executable. The good news is that if you think ahead about how you are handling chunking and things like that, updating the base executable does not have to be that painful and you shouldn't have to do it that frequently. VICTOR: Cool, yeah. We can do the next questions. MICHAEL: But I would think that basically if it is not inside of the assets folder and not visible to the content browser or the asset manager, that is the key. It has to be visible to the asset manager in order to be cooked into a pack file. And very sorry about that, Douglas Adams is barking in the background. There's probably a dog outside that he wants to say hi to. We will have to continue on anyway. VICTOR: Do we get to see him on the stream again today? MICHAEL: We just might, if he decides to come in here and be demanding. Dachshunds are very stubborn, man. OK so, now we get to the fun part of actually implementing the code for Chunk Downloader. Now that we've done all of that set up-- which by the way, if you get stuck on it and you fumble around for a while, it is the most finicky part of setting this whole thing up. A lot of information in this depends on the name that you give the website folder, the name that you put into the config file, and all of that sort of thing. But fortunately, once all of that is set up, the process of working with Chunk Downloader in the game's code is relatively easy. That's going to drive me nuts. VICTOR: OK, he's pretty low on our end. MICHAEL: OK, that's good. So the easiest way to handle Chunk Downloader is to make a custom GameInstance class and initialize and shut down Chunk Downloader there. And then when you want to implement different Chunk Downloader functions and expose them to Blueprint, or expose them to different GameModes, or whatever else needs to have visibility to Chunk Downloader, it is always in this class. And this class is always available anywhere that you are running your game. GameInstance is like a singleton class that is Blueprint accessible and that is just very easy to refer to no matter what GameMode you're in, no matter what map you're in. Wherever you are, you have GameInstance. So to walk through this one. So the process for setting up Chunk Downloader is first, you need to get a TSharedRef or a Shared Reference Pointer to Chunk Downloader using FChunkDownloader get or create. Chunk Downloader is a singleton class that exists in the background. And get or create will either get a copy of it-- well, not a copy of it-- but a shared reference to it, if it exists. Or it will create an instance of it, if there isn't already an instance of it running. And that's how you instantiate Chunk Downloader. You then call the Initialize function and give it a string with the platform name that you're using and an integer value for the number of concurrent downloads in flight that you want to allow Chunk Downloader to use. You can set up a lot of logic to decide what this number is going to be. We've got eight here as just an arbitrary number that's pretty standard. But you can decide to set this lower or higher, based on information that you've got about the user's network or the platform that you're using, or whatever. If you want to allow more or fewer streams, that is something that you can totally do. Once you have called Chunk Downloader to Initialize, then it is up and running and ready to be used. The first thing that you need to do once it is up and running is call LoadCache to build with the DeploymentName for your build, which is going to be in this case Patcher-Live. This DeploymentName is the same thing as what is written here in defaultgame.ini in this section here for Chunk Downloader That name should be the same as this name, basically. Otherwise, when it looks for the CDN URL or any other data that you need inside of the default game config, it will try to find the other ones you've got. If I put in Patcher-Development, it would try to look for this instead. But if I don't have that there it won't find it, and we will get errors and it will try to fall back to a local version of the manifest file. But otherwise, LoadCacheBuild with the DeploymentName, that will try to load up a cached version of the manifest file for comparison against the version that you are going to download. The next thing that you need to do is actually run the Update Build function. And that is going to take the DeploymentName, that is going to take a BuildID-- which I'm going to go over how we're acquiring that in a second-- and then a callback, which we've written in a Lambda function here for what to do when it is finished getting the new manifest file. And then basically, once that is all done, Chunk Downloader is initialized, it has the updated manifest file, and you are ready to download files with it. To be clear, UpdateBuild does not download any files other than the manifest. It just gets the manifest on your computer so that Chunk Downloader has this clipboard that it can look at to see if it's a valid set of chunk files that you're asking it to download later. But we're going back up for a minute and walk through the flow of how this thing is set up. So what we've got here, we have PDGameInstance in it, which is not really doing anything here, but you could initialize Chunk Downloader here if you wanted to. And then we have the shut down function, where we call Chunk Downloader ShutDown. So any time the running GameInstance shuts down, it will also tell Chunk Downloader to stop, unload itself, and all of that good stuff. The ShutDown function actually does a lot of different things under the hood. It is not just unloading the Chunk Downloader module, it is also unmounted any files that are currently mounted in memory. And it also stops any downloads in progress, and then it will shut down the module. So it is a nice, safe method to call to just turn off everything Chunk Downloader is doing. But the component methods for that are all available inside of Chunk Downloader as well. So those are the basic things that you should make sure your game has so that you are starting it up and shutting it down safely. Thereafter, the rest of this stuff that we have defined in this game instance class is all Blueprint callable functions and Blueprint pure functions that are designed to just expose things to Blueprint so that we can manage the patching flow inside of here once all of the setup is done. So I'll walk you through the full flow. The first thing that you end up calling here or that this application calls is InItPatching, which would be like on Begin Play or something like that in a game mode. We feed it this variant name and that corresponds to these variant names. Variant A and Variant B. And that is why we have appended Variant A and Variant B to these different manifests. This is normally the platform name that you're looking at, which is why I made the point of renaming those for Windows and Mac, as a little demonstration earlier. Usually you would tell it what platform you're looking at, and then it would try to fetch a manifest that corresponds to that platform, and that would tell it to grab these files from this platform folder and stuff like that. So that is stuff that is getting fed in through Blueprints. I will go into-- not there, but in LoaderCore in the GameMode. This is where it is set up. We do Begin Play and we grab this GameInstance, set GameMode-- where are we calling that? There's InItPatching, right. So we actually have a user interface for this where we have a button for Variant A and Variant B, That's why it's set up in that arbitrary kind of way instead of based on a platform. Then we call PatchVariant in our GameMode class, that runs InItPatching with the Variant name that we supply from the user interface. And that will set up this platform name. From there, we have a basic HTTP request. None of this functionality is Chunk Downloader stuff. This is just the basic HTTP module doing a simple request to grab an object from the remote website. And we feed it this patch version URL, which is contained in here, under the Protected Properties here. It is just an F String with the URL. And inside of the Blueprints is where I'm actually defining it under this Blueprint version of the GameInstance. So this inherits from the game instant class in C++, and the version URL is just written in here along with an array of chunk IDs that we want to download when the application starts up. So this path to the content BuildID text file is what is getting called here. And all we do is we set up this request with that URL. We set it up as a Get and we set it up with this delegate here to run on PatchVersionResponse. This is the one piece of code here that is not exposed to Blueprint, it is on PatchVersionResponse. This is a very common design pattern. If you are not familiar with web programming or network programming, asynchronous processes are a very common design pattern when you are grabbing information from across a network. Where you tell it to make a request to some remote host, and then the remote host starts an operation or you start downloading a file from it, and then you listen for a response and then fire off a delegate when it's done. Or in this case, when the download is finished and this request is all processed, it will fire off this delegate. This makes it so that you aren't sitting there writing things in the Tick function waiting for this to be finished. But once on PatchVersionResponse is fired off, it will get the content BuildID from that text file as a string. This is, again, this text file. So what it'll get is Patcher-Live from this text file and it will tell it, this is the folder that I want to get, this is the BuildID name that I want to use. You could organize this any number of different ways. I could change this to 1.0.1 or something like that, and then change this folder to 1.0.1. I could have dozens of folders with back versioned versions of this game live on here for whatever purposes I deem fit. But in this case, I just named it the same thing as the DeploymentName, because I'm lazy and get confused with names. But once you get that content BuildID, we can feed it in through UpdateBuild along with the DeploymentName. Otherwise, in between those steps, we are just following the basic initialization flow that I was talking about before where we do get or create, initialize with the platform name that we are designating. This is for its internal management purposes. It can be an arbitrary name if you feel like it. But basically, as long as this is a consistent name for whatever platform you're doing, that is what it's expecting you to do. And then we run UpdateBuild with this manifest complete callback, which is what we call when the manifest finishes downloading, which is a nearly instantaneous thing that fires off because the manifest is such a small file. The one thing that we are having this do, we are telling it that-- we're setting this flag for this Boolean saying that the manifest is or isn't up to date, and we are firing off a delegate called OnPatchReady, which we have declared here. And all this is a multicast delegate that is declared up here, PatchCompleteDelegate Bool succeeded. You get the idea. And this is just a Blueprint assignable function. And what that allows us to do is it allows us to respond when the patching system is fully initialized and the manifest is completely up to date. Here in this GameMode is where the OnPatchReady delegate is implemented. And we actually start it up in Begin Play by binding that event to the delegate by grabbing a copy of the GameInstance. And we actually have a cached copy of the game instance for that purpose in this demonstration. That's what these are. These are grabbing that OnPatchReady delegates out of the GameInstance and just taking these Blueprint events and saying, this is what you're going to fire off when that broadcast call happens. And then after that, we just go right into calling PatchGame. I hope that this is easy to follow so far, because I know it's a little bit of jumping between different classes and different implementations in Blueprint and C++ so far. But this is a fairly clean way to do things just to get it up and running. You could of course, instead of calling OnPatchReady.broadcast, write a C++ function that has all of this stuff written to it already. I could just call PatchGame like this, if I felt like it. Maybe with a couple of extra checks to make sure that the manifest is up to date and that other conditions are met and we're all safe. But just to make this sample easy to play around with, that's why it's all this Blueprint implementable or Blueprint assignable kind of model. So let's see here. So next InItPatching, OnPatchVersionResponse, OnPatchReady. I went over ShutDown. So the Patch Game function is what gets called next. Just right out of here, based on whether or not OnPatchReady succeeded. And that is where we demonstrate downloading files for the first time here, for this demonstration. Patch Game is basically a function that we have written to grab the first batch of files that we need in order to do anything with the game. In this case, it is grabbing information from Chunk Download list-- which again is here under the Chunk Download list that I've defined inside of Blueprint. And we have chunks 1,001 5,001, and 5,002. That is the map that we are going to go into. Not the loader map, but rather the Blueprint office map. So you are here with 1,001. And that is the user interface that we've got set up for each of the different variants. And so, those are the prerequisite files that it needs to download and mount before we can move on to the next scene. And all this really is doing-- we obviously check to see if the manifest is up to date. We have this kind of safety check in place. We use Chunk Downloader GetChecked in order to get a reference to Chunk Downloader. Again, it is a Shared Reference Pointer, so you don't need to cache a reference to this. And then, just for each and every one of these in the list-- well, we actually call MountChunks, which is the function that you call in order to mount every chunk in one big T array. Or rather, is it a T array? Is it actually a T array? Let me double check that. It is a T array. Cool. This is the function that you call in order to-- getting a little turned around here-- in order to process all of the chunks in one big list of integers. And this is the way that it references chunks by the ID number that is assigned to it. There are two functions of note here for this kind of process. There is DownloadChunks, which all it does is download all of the chunks in the list and put them on your hard drive. And then there is MountChunks, which will look to see if you already have them. And if they are available, it will mount them. If they are not available, it will automatically call DownloadChunks and try to download those chunks for you. It can seem like a really good idea to just use mount chunks everywhere, but a lot of the time, if you want to preload stuff, or if you want to think cleverly about it and kind of express some forethought, DownloadChunks is the way to go in order to make sure that the user is prepared with the chunks already available on their device. And again, this is starting up an asynchronous process for downloading these chunks, so it uses this MountComplete callback, which we have written inside of this Lambda function here. And it is simply calling this OnPatchComplete delegate when it is finished to let us know that this big master patch that we're asking it to do with this whole list of downloads is finished. And there is exactly one place that we are calling this, and that is inside of the PatchingGameMode that runs on startup before we jump into gameplay. And I will show you what I mean by that in a couple of minutes. This is a lot of long waits for payoffs, so I do apologize. But I feel it's important to do the walkthrough of what conceptually is happening in the code, then show it. So the other implementation that is useful to know about is downloading single files at a time. So that is why we have this DownloadSingleChunk function declared exposing the functionality for grabbing a single chunk at a time. And the only difference here is that instead of calling MountChunks, we are calling MountChunk, singular. And it only takes one ID and does one file. Again, there is a DownloadChunk function that does just the download without the mounting. Important thing of note that I might have glossed over earlier. So there are two steps to this. There's downloading the chunk to your device and sticking it in the cache resources folder for your game. And then there's mounting the chunk, which is what makes it available. Mounting the chunk basically it's what it sounds like. It mounts the chunk in memory. It takes this pack file and it puts it in active memory for you so that all of its files are available. As though you were using the content browser inside of the editor, but not exactly. That is another reason why it is important to express forethought in how you organize your chunks, because you could just as easily end up making a two gigabyte chunk file that just takes up a ton of space once it's mounted in memory. Whereas, if you use a bunch of smaller ones, you could manage things maybe a little bit more efficiently and a little bit more piecemeal. Just something to think about when you are thinking ahead. But this also calls a MountComplete callback, which is another Lambda. And it has its own OnSingleChunkPatchComplete delegate that it fires off when it's finished. And that very simply is how you ask Chunk Downloader to download files for you. It is a little bit chunky to write out. A little verbose, so to speak, when you are writing it in code like this, because there's all these levels of error handling that you're doing before you get into it. And there's this need to do these delegates and callbacks to respond when you have finished downloads and mounting jobs. But generally speaking, it is a very intuitive way to handle ChunkDownloads. Now that we've got these functions written up, we have this method exposed to Blueprint to doing really simple ChunkDownload requests. So one last thing I want to do before I jump into the Blueprint side and show you a look at some of the things going on there and show you how this works live, I do want to call attention to this function GetPatchStatus. Basically, it is retrieving the loading stats with the Chunk Downloader GetLoadingStats function and outputting it to a special struct that converts the download size of our files into megabytes. So normally, the information that Chunk Downloader is tracking for download progress is stored as UN64. Which in Blueprint, you can't access UN64. So it's not something you can display very easily to users. So we just have this secondary, alternate version of that struct, that display that we are converting that information to megabytes to kind of make it smaller and quantize it. And then we are setting it to an int 32 so that it is something that Blueprint can actually read and so we're not as likely to get overflow issues when we are displaying this information. But basically to get the stats, all you do is you call GetLoadingStats and it will tell you what the current progress of downloads is. There is also a BeginLoadingMode function that you can use to set up special functionality for a loading screen. This demonstration kind of skips that implementation in favor of just using this GetPatchStatus thing to get that information. But BeginLoadingMode will start a mode where it is continuously outputting information through a callback, and then you can use that to track information until the download is completed. And then otherwise, another handy little utility function here IsChunkLoaded. That simply is checking GetChunkStatus. GetChunkStatus will actually output an enum for you, telling you the exact status of the chunk. So we have Mounted for if it is loaded in RAM, Cached where it is downloaded and available on your hard disk, but not mounted yet. We have a DownloadInProgress. We have Partial, where you have partially downloaded it. You have this incomplete file that is not currently being downloaded. And then, statuses for whether or not you actually know whether the status is unknown and whether or not there is actually a-- whether it's not on your disk at all, but it is remotely available. So it's a useful utility function here. We are simplifying this simply to whether or not the chunk is loaded, which is being used. Is it used anywhere in C++? I don't know that it's actually used in the sample, but it's just a handy thing to call attention to in terms of utilities for checking out what the status on your patch is. So now, finally, why don't I actually run this after all this time talking about it. VICTOR: Yeah, let's see it. MICHAEL: --And show you Chunk Downloader in action. Before I do this, I'm going to go to the content folder and I'm going to delete all of these PAK files here. Because, if you leave those alone, it will detect them and it will try to load them up. So you don't really want to do that. I also don't need this BuiltManifest file that I put together just to show you how to write a manifest file. I'm going to go into saved, go to the persistent download directory, and delete these. I'm actually just going to delete all of this, just to make sure we have a clean start up on this. And I'm going to run PatcherDemo.exe. I have to move the window here. OK, so this is the UI. When I click this button, it is going to call the PatchGame function with Variant A as my String. Now that it has begun patching, it displays the loading bar, which is using GetPatchedStatus to output the information on tick to this user interface as it downloads these megabytes of files. It should be getting 5,001 and 10,001, which is a level and a user interface. And now, we see UI Variant A loaded up. And if I hop outside of this and go to the saved persistent download directory, you can see 5,001 and 1,001, just as I predicted. And we can look at the local manifest, this is all of the stuff that it has downloaded and you can see it all listed here. And then we have the CachedBuildManifest, which is the version that it downloaded from our site from Variant A. And this is what it's going to check against the next time we try to do a download. It is going to use this cached manifest file to determine whether or not the file that we're trying to download is valid. Now, we have these mysterious actors. What could these be, Victor? VICTOR: I don't know, perhaps an on demand Chunk Downloader interface? MICHAEL: Yes, as a matter of fact, that is exactly what these are. These actors have been set up to basically act as placeholders, and they have a ChunkID and an Actor class assigned to them. I'll talk about how to reference things that are delivered in pack files in a minute. But basically, the Actor class that it's referencing is contained inside of that pack. And when it finishes downloading, it will spawn that Actor and get rid of the placeholder. So I hit E to download. And there we go, it spawns this bear. And that is the actor that was contained inside of it. If I hit this here, it gives us the progress bar, gives us the troll. And I will check this one as well. This is a much bigger file, so we can see it in action. I believe this is Dekker from Paragon that it should be getting. One caveat for people who wind up looking at the sample, I know that there are a couple of problems that come up if you try to start multiple on-demand downloads at the same time. You should, in good practice, probably be queuing them up instead of trying to run them concurrently. I'm not sure what the nature of that is, it's a heads up that Sebastian gave me, and I am simply heeding his words. And I have had a crash once or twice trying to do it in this implementation. In a live game, you would do a lot more error checking and a lot more-- you'd implement more safety features in order to make sure that you don't get your wires crossed when downloads are in flight. But you can see, it loaded up Dekker, and she is now in our level and available for the game to use. And if we hop back into our persistent download directory-- and this is just in the saved directory of our build output-- we can see that chunks 2,002, 2,004, and 2,005 have all been downloaded onto this device. Now if I hit Alt-F4 and close this out, I will actually do another quick little demonstration. This is the wrong folder, because I am a fool and closed the window. Show in Explorer. Builds. Pack cache, here we are. I will go ahead and delete all of this again. And I will run it a second time. I hit Alt-F4 instead of bringing up the console and resizing the window. And I will hit Variant B. Now, it is patching once again. It is loading a different user interface. And let's have a look at the download directory and see what's going on here. So there it is, finished getting pakchunk5001 and that is now available. Should it be 5001? I think so. Unless I did something stupid with the manifest. I did something stupid with the manifest, didn't I? Yes, I think I did something stupid with the manifest because it's supposed to 5,002. Let us do a little bit of debugging here, then. Hop over to PatcherLive, Variant B, and it is listing 5,002. Interesting. 5,002 is present, OK. But the CachedBuildManifest is listing 5,001 still. So let's go ahead and delete those. They should be getting cleaned up when I call for the new manifest. So it's a little bit strange that that's going on, but it might be because of the goofy way that I've got the pack files organized, or something like that. It could be that maybe you should have both files in the manifest anyway instead of trying to-- I think I know of a way that I can make this a little smarter. Hop into PatcherLive, grab these out of here. take that BuildID. Maybe it's because they've got the same BuildID is what I'm guessing. Let's give that a try and see if that works. I am learning right alongside all of you guys here today. And then we need to go back to PatcherLive and stick these manifests back in. So I know that it will work based on deleting that manifest, let's see if renaming this manifest's BuildID field is going to make Chunk Downloader wake up. Is this the same folder? It's the same folder. OK. I've been jumping in and out of these folders all day, so there are so many of these open. All right, now let's hop back to the exe. And I will hit Variant A. OK, so it is actually expecting that to match. PatcherLive has the DeploymentName, I believe. So let's go ahead and put that back the way that it was and I will simply do a little more research on the correct way to format this kind of thing. I tried to get a little too fancy here, so it's doing a couple of silly things. Get rid of Variant B, now that will correspond to the DeploymentNames and everything that I'm actually using. Hit Variant A, and now it's working again. A little bit of live debugging and experimenting. VICTOR: It's always good, you can learn quite a bit from seeing how someone approaches a problem. MICHAEL: And I will just go ahead and hit Alt-F4 in the middle of this, go to the persistent download directory, and you'll see Chunk 10,001 is not present because it never finished downloading. It basically cleaned itself up, I believe. Or rather, Chunk Downloader has some features to clean that sort of thing up. But I will go ahead and run it one more time. Actually make sure that I clean up the manifests that I've got here as well, why not. And this should be a proper demonstration of using Variant B. VICTOR: You want to take a question while we wait for it to download? MICHAEL: Yes. VICTOR: Let's see, ekiander asked, "Manually making manifests seems very labor intensive. HTTP ChunkInstaller makes those automatically, or at least setting build HTML download does that. MICHAEL: Yes. I don't know if we've got a way to automate that process built-in anywhere. But it would be-- There's Variant B. That's what I would expect it to look like. Sorry about that. So, I believe that Battle Breakers had their own utility for compiling manifests based on the pack file-- you could write a batch file, I think, that could do that for you. Or you could write any kind of standalone utility to do that sort of thing. But I don't think that there's anything built into the Editor that's going to output the manifest for you just yet. But that is something that we are taking into consideration. VICTOR: Cool, yeah. Was there more presentation, Mike, or should we continue with questions? MICHAEL: There is more to the presentation, believe it or not. VICTOR: I figured. MICHAEL: There's a lot of stuff happening to make this incredibly simple demonstration work. OK. So to show a couple of the things that were happening in the back-- why is this highlighted in black the way it is? To show a couple of the things that were happening in the background while this was running-- So OnPatchReady runs. That runs PatchGame. And then that will call the ShowPatch function inside of the user interface, which all that does is it shows the visibility and it will update based on the PatchStatus that you feed in through UpdatePatch. And that is being called through probably the tick function. Yep, on tick, it will check if it's patching, and it will call UpdatePatch on the UI and feed it the PatchStatus. So that is how it's showing the progress bar for the initial patch. And again, all that is this list of chunks that it's trying to download based on this list in this initial set up here, in the GameInstance class. And then, for the user interface, the way that it's displaying that user interface, it is actually caching it, so we call PatchVariant from that user interface and feed it the String for the variant name, but we're also feeding it to the UI class. And rather than being a hard class reference, it is a soft class reference. Those are distinguishable by the soft pink color here instead of the purple color here. And likewise, the startup level for Blueprint Office is a soft object reference, which we can find here at this OpenLevel function that gets called once everything is finished loading. Let me see if I can find the actual references, OK. So when you are separating things out into pack files like that, you want to use soft references to classes and objects. Because basically, you don't have a guarantee that they are going to be present. And soft object pointers and soft class pointers give you a chance to do error handling when you try to resolve the reference to them. OpenLevelByObjectReference is a class that just opens up levels like that. And then UI variant is not handled in here. What happens is in the character-- let me see if I can find it, it should be under-- is it under Blueprint? That is the first person character pawn. That's not the one I want. I want the third person pawn. There it is. This is actually implemented in the third person pawn, I believe. On Posses I think. Yes. So on Posses, it reaches into the PatchingDemo GameInstance, grabs this cached UI variant that we loaded from the pack that we downloaded. We do an async load for it. And then once it is finished loading, we can create the widget and add it to the Blueprint. These are the extra steps that you add for resolving this class reference. And likewise, for soft object references-- let me see if I can make a new soft object. You can use ResolveSoftReference if the Actor is available. If the object reference is actually present on your device, then it could actually resolve this into a hard reference. But otherwise, it will give you a chance to check if this is valid or not. We do have an Is Valid Soft Object Reference function for taking care of that. That is the safety feature that you need to implement any time you are referring to that sort of thing. And we can see this in action in the DownloadablePost object, which has a lot of stuff for showing the UI when you get close, letting you hit the Use button to activate it, and all of that stuff. It has its own widget component that is attached above it that is used for outputting progress. And that just updates on tick the same way that the PatchStatus updates in the start-up screen. No, not the way. This is the start-up screen. I'm sorry, I'm looking at the wrong thing. That's very silly. Get Patch Status. OK, it is actually doing something similar here. Yep, it is just the same thing. OK, it is the same thing, I'm not going crazy. Maybe a little crazy. But the main feature here is Start Download, where it gets the download progress set up on that progress bar. And it will run the Spawn and Replace function when it finishes a download. And it's just doing an async load class, similar to how we were doing it for the widget. But after you cast it to the Actor class, you can actually spot it. So that is basically how you set up this kind of thing, at least a really simple implementation of this kind of thing. Another thing that was really cool in Battle Breaker's implementation was the asset manager had a default asset setup where if you tried to fetch an asset and it wasn't available or it wasn't finished downloading, it could display like a question mark texture instead of a character's portrait or things like that. So that is a nice best practice that you could follow for that sort of thing. In a nutshell, that is a dirt simple implementation of Chunk Downloader, or at least with a couple of bells and whistles that you would commonly use in a game of your own. If you wanted to expand on this, then customizing the asset manager would be a really good idea so that you can manage the different download phases, you could add some metadata to your own custom primary asset label classes and use that to resolve like parent chunks, or even assign the phases for downloading. If you want to have on demand assets versus first time user experience assets, versus title screen assets, you could add that kind of metadata to it and use that to fetch entire lists of chunks like that. There's all kinds of ways that you can use this in order to manage your downloads. And there are still many other features in Chunk Downloader that I have not covered in terms of its cleanup, error handling, and things like that. But you can delve into-- basically, just look at the API reference and it is actually pretty reasonably well documented in terms of how the code comments are set up. So the API reference has some good information for it. Now, I guess I will open the floor to Victor and more questions, if I can answer them. VICTOR: For sure. We got a couple. There were a couple of questions in regards to the documentation. I believe it is the patching site. And that is all up to date, right, with some of the information you're talking about today? MICHAEL: It should all be up to date. I know that we had a few formatting issues that we needed to iron out this week. So there might be some updates that have not yet been pushed that I corrected between yesterday and the day before, basically. I do actually want to do another pass at those tutorials. Because since diving into this in depth for the stream, I've actually gotten a clearer idea of how a lot of these conventions are supposed to work. And some of the naming conventions that we picked for the remote website, and the deployment name, and the build ID, and stuff like that, some of those could be more intuitively named, I think. But yeah, it should be reasonably up to date, barring any lingering issues that have not been caught in the updates in the last couple of days. VICTOR: saxhack had a question. "Does info in the manifest have to be separated by tab?" MICHAEL: Yes. It has to be tab separated. In fact, that was a formatting error that we caught-- whoops-- in the sample stuff. This version String had a space where it was just ver- space, and then the number for the ChunkID. It should be a tab. VICTOR: Sorry, I was muted. edfedermeyer asked, "If we limit the number of concurrent streams, is there any guarantee for the order they will be downloaded? For example, if we really wanted the F to UE download to start downloading for sure as the first one, and other stuff in whatever order." MICHAEL: Interesting question that I think will require a more in-depth answer than I am prepared to give right now. I'm not sure how it is managing the concurrent download streams under the hood, is the thing. I know that ideally, if you tell it to start a download stream-- like whichever one you start up first should probably take precedence. So it should just be a matter of controlling which list you want to download first by ordering it to download that one first, and maybe using a set of booleans or callbacks in order to-- in fact, I'm remembering from looking at the implementation now. Yeah, the way that I think Battle Breakers handled this, they would have a set of callbacks for each of those different phases and they would call them one at a time and wait for each one to finish before starting the next one. I think, at least, that that's how they handled it. But maybe I'm misremembering. That is the ultra, ultra safe way to handle it. I think the concurrent download streams probably refers to how many individual pack files you're allowed to have in-flight. But maybe don't quote me on that. Let me get back to you with more precise information about what's happening under the hood and how you can expect it to work if you try to cue more than one set of downloads at a time. But I think that the likely intended usage is for you to hold off until one list of things is fully downloaded. VICTOR: We can follow up on the formal announcement post thread. MICHAEL: Yeah VICTOR: If we're able to get some more information on that. m_9_ez asked, "Is it smart enough to resume partial downloads, or does it restart from the beginning?" MICHAEL: It'll resume partial downloads if the manifest matches, basically. It will cache the partial download and try to keep it around until you-- so I'm not sure where it actually caches partial downloads. I know it's not in the final Persistent Download Directory here. But I do remember that it keeps the partial download around until the next time you try to run the same download, as long as there isn't a change to the manifest and everything is copacetic with what the remote website says, it should be fine. In fact, I think I remember seeing that while we were playing around with some of these files here. Yeah, I remember quitting out of this and then jumping back in and finding these resuming their downloads. VICTOR: DarknessFX affects asks, "Is there a security feature to block users to replace the local manifest and chunk pack to add hacked content?" MICHAEL: Hmm. So, security features are not my personal forte. That is something I'm going to have to get back to you on. VICTOR: It's a good question, though, because it seems like-- MICHAEL: It's really-- I've been wondering about it too, actually. I was half expecting to get that question. So a lot of security features I know are going to depend on how your website is set up. This local website that I've got is obviously not a very secure implementation. You would expect there to be user accounts verification involved before users can get at that sort of thing. And you might expect some kind of encryption key in order to access those kinds of files and download them. In terms of the local files, I don't know. That's not my area of expertise. VICTOR: Chris Moerland asked, "What would be the process for de-installing packs?" MICHAEL: For uninstalling packs. So that is a very interesting-- so when you get a new copy of the manifest, if it does not match the old manifest based on the BuildID that you are using, it will get rid of files that do not match. And it will also try to get rid of-- let me see-- let me grab Chunk Downloaders functions here. Cache build, update build. OK, FlushCache will get rid of anything that is not currently in the process of being downloaded and anything that is not actively mounted. Is that a public function? Yes, it is a public function, so you can call it. And ValidateCache will check their version hash, which I think-- well, I probably shouldn't make guesses about how that is working under the hood. But yeah, these are the two methods you would mainly use if you wanted to manually get rid of chunks that are not needed on the user's device. FlushCache is going to be fairly drastic. That's going to probably clear out literally everything that is not currently mounted and just clean the whole thing. ValidateCache is going to get rid of anything that is not up to date and not expected to be there. VICTOR: edfedermeyer had another question. "In the web documentation example, there seem to be a lot of issues with N32 versus N64 and parameter order in that Get Loading Process function." Are you familiar with that, Mike? MICHAEL: Let me see. So that's probably the Quickstart guide, is that correct? N32 versus N64. I think I know exactly what that's talking about, in fact. Yeah, this isn't up to date yet. This is another formatting error that we fixed. This dollar sign should not be here in the manifest file. This is supposed to be a code title bar, similar to-- is this just-- maybe I need to clean my cache out, because I remember seeing this all. That's supposed to be a code title bar that looks like this. That's disambiguating what file you're in. But something went wrong in formatting and the new update to this page has not been pushed to the live site yet. I will apologize for that. But the main thing that you need to fix in order to get that N64 error to go away is you need to make sure this is tab-separated, you need to get rid of this dollar sign here, and then this will be a correctly formatted version of a manifest file. Apologies for that. And I'd hoped to have that update pushed by the time we were doing the stream. Alas. VICTOR: Alas. And with that said, I think those were all the questions that we're going to take today. So Mike, thank you so much for coming on and talking to us about the Chunk Downloader. MICHAEL: I hope that was all helpful and I hope that was easy enough to follow, because that was a lot. VICTOR: Quite a bit. Well, we can do a little update on the formal announcement thread when the documentation has been updated. We are also going to upload the project for you to take a look at, give or take a day, until we have that up for you. And then you can break it down and take a look at all the assets that Michael was working on here today. With that said, I do want to let everyone know that next week we are going to have On Point on the stream. They are not a game studio, not a movie studio. They do live virtual theater and they will actually be showing off a bit of the workflow of how they're able to take actors in mocap suits as well as a tracked virtual camera and produce a live virtual theater using Unreal Engine. We've also been working on making sure the quality of that stream is top notch, so I'm super excited about that. So tune in for that. Yeah, they're actually going to have live actors doing a little performance for us, which is pretty cool. That said, make sure that follow us on social media for all news related to Unreal Engine. Twitter, Facebook, all the places. There's plenty of them. We're still looking for new countdown videos, in case you've been watching us from the beginning today. Countdown videos are usually 30 minutes of development that you fast forward up to five minutes and then send that to us to community@unrealengine.com with your logo separate and we will composite the countdown as well as your logo on the video so we can promote he project. Yeah, with that said, I think, Mike, thank you so much again. Is there anything else you want to chat with before we sign off today? MICHAEL: I love you all, thank you for showing up. This is a wonderful opportunity and I'm honored to be here describing the technology that the Battle Breakers team originally put together for you. Thank you. VICTOR: Exciting. With that said, I wish you all to stay safe out there. We'll see you again next week. Take care, everyone.
Info
Channel: Unreal Engine
Views: 22,341
Rating: undefined out of 5
Keywords: Unreal Engine, Epic Games, UE4, Unreal, Game Engine, Game Dev, Game Development
Id: h3A8qVb2VFk
Channel Id: undefined
Length: 118min 29sec (7109 seconds)
Published: Thu Feb 18 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.