AssetBundles and Subnautica Mods - NeisesMike/VehicleFramework GitHub Wiki

Let's add assets to Subnautica

This document should cover all AssetBundle-related topics in modding Subnautica. The following are knowledge prerequisites:

  • You know how to create a prefab in Unity.
  • You know how to write a mod for Subnautica.
  • You know your way around the basic elements of the Unity Editor interface.

The High Level Procedure

  1. Ensure you have an appropriate version of Unity.
  2. Prepare your GameObject.
  3. Convert your GameObject to a prefab.
  4. Add that prefab to an AssetBundle in the Inspector Window.
  5. Build all AssetBundles.
  6. Move the AssetBundle file into your mod folder.
  7. Load the AssetBundle and extract your GameObject.

Unity Versions

You should prepare your AssetBundle in a Unity Editor which matches the version used to build Subnautica. You can find which version was used to build Subnautica in the qmodmanager_log-Subnautica.txt file in the Subnautica root directory. In the top few lines, you should find a line that looks like this:

Initialize engine version: 2019.2.17f1 (441)

In this case, we should download Unity version 2019.2.17f1, or at least the closest version we can find. For example, 2019.2.17 might suffice if we cannot find 2019.2.17f1.

Building AssetBundles

By this point, you should already have a prefab designated to be part of an AssetBundle, like this:

At the end of this section is a file you should put in a directory called exactly "Editor" in the Assets folder of your Unity project. The name "Editor" is critical because it is a special folder name in Unity:

This adds a button to the bottom of the Assets menu in the Unity editor. So you should have the folder structure "Assets/Editor/thisFile".

The button is called "Build AssetBundles," and it does exactly what it says. This might take several minutes to execute, but when you're done you should have a file given the same name you gave the AssetBundle in the Inspector earlier. This file will be stored in the Assets/AssetBundles folder, and it will be easily recognizable both by its lack of an extension (no file type) and by its considerable size. Any non-AssetBundles in the folder will by tiny in comparison- on the order of 1 or 2 KB.

using UnityEditor;
using System.IO;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        string assetBundleDirectory = "Assets/AssetBundles";
        if (!Directory.Exists(assetBundleDirectory))
        {
            Directory.CreateDirectory(assetBundleDirectory);
        }
        BuildPipeline.BuildAssetBundles(assetBundleDirectory,
                                        BuildAssetBundleOptions.None,
                                        BuildTarget.StandaloneWindows);
    }
}

The Special Case of Sprites

  1. Add a Sprite. You can do this by drag-and-dropping an image into the project window. You must then change the type of the image to "Sprite (2D and UI)."
  2. Put the Sprite in a SpriteAtlas. First use Assets>Create>SpriteAtlas to create an empty SpriteAtlas. Then click on the SpriteAtlas and look at the bottom where it says "Objects for Packing," and click the plus + sign to add your Sprite to the SpriteAtlas.
  3. Add the SpriteAtlas to your AssetBundle like normal.
  4. Make sure you set Unity to always pack sprites, or else your sprites will not actually be included in your AssetBundle. Search "Unity Sprite Packer Mode" for more information.

Loading the AssetBundle

First we must ensure we've included as a reference the file: UnityEngine.AssetBundleModule.dll.

The following is an example of how to load an AssetBundle and extract a GameObject and a Sprite from it. In this example, the AssetBundle is placed in a folder called "assets" which is placed inside the mod folder in the QMods folder. In other words, we have the folder structure

Subnautica/QMods/MY_MOD_NAME/assets/MY_ASSET_BUNDLE

Notice we must create the AssetBundle with our sprite in a SpriteAtlas, but we later cast it into an Atlas.Sprite. To build the AssetBundle requires the sprite to be in a SpriteAtlas, but Atlas.Sprite is the type oft-required by Subnautica.

// We will extract our assets to these two variables.
GameObject myAsset;
Atlas.Sprite mySprite;

// We can establish the filepath to our AssetBundle in this way.
string modPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(modPath, "assets/MY_ASSETBUNDLE_NAME"));
if (myLoadedAssetBundle == null)
{
	Logger.Log("Failed to load AssetBundle!");
	return;
}

// We must iterate over all the assets in our AssetBundle,
// wherein we match them to our target variables by their prefab names.
System.Object[] arr = myLoadedAssetBundle.LoadAllAssets();
foreach (System.Object obj in arr)
{
	if (obj.ToString().Contains("MY_SPRITE_ATLAS_NAME"))
	{
		SpriteAtlas thisAtlas = (SpriteAtlas)obj;
		Sprite myRawSprite = thisAtlas.GetSprite("MY_SPRITE_NAME");
		mySprite = new Atlas.Sprite(mySprite);
	}
	else if (obj.ToString().Contains("MY_GAMEOBJECT_NAME"))
	{
		myAsset = (GameObject)obj;
	}
}