AssetDatabase: Replacing an asset, but leaving reference intact

I am creating a mesh via a custom import script. After generating the mesh I am using AssetDatabes.CreateAsset() to write that to disk as a .asset file. All of that works just fine.

However, when this process runs again, CreateAsset() seems to explicitly delete the previous asset prior to putting the newly created one there, thereby invalidating any reference to that asset that is on other components.

Is there anyway to REPLACE the asset instead of creating it anew. Essentially I'm looking for functionality similar to ReplacePrefab()

-ryan

I’ve found this method that apparently may work to clone any UnityEngine.Object asset:

AnimationClip outputAnimClip = AssetDatabase.LoadMainAssetAtPath (path) as AnimationClip;
if (outputAnimClip != null) {
  EditorUtility.CopySerialized (animClip, outputAnimClip);
  AssetDatabase.SaveAssets ();
}
else {
  outputAnimClip = new AnimationClip ();
  EditorUtility.CopySerialized (animClip, outputAnimClip);
  AssetDatabase.CreateAsset (outputAnimClip, path);
}

That snippet clones animClip into outputAnimClip. If the target asset doesn’t exist at path, it will be created; otherwise, it’s copied and replaced, but the links are maintained.

First, it gets a reference to the asset at path. If the reference is not null, the asset already exists and it simply replaces it by copying the contents of animClip into outputAnimClip (which references the existing asset), and saving all the assets. If the reference is null, then the asset doesn’t exist, creates a new animation clip, copies the contents, and creates an asset using that object outputAnimClip and the given path.

I guess this will work with any other subclass of UnityEngine.Object, although they would require a different treatment (specially in their instantiation). Maybe this could be rewritten as a generic function requiring the parameter T to be a subclass of UnityEngine.Object and have a parameterless constructor.

This question is fairly old, I know, but as there’s yet no official implementation and no generic answer, yet some people may find it useful, I’m leaving this here. Hope it helps! :slight_smile:

This seems to work:

Mesh dummy = (Mesh)AssetDatabase.LoadAssetAtPath(asset_path, typeof(Mesh));
if (!dummy) {
    dummy = new Mesh();
    dummy.name = name;
    AssetDatabase.CreateAsset(dummy, asset_path);
} else
    dummy.Clear();

// [... import dummy ...]

AssetDatabase.SaveAssets();

(attempting to load/modify mesh then clear it and import from the new version of the resource)

Meshes need to be cleared in order to properly write to them, even when using CopySerialized.
Directly assigning the vertices and triangles arrays to a serialized mesh was about 1.5x faster for me though.

    private T CreateOrReplaceAsset<T>(T asset, string path) where T : Object
    {
        T existingAsset = AssetDatabase.LoadAssetAtPath<T>(path);

        if (existingAsset == null)
        {
            AssetDatabase.CreateAsset(asset, path);
        }
        else
        {
            if (typeof(Mesh).IsAssignableFrom(typeof(T))) { (existingAsset as Mesh)?.Clear(); }
            EditorUtility.CopySerialized(asset, existingAsset);
            existingAsset = asset;
        }

        return existingAsset;
    }