Skip to content

Commit

Permalink
JSON plugin: Fixed reading of infinite maps
Browse files Browse the repository at this point in the history
In change fca34d6 I forgot to also
adjust the VariantToMapConverter to handle chunked tile layer data,
probably because I based those changes on the earlier adaption of the
Lua format, which did not have a reader. This obviously causes problems
for those who use the JSON not only for exporting.

The JSON reader is now also capable of:

* Reading non-infinite maps that use the chunked data format.
* Reading infinite maps that do not use the chunked data format.

This may not be very useful right now since whether chunked data format
is used directly depends on whether the map is infinite or not, but in
the future this may change since the chunked format can also be
preferable for non-infinite maps.

Closes #1858
  • Loading branch information
bjorn committed Jan 30, 2018
1 parent 27f7eca commit 92875ab
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 62 deletions.
7 changes: 2 additions & 5 deletions src/libtiled/gidmapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,8 @@ GidMapper::DecodeError GidMapper::decodeLayerData(TileLayer &tileLayer,
Q_ASSERT(format != Map::XML);
Q_ASSERT(format != Map::CSV);

if (bounds.isEmpty())
bounds = QRect(0, 0, tileLayer.width(), tileLayer.height());

QByteArray decodedData = QByteArray::fromBase64(layerData);
const int size = (bounds.width() * bounds.height()) * 4;
const int size = bounds.width() * bounds.height() * 4;

if (format == Map::Base64Gzip || format == Map::Base64Zlib)
decodedData = decompress(decodedData, size);
Expand Down Expand Up @@ -218,7 +215,7 @@ GidMapper::DecodeError GidMapper::decodeLayerData(TileLayer &tileLayer,
tileLayer.setCell(x, y, result);

x++;
if (x == bounds.right() + 1) {
if (x > bounds.right()) {
x = bounds.x();
y++;
}
Expand Down
2 changes: 1 addition & 1 deletion src/libtiled/gidmapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class TILEDSHARED_EXPORT GidMapper
DecodeError decodeLayerData(TileLayer &tileLayer,
const QByteArray &layerData,
Map::LayerDataFormat format,
QRect bounds = QRect()) const;
QRect bounds) const;

unsigned invalidTile() const;

Expand Down
140 changes: 84 additions & 56 deletions src/libtiled/varianttomapconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,65 +414,23 @@ TileLayer *VariantToMapConverter::toTileLayer(const QVariantMap &variantMap)
}
mMap->setLayerDataFormat(layerDataFormat);

switch (layerDataFormat) {
case Map::XML:
case Map::CSV: {
const QVariantList dataVariantList = dataVariant.toList();

if (dataVariantList.size() != width * height) {
mError = tr("Corrupt layer data for layer '%1'").arg(name);
if (dataVariant.isValid()) {
if (!readTileLayerData(*tileLayer, dataVariant, layerDataFormat,
QRect(startX, startY, tileLayer->width(), tileLayer->height()))) {
return nullptr;
}

int x = 0;
int y = 0;
bool ok;

for (const QVariant &gidVariant : dataVariantList) {
const unsigned gid = gidVariant.toUInt(&ok);
if (!ok) {
mError = tr("Unable to parse tile at (%1,%2) on layer '%3'")
.arg(x).arg(y).arg(tileLayer->name());
return nullptr;
}

const Cell cell = mGidMapper.gidToCell(gid, ok);

tileLayer->setCell(x + startX, y + startY, cell);

x++;
if (x >= tileLayer->width()) {
x = 0;
y++;
}
}
break;
}

case Map::Base64:
case Map::Base64Zlib:
case Map::Base64Gzip: {
const QByteArray data = dataVariant.toByteArray();
GidMapper::DecodeError error = mGidMapper.decodeLayerData(*tileLayer,
data,
layerDataFormat);

switch (error) {
case GidMapper::CorruptLayerData:
mError = tr("Corrupt layer data for layer '%1'").arg(name);
return nullptr;
case GidMapper::TileButNoTilesets:
mError = tr("Tile used but no tilesets specified");
return nullptr;
case GidMapper::InvalidTile:
mError = tr("Invalid tile: %1").arg(mGidMapper.invalidTile());
return nullptr;
case GidMapper::NoError:
break;
} else {
const QVariantList chunks = variantMap[QLatin1String("chunks")].toList();
for (const QVariant &chunkVariant : chunks) {
const QVariantMap chunkVariantMap = chunkVariant.toMap();
const QVariant chunkData = chunkVariantMap[QLatin1String("data")];
int x = chunkVariantMap[QLatin1String("x")].toInt();
int y = chunkVariantMap[QLatin1String("y")].toInt();
int width = chunkVariantMap[QLatin1String("width")].toInt();
int height = chunkVariantMap[QLatin1String("height")].toInt();

readTileLayerData(*tileLayer, chunkData, layerDataFormat, QRect(x, y, width, height));
}

break;
}
}

return tileLayer.take();
Expand Down Expand Up @@ -715,6 +673,76 @@ TextData VariantToMapConverter::toTextData(const QVariantMap &variant) const
return textData;
}

bool VariantToMapConverter::readTileLayerData(TileLayer &tileLayer,
const QVariant &dataVariant,
Map::LayerDataFormat layerDataFormat,
QRect bounds)
{
switch (layerDataFormat) {
case Map::XML:
case Map::CSV: {
const QVariantList dataVariantList = dataVariant.toList();

if (dataVariantList.size() != bounds.width() * bounds.height()) {
mError = tr("Corrupt layer data for layer '%1'").arg(tileLayer.name());
return false;
}

int x = bounds.x();
int y = bounds.y();
bool ok;

for (const QVariant &gidVariant : dataVariantList) {
const unsigned gid = gidVariant.toUInt(&ok);
if (!ok) {
mError = tr("Unable to parse tile at (%1,%2) on layer '%3'")
.arg(x).arg(y).arg(tileLayer.name());
return false;
}

const Cell cell = mGidMapper.gidToCell(gid, ok);

tileLayer.setCell(x + bounds.x(), y + bounds.y(), cell);

x++;
if (x > bounds.right()) {
x = bounds.x();
y++;
}
}
break;
}

case Map::Base64:
case Map::Base64Zlib:
case Map::Base64Gzip: {
const QByteArray data = dataVariant.toByteArray();
GidMapper::DecodeError error = mGidMapper.decodeLayerData(tileLayer,
data,
layerDataFormat,
bounds);

switch (error) {
case GidMapper::CorruptLayerData:
mError = tr("Corrupt layer data for layer '%1'").arg(tileLayer.name());
return false;
case GidMapper::TileButNoTilesets:
mError = tr("Tile used but no tilesets specified");
return false;
case GidMapper::InvalidTile:
mError = tr("Invalid tile: %1").arg(mGidMapper.invalidTile());
return false;
case GidMapper::NoError:
break;
}

break;
}
}

return true;
}

Properties VariantToMapConverter::extractProperties(const QVariantMap &variantMap) const
{
return toProperties(variantMap[QLatin1String("properties")],
Expand Down
5 changes: 5 additions & 0 deletions src/libtiled/varianttomapconverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ class TILEDSHARED_EXPORT VariantToMapConverter
QPolygonF toPolygon(const QVariant &variant) const;
TextData toTextData(const QVariantMap &variant) const;

bool readTileLayerData(TileLayer &tileLayer,
const QVariant &dataVariant,
Map::LayerDataFormat layerDataFormat,
QRect bounds);

Properties extractProperties(const QVariantMap &variantMap) const;

Map *mMap;
Expand Down

0 comments on commit 92875ab

Please sign in to comment.