Skip to content

Releases: SSBMTonberry/tileson

Release 1.4.0

01 Oct 18:18
ccc4a3d
Compare
Choose a tag to compare

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 the class property with your own class definitions. Same goes for Tiled `enums``.
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 for OSX (#82) - Thanks to dmlary
  • Now using Github Actions instead of Travis 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 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

24 May 18:22
Compare
Choose a tag to compare

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() of tson::Tile now returns an own tson::Animation object who can be used to perform animations and stores a small animation state, instead of simply returning a std::vector<tson::Frame>. You can still get this exact data by calling tile.getAnimation().getFrames(). (#40)

Breaking changes

  • getVersion() of tson::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 with getTiledVersion(), which will give a string displaying the version of Tiled used to save the current map.
  • getAnimations() of tson::Tile now returns a tson::Animation instead of a std::vector<tson::Frame> (see Improvements)
  • All tile IDs should now correctly use the type uint32_t instead of int.

Bug-fixes

  • tson::Frame now stores a Tile ID who is consistent with the actual Tile ID used in Tileson. (#41)
  • DrawingRect now takes spacing and margin into account (#31)

Release 1.3.0 alpha

01 Feb 16:57
Compare
Choose a tag to compare

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 from 68,6 KiB to 2,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. See include/common/Lzma.hpp for an example how this is implemented using PocketLzma.

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 for Json11 (default), Nlohmann and Picojson (there are single-header versions of these libraries in the extras folder)

  • The bundled Json backend in Tileson has been changed from Nlohmann to Json11. 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 supported nlohmann.hpp, picojson.hpp or json11.hpp (included in tileson.hpp as default), or simply create your own! Examples showcasing the use of Nlohmann or Picojson 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 inside include/external and a Gason.hpp inside include/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>.
  • 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 for tson::World and tson::Project.

Bug-fixes

  • Wrong tileset is referenced when using multiple tilesets (#27) - Thanks to davidreynolds for fix!

Release 1.2.0

13 Dec 12:44
Compare
Choose a tag to compare

Features

  • There is now an option to use a tileson_min.hpp file which only contains the Tileson related code (~5000 lines of code). This requires the user to include their own version of nlohmann/json before including tileson_min.hpp, but is less bloated and gives the user freedom to use whatever improved version of nlohmann/json they want (for reference: Tileson is implemented with version 3.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 as tson::TileObject. A tson::TileObject contains all the information needed to be able to draw a Tile at a specific location, and it also knows which Tileset 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 using Tileson. NB! This functionality requires std::filesystem to be enabled (DISABLE_CPP17_FILESYSTEM not defined (default)). (See examples 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 all map and world data, but the files themselves must be parsed separately using Tileson. NB! This functionality requires std::filesystem to be enabled (DISABLE_CPP17_FILESYSTEM not defined (default)). (See examples 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 from tson::Tile, tson::TileObject and tson::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 in examples has been greatly improved to showcase the most important features of Tileson 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 and tson::Tileset now has a pointer to the map they are owned by, which can be retrieved with tson::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 internal tile map and tile data will be empty. (#17 )

  • Added all new properties introduced after Tiled 1.2.4. Up to version 1.4.1. editorsettings not included. (#9 )

  • Added the missing color property of tson::Text (#21 ).

  • Greatly improved the CMakeLists.txt build script for the examples, making it more flexible. This removes the 32-bit-restriction of Windows systems.

  • tson::Tile now has an own property of gid, which will always be the actual graphics ID. When
    flip flags are not in use, the id and gid will be equal, but in cases where flip flags are used, the id will represent the ID + flip flag bits, where gid still will be the same ID.

  • tson::Map now has a function to get tson::Tileset by providing a gid from a tile or object: getTilesetByGid(uint32_t gid)

Breaking changes

  • The parser now returns a std::unique_ptr<tson::Map> instead of a tson::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 to tson::Tile (or related to tiles in general) had to be changed from int to uint32_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 support std::filesystem, and certain features requires this to work.

Release 1.1.0

21 Jul 19:25
f5d6258
Compare
Choose a tag to compare

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 or single_include directory. The includefolder has an own header for each component, but still only requires you to include the tileson.h file. The single_includefolder contains one big tileson.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 the nlohmann/json, which is also included there). In those cases using the include 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 to tson::ParseStatus
  • tson::Layer::Type renamed to tson::LayerType
  • tson::Object::Type renamed to tson::ObjectType
  • tson::Layer::Typerenamed to tson::LayerType
  • Preprocessor DISABLE_CPP17_FILESYSTEM now used in favor of USE_CPP17_FILESYSTEM when you want to DISABLE the C++17 filesystem feature

Release 1.0.1

21 Sep 21:29
Compare
Choose a tag to compare

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

25 Aug 09:04
Compare
Choose a tag to compare
v1.0.0

Updated the version to 1.0.0