Issue with retaining fileIDs in Unity's Scripted Importer

Hello,

I’ve encountered an issue regarding fileIDs generated by Unity’s Scripted Importer when importing assets and creating child GameObjects (prefabs).

Here’s the scenario:

I have a ScriptedImporter that imports .pyxel files and generates a series of child assets like textures, sprites, and prefab GameObjects. These child assets are created with a specific identifier and are referenced in other prefabs.

The problem I’m facing is when I change the name of the .pyxel file in Unity, the GameObjects (prefabs) generated as child assets are given new fileIDs, even though the identifier used in the creation process stays the same (it doesn’t include the name of the asset). This doesn’t occur with other child assets like textures or sprites, they retain the same fileIDs as expected. This change in fileID for the prefabs results in broken references in my prefabs.

From my understanding, Unity’s fileID is supposed to remain constant for an asset, provided the identifier stay the same. However, the GameObjects (prefabs) seem to behave differently, getting new fileIDs when their name changes. I’d like the GameObjects to reflect the name of the source asset, but changing the name should not result in broken references. Do note that the textures, sprites etc for which the fileIDs are retained, the name is also changed. So the issue seems to be specific for GameObjects (Prefabs). I’ve tried creating the prefabs using new GameObject(), Instantiate and PrefabUtility.InstantiatePrefab. The behavior is the same.

Does anyone have any suggestions on how to ensure persistent fileIDs for GameObjects across name changes? Is there any step I might be missing in my import or GameObject creation process? Any help would be greatly appreciated.

Thank you for your time.

Unity: 2023.1.6f1

Posted workaround in this related thread: How to control fileID using custom ScriptedImporter

Hi there!
I’ve looked at your post here and on the other forum post and ran some tests locally.
From what I understand, while the gameobject name is used to build the fileID, the Prefab name itself will always be the file name and this is reflected in the scene.
So you should always create the root GameObject during import with a fixed name, and let Unity manage its name in the scene and project view.
Also, it is important to note that while it works for the root GameObject, it wont for anything inside the hierarchy, so renaming a children GameObject will definitely break the references.

using System.IO;
using UnityEditor.AssetImporters;
using UnityEngine;

[ScriptedImporter(3, "empty")]
public class EmptyFileImporter : ScriptedImporter
{
    public bool useFileName = true;

    public override void OnImportAsset(AssetImportContext ctx)
    {
        var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(ctx.assetPath);

        GameObject go = new GameObject(useFileName ? fileNameWithoutExtension : "SomeRootStandardName");
        go.AddComponent<Camera>();

        ctx.AddObjectToAsset("Main Obj", go);
        ctx.SetMainObject(go);
    }
}

I’ve looked into the script naming and references issues too, and yes, it is a big problem for which we need to figure out a solution, I’ll discuss that more in detail with the team in the next few weeks and see what we can do to improve the situation.

In the meantime, what I would suggest is the following:

  • From a scene, always reference the GameObject prefab directly and not a component or a child transform.
  • During the import, add a script on the root GameObject that would reference any other component or child transform that is useful to know in the created prefab.
  • While instantiating the prefab in the scene (or on Start/Awake if the prefab is already in the scene), use a GetComponent call to find the reference component in order to have access to everything else.

Doing so will make sure that if any Script name changes, because the references are made during the import from inside the prefab, everything will be updated with the new script names. And because the reference script is found at runtime, your runtime code doesn’t use a direct reference to it and the GetComponent will use your new script name.

Hello Bastien,

Thank you for your comprehensive response and suggestions.

However, in my specific use case, I generate multiple prefabs from a single asset. For instance, from a ‘Bush.pyxel’ asset, I generate ‘Bush (Green).prefab’, ‘Bush (Blue).prefab’, and ‘Bush (Red).prefab’ as child assets based on settings defined in my importer. This approach provides the convenience of drawing a bush once and generating multiple variants.

If the names of these prefabs don’t include the term “Bush”, they would be named ‘(Green).prefab’, ‘(Blue).prefab’, etc., which, when referenced in a component in the inspector, would appear as just ‘Green’ or ‘Blue’. This naming is insufficient and ambiguous as it doesn’t clearly indicate that these are variants of a bush.

I do appreciate your efforts to discuss improvements in script naming. Please also consider the suggestions in the other post: How to control fileID using custom ScriptedImporter I have suggested an alternative approach to fileID generation there, based solely on identifiers without considering paths, types, etc. While this would necessitate ensuring uniqueness, I believe the increased flexibility would make this effort worthwhile. It would typically be an overload of AddObjectToAsset or a new method to not break the current behavior.

I look forward to hearing about your team’s progress on these issues.