#Serializable reference troubles

1 messages · Page 1 of 1 (latest)

stable mountain
#

This is related to the issue I was having here #1390355039272439868 message, essentially I'm trying to get all my code straightened out so I can work with my editor tool without domain reloading causing things to become null.

I dont totally understand why the error exactly happens here when the debugger shows the first error:

System.NullReferenceException: Object reference not set to an instance of an object
  at VoroSystem.Generation.GraphSystem.Graph.VoroGraph.ComputeHash () [0x00001] in ../VoroGraph.cs:25 
  at VoroSystem.Generation.GraphSystem.DesignerComponent.Update () [0x00011] in ../DesignerComponent.cs:35 ```

My `[Serializable] public class VoroGraph {`  has the attribute, so I think thats all it needs, as for the Component, the field is `[SerializeField] public VoroGraph graph;` which also seems like all it should require. Clearly thats not the case.
odd sentinel
#

!code

sullen fernBOT
stable mountain
#

Thats both of the classes

odd sentinel
#

share it properly with the large code blocks section please

stable mountain
#

Do the embedded files not show correctly?

odd sentinel
#

i'm not counting out 35 lines, mate

stable mountain
#

huh, thats odd it doesnt include the line numbers

odd sentinel
#

discord's preview is for viewing files, not specifically dedicated for viewing code

#

it won't have the features that dedicated tools have

#

the preview doesn't even show over 100kb, iirc

silent torrent
stable mountain
odd sentinel
#

so, something on line 25 is null, that can either be Layers or one of the layers inside the callback

#

is GraphLayer serializable / is Layers serialized?

stable mountain
#

Ah, so it is still do to the with the List from before

odd sentinel
#

did you like, not check the line the stacktrace mentioned at all lol

stable mountain
#

GraphLayer is serializable, yeah
and I'm sure Layers is serialized, if I understand Rider showing it with the dark grey text implying its redundant

#

as the class itself is Serializable, any field within, should also be (thats how I interpret this at least)

odd sentinel
#

it's redundant because of the public, i don't think it necessarily means it's serialized

#

Serializable doesn't make everything inside serializable, it just marks the class/struct itself as serializable
for each field, if it's public/marked serializefield, and has a serializable type, it'll be serialized as part of the class/struct

blissful urchin
#

need field: in serializefield for properties too

odd sentinel
#

and also, Layers isn't a field.

#

im dumb lmao

#

it's not serialized here

#

if you want it to be serialized, you would have to mark the backing field serialized, like batby mentioned

stable mountain
#

Whats the difference between [SerializeField] and [field: SerializeField] then?

odd sentinel
#

what's the point of VoroGraph being serializable if it doesn't have any fields that are serialized

odd sentinel
stable mountain
odd sentinel
#

i don't think it being serializable has any effect

#

it's not the thing becoming null anyways

#

are you mutating Layers anywhere other than CreateLayer?

stable mountain
#

I just run the tool, let it do its thing, and then I make a tweak to the code and force it to reload

odd sentinel
#

what's the overall goal here? i think i'm making an assumption that's wrong

stable mountain
#

I've made this editor extension, but as soon as I alter any code, things break due to null exceptions. Its frustrating to do stuff with it, as I have to keep repeatedly deleting all the objects and remaking them

odd sentinel
#

and the nulls come from domain reloads?

#

it kinda sounds like there are stale objects from before the reload that actually have data, but new ones created after the reload don't, but assume they do

stable mountain
#

console fills up with those once it reloads

#

My understanding is if something isnt serialised, it gets cleared upon the domain reload

#

its not very practical for an editor extension if I have to repeatedly recreate everything from scratch the moment I start writing code

#

I did add field: and I still get the same errors from before. To make it easier, how do I work out the "root cause" while im in debug mode and its showing me the null reference exception?

odd sentinel
#

where is everything ultimately stored? an MB/SO somewhere?

stable mountain
#

No scriptable objects, its only this set of MBs along with my plain C# classes

silent torrent
#

Last graph hash, doesn't really serialize anything, as you can see it's being empty.

odd sentinel
odd sentinel
blissful urchin
#

Also this could be totally wrong but do you need to define a setter for a property to correctly serialize

odd sentinel
silent torrent
odd sentinel
blissful urchin
#

Dunno i just have that vibe, also can’t check directly lol

stable mountain
#

Okay, so Ive run the tool and its set up now, no errors (debugger is active). I'll just add some line to an unrelated class to make it domain reload, before I do that, is there something I can do to make it easier to check what the problem might be?

#

Its naive to say, but like some kind of AB comparison where it shows what changed between the two "states"

stable mountain
blissful urchin
#

those are fields not properties

blissful urchin
#

(I understand that the naming for this is stupid)

stable mountain
odd sentinel
#

it's VoroGraph.Name and VoroGraph.Layers that need the field:, because those are properties

blissful urchin
#

You need field field for no field 😭

odd sentinel
#

field - Type name; / Type name = value;
property - Type name { ... } / Type name { ... } = value;

#

still bothers me that uninitialized props, not only don't need a semi, but can't have a semi

stable mountain
#

To be clear, do you mean [field: SerializeField] public string Name { get; } ?

odd sentinel
#

yes, and same on Layers

#

you should then see those in the inspector

stable mountain
#

how strange

odd sentinel
#

you might have to remove the field: in DesignerComponent

#

also make sure to reload

stable mountain
#

No change

#

ooh, is it due to the getter?

#

let me see

#

It was

odd sentinel
#

no clue what you mean by that

stable mountain
#
    [field: SerializeField] public string Name { get; }
    [field: SerializeField] public List<GraphLayer> Layers { get; } = new();```
is now
```cs
    [field: SerializeField] public string Name;
    [field: SerializeField] public List<GraphLayer> Layers = new();```
#

They show up in the inspector now, but also the first set of NREs I get have also changed

odd sentinel
#

they aren't properties anymore, they can be set by other stuff. is that what you're going for?

blissful urchin
#

I actually didn’t know fields would serialize with the specification there, makes you wonder why it’s not just default behaviour that covers both 🤔

stable mountain
odd sentinel
#

i don't know if it'd work either lol

odd sentinel
#

you're now pingponging between ways of serializing them

#

to have something be serialized, you need:

  • a serializable type
  • one of:
    • a public field
    • a field marked [SerializeField]
    • an autoproperty, with its backing field marked [field: SerializeField]
stable mountain
#

I'm guessing this must be done for 100% of my classes? ie I just need to open up every single file in the project and append the attributes

odd sentinel
#

you need to serialize everything that needs to be saved

stable mountain
#

Hmm, I suppose this is an aspect I've never really needed to think about. Because I feel like that applies to everything in the project

odd sentinel
#

then you'd serialize them

stable mountain
#

But that also doesnt sound right

odd sentinel
#

well, stuff that's computed from other stuff or caching doesn't need to be saved

#

runtime state stuff doesn't need to be saved

#

it's perfectly normal to not have any of those

blissful urchin
stable mountain
stable mountain
blissful urchin
#

You might not be but one step at a time for this kinda stuff tbh

#

Personally I end up using scriptableobjects for that kinda stuff to keep stuff less essential on scene setup but lotta ways it can be done

stable mountain
#

As rider gives me errors I can chip away at the fixes.
SOs have been in the back of my mind, but I havent worked out what would be a viable use of them for this project

#

I've made use of them in earlier projects, but its always been a more "game-ified" use case with those. Which also happens to be the only real examples I see of them online, things like enemies or guns, less so internal workings for more technical aspects

silent torrent
#

Also, if you're modifying these fields via a custom editor window, you might need to dirty the objects so that these changes are actually saved.

wide snow
#

To give some information regarding domain reload: private fields are also serialized on domain reload. Fields don't need to be public or marked with [SerializeField]. If the field can be serialized (e.g. the type is [Serializable]), the engine will do it.

This is very surprising the first time you stumble upon it, but it's documented here, 3.a:
https://docs.unity3d.com/6000.2/Documentation/Manual/configurable-enter-play-mode-details.html

OnDisable and OnEnable are always called around domain reloads, but Awake and OnDestroy are not

So, I thin kyou can rely on this serialization for whatever is editor class to persist, and/or save stuff to an asset in OnDisable and reload it in OnEnable.

stable mountain
#

It might be a silly question, do MonoBehaviours ever need any sort of Serializable attribute? I've gone through every file, and appended the various SerializeField attributes, as far as I can tell, the null reference error I'm not getting is due to one of my singleton components not persisting on reload

#

is there a resource that I can read up on about all this stuff, I still dont really get it. All it feels like I'm doing is blindly appending the attributes and hoping that it sticks

odd sentinel
#

unity Objects are serialized by reference

#

have you gone through the serialization rules manual page? it just occured to me that i don't think ive linked that to you

stable mountain
#

I hope it can shine a light on whatever im missing, as my flawed approach of blindly throwing [SerializeField] [field: SerializeField] [SerializeReference] [field: SerializeReference], while it seems to solved a lot of the errors, its meant that now I'm left with further problems that I dont totally get how to correct

#

I might remove every single attribute I added and start from scratch following what this page says

silent torrent
#

You only need the attribute of you want unity to serialize non public fields. That's basically it.

odd sentinel
#

you might need to just step back and design the system out first rather than diving into the code

silent torrent
#

Backing fields of properties

stable mountain
odd sentinel
#

and are domain reloads part of a normal workflow when working with the system?

#

if so, then your system isn't fully working yet

#

to clarify - i don't mean designing it out from scratch

#

just the aspect of how/where you're storing data

#

that seems to be the part you're struggling with, and that's kind of twofold - you're having trouble figuring out what to serialize, and how to serialize

#

separate those problems out

#

draw out your system as it is, and design what stuff needs to be serialized

#

then implement the serialization as desgined

stable mountain
odd sentinel
#

so that's a yes

#

your system should handle domain reloads, and it currently isn't - so you have more work to do

stable mountain
odd sentinel
#

then you better make sure it's all serialized

#

perhaps check if stuff needs to be by value or by reference to link up properly

stable mountain
#

mhmm. All the attributes have been removed so I can start from a clean slate. Thankfully it doesnt actually break anything by adding/removing them 😅

silent torrent
#

Attributes just tell unity what in the object should be serialized when serialization is touching the object. But the object needs to be considered for serialization in the first place.
I've mentioned earlier, but if you modify properties via code, unity might not even consider that they need to be saved.
This depends on how you have your editor script implemented.

wide snow
stable mountain
#

However, if that truly was the problem I cant say

wide snow
#

for edition-time singletons I usually implement a separate getter that does a find first object by type if it's null

odd sentinel
#

i recall someone saying Awake wouldn't be called on domain reload? if that's the case, i don't think typical singletons using ExecuteAlways would survive a domain reload

wide snow
#

indeed

odd sentinel
#

you wouldn't want to serialize a singleton instance by value

stable mountain
#

Fortunately I think the only singletons I have are exclusively within the MonoBehaviour classes. And it just so happens that these ended up all existing on the same GameObject anyway

#

I wont make those changes yet, getting the fields in order is top priority, actual modifications can come later

#

though its really only going to be putting in some GetComponent

halcyon forum