Stream an asset from the internet

Hi, I would like to know if it is possible to stream an asset from the internet for a mobile application made in unreal, where I could have an option to download new products to view in 3D inside the app (game).

Cheers,

Daniel

Yes there is. But it is a bit harder then in Unity (at the moment at-least). The solution has two steps, one is preparing the assets in a bundle and the other is serving the asset and streaming it.

1) Bundling your assets

The first step is to bundle all your assets (BPs are yet another question) into a so called PAK file. Unreal comes with a tool to bundle uassets and umaps into PAK files called UnrealPak. I have posted more info about UnrealPak in the following thread: https://answers.unrealengine.com/questions/105923/downloadable-content-1.html

2) Serving your bundles

Again we have to use a tool called the UnrealFileServer, its a static file server that handles the Unreal network protocol and is able to stream PAK files. You can then create a NetworkPlatformFile that is able to open remote files and stream the content of the PAK files. This even works when you stream a texture where texture streaming is applied.

There is quite a bit of work in this part part you should be able to start with this engine module: NetworkFileSystem and its FNetworkFileServer class.

One side note that took me days to discover is that once you are able to stream a PAK file you have to mount that file within the realm of Unreal’s file system (all the /Game/ /Engine/ paths). The tricky thing is that to be able to load and mount a PAK file from the network asynchronously is that you have to mount it in the engine path starting with /Engine/ instead of the game path /Game/. What I do is just adding a path that will be unique for me and my game like /Engine/Content/MyAwesomeGame/ to avoid collisions with existing engine assets.

Snippets

To initialize the network you require to create several platform files. A platform file is a file manager providing you with the ability to load certain files.

You require to hold a reference to the current one you will be using and to the others so you can switch between them (for local and remote loading), you might end with something like this in your helper object.

IPlatformFile* PlatformFile;
TSharedPtr<FStreamingNetworkPlatformFile> NetPlatform;
TSharedPtr<FPakPlatformFile> PakPlatform;

It could be that you need to create forward declarations for the above types

class IPlatformFile;
class FStreamingNetworkPlatformFile;
class FPakPlatformFile;

Don’t forget to initialize the NetPlatform and the PakPlatform.

NetPlatform = new FStreamingNetworkPlatformFile();
PakPlatform = new FPakPlatformFile();
// We will hold a refernce to the normal local platform file for all local manglings :D
PlatformFile = &FPlatformFileManager::Get().GetPlatformFile();

So we have now our files ready and can start to initialize the network one using a host string (host:port)

if (NetPlatformFile && PakPlatformFile)
{
    if (NetPlatform.IsValid())
    {
        if (!NetPlatform->Initialize(PlatformFile, *FString::Printf(TEXT("-FileHostIP=%s"), *ServerHost)))
        {
            // Failed to initialize! Raise an error?
        }
    }
}

The following presents the structure of how to stream using the NetPlatform. You will also need a refernce to a FStreamableManager, I recomend you to add one into your GameSingleton class (A new, community-hosted Unreal Engine Wiki - Announcements - Unreal Engine Forums).

    // Initialize the PakPlatform to use the NetPlatform
    if (PakPlatform.IsValid())
    {
        IPlatformFile* InnerPlatform = NetPlatform.Get();
        if( InnerPlatform && PakPlatform->Initialize(InnerPlatform, TEXT("")) )
        {
            // Use PakPlatform ffor streaming
            FPlatformFileManager::Get().SetPlatformFile(*PakPlatform);

            // The path of the pak file within the remote server
            const FString PakFileRemotePath = ...;
            FPakFile PakFile(*PakFileRemotePath, false);
            if (PakFile.IsValid())
            {
                // We have to mount the file into the engine content dir, if not you will not be able to load it async!
                PakFile.SetMountPoint(*FPaths::EngineContentDir());
                if (PakPlatform->Mount(*PakFileRemotePath, 0 /* This is the byte order */, *FPaths::EngineContentDir()))
                {
                    // The assets we will stream from the Pak file
                    TArray<FStringAssetReference> TargetAssets;
                    TSet<FString> PakContent;
                    PakFile.FindFilesAtPath(PakContent, *PakFile.GetMountPoint(), true, false, true);

                    for (TSet<FString>::TConstIterator SetIt(PakContent); SetIt; ++SetIt)
                    {
                        FString AssetName = *SetIt;
                        // You might load other such as .umaps too I guess :D
                        if (AssetName.EndsWith(FPackageName::GetAssetPackageExtension()))
                        {
                            // This is where we change the path to be an engine path (as stated earlier)
                            FString AssetShortName = FPackageName::GetShortName(AssetName);
                            AssetShortName.RemoveFromEnd(FPackageName::GetAssetPackageExtension());
                            AssetName = TEXT("/Engine/") + AssetShortName + TEXT(".") + AssetShortName;

                            TargetAssets.Add(AssetName);
                        }
                    }

                    // Now you will need an instance of FStreamableManager
                    FStreamableManager& Streamable = UMyGameSingleton::Get().GetStreamableManage();

                    // Now should create a delegate that you will use once the streaming is finished (you should also record the TargetAssets somewhere)
                    FStreamableDelegate StreamableDeleagte = FStreamableDelegate::CreateRaw(this, OnStreamingCompleteDelegate);
                    Streamable.RequestAsyncLoad(TargetAssets, StreamableDeleagte);
                }
            }
        }
    }

The next part would be performing the local loading part, which si very similar to the remote one. Just initialize the PakPlatform to be using the saved PlatformFile from the initialization phase.

You must also adapt your build.cs file to include the following.

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "NetworkFile" });
PrivateDependencyModuleNames.AddRange(new string[] { "PakFile", "StreamingFile", "NetworkFile"});

When using 4.5 you must also change the buid.cs file of an engine module (I’m preparing a pull request for this). The StreamingFile modules needs to add the Socket module as its public dependencies. You could also try to adding the Socketsn dependency to your public dependencies instead the engine modules one. But just in case:

PublicDependencyModuleNames.AddRange(new string[] { "Sockets" });

I know this is a loooooot of stuff :smiley: But I hope you will be able to start your work streaming pak files from the net! This will be all included in a plugin I’m preparing with Ruben (the one who posted earlier :D)

EDIT: This is a sample plugin featuring the above code: GitHub - moritz-wundke/AsyncPackageStreamer: Simple plugin giving you the ability to load PAK files from the local FS or a remote one.

Cheers,
Moss

1 Like

Awesome! Can you post the link here too!? Thanks for the help!

Hi Daniel. Soon we are going to release a plugin to perform asset streaming from internet. Hopefully it could help you to resolve your problem. We well make you know when it is ready!

Cheers,
Ruben

Sorry for the delay, I will post some code snippets this weekend. We had some delays in the release of the plugin ^^

Ok! Thanks =)

I’m editing the answer with the new snippets :smiley: Hope I get it done in an hour or so :smiley:

Hi, i’m trying to use this method to load assets from a server but FStreamingNetworkPlatformFile and FPakPlatformFile are undefined. Im using the 4.5.1 version of ue4 so I’ve change the build.cs file. Does I need to include specific files ?
cheers
louis

This a plugin that I made which will show you the basics of streaming from a remote file system: GitHub - moritz-wundke/AsyncPackageStreamer: Simple plugin giving you the ability to load PAK files from the local FS or a remote one.

Please try not to reopen old answers, instead make a new one because the answers will then change into un-accepted.

Added link to my sample plugin. Could you re-accept the answer?

How to mount a PAK file in the engine path starting with /Engine/ ? I have packed uasset files into a pak file with UnrealPak.exe but have no idea where to put it and how to access it from within the code.

I have the same problem, FPakPlatformFile is not defined. Have you figured it out?

Has the plugin been released already?

Same issue. Working on a IOS app. we want load file like uasset from server to save size of game cause will play on mobile(IOS). Seem like both method above should be functional. But did not decide which to go. Or is there any other way to load Uasset from server in order to reduce size of game for IOS.

Working on UE4.10 .Is there any function for stream uasset from internet server already in there do the job?
And how about UE4.11?

Many thanks for any repley.

我的新链接

@Moss: I am facing this Mounting pak files at runtime - World Creation - Epic Developer Community Forums
issue while Stream a local file at C:\Test.

It is crashing every time. Could you comment there to help us out.


Thanks!

Hello, I’ve a problem to connect to file server :
LogNetworkPlatformFile:Warning: Created transport for 127.0.0.1:8081. LogNetworkPlatformFile:Error: Failed to connect to file server at 127.0.0.1:8081.

… dude , can you please update your plugin for 4.17 … I extremely need this works on a huge project we have and , this plugin is the Key for us to make things work.
Please … . . . … . . . … ; ] , , ,. .

to Vahil
if you start UnraelFileServer.exe , on client just type 127.0.0.1 , for example :
NetPlatform->Initialize(&InnerPlatform, *FString::Printf(TEXT("-FileHostIP=127.0.0.1")));