Steps to reproduce:
- Install Newtonsoft.Json-for-Unity.Converters
- Create a monobehavior implementing ISaveable which returns a Vector3 from ISaveable.CaptureState
- Cast to Vector3 in ISaveable.RestoreState
- Run the scene with a SaveManager in scene
- Save, then load
- Observe an InvalidCastException, due to the argument passed in to ISaveable.RestoreState being a JObject rather than a Vector3
Or, open the reproduction project: https://github.com/dsmiller95/SaveAsyncEditingProject
- open and run Assets/Scenes/SampleScene
- Click "Save stuff"
- Click "Load stuff"
- Observe exception in console.
Proposed solutions
Include top-level type information via generic
An optional alternative ISaveable interface could allow implementers to opt-in to providing extra typing information to the (de)serializer. This would simplify the output JSON file by no longer requiring all Data JSON to include a "$type" field like "Data":{"$type": "typename", ...}. This could live alongside the generic ISaveable for backwards compatibility, but would be required for ISaveables which return an object with an overriden converter like Vector3.
For example:
public interface ISaveable<T>
{
public string Key { get; }
public string Filename { get; }
T CaptureState();
void RestoreState(T state);
}
Include top-level type information via existing interface
Instead of a generic interface, add a new getter to ISaveable. I.E. public System.Type SaveType { get; } . Use this to provide type information to the (de)serializer. Will be a breaking change, although minor.
Force Iincluding TypeName information in JSON
Modify the JSON.Net JsonConverter settings used by the SaveManager to force including typename information, even when using external converters like Newtonsoft.Json-for-Unity.Converters .
Ignore and document
Do not fix, and document that this use case may be unstable. Require users to wrap save data inside a save object.
Steps to reproduce:
Or, open the reproduction project: https://github.com/dsmiller95/SaveAsyncEditingProject
Proposed solutions
Include top-level type information via generic
An optional alternative ISaveable interface could allow implementers to opt-in to providing extra typing information to the (de)serializer. This would simplify the output JSON file by no longer requiring all Data JSON to include a "$type" field like
"Data":{"$type": "typename", ...}. This could live alongside the generic ISaveable for backwards compatibility, but would be required for ISaveables which return an object with an overriden converter like Vector3.For example:
Include top-level type information via existing interface
Instead of a generic interface, add a new getter to ISaveable. I.E.
public System.Type SaveType { get; }. Use this to provide type information to the (de)serializer. Will be a breaking change, although minor.Force Iincluding TypeName information in JSON
Modify the JSON.Net JsonConverter settings used by the SaveManager to force including typename information, even when using external converters like Newtonsoft.Json-for-Unity.Converters .
Ignore and document
Do not fix, and document that this use case may be unstable. Require users to wrap save data inside a save object.