Releases: SSBMTonberry/tileson
Release 1.4.0
Should support the most recent version of Tiled: 1.10.2.
Features
- Tiled 1.9 support (#68)
- Tiled 1.8 support (#60)
- Class and enum properties: When having maps related to a
Project, you can use theclassproperty with your own class definitions. Same goes forTiled`enums``.
- Class and enum properties: When having maps related to a
fs::path pathToUse = fs::path("path/to/project.tiled-project");
tson::Project project{pathToUse};
auto folderFiles = project.getFolders().at(0).getFiles();
for(fs::path &f: folderFiles)
{
fs::path path = project.getFolders().at(0).getPath() / f.filename();
std::string filename = f.filename().generic_string();
if(filename == "map1.json")
{
tson::Tileson t{&project};
std::unique_ptr<tson::Map> m = t.parse(path);
tson::Layer *objectLayer = m->getLayer("Da Object Layer");
//Get class from object
tson::TiledClass *objectClass = objectLayer->firstObj("TestObject")->getClass();
//Asserts as example how to use members
REQUIRE(objectClass != nullptr);
REQUIRE(objectClass->getName() == "Enemy");
REQUIRE(objectClass->get<int>("hp") == 10);
REQUIRE(objectClass->get<std::string>("name") == "Galderino");
//Get class from tile
tson::Tile *tile = m->getTileset("demo-tileset")->getTile(1);
tson::TiledClass *tileClass = tile->getClass();
//Example how to get member of different types with asserts
REQUIRE(objectClass->getMember("Age")->getType() == tson::Type::Int);
REQUIRE(objectClass->getMember("Age")->getValue<int>() == 49);
REQUIRE(objectClass->get<int>("Age") == 49);
REQUIRE(objectClass->getMember("CanDestroy")->getType() == tson::Type::Boolean);
REQUIRE(objectClass->get<bool>("CanDestroy"));
REQUIRE(objectClass->getMember("ExtraFile")->getType() == tson::Type::File);
REQUIRE(objectClass->get<fs::path>("ExtraFile") == fs::path("../ultimate_test.json"));
REQUIRE(objectClass->getMember("MoneyInBag")->getType() == tson::Type::Float);
REQUIRE(tson::Tools::Equal(objectClass->get<float>("MoneyInBag"), 16.9344f));
REQUIRE(objectClass->getMember("MyObject")->getType() == tson::Type::Object);
REQUIRE(objectClass->get<uint32_t>("MyObject") == 39);
REQUIRE(objectClass->getMember("Name")->getType() == tson::Type::String);
REQUIRE(objectClass->get<std::string>("Name") == "James Testolini");
REQUIRE(objectClass->getMember("ShoeColor")->getType() == tson::Type::Color);
tson::Colori color = objectClass->get<tson::Colori>("ShoeColor");
REQUIRE(color == "#ff069504");
REQUIRE(color.a == 0xff);
REQUIRE(color.r == 0x06);
REQUIRE(color.g == 0x95);
REQUIRE(color.b == 0x04);
//Example of different enum properties stored within objects
//Numeric and string based enums with and without flag properties
tson::Object *enumObj = objectLayer->firstObj("TestObjectEnum");
tson::TiledClass *objectClassEnum = enumObj->getClass(); //Object is changed from default values
tson::TiledClass *tileClassEnum = tileClass;
REQUIRE(enumObj->getProp("num_enum") != nullptr);
tson::EnumValue objPropNumEnum = enumObj->get<tson::EnumValue>("num_enum");
REQUIRE(enumObj->getProp("num_enum_flags") != nullptr);
tson::EnumValue objPropNumEnumFlags = enumObj->get<tson::EnumValue>("num_enum_flags");
REQUIRE(enumObj->getProp("str_enum") != nullptr);
tson::EnumValue objPropStrEnum = enumObj->get<tson::EnumValue>("str_enum");
REQUIRE(enumObj->getProp("str_enum_flags") != nullptr);
tson::EnumValue objPropStrEnumFlags = enumObj->get<tson::EnumValue>("str_enum_flags");
REQUIRE(objPropNumEnum.getValue() == 3);
REQUIRE(objPropNumEnum.getValueName() == "GetNumber");
REQUIRE(objPropNumEnumFlags.getValue() == 9);
//Flags enums (numeric and string) may use custom enum classes, as long as they have applied flags logic applied to them. See details how this can be achieved below this code example
REQUIRE(objPropNumEnumFlags.hasFlag(tson::TestEnumNumberFlags::HasCalculatorFlag | tson::TestEnumNumberFlags::HasInvisibilityFlag));
REQUIRE(objPropStrEnum.getValue() == 2);
REQUIRE(objPropStrEnum.getValueName() == "DeletePlayer");
REQUIRE(objPropStrEnumFlags.getValue() == 6);
REQUIRE(objPropStrEnumFlags.hasFlag(tson::TestEnumStringFlags::HasJobFlag | tson::TestEnumStringFlags::HasHouseFlag));
//Another example with flags more in depth
tson::EnumValue numEnumC2 = someClass.getMember("NumFlag")->getValue<tson::EnumValue>();
tson::EnumValue strEnumC2 = someClass.getMember("StrFlag")->getValue<tson::EnumValue>(); //Not used here, but will work in the same way
REQUIRE(someClass.getMember("NumFlag")->getType() == tson::Type::Enum);
REQUIRE(numEnumC2.getValue() == 10);
REQUIRE(numEnumC2.hasFlag(tson::TestEnumNumberFlags::HasBombFlag | tson::TestEnumNumberFlags::HasInvisibilityFlag)); //Has both these flags - OK
REQUIRE(numEnumC2.hasFlag(tson::TestEnumNumberFlags::HasBombFlag)); // Has this flag - OK
REQUIRE(numEnumC2.hasFlag(tson::TestEnumNumberFlags::HasInvisibilityFlag)); // Has this flag - OK
REQUIRE(numEnumC2.hasAnyFlag(tson::TestEnumNumberFlags::HasBombFlag | tson::TestEnumNumberFlags::HasHumorFlag)); //hasAnyFlag is okay as long as one of the flags here are set
REQUIRE(!numEnumC2.hasFlag(tson::TestEnumNumberFlags::HasHumorFlag)); //Doesn't have this flag - OK
}
}The enum bitflags used in the examples above, uses a macro defined in include/common/EnumBitflags.hpp to be able to use them for bitflag checks. The only restriction this macro has, it's that it requires the tson namespace of any enums using it. With that in mind, here is an example how to create a flags enum:
namespace tson
{
enum class ExampleFlags : uint32_t
{
None = 0,
Big = 1 << 0,
Slippery = 1 << 1,
Funny = 1 << 2,
Lazy = 1 << 3,
All = Big | Slippery | Funny | Lazy
};
}
TILESON_ENABLE_BITMASK_OPERATORS(ExampleFlags)If you need the flags to be another namespace: Feel free to just steal the code and modify it for you own use.
- Added
quomas amalgamate tool forOSX(#82) - Thanks to dmlary - Now using
Github Actionsinstead ofTravisfor CI (#50) - Thanks to Laguna1989 - C++20 support (#53) - Thanks to gamecoder-nz
Improvements
- Only include
external_libsfolder if examples or tests are required (#96) - Thanks to Laguna1989 - Tests are now stricter and treats warnings as errors (#90) - Thanks to dmlary
- CI improvements: Added
MacOS, separated CI by system and added Clang 12 and 13 support on Linux (#88) - Fixed some Apple Clang 13 compile warnings (#84) - Thanks to dmlary
- Updated Catch2 to support
GCC 11.2(#59) - Added missing properties to
tson::Text(#75)
Breaking changes
- Should be none.
Bug-fixes
- Fixed bug where template objects did not correctly override properties (#100) - Thanks to jpeletier
- Fixed bugs related to not being able to resolve
TiledEnums in certain contexts (#98) - Tile properties should now be properly loaded when using multiple tilesets. (#54) - Thanks to Laguna1989
- Added missing virtual destructor to IJson and IDecompressor. (#47) - Thanks to matthew-nagy
Release 1.3.0
Also see the release notes of version 1.3.0 alpha to get the complete v1.3.0 release details.
Features
- Tileson now supports Tiled up to version 1.6. (#34 , #37)
- Tileson now supports external tilesets in json format. These Tilesets will be automatically loaded, but must be in the correct relative path specified inside the Tiled json. Keep in mind that everything else must be included in the same Tiled map to be resolved. (#33)
- SFML-example now showcases how to use animations and is capped at 60 fps.
Improvements
getAnimation()oftson::Tilenow returns an owntson::Animationobject who can be used to perform animations and stores a small animation state, instead of simply returning astd::vector<tson::Frame>. You can still get this exact data by callingtile.getAnimation().getFrames(). (#40)
Breaking changes
getVersion()oftson::Mapno longer exists. Removed due to sudden change of type in Tiled 1.6, and the fact that I do not consider this a useful variable. Not to be confused withgetTiledVersion(), which will give a string displaying the version ofTiledused to save the current map.getAnimations()oftson::Tilenow returns atson::Animationinstead of astd::vector<tson::Frame>(seeImprovements)- All tile IDs should now correctly use the type
uint32_tinstead ofint.
Bug-fixes
Release 1.3.0 alpha
Since I'm planning a little break from the Tileson project, I'm releasing a near-complete 1.3.0 alpha with a few nice new features and a complete overhaul of the Json parsing logic. Most noticable changes is the great reduction in library size, support for several Json backends and support for fully LZMA compressed maps.
Features
- Tileson now supports reading fully LZMA compressed Tiled-maps. LZMA compression can greatly reduce your file size , and does not take much longer to load compared to regular maps. This requires another single-header library PocketLzma to be included, but it does not require much work. as an example, the
ultimate_test.jsonmap gets reduced from68,6 KiBto2,4 KiBwhen LZMA compressed. Here is a small code example how to read lzma-compressed maps:
#define POCKETLZMA_LZMA_C_DEFINE //Must be defined once in a source (.cpp)-file before
#include "pocketlzma.hpp" //Must be declared BEFORE tileson.hpp
#include "tileson.hpp"
int main(int argc, char **argv)
{
fs::path file {"ultimate_test.lzma"};
tson::Tileson t;
std::unique_ptr<tson::Map> map = t.parse(file, std::make_unique<tson::Lzma>());
return (map->getStatus() == tson::ParseStatus::OK) ? 0 : 1;
}- While there are no plans to support other types of compression, you can easily implement your own override of
IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>and create support for your own compression. Seeinclude/common/Lzma.hppfor an example how this is implemented usingPocketLzma.
Improvements
-
Tileson now uses a
tson::IJsonabstraction to make it possible to use several possible Json backends. It even makes it possible for the user to define his/her own IJson implementation using whatever Json library they like. Implementations forJson11(default),NlohmannandPicojson(there are single-header versions of these libraries in theextrasfolder) -
The bundled Json backend in Tileson has been changed from
NlohmanntoJson11. As a result Tileson should get a slight performance increase, as well as getting a massive reduction in library size, from ~26000 to ~7000 lines of code. -
As in the previous release, you are free to use
tileson_min.hppas an alternative, and choose your own backend. You can use the supportednlohmann.hpp,picojson.hpporjson11.hpp(included intileson.hppas default), or simply create your own! Examples showcasing the use ofNlohmannorPicojsonas alternatives:
#include "nlohmann.hpp" //Must be included before tileson.hpp
#include "picojson.hpp" //Must be included before tileson.hpp
#include "tileson.hpp"
int main(int argc, char **argv)
{
tson::Tileson j11; //This will use the Json11-backend (default)
tson::Tileson nlohmann {std::make_unique<tson::NlohmannJson>()}; //Uses the Nlohmann backend
tson::Tileson picojson {std::make_unique<tson::PicoJson>()}; //Uses the Picojson backend
tson::Project projectJ11; //This will use the Json11-backend (default)
tson::Project projectNlohmann {std::make_unique<tson::NlohmannJson>()};
tson::Project projectPicojson {std::make_unique<tson::PicoJson>()};
tson::World worldJ11; //This will use the Json11-backend (default)
tson::World worldNlohmann {std::make_unique<tson::NlohmannJson>()};
tson::World worldPicojson {std::make_unique<tson::PicoJson>()};
return 0;
}- For you lurkers out there, you may notice that there is a
gason.hppfile insideinclude/externaland aGason.hppinsideinclude/json. I tried to make this library work, and it passed the simple tests, but when reading a regular map I experienced memory corruption problems after a few layers was read, which would be hard to figure out. Gason is thus not supported, but is left there in case someone wants to experiment with it. Gason is blazingly fast, but also does a lot of memory trickery which I suspect is the reason why I had issues making it work.
Breaking changes
-
Only if someone used the IDecompressor interface for internal Tiled decompressions:
- IDecompressor now takes in two template parameters
<class TIn, class Tout>. - Regular file decompression (LZMA), uses a base of
IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>. - Tiled-related decompression, like the Base64-decoder, uses a base of
IDecompressor<std::string_view, std::string>.
- IDecompressor now takes in two template parameters
-
DISABLE_CPP17_FILESYSTEM is no longer an option. Reason being all major compilers now supports all the C++17 features required by Tileson, and
std::filesystemis required fortson::Worldandtson::Project.
Bug-fixes
- Wrong tileset is referenced when using multiple tilesets (#27) - Thanks to davidreynolds for fix!
Release 1.2.0
Features
-
There is now an option to use a
tileson_min.hppfile which only contains theTilesonrelated code (~5000 lines of code). This requires the user to include their own version ofnlohmann/jsonbefore includingtileson_min.hpp, but is less bloated and gives the user freedom to use whatever improved version ofnlohmann/jsonthey want (for reference: Tileson is implemented with version3.7.0of this library).tileson.hppwith the full functionality is, of course, still available. -
All tiles in a
Tilelayer can now get retrieved astson::TileObject. Atson::TileObjectcontains all the information needed to be able to draw aTileat a specific location, and it also knows whichTilesetit is related to (#1 , #11 ):
for (const auto& [pos, tileObject] : layer.getTileObjects())
{
tson::Tileset *tileset = tileObject.getTile()->getTileset();
tson::Rect drawingRect = tileObject.getDrawingRect();
tson::Vector2f position = tileObject.getPosition();
//If using SFML to draw (sprite is a sf::Sprite (if used with SFML))
sprite->setTextureRect({drawingRect.x, drawingRect.y, drawingRect.width, drawingRect.height});
sprite->setPosition({position.x, position.y});
m_window.draw(*sprite); //sf::RenderWindow
}-
Base64-encoded data inside
Tiledmaps are now supported! (#5 ) -
Tileson now supports
Tiled worlds. These contains a collection of several maps that can be tied together, but the files themselves must be parsed separately usingTileson. NB! This functionality requiresstd::filesystemto be enabled (DISABLE_CPP17_FILESYSTEM not defined (default)). (Seeexamplesto get a full idea how worlds works)(#12 ).
tson::Tileson t;
tson::World world;
world.parse(fs::path("path/to/you/file.world"));
//world.get("w1.json") can be used to get a specific map
for(const auto &data : world.getMapData())
{
std::unique_ptr<tson::Map> map = t.parse(fs::path(world.getFolder() / data.fileName));
//...
}
- Tileson now supports
Tiled projects. These contains allmapandworlddata, but the files themselves must be parsed separately usingTileson. NB! This functionality requiresstd::filesystemto be enabled (DISABLE_CPP17_FILESYSTEM not defined (default)). (Seeexamplesto get a full idea how projects works)
(#8 ).
tson::Tileson t;
tson::Project project;
bool ok = project.parse(fs::path("path/to/you/file.tiled-project"));
for(const auto &folder : m_project.getFolders())
{
// You can check if a project folder contains a world with -> folder.hasWorldFile()
// If it does, you can get the world data with -> folder.getWorld()
for(const auto &file : folder.getFiles())
{
std::unique_ptr<tson::Map> map = t.parse(fs::path(folder.getPath() / file.filename()));
//...
}
}
- Added support for
flipped tiles. Flip flags can be retrieved fromtson::Tile,tson::TileObjectandtson::Object(specifically used when using tile graphics):
tson::Object *obj = map->getLayer("Object Layer")->firstObj("mario_ver_flip");
tson::Tile *tile = map->getLayer("Main Layer")->getTileData(28, 15);
tson::TileObject *tileObj = map->getLayer("Main Layer")->getTileObject(28, 14);
bool hasFlags1 = obj->hasFlipFlags(tson::TileFlipFlags::Vertically);
bool hasFlags2 = tile->hasFlipFlags(tson::TileFlipFlags::Horizontally);
bool hasFlags3 = tileObj->getTile()->hasFlipFlags(tson::TileFlipFlags::Vertically | tson::TileFlipFlags::Diagonally);- The
SFMLdemo inexampleshas been greatly improved to showcase the most important features ofTileson v1.2.0. Check it out!
Improvements
-
New helper functions for
tson::Tile(#3 , #1 ):inline tson::Tileset * getTileset() constinline tson::Map * getMap() constinline const tson::Rect &getDrawingRect() constinline const tson::Vector2f getPosition(const std::tuple<int, int> &tileDataPos)inline const tson::Vector2i getPositionInTileUnits(const std::tuple<int, int> &tileDataPos)inline const tson::Vector2i getTileSize() const
-
tson::Layerandtson::Tilesetnow has a pointer to the map they are owned by, which can be retrieved withtson::Map *getMap() -
Unresolvable tiles no longer crashes during parsing (example: By accidentally using external tilesets, which is not supported by
Tileson), but as a result the internaltile mapandtile datawill be empty. (#17 ) -
Added all new properties introduced after Tiled
1.2.4. Up to version1.4.1.editorsettingsnot included. (#9 ) -
Added the missing
colorproperty oftson::Text(#21 ). -
Greatly improved the
CMakeLists.txtbuild script for theexamples, making it more flexible. This removes the32-bit-restriction ofWindowssystems. -
tson::Tilenow has an own property ofgid, which will always be the actual graphics ID. When
flip flags are not in use, theidandgidwill be equal, but in cases where flip flags are used, theidwill represent the ID + flip flag bits, wheregidstill will be the same ID. -
tson::Mapnow has a function to gettson::Tilesetby providing agidfrom a tile or object:getTilesetByGid(uint32_t gid)
Breaking changes
- The parser now returns a
std::unique_ptr<tson::Map>instead of atson::Map. This should have been done from the start, but now there are some parts where it really is required that the physical space in memory is unchanged. At the same time a unnecessary copy will no longer happen during the parsing, so a minor performance increase should be expected. - Due to the implementation of the missing
flip flagsfor tiles, which uses the upper bits of a 32-bit unsigned int, all IDs related totson::Tile(or related to tiles in general) had to be changed frominttouint32_t, which cannot be negative.
Deprecated
- The DISABLE_CPP17_FILESYSTEM preprocessor has been deprecated, and will be removed in the next version of
Tileson. This is because all mayor compilers now should supportstd::filesystem, and certain features requires this to work.
Release 1.1.0
Features
- Tileson now provides an example of use, using SFML. These examples are provided as a compressed file in the Release.
Improvements
- Tileson is now header-only, which means that Tileson no longer needs to be compiled to be used. Simply copy the content of the
includeorsingle_includedirectory. Theincludefolder has an own header for each component, but still only requires you to include thetileson.hfile. Thesingle_includefolder contains one bigtileson.hppfile who contains absolutely everything to be able to run Tileson as one header.
Please note that depending on your IDE, the single_include version can be a bit heavy, due to being large (as it also has a dependency to thenlohmann/json, which is also included there). In those cases using theincludefolder and its content should be less heavy. - All OS-checks related to
std::filesystemnow uses native symbols to check for the OS and compiler.
Breaking changes
tson::Map::ParseStatusmoved totson::ParseStatustson::Layer::Typerenamed totson::LayerTypetson::Object::Typerenamed totson::ObjectTypetson::Layer::Typerenamed totson::LayerType- Preprocessor
DISABLE_CPP17_FILESYSTEMnow used in favor ofUSE_CPP17_FILESYSTEMwhen you want to DISABLE the C++17 filesystem feature
Release 1.0.1
Release notes
- Fixed an issue that would occur when trying to retrieve a tile that had no properties of any kind attached to it. Reason being Tiled not really storing any information at all if a tile does not have any properties. Now all existing tiles should be possible to retrieve even when not having properties. (#4 )
Release 1.0.0
v1.0.0 Updated the version to 1.0.0