-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New persistence strategy for better cross-version compatibility #1502
Comments
is json better than xml? |
binary serialization is possible in theory but is clunky in practice specially with this old version of mono. |
Json's simplicity tends to mean less setup and tweaking to get the results you need, which I think makes it better for small applications like TMPE. For large and complex data models I tend to lean toward XML, but in smaller applications like this, XML done right could end up being I also prefer XML for files intended to be manually edited. Json can be manually edited, but in my opinion it is a slightly less friendly format for that. (If you're wondering, I think XML is a better fit for AN, both because your long-term plans involve much more complex data, and because it's intended to be manually editable.)
There's actually a binary version of Json, unsurprisingly called Bson, and the version of mono is a non-issue as far as that goes. But text serialization is easier to troubleshoot, and I don't think we're talking about enough data for file size to be a concern. |
Also, |
Json sounds great. |
in AN ppl manually modify pops so I think XML is good |
XML allows saving more complex data structures which will be way more readable for the user if he wants to edit something. Having a JSON or even XML will make it at least editable -> you can dump the binary data into (JSON/XML) string and modify it at worst case or prepare small migration function which could automatically fix/transform things in case we make a mistake somewhere. We are limited with size of binary array which can be saved by Anyways I asked @Elesbaan70 about other ways for serialization since I also want to introduce changes to TMPE savegame data. I hope migration out of binary serialization will solve that problem at least partially. Obviously the current (de)serialization code needs to stay where it is to allow loading data from older savegames. |
Completely different because it's a standalone file and theoretically editable. Although in practice it's not a good implementation for manual editing--you can't even tell which switches are which, except by counting from the top. XML should be considered for any future standalone TMPE files. |
It's worth noting, in case it's relevant to the choices we're making, that binary serialization doesn't have to be this way. Bson doesn't behave this way. It's a question of how the binary serialization is accomplished.
|
@aubergine10 The "Settings" label is incorrect for this. It should be labeled "serialization" and "lifecycle". I would fix it, but I don't have any permissions here. :-) |
Yes I know, but I meant |
tell me about it! I do that all the time! I was thinking about overriding the Serializer but I think its easier to just add something in the maintenance tab. |
As I'm currently implementing it (a bit different from the demonstration code I showed you before), manager data is saved in a The dictionary itself is also serialized as Json, which is converted to a byte array using StreamWriter. It could be serialized as Bson instead, but there wouldn't be much savings since the data is text anyway, and staying with Json saves us from having to bring in a second external dependency for the Bson library. |
After all this discussion, it turns out that we will have to go with XML anyway. The Unity port of Newtonsoft.Json doesn't really work, and it hasn't been maintained in several years. *sigh* |
Lets use a port of XML that is less problematic. I suspect this old version of mono does not have very good XML. I see macsurgey's mods have provided their own |
Linq to XML is a DOM, not a serializer. I haven't look at it in a while, so I'll take a fresh look, but working with a DOM basically means you're assembling and interpreting the XML elements manually, so it ends up being a lot of work. Maybe I'm just being naïve, but I'm not very worried about Mono's |
If I recall properly lists are a pain to work with.
doing it ourselves? why not to just use 3rd party library? |
I guess I don't have context for that, because I'm not sure what you're referring to.
I meant "doing it ourselves" in the sense of processing all the elements manually, like MacSergey is apparently doing since he uses Linq to XML. If you know of third-party serialization that will work under Unity and has a solid track record and active development, I'm all for it. But the Unity port of Newtonsoft.Json being nonfunctional and abandoned is an example of where this can eventually lead if we're not careful. |
I don't know I have to do some tests. i think I had to convert list to array for it to work. |
I was struggling with xml here: https://github.com/Quboid/CS-MoveIt/blob/da6d67d770ff013162f931f01b3e88949ee7b3cc/MoveIt/Moveable/Instance.cs#L120 I don't know if there was an issue with dictionary or list or both but I had to use array. |
Yes, that's one of the annoying limitations I mentioned in After sleeping on it, I'm starting to warm up to the idea of using Linq to XML like MacSergey appears to be doing (I'm assuming this based on the presence of |
If anyone wants to follow the progress in code, it is here: https://github.com/Elesbaan70/TMPE/tree/xml-persistence |
Yup, but do we want to require a manual install of Mono? I think Linux users would generally be more comfortable with this kind of requirement than on other platforms, but it still seems less than ideal. |
whats the point of using xml if we are going to compress it? its no longer human readable. |
* XML does more than that, but that remains the essence of what XML serialization is doing. |
@Elesbaan70 we don't need to compress the global config though. |
I haven't even touched the global config yet. |
I mean, we're talking about global config, so it's not part of this anyway, right? |
yeah |
I think you didn't notice why compression might be required. The reason is simple. We still save data as byte[] in the savegame and there is a limit (~16MB IIRC) for a value. |
It uses a super-lightweight serializer I built on top of Linq to XML, that lets you serialize stable types but doesn't assume you've built a serializable model of your entire dataset. It's not intended to do that kind of heavy lifting, so it's stupid-simple and fits well in how Linq to XML does things. |
@Elesbaan70 in case you don't know, the problem with compression on Linux won't just fail or throw an exception... With regards to size, I think we will/could follow the idea of splitting "managers" into separate containers, so theoretically the limit of 16MB would be per manager, not whole data set. Anyways code for Junction Restriction is much more readable and understandable for me, compared to ugly from the Traffic Lights 😅 |
Yikes. So....
Okay, that's an easy enough change.
Yes! And yet, I suspect you will find it easiest to use the half-baked model approach I used in TTL. A full model like I created in the junction restrictions might require too much change to the manager's implementation. I chose Junction Restrictions for the full model example because I identified it as the easiest place to make a change of that kind. When I say "half-baked model," I mean that TTL implements a set of interfaces for its model, and the save code writes XML from those interfaces. But from the TTL implementation's point of view, that is a one-way trip. You can't hand a model to the TTL to set up traffic lights; the load code has to convert the incoming XML data into method calls that TTL understands for setting up the traffic lights. |
This change is now complete. |
@Elesbaan70 what does that mean? did you move lane arrow flags inside lane arrow manager? |
to detect if you are in linux you can check |
Huh? This issue is about how we store things in a savegame.
Cool, now how do I know if mono is installed? Or better yet, how do I detect the condition that causes the game crash? I will not knowingly merge code that causes someone's game to crash. A workaround that can be implemented in code is absolutely necessary. |
what change is complete? what does it mean to separate containers? |
you can look at original harmonys code. it has checks for mono version and stuff. which version of mono crashes? which version of mono works? are we talking bout dnSpy mono? |
The change history is on the draft PR associated with this case. The code for this issue isolates the logic for each manager in such a way that failing to load one manager's data does not prevent the others from loading. (That's one of the problems with the current code.) From my point of view, this was just a logic problem, but @krzychu124 understood it to mean that I was actually putting each manager's data in a separate container under But then @krzychu124 pointed out that it may be useful to use separate containers, since the container has a size limit. So now I've changed it to work the way he expected. |
On some Linux distros, the Mono bundled with the game does a hard crash if you try to use compression. Installing Mono independently of the game resolves this. |
Exactly, more info about crashing mono and solution you can find here: MacSergey/NodeMarkup#96 (already mentioned in this thread) Since we have limited size to be stored, @Elesbaan70 have you measure worst case scenario, how much data we really need to store - assuming we use container per manager? We usually use arrays of known size so we could calculate if generated xml will fit without compression or not |
we can ask in the harmony discord about this. they probably know something. |
Two-step light on a 4-way node without complex lane groupings: 2309 bytes, or about 7,000 total stoplights of this configuration. The more I think about this, the more I realize it's all or nothing. Otherwise we end up with savegames that some people can't read. Here's a possible ugly way of addressing the issue:
|
This code is basically ready to go. But the Linux compression issue needs to be worked out. |
I am reluctant to rely on an external library for a core feature. Also, a third-party compression library will be managed code, and so it will be slower, and compression is the kind of thing where that matters. So, what I'm looking at for the compression issue is:
|
its not like we have a better option. |
@krzychu124 finally got around to mentioning that there's a compression library distributed with CS. Wish I'd known that earlier! LOL |
Here is the wiki page. I'll improve this based on feedback. |
I thought you've tried "obvious" solution and it hadn't worked😂 I haven't tried using it for other things than collecting files from disk to create a zip file. |
Note - This issue originally called for the use of Json, which was determined be unfeasible due to the lack of a good full-featured Json serializer that is compatible with Unity.
Describe your idea
In TMPE's current persistence strategy, the introduction of a new type into the persistent data will break backward compatibility. Although old versions are not supported, players reverting from alpha to stable should not lose savegame data needlessly.
The same issue also affects forward compatibility in ways that restrict future development choices. Ideally, the save data would not be bound to specific types. A move away from strongly typed serialization would give everyone more flexibility moving forward.
Requirements
SerializableDataExtension
enumerates a collection of managers and callsLoadData()
andSaveData()
methods basically like the ones we have today.SerializableDataExtension
will save the data from each manager separately, to isolate them and minimize the risks associated with changes to persistent data.TrafficLightSimulationManager
will be the first converted to the new persistence strategy, since displaced lane support was the breaking change that prompted this issue. Its conversion to the new persistence strategy will be delivered separately from and prior to displaced lane support.Tasks
SerializableDataExtension
)The text was updated successfully, but these errors were encountered: