Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Can't override type of SerializeReference fields in prefab instances

Discussion in '2019.3 Beta' started by menderbug, Nov 12, 2019.

  1. menderbug

    menderbug

    Joined:
    May 14, 2018
    Posts:
    26
    I ran into another issue with
    [SerializeReference]
    . If I have such a field on a component that's used in a prefab, and I then change the type inside the that field to something else in a prefab instance (either as part of another prefab, or in the scene itself), the new type doesn't actually get saved. I think this is because Unity's serialisation format doesn't actually have a way to specify type overrides yet.

    Is this a known issue? Are there any known workarounds?

    With all these teething issues, I'm probably going to go back to
    [SerializeField]
    ,
    ISerializationCallbackReceiver
    and type-indicating enums for now. The new feature to serialise references is really powerful, but doesn't quite feel like a first-class citizen in Unity just yet.
     
  2. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    3,136
    Not a known issue AFAIK. Could you please submit a bug report?
     
  3. menderbug

    menderbug

    Joined:
    May 14, 2018
    Posts:
    26
    Sorry, took me a few days to make a separate Unity project for this, but I've submitted a bug report now (case 1199395).
     
    LeonhardP likes this.
  4. menderbug

    menderbug

    Joined:
    May 14, 2018
    Posts:
    26
  5. menderbug

    menderbug

    Joined:
    May 14, 2018
    Posts:
    26
    @LeonhardP can you say if there are any plans to include a default property renderer for [SerializedReference] fields? (I'm imagining something that just gives you a dropdown for all types derived from field's type and then just uses the normal property rendering for the actual value.)
     
  6. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    3,136
    Thanks for the bug report! I've relayed your question to the devs.
     
    menderbug likes this.
  7. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    3,136
    Got two replies from the devs.

    Re: default property renderer, there are no plans at the moment.

    Re: overriding type in a prefab instance,
    unfortunately this isn't possible due to how prefab instances store modifications (path/value). It's a known limitation but is currently undocumented. We'll include a note in the docs.
     
  8. menderbug

    menderbug

    Joined:
    May 14, 2018
    Posts:
    26
    Thanks for the quick response. That's unfortunate. The lack of a default renderer isn't a huge issue, since it's not too hard to write one yourself, but not being able to actually change the type of a field is a pretty big deal breaker for a feature that's supposed to enable polymorphic serialisation.
     
    kyuskoj likes this.
  9. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    429
    Prefab variant fields are resetted too from my testing.
    Do that limitation applies to prefab variants?
     
  10. menderbug

    menderbug

    Joined:
    May 14, 2018
    Posts:
    26
    I'm pretty sure it does, since it's just a fundamental limitation of Unity's current serialisation format.
     
    TextusGames likes this.
  11. kaiyum

    kaiyum

    Joined:
    Nov 25, 2012
    Posts:
    686
    This is my setup:
    The interface and the implementation:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public interface IBullet
    6. {
    7.     void Fire();
    8. }
    9.  
    10. public class MachineGunBullet : IBullet
    11. {
    12.     [SerializeField] string aName = "MachineGun bullet";
    13.     void IBullet.Fire()
    14.     {
    15.        
    16.     }
    17. }
    18.  
    19. public class AK47Bullet : IBullet
    20. {
    21.     [SerializeField] string aName = "AK47 bullet";
    22.     [SerializeField] GameObject particle;
    23.     void IBullet.Fire()
    24.     {
    25.        
    26.     }
    27. }
    28.  
    29. public class ShotGunBullet : IBullet
    30. {
    31.     [SerializeField] string aName = "ShotGun bullet";
    32.     [SerializeField] AudioClip shotSound;
    33.     void IBullet.Fire()
    34.     {
    35.        
    36.     }
    37. }
    And the component:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Shooter : MonoBehaviour
    6. {
    7.     [SerializeReference] [SerializeReferenceButton] IBullet mainBullet;
    8.     [SerializeReference] [SerializeReferenceButton] List<IBullet> bullets;
    9.     // Start is called before the first frame update
    10.     void Start()
    11.     {
    12.        
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update()
    17.     {
    18.        
    19.     }
    20. }
    21.  
    The '[SerializeReferenceButton]' comes from a plugin developed by @TextusGames. Basically it creates a button beside the field which lets you to create and add an implementation of the interface from a dropdown list of all available implementation.

    The shooter is attached to a gameobject which is a prefab. The default implementation of 'mainBullet' in shooter is 'ShotGunBullet'. If I drag the prefab into scene and modify 'mainBullet' to 'AK47Bullet' from 'ShotGunBullet', I am able to do so. Then if I press play and enter playmode, the field 'mainBullet''s data does not get lost or revert into something. Even I can drag the prefab into another prefab and yet no data loss. Is the issue fixed? I am confused.

    Unity version 2020.3 Mac for iOS platform.