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 theclass
property 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
quom
as amalgamate tool forOSX
(#82) - Thanks to dmlary - Now using
Github Actions
instead ofTravis
for CI (#50) - Thanks to Laguna1989 - C++20 support (#53) - Thanks to gamecoder-nz
Improvements
- Only include
external_libs
folder 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
TiledEnum
s 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::Tile
now returns an owntson::Animation
object 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::Map
no 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 ofTiled
used to save the current map.getAnimations()
oftson::Tile
now returns atson::Animation
instead of astd::vector<tson::Frame>
(seeImprovements
)- All tile IDs should now correctly use the type
uint32_t
instead 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.json
map gets reduced from68,6 KiB
to2,4 KiB
when 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.hpp
for an example how this is implemented usingPocketLzma
.
Improvements
-
Tileson now uses a
tson::IJson
abstraction 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),Nlohmann
andPicojson
(there are single-header versions of these libraries in theextras
folder) -
The bundled Json backend in Tileson has been changed from
Nlohmann
toJson11
. 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.hpp
as an alternative, and choose your own backend. You can use the supportednlohmann.hpp
,picojson.hpp
orjson11.hpp
(included intileson.hpp
as default), or simply create your own! Examples showcasing the use ofNlohmann
orPicojson
as 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.hpp
file insideinclude/external
and aGason.hpp
insideinclude/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::filesystem
is required fortson::World
andtson::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.hpp
file which only contains theTileson
related code (~5000 lines of code). This requires the user to include their own version ofnlohmann/json
before includingtileson_min.hpp
, but is less bloated and gives the user freedom to use whatever improved version ofnlohmann/json
they want (for reference: Tileson is implemented with version3.7.0
of this library).tileson.hpp
with the full functionality is, of course, still available. -
All tiles in a
Tile
layer can now get retrieved astson::TileObject
. Atson::TileObject
contains all the information needed to be able to draw aTile
at a specific location, and it also knows whichTileset
it 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
Tiled
maps 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::filesystem
to be enabled (DISABLE_CPP17_FILESYSTEM not defined (default)). (Seeexamples
to 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 allmap
andworld
data, but the files themselves must be parsed separately usingTileson
. NB! This functionality requiresstd::filesystem
to be enabled (DISABLE_CPP17_FILESYSTEM not defined (default)). (Seeexamples
to 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::TileObject
andtson::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
SFML
demo inexamples
has 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() const
inline tson::Map * getMap() const
inline const tson::Rect &getDrawingRect() const
inline 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::Layer
andtson::Tileset
now 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 map
andtile data
will be empty. (#17 ) -
Added all new properties introduced after Tiled
1.2.4
. Up to version1.4.1
.editorsettings
not included. (#9 ) -
Added the missing
color
property oftson::Text
(#21 ). -
Greatly improved the
CMakeLists.txt
build script for theexamples
, making it more flexible. This removes the32-bit
-restriction ofWindows
systems. -
tson::Tile
now has an own property ofgid
, which will always be the actual graphics ID. When
flip flags are not in use, theid
andgid
will be equal, but in cases where flip flags are used, theid
will represent the ID + flip flag bits, wheregid
still will be the same ID. -
tson::Map
now has a function to gettson::Tileset
by providing agid
from 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 flags
for 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 fromint
touint32_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
include
orsingle_include
directory. Theinclude
folder has an own header for each component, but still only requires you to include thetileson.h
file. Thesingle_include
folder contains one bigtileson.hpp
file 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 theinclude
folder and its content should be less heavy. - All OS-checks related to
std::filesystem
now uses native symbols to check for the OS and compiler.
Breaking changes
tson::Map::ParseStatus
moved totson::ParseStatus
tson::Layer::Type
renamed totson::LayerType
tson::Object::Type
renamed totson::ObjectType
tson::Layer::Type
renamed totson::LayerType
- Preprocessor
DISABLE_CPP17_FILESYSTEM
now used in favor ofUSE_CPP17_FILESYSTEM
when 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