How to properly use Content.Load in a Cooked/Built Game?

I’ve been using Content.load to load prefabs from Content (Like Resources.Load From Unity), However, I’m running into an issue only when the game is cooked. I feel like i am missing something.

Currently, i’ve been loading prefabs using “Content.Load(Path.join(GlobalContentPathOrDir, prefabName))” and this works fine in the editor when the assets aren’t packed into one file.

And that’s where the issue is, When i cook the game and the files get packed into “Data_0.flaxpac” it no longer works, everything else does but not getting a prefab from Content.Load, which makes me think it’s trying to locate the prefab as a file that doesn’t exist in the cooked content folder (I don’t know if that’s actually how that works).

I… will be honest i don’t entirely know how to load prefabs with GUID, I haven’t been able to get it working, i’ve tried copying the Asset ID and hardcoding it, and even with hardcoded dashes in the correct positions.

So my question is about how to load prefabs properly (Assuming i’m doing it wrong, or not how it’s intended to be done) from either the packed data files when they’re loaded (Data_0), or if they’re referenced a different way (Or pathed differently) internally that i can get after the game is cooked.
I Do remember seeing a topic about adding DLC functionality to the engine, but was that talking about this?
DLC Thread

I’m not sure what i am doing wrong.

This is my original method (To get the what i assume is the GUID, I right click the prefab and ‘Copy Asset ID’)

//Global Variable
string prefabPath = Globals.ProjectContentFolder + "\\Prefabs\\";
string prefabEnd = ".prefab";

public static Prefab getPrefabFromStringId(string id, string subDir)
{
    return Content.Load<Prefab>(Path.Join(prefabPath, subDir, id + prefabEnd));
}

I have tried these:

return Content.Load<Prefab>(Path.Join(prefabPath, subDir, id + prefabEnd));// (Works in editor, but not cooked)
return Content.Load<Prefab>(Guid.Parse("XXXXX...."));// (returned null for everything)
return Content.Load<Prefab>(Guid.Parse("XXXXX.... with dashes")); //(returned null for everything)
return Content.Load<Prefab>(new Guid("XXXXX....")); //(returned null for everything)
return Content.Load<Prefab>(new Guid("XXXXX.... with dashes"));// (returned null for everything)
return Content.LoadInternal<Prefab>(Path.Join(subDir, id));//(Null)
return Content.LoadInternal<Prefab>(Path.Join("Content/Prefabs", id));//(Null)

Trying to debug i have checked:

Content.GetAsset(new Guid("XXXXXX...."));// (null)
Content.GetAsset(Guid.Parse("XXXXX....")); //(null)

I am sorry if this is simple, Thank you for any Tips/Help/Answers. I appreciate it.

You can use content.load with a path relative to the content folder, like “Content/file.flax”. You also need to make sure that you are including the assets that are not linked to any cooked scenes in your Build Settings asset. There are options to include specific folders or files in a cooked build.

If you wanted to go the guid route, you could also expose a Guid variable with the AssetReference attribute to get the Guid of an asset easily.

2 Likes

OH! I see… Okay, yeah that works as expected now!
Thank you so much!

For anyone that finds this thread in the future Here’s what/where it is, Thanks to Tryibion for that.

Flax(v1.10)

1 Like

Thank you for linking the thread to notify, I am happy to see another researcher!

Can you explain a little more what you had tested and succeeded? I am trying to follow your experiment, and not sure exactly how to load prefab object as an external file in runtime with the built executable.

As I can see in your post, I added:

  • Added ‘Content/Prefabs’ in Build Settings
  • Created a sample prefab in Project Root/Content/Prefabs folder (Content/Prefabs/PrefabBox.prefab)
  • Added a sample script loading and spawning the prefab

image

public override void OnEnable()
{
    // Here you can add code that needs to be called when script is enabled (eg. register for events)
    var prefab = Content.Load<Prefab>("PrefabBox.prefab");
    PrefabManager.SpawnPrefab(prefab, new Vector3(0, 10, 0));
}

And tested:

  • In editor run, prefab spawned with no error
  • Cooking the project requested /Content/Prefabs folder to be exist (path to export)

But prefab did not spawn with the built runtime executable.
I copied PrefabBox.prefab to the root (.exe location), root/Content, and root/Content/Prefabs (created it) but in every cases prefab image did not loaded.

I would appreciate it if you could let me know about what you found out, loading the prefab in runtime.

I am not sure bare .prefab file could be loaded by the runtime executable. Or it must be cooked to .flax form in build time and reading which is not included with initial cooking is unsupported yet…?

So, one thing that i did have to get use to was that unlike unity it doesn’t start in that “extra” asset folder. Instead, it wants a relative path from the base project/.exe location to the “Resources” folder. More specifically the folder where the prefab is contained.
IE:
“/Content/Prefabs/” + PrefabName.prefab
“/Content/Prefabs/Blocks/” + PrefabName.prefab
“/Content/Prefabs/NPCs/” + PrefabName.prefab
“/Content/Prefabs/Guns/” + PrefabName.prefab
“/Content/Prefabs/etc…” + PrefabName.prefab

Unity Resources.Load: (‘easier’ Resources.Load(‘PrefabBox’)), Just uses the prefab name relative to the Resources Folder, no extension needed to find and load the asset.
…/Assets/Resources/… By default

GameObject.Instantiate(Resources.Load("Prefab"));

Content.Load: (more ‘manual’ Resources.Load(‘Relative path to folder ie Globals.ProjectContentFolder + \Prefabs’ + ‘PrefabBox.prefab’)), Is not set up to default to Content/Prefabs, so you need to tell it where to look.
…/PathTo.exe/PrefabBox.prefab… Default, Does not exist in internal Data0
…/PathTo.exe/Content/Prefabs/PrefabBox.prefab… What its expecting, PrefabBox.prefab is contained in the packed DataX Files under the ‘Content/Prefabs’ Path, meaning in the cooked game it’s not looking for a file called “PrefabBox.prefab” inside of the Content folder, you’re telling it to look for the asset with the path of “Content/Prefabs/PrefabBox.prefab” inside of it’s packed files. Which is why you need to add the “extra folder” inside of Build settings. (well, i don’t actually know if that’s why, but you need to add it for it to work…)

string PathToResources = Globals.ProjectContentFolder + "\\Prefabs\\";
string PrefabName = "PrefabBox.prefab"; //Can replace type with other
//string AudioClip test = "TestAudio.flax";   


//Grab the Prefab from Flaxs' assets (Contained in the Data0.FlaxPack like Unity Resources.Resources or LZa Archives)
//The prefab is not a physical file that you put into the built game. Flax automatically builds the prefab into it's internal database and you can reference it there with a relative path.

Prefab toSpawn = Content.Load<Prefab>(Path.Join(PathToResources, PrefabName));
PrefabManager.SpawnPrefab(toSpawn, new Vector3(0, 10, 0));
//^ This Is to load a Prefab from .../Content/Prefabs/PrefabBox.prefab  and spawn it
//

I feel like i repeated myself a lot, but the main thing is that Files are packed into one file (like unity), but the Resources.Load for Flax is more manual than unity is, requiring a path and ‘file type’.

Here is my code from your example that works.

public override void OnEnable()
{
    // Here you can add code that needs to be called when script is enabled (eg. register for events)
    Prefab prefab = Content.Load<Prefab>(Path.Join(Globals.ProjectContentFolder + "\\Prefabs\\", "PrefabBox.prefab"));//Making it a variable here is just for readability and understanding.
    PrefabManager.SpawnPrefab(prefab, new Vector3(0, 10, 0));
    Debug.Log("Spawn");
}
1 Like

Thank you for detailed explanations.

Following your example, I made up…

  • Content.Load () reads resource under Content folder.
    → When in editor mode, .prefab files are supposed to be under path Dev_Root/Content/
    → When in runtime mode, prefab resource data are supposed to be inside the file Cooked_Root/Content/Data_x.flaxpac.
  • Additional Asset Folders entries in Build Settings makes Content.Load() method ‘Accessible’ to the ‘path-filename representation’ of flaxpac-ed resources.
    → When in editor mode & no Asset Folder Entry, Content.Load() can read Dev_Root/Content/xxx.prefab because there exists the file actually.
    → When in editor mode & Asset Folder Entry, Content.Load() can read Dev_Root/Content/xxx.prefab regardless of the settings.
    → When in runtime mode & no Asset Folder Entry, Content.Load() cannot read Dev_Root/Content/xxx.prefab even if the xxx.prefab file is copied to Dev_Root/Content/, it only enables to read from packed resources.
    → When in runtime mode & Asset Folder Entry, Content.Load() can read Dev_Root/Content/xxx.prefab regardless of the xxx.prefab file is copied to Dev_Root/Content/, because engine is loading the prefab from the data cooked inside the resource file during the build.

In conclusion, scripting Content.Load("…prefab") does not allow the runtime game to load ‘after-released resources’. All contents must be accessible at the point of time of the game build.
Too bad reconfirming that ‘DLC-capable content loading’ is not yet available, but learned a lot from you!

As mentioned above Flax has built in. I am simply linking the manual location for this. I think the manual should add some details shown above to make this more obvious.

I am still playing around with Loading/Spawning and Unloading Prefabs at runtime so I am no pro with this yet.