GetComponent is genuinely broken

In that case, you should have used a Data class (a.k.a POCO), that holds all the object’s data , instead of a bunch of private serialized fields. Then you would just deserialize it from Json and pass it to the Prefab instance. Very simple and efficient.

EDIT: Can you tell us how did you solve it, for future readers. Thank you and happy that you solved it.

There are various ways I could improve it I’m sure, but for now as long as it works I find it really easy to use when I create a new script and need to specify what should/shouldn’t be saved.

I used TryGetComponent instead and that worked - see my post above

I’m hesitant to wade into this whole debate; but this system seems brittle for another reason not brought up: many components can be included more than once on the same GameObject. Colliders are a prime example, but any MonoBehaviour can be stacked unless you explicitly declare it [DisallowMultipleComponent]. Checking if a component is present will only work when you’re sure that there’s only ever going to be one copy of the component.

There’s a reason Unity has decided not to provide a “save whole object at runtime” facility, even though it relies heavily on saving scenes, saving prefabs, inspecting objects, providing an Undo stack, and instantiating objects all via the very same serialization mechanism. In the Editor’s case, it can know when the code underlying the Type differs from the saved serialized form. At runtime, you’re going to have to be just as sensitive to all the quirks of the internal object model and contracts that the Editor implements.

The „working fine so far“ part may come apart when you have made your first release, and then update your game, and then realize old saves aren‘t compatible with the changes you made.

Every savegame system needs versioning, on the savegame level at least and typically also on a per type level. You don‘t want to be in a situation where you need to load old fields and decide what to do with their data without knowing what savegame version they belong to, or: not knowing what data you are reading and how to interpret it. The real tricky changes are when no field name or type changed but how the value gets interpreted. Perhaps it used to be euler angles but now that same Vector3 is in radians - but was it already saved as radians or not? And was it the version with the bug where the xz values were accidentally flipped?

Pretty much this. Data you want to save really should be wrapped into pure C# objects. A good save system should contain as little, if not zero, quirky Unity specific data unless the serialiser specifically supports them (such as the Odin serialiser).

Separating model from view helps a lot here. If you plan ahead, you easily save the state of your game without much work by keeping it all separate in the pure C# land.

This is something I am aware of. Currently I don’t re-use the same component more than once on an object so it’s not an issue but if I ever do then I’ll update my code to proces duplicates. Things like colliders are not included in the save file as they don’t change so there is nothing to save.

The save file also includes a version number, if there is anything that would break between versions - this is handled by a separate function to patch the save file before it’s loaded. This isn’t even a problem specific to my solution. Even if you went the more typical route and used a C# class to create a save file, you’re still going to get errors if you later delete something from that object, or add something new unless you handle it.

Nah, not with JSON.

  • If a field is provided in the JSON data stream and no longer present in the save class, it is ignored.

  • If a new field is present in the save class and there is no data for it, it remains default(T)

While both of those things may later cause errors in your game’s business logic, you won’t “get errors” from either of those cases from the underlying serialization process.

JSON is awesome. Also, always be sure to leverage sites like:

https://csharp2json.io

Exactly. An error is an error, regardless of where it props up it’s still going to need handling.
And I am already using JSON…the only difference is the source of the data
My system would have the exact same results as what you described - values will just be their default if they don’t exist in the save file.
It works like this:
Serialise the component using JSON utlities
Delete anything that isn’t wanted in the save file.

Then for loading:
Load the JSON using json utilities.

It works the same as a normal save system. Just the structure is not predefined by a class. There is no reflection based stuff on the fields - only on the components and attributes so it knows where they go then the usual JSON deserialisation stuff happens

E.g. say I have 3 objects each with 1 component (call them A, B, C)
FOR SAVE:
Serialise object1.A (same way as you would for a save class object), delete anything that is flagged to be excluded from the save file.
Serialise object2.B, delete anything that is flagged to be excluded.
Serialise object3.C, delete anything that is flagged to be excluded.

FOR LOAD:
Instantiate object1 prefab (this already has an A component)
Detect that some block of fields belong to the A component of object1.
Deserialise that JSON to populate object1.A
Fix references to other objects

Repeat for the other objects.

It’s really not that much different to a regular save system at its core, just allows me an easier way to define what should/shouldn’t be saved