Search Unity

Feedback Add information about serialization of fields inside preprocessor directives

Discussion in 'Documentation' started by Trisibo, Jul 24, 2019.

  1. Trisibo

    Trisibo

    Joined:
    Nov 1, 2010
    Posts:
    245
    It would be really really great if there was clear information about what to expect in situations like this:

    Code (CSharp):
    1. public class Example : MonoBehaviour
    2. {
    3. #if XXXXXXX
    4.     [SerializeField] string someField;
    5. #endif
    6. }
    The "Platform dependent compilation" section of the documentation only mentions code, and the "Script Serialization" section says nothing at all. It is known that in some situations it can cause issues (for example, having a build-only field), while others seem to be innocuous and working fine in practice (like having an editor-only field), but I don't see any official guidelines about it.

    I believe having editor-only fields this way is a fairly common practice, used even by high-profile plugins (e.g., https://github.com/PlayFab/UnitySDK...DK/Shared/Models/PlayFabSharedSettings.cs#L11, which removes "dangerous" data from normal builds), and I've seen users asking for some kind of "EditorOnlySerializeField" in several places, so I think it's very important to address this usage in the documentation and explain what is safe and what isn't (and hopefully commit to ensure that what people is already doing today will always be safe).
     
  2. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    One of the issues this may be related to is the fact, that its not allowed to "change the serialization layout" (quote error messages thrown by Unity), when excluding serialized fields via preprocessor directives on AOT platforms. For other platforms, e.g. Windows, this is not an issue, but I believe this info is not mentioned in the documentation, or at least it is very hard to find.
     
  3. CharlesWard

    CharlesWard

    Unity Technologies

    Joined:
    Apr 19, 2017
    Posts:
    23
    Hi @DED-Games, I'm looking into improving our documentation of this area. Can you provide more details about the scenarios in which you have found serialization to be problematic so I can make sure we cover them in our documentation? Thanks!
     
  4. Trisibo

    Trisibo

    Joined:
    Nov 1, 2010
    Posts:
    245
    Great, thanks! Personally I haven't found this kind of issues in many scenarios, only in these two as far as I remember:
    • Having a serialized field only on builds. In this case Unity throws an error when building ("Type '[Assembly-CSharp]xxx' has an extra field 'xxx' of type 'xxx' in the player and thus can't be serialized") and doesn't continue in the first attempt, but when you try again it generates the build without complaining. At runtime an error appears twice: "The file 'xxxx/level1' is corrupted! Remove it and launch unity again! [Position out of bounds!]". Of course, a serialized field that exists only on builds is not very useful, but I wonder if there could be other situations that can cause the issue.
      Code (CSharp):
      1. public class Test : MonoBehaviour
      2. {
      3.     [SerializeField] string field1 = default;
      4.     #if !UNITY_EDITOR
      5.     [SerializeField] int field2 = default;
      6.     #endif
      7. }
    • The issue 1103759 (https://issuetracker.unity3d.com/is...ses-with-fields-that-only-exist-in-the-editor), which is a fairly specific scenario very unlikely to happen to most people. I can't remember what test project I sent, but something like this would trigger the issue for field "b":
      Code (CSharp):
      1. [Serializable]
      2. public class GenericBase<T>
      3. {
      4.     [SerializeField] int a;
      5.     #if UNITY_EDITOR
      6.     [SerializeField] T b;
      7.     #endif
      8. }
      9.  
      10. [Serializable]
      11. public class GenericDerived : GenericBase<float> {}
      12.  
      13. public class Test : MonoBehaviour
      14. {
      15.     [SerializeField] GenericDerived derivedField = default;
      16. }
    I have seen other posts and questions of people with similar serialization+preprocessor issues, but I'm not sure under what exact situations. At least in some cases, they seemed to be caused by a Unity bug that has already been fixed, involving just serialized fields inside "#if UNITY_EDITOR" AND asset bundles (https://forum.unity.com/threads/serialization-layout-and-asset-bundles.409743/#post-2669177). That this was considered a bug seems to say that this usage is actually supported by Unity:
    Code (CSharp):
    1. public class Test : MonoBehaviour
    2. {
    3.     [SerializeField] int intField = default;
    4.  
    5.     #if UNITY_EDITOR
    6.     [SerializeField] string stringField1 = default;
    7.     #endif
    8. }
    Which I have been using for some time without issues so far, as well as other people, I believe, but it would be nice to definitely know that it is an acceptable usage.
     
  5. Trisibo

    Trisibo

    Joined:
    Nov 1, 2010
    Posts:
    245
    Is there actually a difference between AOT and JIT platforms in this case? I have done some tests on Windows, Android and iOS (the ones in my answer above), and I haven't found any difference, the errors or lack of them were the same on the three platforms.

    This post mentions a difference in the .NET scripting backend, could it be the difference you mention? Though supposedly it was fixed: https://forum.unity.com/threads/serialization-layout-and-asset-bundles.409743/#post-2669177
     
  6. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    I don't really know what the background is, since I couldn't find documentation, but I've read a forum post that said this affects AOT platforms. I don't think this means its a JIT vs AOT issue, but instead that it happens on platforms such as Nintendo Switch, Android, iOS, Xbox and Playstation. I can confirm that the error is logged when I run a Nintendo Switch player, but not on Windows Standalone.
     
  7. Trisibo

    Trisibo

    Joined:
    Nov 1, 2010
    Posts:
    245
    There must be something more to it than just being an AOT platform, since in my tests the errors also appeared on Windows and Android (both JIT in my case since I used Mono instead of IL2CPP, correct me if I'm wrong). Do you remember what kind of situation it was?