Parsing template objects and overriding properties
jpeletier opened this issue ยท 2 comments
We are working on a new game where we are leveraging Tiled's template objects, but are having trouble with using Tileson to handle them.
When parsing map files that have map objects based on templates, it is not possible to know if the instance of the template in the map is overriding some properties, because tson::Object
has no concept of a field missing when parsing, thus it is initialized to its default value.
This means that if for example, width
/height
are not specified, they are initialized to a default Vector2i
of (0,0), which is incorrect since width
/height
were not really specified. When working with templates, we need to know whether or not the object instance in the map is overriding values or it is actually inheriting them from the template.
I propose a backward-compatible solution whereupon most of the properties of tson::Object
return an optional<type>
instead of type
, where optional<type>
is not std::optional
, but a very simple implementation that automatically converts to type
. Therefore, client code can remain unchanged.
Thus, following the above strategy for the width/height example:
// Object.hpp
const Vector2i &getSize() const
would become:
// Object.hpp
const tson::optional<Vector2i> &getSize() const
Example: suppose a tson::Object
with name obj
has been parsed out of the following JSON:
// (included as part of a layer)
{
"id": 1,
"x": 10,
"y": 20
},
Now, to obtain the size, the following old code will work:
tson::Vector2i size = obj.getSize();
Because I will write tson::optional<type>
to automatically convert to type
via a conversion operator.
This also will work, which is what we want to get to:
tson::optional<tson::Vector2i> size = obj.getSize();
if (size.has_value()) {
// override value coming from template
} else {
// use value coming from template
}
This way, client code can either get the value as before, or explicitly request to have an optional
delivered so it can check whether or not the field was actually present in the JSON or not.
This will also be a building block for Tileson parse template files.
I need this for our project, so I would be glad to make a contribution in this direction, be it following the above proposed solution with tson::optional<>
or any other, for example, adding new methods like "bool hasSize()" to be able to know if the fields were present or not in the JSON.
Thanks!
After giving this a second look, I think it would be more appropriate to modify tson::Object::parse()
to also load the template, if any, to return the resulting object after applying the template.
Therefore, for the height/width example, the following in tson::Object::parse()
:
if(json.count("width") > 0 && json.count("height") > 0)
m_size = {json["width"].get<int>(), json["height"].get<int>()}; else allFound = false;
would become something along the lines of:
if(json.count("width") > 0 && json.count("height") > 0)
m_size = {json["width"].get<int>(), json["height"].get<int>()};
else if(m_template != "") {
m_size = m_templateObj.getSize();
}
else allFound = false;
Where m_templateObj
is a parsed template object.
I will be working in this direction in our fork because I need a solution now and because it is straightforward, simple and fully backward compatible, but would love to discuss the best approach so we can improve this awesome lib!
Hello, @jpeletier, and thank you for your issue ๐
Glad to hear you are enjoying Tileson
! Just remember to use the version from the master
branch to be sure to get all the up to date features (it's basicly v1.4.0, just without finished release notes).
With that said: I understand your issue, and I think your latest post looks like a good solution. Your first post would make an undesireable signature change in a common object used by Tiled
, so in that sense your second solution is much better, as I aim to make the library as compatible as possible, without breaking changes (unless absolutely necessary) ๐
Feel free to post a pull request when your changes are done, and I'll do a review, and eventually include it in the 1.4.0 release. Just remember to do the changes in Object.hpp
and not in tileson.hpp
(as that file is generated by the amalgamate tool).