Search Unity

Overwrite file using AssetDatabase?

Discussion in 'Asset Database' started by yellowyears, Sep 24, 2020.

  1. yellowyears

    yellowyears

    Joined:
    Feb 14, 2020
    Posts:
    36
    Can't seem to find a satisfying solution for this one. If I try and save an asset twice using
    AssetDatabase.CreateAsset(savedPose, $"Assets/XRPoses/{_poser.gameObject.name}.asset");
    It gives the error
    Couldn't add object to asset file because the MonoBehaviour 'Sphere' is already an asset at 'Assets/XRPoses/Sphere.asset'!


    I tried to delete the old asset, then create a new one, I tried to do AssetDatabase.SaveAssets() after creation, I tried to check if it already existed and then save it, although that didn't make sense to me because I would only be able to save it once ever.
     
    ZDM1998 likes this.
  2. DiegoDePalacio

    DiegoDePalacio

    Unity Technologies

    Joined:
    Oct 28, 2009
    Posts:
    507
    Hi @yellowyears,

    Once you call
    AssetDatabase.CreateAsset
    , the related file is created. Calling it again will not work because the asset is already created.

    For "overwrite" the file with a newer version, you should simply call
    AssetDatabase.SaveAssets
    after the asset has been changed.

    You can find more information about it here: https://docs.unity3d.com/ScriptReference/AssetDatabase.SaveAssets.html

    More general overview of using the AssetDatabase method can be checked here: https://docs.unity3d.com/Manual/AssetDatabase.html


    I hope it helps!
     
    Swayfaren, Alekxss and threebobs like this.
  3. yellowyears

    yellowyears

    Joined:
    Feb 14, 2020
    Posts:
    36
    I thought that, but it didn't seem to work reliably and consistently. I found a workaround seeing as AssetDatabse.CreateAsset() goes from reference, not name. If I create a new instance when I save it's going to be a different reference, even if it has the same values. Thank you for your help.
     
    DiegoDePalacio likes this.
  4. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,555
    Code (CSharp):
    1. // get a reference to the existing asset:
    2. Mesh meshAsset = myMeshFilter.sharedMesh;
    3. // ..and to whatever you want to overwrite it with:
    4. Mesh newMeshAsset = new Mesh();
    5.  
    6. // get current asset path (or provide one):
    7. string path = AssetDatabase.GetAssetPath(meshAsset);
    8.  
    9. // delete the asset at the path if it already exists:
    10. AssetDatabase.DeleteAsset(path);
    11.  
    12. // save the replacement asset:
    13. AssetDatabase.CreateAsset(newMeshAsset, path);
    14.  
    15. // update the reference:
    16. myMeshFilter.sharedMesh = newMeshAsset;
    17.  
    18. // flag the object holding the reference as needing to be saved:
    19. EditorUtility.SetDirty(myMeshFilter);
    20.  
    21. // optionally, save immediately:
    22. AssetDatabase.SaveAssets();
    Edit: to edit an existing asset (as opposed to overwrite)..
    Code (CSharp):
    1. string path = "..."; // whatever path, or get from a reference:
    2. // string path = AssetDatabase.GetAssetPath(myMeshFilter.sharedMesh);
    3. Mesh existingMesh = AssetDatabase.LoadAssetAtPath<Mesh>(path);
    4. // edit the asset however
    5. existingMesh.Clear();
    6. // [...]
    7. // save changes to it
    8. AssetDatabase.SaveAssets();
     
    Last edited: Sep 25, 2020
    ojaseminem and threebobs like this.
  5. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,555
  6. yellowyears

    yellowyears

    Joined:
    Feb 14, 2020
    Posts:
    36
  7. zwcloud

    zwcloud

    Joined:
    Mar 15, 2016
    Posts:
    377
  8. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    345
    Note that EditorUtility.CopySerialized needs the existingMesh.Clear() beforehand too to be able to write the new mesh properly. Directly assigning the vertices and triangles arrays to a serialized mesh was about 1.5x faster for me though.

    I want to add that I might be wrong, directly assigning was faster for vertices and trianlges only, obviously when you set all UV channels and normals as well things might be different.
     
    Last edited: Sep 5, 2022
    yellowyears likes this.
  9. koirat

    koirat

    Joined:
    Jul 7, 2012
    Posts:
    2,073
    But were you able to copy vertices using EditorUtility.CopySerialized ?
    Strangely it copied only indices for me, I'm trying to update mesh with bone weights.
     
  10. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,956
    Why does everyone keep thinking that "Hey, I just CREATED an asset, now i need to SAVE it - and not just that, I need to save ALL of whatever might have changed". :rolleyes:
    (not meant personally, but generally)
    Code (CSharp):
    1. // Create and (UNNECESSARILY) save ALL (!!) assets ...
    2. AssetDatabase.CreateAsset(savedPose, assetPath);
    3. AssetDatabase.SaveAssets();
    That is just total bollocks. CreateAsset is already saving the asset! What else would it do? Serialize the object but only keep it in memory, waiting for it to be saved?

    ... and don't get me started on Refresh. Something's not working right? Oh, you gotta add a Refresh(). Did you know that Refresh() should really have been called ImportAllExternallyModifiedAssetsAndUnloadUnusedAssets() ? :cool:

    Notice the 'external' part. As long as all operations are done via the AssetDatabase, calling Refresh is unnecessary!
     
    Last edited: Jan 18, 2024
  11. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    345
    I think many people just call refresh / reimport / save because they want xyz to happen and that might sometimes be a side effect of whatever else they are executing with save/refresh etc.. Unfortunately the UnityEditor namespace code is just not as well documented / easily understandable as the main UnityEngine code.
    There are similar situations for the Undo and set dirty mechanisms.
     
    CodeSmile likes this.