Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

m_Modification doesn't clear old references when the prefab is modified

Discussion in 'Prefabs' started by Baste, Oct 15, 2019.

  1. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,940
    I've got a bunch of prefabs with a script on them that used to have a field that's been removed. Some of the prefab instances have modifications to that field. I thought that modifications to removed fields would automatically be removed when the prefab instance got reserialized due to something else changing, but it's not happening.

    The reason this is especially bad is that the field in question is a ScriptableObject, and that SO was stored as a part of the scene. Unity cleans out such SO's when they're not referenced anymore. SInce the modification to that field stays there, the SO won't get cleared out.
    In addition to all of this, we have deleted that SO's type. This means that each of these SO's are causing these warnings to appear in the console on startup:
    Code (csharp):
    1.  
    2. The referenced script (Unknown) on this Behaviour is missing!
    3. The referenced script on this Behaviour (Game Object '<null>') is missing!
    In the scene file, this looks like this. I've got a prefab instance with this in it:
    Code (csharp):
    1.  
    2. --- !u!1001 &1435652222
    3. PrefabInstance:
    4.   m_ObjectHideFlags: 0
    5.   serializedVersion: 2
    6.   m_Modification:
    7.     ...
    8.     - target: {fileID: 114238998614804306, guid: ff4165164015226499e68b7cb5fdc74e,
    9.         type: 3}
    10.       propertyPath: navLocation
    11.       value:
    12.       objectReference: {fileID: 218451484}
    The "navLocation" field on the script has been deleted. This is one of several fields who's overrides are not getting removed, but this is the one causing the most problems.

    Further down the file is this line:

    Code (csharp):
    1.  
    2. --- !u!114 &218451484
    3. MonoBehaviour:
    4.   m_ObjectHideFlags: 0
    5.   m_CorrespondingSourceObject: {fileID: 0}
    6.   m_PrefabInstance: {fileID: 0}
    7.   m_PrefabAsset: {fileID: 0}
    8.   m_GameObject: {fileID: 0}
    9.   m_Enabled: 1
    10.   m_EditorHideFlags: 0
    11.   m_Script: {fileID: 11500000, guid: 35134fd8a34d47be92f33e58371449fc, type: 3}
    12.   m_Name: Krathaven 9_Location
    13.   m_EditorClassIdentifier:
    35134fd8a34d47be92f33e58371449fc references a deleted script.

    Things I have tried to clean this up:
    - Make changes to the prefab instance. In my experience, that causes the prefab instance to reserialize, Which usually fixes things like this, but no dice
    - Reserialize the entire scene asset, using AssetDatabase.ForceReserializeAssets. That doesn't work either.

    - Delete the prefab instance, enter play mode, exit play mode, Undo.
    This half-solves the issue, as the SO is removed from the scene file. The prefab modification is still there, but now with
    objectReference: {fileID: 0}


    Any advice? Is this a bug? What's supposed to make prefab modifications that are not relevant anymore be cleared?
     
  2. runevision

    runevision

    Unity Technologies

    Joined:
    Nov 28, 2007
    Posts:
    1,796
    It's not a bug, but we're aware the design has some issues.

    In general, Unity is very conservative with regards to deleting user data. For example, if you setup properties on a Material and later change the shader to a different one that doesn't have those properties, we don't delete the properties, and if you switch the shader back, your saved values are still there. This principle is used throughout lots of data in Unity.

    For this Prefab case, say you remove that script property, but later revert that via version control or other means. Your old data is now back in the state you left it in. This is frequently convenient. The unused overrides data is still stripped from builds, since builds don't has any concept of overrides at all, so it doesn't cause overhead in that sense. But it does cause issues sometimes, and I think the fact that dependencies are still tracked for unused overrides is one such issue.

    There are a few cases where we do remove unused overrides. For examples, if you have overrides on a component, but then remove that component (and applies it), then the overrides for that component are removed as well. But in more indirect cases, we don't remove them.

    Having tooling to allow cleaning up unused overrides is one of the things that are up for consideration for future improvements we'll work on.
     
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,940
    In our case, this is really bad, because the ScriptableObject type that the removed field is referencing has been removed from the project. Since Unity only removes ScriptableObjects that are a part of the scene when there's no scripts removing them, those are permanently stuck there, and are puking warning messages into the console on startup.

    The warning messages, together with the bloat of thousands of unused fields and ScriptableObjects cause our project size to bloat, and the warning messages also causes entering play mode to take a lot longer, since warning messages are slow. They also make it super hard to find real warning messages that we care about.


    Unity also has a long-standing issue where you cannot delete nested assets who's type is not known. If these were ScriptableObjects who's type were known, I could probably fix this by doing LoadAllAssetsAtPath for the scene file, and deleting the instances I wanted gone. But in this instance that becomes impossible.


    The warning message is also really, really hard to track down, as they look like this:
    Code (csharp):
    1. The referenced script (Unknown) on this Behaviour is missing!
    and:
    Code (csharp):
    1. The referenced script on this Behaviour (Game Object '<null>') is missing!
    There's no context for any of these messages, and they're wrong, as the referenced script is not a Behaviour, and not attached to any GameObject. I had to spend hours binary search deleting the objects in the scene in order to even understand what's going on.


    I think I can fix this, by creating a new, empty ScriptableObject, assigning it the GUID of the deleted ScriptableObject, and then search for instances of that to delete. That's really, really hacky, and requires quite a lot of in-depth understanding of how Unity works - I think a lot of users would just be stuck with not being able to use warning messages for the rest of their project.
     
  4. runevision

    runevision

    Unity Technologies

    Joined:
    Nov 28, 2007
    Posts:
    1,796
    Yeah it sounds frustrating.

    I forgot to be more clear that I meant that the fact that overrides are not removed is not a bug, but the fact that it causes referenced objects to be kept in the scene might still be. We'd appreciate a bug report on this.

    It sounds like there's also an unrelated issue with some of our warning messages that are not really related to Prefabs, but feel free to file bug reports about that too of course.
     
    Baste likes this.
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,940
    I've reported both; 1191638 and 1191643.
     
    runevision likes this.
  6. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,940
    Hi!

    I eventually got both bugs back as "by design", with mentions that a tool to clear the outdated references might be in the pipeline.

    We just ran into this issue again in a different manner. We have some assets that used to be directly linked, but are now loaded from an asset bundle. So we went from:

    Code (csharp):
    1. public class Foo : MonoBehaviour {
    2.     public Bar bar; // Bar is an asset file
    3. }
    To this:

    Code (csharp):
    1. public class Foo : MonoBehaviour {
    2.     public string barID;
    3.     private Bar bar;
    4.  
    5.     void Start() {
    6.         var = GetFromAssetBundle(barID);
    7.     }
    8. }
    The problem here is that Foo is on prefab instances, and prefab instances has old m_Modification's that reference bar. This causes the Bar assets to be included both in the asset bundle, and in the game build itself, due to there being a reference from the scene the Foo instance is in, to the Bar asset.

    That has to be an actual bug, right? We're getting an asset included in a build, without having any editable references to that asset - all of our references are outdated m_Modification's that we can't really touch.

    If I create a bug report showing this, any chance it'll be handled? The m_Modification hanging around forever is sketchy, but fine. That that causes files that shouldn't be included in builds to be included is pretty bad.
     
  7. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    544
    Hi,

    I just wrote a long reply about how keeping property modification is by design and bla bla bla, but in the end you are right that should not cause assets to be included in the build. I'll see if I can make a fix
     
    Baste likes this.
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,940
    Hey, thanks. If you want to, I can sit down and create a repro project for exactly that issue and create a bug report.
     
  9. steinbitglis

    steinbitglis

    Joined:
    Sep 22, 2011
    Posts:
    138
  10. sschoellhammer

    sschoellhammer

    Joined:
    Feb 15, 2013
    Posts:
    30
    Hey @steinbitglis
    This looks great. We had - I believe - the same issue (https://forum.unity.com/threads/removing-dangling-dependencies.892948/#post-5865292)

    So I tried your tool :). Maybe I'm missing something, but it doesn not show me anything to clean up in my scene.

    In the test project attached is a "test" script which exposed a
    "PrefabDependency" field, which then got removed.
    The assignment however persists on the Cylinder prefab (causing a "hidden dependency"):

    PrefabDependency: {fileID: 611505733756841739, guid: 9d8d10dd541e6d94799fc2a7344510b4,
    type: 3}

    I was hoping this is something your tool would find and clean out, or am I mistaken?

    Thanks in advance!

    seb
     

    Attached Files:

  11. steinbitglis

    steinbitglis

    Joined:
    Sep 22, 2011
    Posts:
    138
    In the project you've posted here, there is no prefab instance override data for the field that you have removed.
    If you assign some data to the field (and save)., then remove it ... then the window will pick it up and suggest removal.
    PrefabCleaner_help.png
     
    KAJed likes this.
  12. steinbitglis

    steinbitglis

    Joined:
    Sep 22, 2011
    Posts:
    138
    KAJed likes this.
  13. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    57
    The cleaner script is awesome - but it would be good if it supported more than just prefabs in scenes!

    But also... please fix this Unity!
     
  14. steinbitglis

    steinbitglis

    Joined:
    Sep 22, 2011
    Posts:
    138
    Prefab instances in the project (nested prefab children) are also supported. Are there other things that need this?
     
  15. Ziflin

    Ziflin

    Joined:
    Mar 12, 2013
    Posts:
    58
    @runevision What are the plans to fix this issue as I now have several prefab modifications in a scene that no longer need to be there? Is there an API call that can be made to remove currently invalid modifications?
     
  16. runevision

    runevision

    Unity Technologies

    Joined:
    Nov 28, 2007
    Posts:
    1,796
    You would have to ask Steen who last commented on it here, since I'm not aware of the status:
    https://forum.unity.com/threads/m_m...n-the-prefab-is-modified.761219/#post-5397249
    He's currently on vacation though.

    In the mean time it looks like several people have found this workaround tool by steinbitglis useful:
    https://forum.unity.com/threads/m_m...n-the-prefab-is-modified.761219/#post-5436957
     
  17. Ziflin

    Ziflin

    Joined:
    Mar 12, 2013
    Posts:
    58
    Thanks for the reply @runevision. I took a look at the tool above, but it was easier to just manually edit the file and remove what was needed for now.

    @SteenLund It would still be nice if there was a least an API call to clean a scene / prefab of invalid modifications. In our case we were left with a large orphaned array of assets still referenced from m_Modifications that I assume would still be loaded while in the editor.
     
unityunity