SSBMTonberry/tileson

Access violation when getting the drawing rect of a tile by id

rsa16 opened this issue ยท 4 comments

rsa16 commented

In my program, I'm getting a specific tileset by calling map->getTileset("Water"). After that, I call getTile(0) on the tileset and try to get the drawingRect of the tile. Doing so, however, results in an access violation. This only happens with animated tiles

Specifically, I get this error:
Exception thrown at 0x00007FF78E0B11AF in TestingTileson.exe: 0xC0000005: Access violation reading location 0x00000000000003C0.

I'm using c++20, Tiled 1.9.2, and the master branch of Tileson. No errors occur during build, only during runtime.

How to reproduce:

  1. Create a new map with Tiled 1.9.2 and create a tileset with four tiles (i'm using this: Water)
  2. Create a regular c++ project and add the code below to main.cpp:
#include <tileson.hpp>

using namespace tson;
int main()
{
	Tileson ts;
	std::unique_ptr<Map> map = ts.parse(fs::path("./test.json"));
	printf("Loading map...\n");
	if (map->getStatus() == ParseStatus::OK)
	{
		Tileset* tileset = map->getTileset("Water");
		Tile* tile = tileset->getTile(0);
		Rect rect = tile->getDrawingRect();
		printf("No errors occured if you've gotten this far in the program.\n");
	}
	return 0;
}
  1. Save the map as a json with base64 uncompressed and place it in the same directory as main.cpp
  2. Compile and run.

Any idea why this is happening? I'm fairly sure this is a bug but if it isn't is it a problem with my code?

Thank you for you issue ๐Ÿ™‚
Could you post the test.json file you've used in your code snippet?
I could be that the Tileset cannot be resolved, either by the reason of that it is external and not in json format (or the external tileset file simply is not found). You may alternatively embed the Tileset information to be completely sure this does not happen. It's hard to know for sure without having all the files you've tested with, but my gut feeling is telling me that the reason behind your error is that the Tileset cannot be resolved.

rsa16 commented

Sure. Github says that I can't just upload it, so here's the file:

{ "compressionlevel":-1,
 "height":20,
 "infinite":false,
 "layers":[
        {
         "compression":"",
         "data":"AQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAA=",
         "encoding":"base64",
         "height":20,
         "id":1,
         "name":"Tile Layer 1",
         "opacity":1,
         "type":"tilelayer",
         "visible":true,
         "width":25,
         "x":0,
         "y":0
        }],
 "nextlayerid":2,
 "nextobjectid":1,
 "orientation":"orthogonal",
 "renderorder":"right-down",
 "tiledversion":"1.9.2",
 "tileheight":16,
 "tilesets":[
        {
         "columns":4,
         "firstgid":1,
         "image":"..\/..\/pythongaem\/pythongaem\/data\/images\/tilesets\/Water.png",
         "imageheight":16,
         "imagewidth":64,
         "margin":0,
         "name":"Water",
         "spacing":0,
         "tilecount":4,
         "tileheight":16,
         "tilewidth":16
        }],
 "tilewidth":16,
 "type":"map",
 "version":"1.9",
 "width":25
}

@rsa16: I think I know what the problem is, without having looked at the parsing of your map yet.
I think the problem is that the tile with the ID 0 means No tile. The reason for this is that Tileson maintains consistency of stored tile information and the map data. Inside the Tiled map, the first tile has ID 1, but it's not very obvious when looking at your map as it's base64 encoded, and you have no special properties on your tiles. In short: To get information about the first tile, you would have to use tileset->getTile(1);

This is also stated in the code example in the README in the root folder, but I understand it's much more fun to just dive right into it and start experimenting ๐Ÿ™‚
image

If this doesn't solve your problem, get back to me ๐Ÿ™‚

Also, if you want to traverse through all the tiles in your map, Tileson has this neat thing called TileObjects that can be retrieved from a Tile Layer. This keeps track of the tile information needed to draw the tile. To use it, you could do something like this:

    tson::Layer *tileLayer = map->getLayer("Tile Layer 1");

    //Example from a Tile Layer
    //I know for a fact that this is a Tile Layer, but you can check it this way to be sure.
    if(tileLayer->getType() == tson::LayerType::TileLayer)
    {
        //pos = position in tile units
        for(auto &[pos, tileObject] : tileLayer->getTileObjects()) //Loops through absolutely all existing tileObjects
        {
            tson::Tileset *tileset = tileObject.getTile()->getTileset();
            tson::Rect drawingRect = tileObject.getDrawingRect();
            tson::Vector2f position = tileObject.getPosition();

            //Here you can determine the offset that should be set on a sprite
            //Example on how it would be done using SFML (where sprite presumably is a member of a generated game object):
            //sf::Sprite *sprite = storeAndLoadImage(tileset->getImage().u8string(), {0, 0});
            //if (sprite != nullptr)
            //{
            //    sprite->setTextureRect({drawingRect.x, drawingRect.y, drawingRect.width, drawingRect.height});
            //    sprite->setPosition({position.x, position.y});
            //    m_window.draw(*sprite);
            //}
        }
    }
rsa16 commented

You're right! That was the problem. I didn't know that the tiles started with 1 in Tileson since in the tiled map editor the ids for the tiles started with zero. Yeah, I wasn't really looking at the examples, wanted to experiment first. Thank you for your help!