Search Unity

Feature Request Serializable static fields

Discussion in 'Editor & General Support' started by Were_Elf, May 9, 2022.

  1. Were_Elf

    Were_Elf

    Joined:
    Feb 25, 2022
    Posts:
    53
    It'd be really useful if we can have serializable static fields. Will make Unity much more convenient to use.
    And excuse me, if it already has this feature, but I couldn't find it. I only found a workaround, where you can duplicate the static fields with non-static ones and upon initialization copy the values form the non-static fields. But this is inconvenient and kills the whole purpose of having static fields in the 1-st place.
     
    MarshCZA likes this.
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,927
    You can't serialise static fields. That's an inherit part of them being static. How would that even work?

    Best you can do is make a scriptable object that acts as a single source of truth.
     
    Abdulrazek likes this.
  3. Were_Elf

    Were_Elf

    Joined:
    Feb 25, 2022
    Posts:
    53
    I imagine it working like this:
    When you select the script (in your assets, not on a game object) - you can set the static variables. This way you will be able to set them only once.
     
    MarshCZA likes this.
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,927
    Okay, but where would the actual data get serialised? Those script files themselves aren't assets, strictly speaking, but are all compiled into your assemblies come build time.

    Note this line on the C# documentation:
    So again, where would this data be serialised to?

    A better question is: why would you need this? There are many better ways to structure your systems to not require static values. Again, scriptable objects are a great alternative.
     
  5. Were_Elf

    Were_Elf

    Joined:
    Feb 25, 2022
    Posts:
    53
    I think I may or may not have misunderstood something. So let me see if I have the correct terminology. When I say "Serializable static field" I mean having a static variable, which can be set through the Unity GUI. I am using "Serializable", because when you use [SerializeField] for a private variable, you can initialize it via the GUI. And when you use [System.Serializable] for a class or struct, you can initialize them again via the GUI. So I just associated "Serializable" with "can be set up via the GUI".
    This is where I imagine them being set up:
    upload_2022-5-10_7-50-34.png
    I'm certain that the developers of Unity can figure a way to make this work.

    As for why would anyone need this. I can give an example:
    Imagine having an item in the game, which changes the icons and prefabs of some of your abilities. When you remove it they get reverted back to normal. You also have lots of item types. The way I've scripted the items is not as objects. I've scripted the "shop" and "inventory" and I have a class "ItemsList", containing all the items. So what would be the best way to do this? The way I've done it is: When the item is purchased, I check if it has a "special property", and execute the corresponding code, based on the property. So for the mentioned item, I need to replace the abilities' icons and the prefabs of the missile they spawn.
    In the "ItemsList" script I have a static void which does this. However, since I need a reference to the new icons and prefabs, I can't save the new icons and prefabs as static, as setting them up then would be a nightmare. Instead I need to make a static "ItemsList" variable, which I use in order to reach the non-static members in this static method.

    While this solution isn't that terrible, I'd much rather set the variables as static, rather than adding a static reference to an object instance. And while this depends on the programmer, what if they want such properties to be saved in a script, which isn't used a single time? Would be a waste of memory for each instance of the object to hold the same values as every other object of the type.
     

    Attached Files:

    MarshCZA likes this.
  6. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,927
    Your terminology is correct there, but you have to understand what serialising data means. Ergo, it means writing computer data in such a way that it can be read at a later date. In the context of Unity, and in many other cases, this means writing it to disk.

    For components in scenes or prefabs, they are written into the scene or prefab file. In the context of scriptable objects, they are written into their respective .asset files. You can open these files in a text editor and you can see the serialised data.

    So hence the question, where does the data of static fields get serialised? They belong to the type, not to any object. The script isn't an asset so it can't be serialised into that.

    On top of that, what initialises the field? Serialised fields get initialised when their respective objects are deserialised. Ergo, when an asset is loaded into memory, it's serialised data gets deserialised into runtime computer data and populates each matching field. Static constructors exist, and you can initialise these with [RuntimeInitializeOnLoad] and similar attributes in the context of Unity, but you'd still need an instance of some kind of asset holding data to pull the values from, so why bother when you could just reference that asset?

    Why does this method need to be static? Static methods are for when instance member information is not required. A method being static or not also has no bearing on memory usage.

    Everything here sounds like it can be done with scriptable objects and shallow inheritance, or perhaps by using some composition via the new
    SerialiseReference
    attribute.

    The item's themselves should contain the information on what happens when they are picked up/bought, especially if you say you have lots of items.

    I've not found myself in a situation where I've needed to serialise static data. I do have a number of singleton scriptable objects which act as a single source of truth; this should be what you could look into, or reconsider your current approach.
     
  7. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,927
    Put it this way, what you're suggesting is akin to Resources or PlayerPrefs, two old systems that often get abused/overused/used in ways they shouldn't be because of their ease of use, which leads to problems for those using them later down the line.

    Unity definitely doesn't need to introduce another system like that, not when there's many other better approaches readily available to you.
     
  8. Were_Elf

    Were_Elf

    Joined:
    Feb 25, 2022
    Posts:
    53
    I know that there are significant differences between C++ and C#, but for example in C++ you can initialize a static variable outside the class it belongs to:
    Code (CSharp):
    1. class MyClass{
    2. public:
    3.     static int myInt;
    4. };
    5.  
    6. int MyClass::myInt = 0;
    So I was thinking of creating a new script (internal for Unity or something), which initializes all of the static variables in the beginning.
    Actually, when I think about it, I can do something like that myself...

    It doesn't NEED to be static, but a member information is indeed not really required... or wouldn't have been required if I could initialize the variables I needed as static. And I'd need a reference to the member to call the method if it wasn't static. Although the way I've done it, I could just call the method, using the static variable, with the object's instance, but that'd be fairly similar to using that within the method itself, as I'm currently doing.

    Anyways.... the real problem here is how to initialize a static variable to an asset, as I haven't yet discovered a convenient way to do so.
     
  9. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,927
    As I already mentioned [RuntimeIntializeOnLoad] is a pre existing attribute that can be used to invoke static methods or static constructors at various stages of Unity initialising. [InitializeOnLoad] exists for editor purposes as well.

    Just

    use

    scriptable objects
     
  10. unity_59501B09AA827A202D8D

    unity_59501B09AA827A202D8D

    Joined:
    Oct 17, 2022
    Posts:
    1
    Static is best practice for game development. I think that static field really should be serializable in Unity.
     
  11. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,927
    I think you have a lot to learn about coding practices then.
     
  12. david-wtf

    david-wtf

    Joined:
    Sep 30, 2021
    Posts:
    25
    While I also agree that static is not the way to go in most cases, there's a tradeoff to make between configuring resources using serialized references (i.e. Unity's GUIDs) or accessing them using strings. For example, right now, it is not easily doable to configure "default assets" for a MonoBehavior script to use, without writing custom code generators that bridge the gap between the asset system and the C# code of your script (we have a decent amount of code generators in our project that take over this job because of the lack of Unity support).

    It's a common pattern to have a script that requires some pre-defined asset to operate on, and the most common way that is used by developers is to refer to those assets using a string (either a name, an asset path, etc.). This is bad, because strings are fragile, prone to typos, and hard to maintain and refactor. A static accessor for assets configured "on the C# script asset itself" would be a decent solution against this issue.

    As for the question where those variables would be serialized into: Each C# script has a .meta file, just like any other file, which can contain serialized variables. The same system is used by `UnityEngine.Editor` classes, which can already serialize "static fields" into the editor's C# asset. (Note that those are not `static` fields, because Editor types are singletons by concept anyways.)
     
    MarshCZA likes this.
  13. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,927
    Actually it's super easy.

    Step 1: Have a scriptable object with a singleton instance that initialises itself in
    OnEnable()
    .
    Step 2: Put in preloaded assets
    Step 3: Profit

    There's even a code example in the docs: https://docs.unity3d.com/ScriptReference/PlayerSettings.GetPreloadedAssets.html

    I use it all the time. You can even combine it with a SettingsProvider to make it look all fancy.
    upload_2022-10-21_22-55-9.png