Have Unity Support Your Custom File! (Part 4/6)

Learn how Unity imports assets when you click and drag files using Scripted Importers.

Miijii
Miijii’s Unified Works
6 min readMar 4, 2023

--

An sample of a importer used to import .xvnml files.

It’s now the moment that you’ve been waiting for! The last piece to supporting our custom file. If you don’t know Unity’s Asset Pipeline, the first step in the pipeline is importing an asset.

“An asset is any item that you use in your Unity project to create your game or app.” ~ (Unity’s Official Documentation)

You can either create the asset inside the Unity Editor, or outside the editor. There are many file formats in which can be clicked and dragged into Unity and be converted into a tangible asset. If we were to continue with our Digicard example, we’ll most likely be creating the file inside the Unity Editor.

If you had remembered, previously, we had used a hidden feature of Unity called Script Templates to create a reusable format for our Digicard file (ending with the .digicard extension). We had to hand type our format (which we used JSON). However, we gave methods to our DigicardAsset class called Save() and Load(). In Part 4 of our Custom Files series, we’ll be making use of the Load() method when we create or import our Digicard file. This can all be accomplished by using ScriptedImporters.

A ScriptImporter is a class that we can inherit from to create our own Custom Importer. We can specify a file extension that we want to be able to detect when being dragged in outside of Unity by calling the OnImportAsset() method. On import, we will validate this file, and the convert it into an asset that it can use in the Editor and be included in your Unity Build.

Overriding this method, we’ll be provided with the AssetContext called ctx. The AssetContext containes many properties. However, it’s main purpose is providing us with all the contextual information necessary to process the import event (the moment we click and drag our asset into Unity). It can also be used to store the resulting Unity Asset. And there’s 2 methods given to us that does just that. Those being AddObjectToAsset(), and SetMainObject().

We also require a static method coming from ScriptableObject called CreateInstance(). We’ll be using this to create an instance of our DigicardAsset class.

using UnityEditor;
using UnityEditor.AssetImporters;
using UnityEngine;

/// <summary>
/// Import any files with the .digicard extension
/// </summary>
[ScriptedImporter(1, "digicard", AllowCaching = true)]
public sealed class DigicardAssetImporter : ScriptedImporter
{
public override void OnImportAsset(AssetImportContext ctx)
{
// Create our DigicardAsset
var asset = ScriptableObject.CreateInstance<DigicardAsset>();
ctx.AddObjectToAsset(GUID.Generate().ToString(), asset);
ctx.SetMainObject(asset);
}
}

First, we tell our importer that we’ll be targetting any file that ends with the extension .digicard. When called the AddObjectToAsset() method, we’ll need to pass in a identifier. We do have a way of setting the identifier, but for now, we’ll give it a GUID. Once you add the object to the AssetContext, set it as the main object with the SetMainObject method. With both of these methods, we have effectively “fused” our Scriptable Object with our .digicard file (or at least, we’ve established a connection between the two object).

This is the moment where Unity acknowledges our newly created asset. No more will we generate an .asset file. Instead, we would have generated a .digicard file, which is “fused” with our DigicardAsset. This means our file can be used, and exported into the final build of our Unity project (with all our information intact)!

However, we need to initialize our DigicardAsset prior to the fusion. This is where our “Load” method comes in. Not only will we get the name of our card, but we’ll also be able to use it as our identifier when adding the object to the AssetContext.

using UnityEditor;
using UnityEditor.AssetImporters;
using UnityEngine;

/// <summary>
/// Import any files with the .digicard extension
/// </summary>
[ScriptedImporter(1, "digicard", AllowCaching = true)]
public sealed class DigicardAssetImporter : ScriptedImporter
{
public override void OnImportAsset(AssetImportContext ctx)
{
// Create our DigicardAsset
var asset = ScriptableObject.CreateInstance<DigicardAsset>();

// We can get our asset path, which points
// to our generated .digicard file
var assetPath = ctx.assetPath;

// We pass in the filePath of this asset prior
// to loading our .digicard file (which is just a JSON file)
asset.filePath = assetPath;
asset.Load();

ctx.AddObjectToAsset(GUID.Generate().ToString(), asset);
ctx.SetMainObject(asset);
}
}

If you save and try to create another Digicard asset, you should get something like this (notice how now your asset doesn’t end in the extension .asset):

Creating a new Digicard file called “Aspiring Legacy”. This time, it doesn’t have the .asset extension.

You may also have noticed that we can’t really customize our Scriptable Object anymore. This is okay; we can always create our UI in our created Importer. We’ll also be able to have the option to Save and Load our file on command. We’ll create our own Custom Editor for our DigicardAssetImporter class on Part 5 of creating Custom Assets.

This lesson was pretty short, but it’s all we need to be able to have our .digicard file be used by Unity in both Editor-Time, Runtime, and when we create a Build of our project. As an extra bonus, you may have noticed that when you’re inside Visual Studio, you can’t see any of your created .digicard files. This fix is quite simple to do. Simply go to Edit>Project Settings>Editor. Search for “Additional extensions to include”. Include “digicard” into your list.

Including any .digicard files in our Project Settings

Once you’ve applied those changes, close and reopen Unity. Head back into Visual Studio, and you should notice that it recognizes your .digicard files.

Unity finally acknowledge our Digicard files! 💞

Of course, you can add this programmically when you import a .digicard file for the first time using the EditorSetting static class.

using System.Linq;
using UnityEditor;
using UnityEditor.AssetImporters;
using UnityEngine;

/// <summary>
/// Import any files with the .digicard extension
/// </summary>
[ScriptedImporter(1, "digicard", AllowCaching = true)]
public sealed class DigicardAssetImporter : ScriptedImporter
{
private const string DigicardExtension = "digicard";

public override void OnImportAsset(AssetImportContext ctx)
{
// Create our DigicardAsset
var asset = ScriptableObject.CreateInstance<DigicardAsset>();
var assetPath = ctx.assetPath;
asset.filePath = assetPath;
asset.Load();
ctx.AddObjectToAsset(GUID.Generate().ToString(), asset);
ctx.SetMainObject(asset);

// If extension not included in our project
// add it.
TryIncludeDigicardExtension();
AssetDatabase.Refresh();
}

private static void TryIncludeDigicardExtension()
{
if (EditorSettings.projectGenerationUserExtensions.Contains(DigicardExtension)) return;
var list = EditorSettings.projectGenerationUserExtensions.ToList();
list.Add(DigicardExtension);
EditorSettings.projectGenerationUserExtensions = list.ToArray();
}
}

Now that you’ve created you own Custom File that’s acknowledge by Unity, we’ll go ahead and address the disabled control on our Scriptable Object. We’ll also be giving our new File Type with it’s own File Icon (OHHHHHHH! EXICTING!) And then, we’ll be adding the finishing touches, polishing, and conclude this 6 part series.

If you like what you read, be sure to leave a like. Also, consider following me so that you can be provided with more Unity and Game Development tips, tricks, and guides that’ll mark you Game Developing journey much simplier. Feel free to comment anything that could of been elaborated in more detail. I’m open to any questions or positive constructive criticism. Also comment if you had learned anything useful, or if it gave you some insight on how Unity works under the hood.

コーディング諦めないぞ!Don’t Stop Coding! Everyone, have a wonderful rest of your day!

Click here for Part 5: Custom Editors!

--

--

Miijii
Miijii’s Unified Works

Miijii (Pen-Name) | Game Developer | Developing XVNML, XVNML2U, and Tomakunihahaji