-
Notifications
You must be signed in to change notification settings - Fork 20
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
Serialization overhaul #830
Comments
I'm game for using a Dictionary type object. Without looking too deep into the Dictionary class, can I suppose that's all down to the implementation details but I'm totally in favor of doing it this way. Not having to deal directly with XML processing would simplify so many things. |
The underlying code uses We could potentially upgrade |
All except one use of the XML The Now that attributes have been largely dealt with, some consideration needs to be given to the Another approach we could take is to flatten the saved game file structure a bit. That may make a lot of sense in some cases. I don't know that it would apply everywhere though. One downside of a structural change from flattening the saved game data, is the affects it would have on saved game file compatibility. This can be partially mitigated by providing an upgrade path where certain versions of the game can load old files and re-save them in a new format. Though I'm hesitant to put too much effort into that when we are still reasonably far from a v1 release. |
I wouldn't be too worried about compatibility yet considering it is tough to play for more than an hour tops right now with the current content. I had thought splitting tilemap serialization into smaller functions was a good idea as well. |
I'm really not worried about savegame compatibility at this point. As Brett pointed out, there's not yet much to lose other than a bit of time. Now would be the time to make the changes especially with the research tree coming due for development where users will want to actually save their games and come back to it (actual progress can be made at that point). So yeah, now's the time to make breaking changes. |
I've been looking back at this. We've removed most direct uses of We still have a fair bit of code in OPHD that directly uses In terms of |
I've noticed rather repetitive error reporting code, that reports a file line number and column that lead to a parse error. Potentially we could abstract away that error reporting too. Currently most parse code is driven by data format specific functions, which make calls into XML handling objects. This means when that custom code detects an error, it must also include custom error reporting code. Instead, we could potentially invert things, and have a generic parse function that takes a parse method as a parameter, and can call that method with a new data type roughly representing an Example: const auto parsedData = parseFile("filename.xml", parseFunction); auto parseFunction(const DataStore& genericRecursiveDataStoreObject)
{
// ...
if (isError)
{
throw std::runtime_error("Something very specific and bad happened");
}
return data;
}
Or maybe an error occurs while parsing a sub-object instead. Example: auto parseFunction(const DataStore& genericRecursiveDataStoreObject)
{
// ...
const auto subData = genericRecursiveDataStoreObject["subObjectSectionName"].parse(subObjectParseFunction);
// ...
}
auto subObjectParseFunction(const DataStore* genericRecursiveDataStoreObject)
{
// ...
if (isError)
{
throw std::runtime_error("Problem parsing SubObject");
}
// ...
}
|
Continuing the above idea, to do automatic error reporting, the parsing needs to be wrapped in generic library methods that handle the actual XML data. That means passing callbacks into this methods so they can parse the data into arbitrary data structures. To implement such generic library methods, they will need a templated return type, as they won't know what specific data structure will be parsed. They will also need a parsing function parameter, with that return type, which could be a templated callable object. It may be tempting to use One downside to using a templated method, is the implementation would need to be placed in the header file, and any code used by the implementation would need corresponding Alternatively, we could design an API with no return type, and leave extracting the data to some other means. Presumably a lambda could capture an object it needs to feed the data to, and writing that data could become part of the parse function. That seems like a little bit less clean of a concept though. const auto parseFunction = [&object](const DataStore& genericRecursiveDataStoreObject) {
object.data = ... // Parse and assign some data
};
parseFile("filename.xml", parseFunction); As another possible alternative, maybe the const auto rootSection = parseXml("filename.xml");
const auto version = VersionString{rootSection.get("version")};
if (version < "1.0.0") {
rootSection.throw("Expected version 1.0.0 or greater. File version: " + version);
}
const auto dataSection = rootSection["data"];
// ...
if (...) {
dataSection.throw("Missing required attribute: size");
} Possible error outputs:
I think I may want to explore this last possibility, as it may be the most natural to many programmers, avoids putting implementation in templated methods in header files, and still provides support for generic parsing error messages. Reported file positions in error messages might have limited granularity, perhaps indicating the section, rather than a specific attribute or sub element. For instance, there might be a "root" |
The save/load code has a lot of direct calls to the XML code in NAS2D. There is a plan to update the NAS2D XML code from TinyXML1 (with local modifications and renames) to TinyXML2. Such an upgrade will break a lot of existing code. We should try to minimize the number of direct calls to XML code to ease the transition.
References:
vcpkg
to install TinyXML lairworks/nas2d-core#211As much of the save/load code needs to save and restore arbitrary data, much of it works with
XmlElement
objects. Instead, we could potentially have objects return aDictionary
of data that needs to be saved, or to accept aDictionary
of data to process when loading.Reference: https://github.com/lairworks/nas2d-core/blob/master/NAS2D/Dictionary.h
We could have methods that convert
Dictionary
objects to/fromXmlElement
nodes. For loading code, the ParserHelper methods can be used to validate the presence of required fields. It can also be used to detect extra unknown fields.Reference: https://github.com/lairworks/nas2d-core/blob/master/NAS2D/ParserHelper.h
Using these objects may allow for simplifications in the loading code. It should also allow the XML references to be lifted to a higher level and reduced in number.
The text was updated successfully, but these errors were encountered: