From 5f0bf4f5fe2de221d54047f1fcdbaa138558b6ea Mon Sep 17 00:00:00 2001 From: EtlamGit Date: Sat, 11 Aug 2018 19:29:20 +0200 Subject: [PATCH] migration from STRING to HASH to handle Blocks internally Accessing a QMap and searching Blocks is very very slow because of the QString handling. Compared to the old code before 1.13 it has a penalty of 2x .. 3x rendering time for a map. Using qHash to convert all QStrings into numbers and using this hached ID (hid) brings back the speed. I measured also 2x .. 3x performance gain and old maps render as fast as before. --- blockdata.h | 1 + blockidentifier.cpp | 28 ++++++++++++++++++++++------ blockidentifier.h | 4 ++-- chunk.cpp | 15 ++++++++------- chunk.h | 17 ++++++++--------- flatteningconverter.cpp | 6 +++++- mapview.cpp | 18 +++++++----------- 7 files changed, 53 insertions(+), 36 deletions(-) diff --git a/blockdata.h b/blockdata.h index 654d0794..5bb81644 100644 --- a/blockdata.h +++ b/blockdata.h @@ -7,6 +7,7 @@ class BlockData { public: + uint hid; // we use hashed name as ID QString name; QMap properties; }; diff --git a/blockidentifier.cpp b/blockidentifier.cpp index 55a94162..64ecdab8 100644 --- a/blockidentifier.cpp +++ b/blockidentifier.cpp @@ -1,6 +1,7 @@ /** Copyright (c) 2013, Sean Kasun */ #include +#include #include #include @@ -83,7 +84,7 @@ BlockIdentifier::BlockIdentifier() { for (int i = 0; i < 16; i++) unknownBlock.colors[i] = 0xff00ff; unknownBlock.alpha = 1.0; - unknownBlock.setName("Unknown"); + unknownBlock.setName("Unknown Block"); } BlockIdentifier::~BlockIdentifier() { @@ -93,10 +94,10 @@ BlockIdentifier::~BlockIdentifier() { } } -BlockInfo &BlockIdentifier::getBlock(QString name) { +BlockInfo &BlockIdentifier::getBlockInfo(uint hid) { // first apply the mask - if (blocks.contains(name)) { - return *blocks[name]; + if (blocks.contains(hid)) { + return *blocks[hid]; } // data &= blocks[name].first()->mask; // @@ -126,8 +127,8 @@ BlockInfo &BlockIdentifier::getBlock(QString name) { // } // } // } + // no blocks at all found.. dammit - unknownBlock.setName(name); return unknownBlock; } @@ -272,6 +273,21 @@ void BlockIdentifier::parseDefinition(JSONObject *b, BlockInfo *parent, parseDefinition(dynamic_cast(variants->at(j)), block, pack); } - blocks.insert(name, block); + uint hid = qHash(name); + if (blocks.contains(hid)) { + // this will only trigger during development of vanilla_blocks.json + // and prevents generating a wrong definition file + QMessageBox::warning((QWidget*)(NULL), + "Error hashing Block", + name, + QMessageBox::Cancel, QMessageBox::Cancel); + } + blocks.insert(hid, block); packs[pack].append(block); + + // we need this ugly code to allow mob spawn detection + // todo: rework mob spawn highlight + if (block->getName() == "minecraft:air") { + blocks.insert(0, block); + } } diff --git a/blockidentifier.h b/blockidentifier.h index 3ac9a19c..234625e5 100644 --- a/blockidentifier.h +++ b/blockidentifier.h @@ -73,10 +73,10 @@ class BlockIdentifier { int addDefinitions(JSONArray *, int pack = -1); void enableDefinitions(int id); void disableDefinitions(int id); - BlockInfo &getBlock(QString name); + BlockInfo &getBlockInfo(uint hid); private: void parseDefinition(JSONObject *block, BlockInfo *parent, int pack); - QMap blocks; + QMap blocks; QList > packs; }; diff --git a/chunk.cpp b/chunk.cpp index 5bb79743..ce8cd740 100644 --- a/chunk.cpp +++ b/chunk.cpp @@ -147,6 +147,7 @@ void Chunk::loadSection1519(ChunkSection *cs, const Tag *section) { cs->palette = new BlockData[cs->paletteLength]; for (int j = 0; j < rawPalette->length(); j++) { cs->palette[j].name = rawPalette->at(j)->at("Name")->toString(); + cs->palette[j].hid = qHash(cs->palette[j].name); if (rawPalette->at(j)->has("Properties")) cs->palette[j].properties = rawPalette->at(j)->at("Properties")->getData().toMap(); } @@ -173,10 +174,10 @@ Chunk::~Chunk() { if (sections[i]) { if (sections[i]->paletteLength > 0) { delete[] sections[i]->palette; - sections[i]->paletteLength = 0; - } else { - sections[i]->palette = NULL; } + sections[i]->paletteLength = 0; + sections[i]->palette = NULL; + delete sections[i]; sections[i] = NULL; } @@ -184,16 +185,16 @@ Chunk::~Chunk() { } -QString ChunkSection::getBlock(int x, int y, int z) { +uint ChunkSection::getBlock(int x, int y, int z) { int xoffset = x; int yoffset = (y & 0x0f) << 8; int zoffset = z << 4; - return palette[blocks[xoffset + yoffset + zoffset]].name; + return palette[blocks[xoffset + yoffset + zoffset]].hid; } -QString ChunkSection::getBlock(int offset, int y) { +uint ChunkSection::getBlock(int offset, int y) { int yoffset = (y & 0x0f) << 8; - return palette[blocks[offset + yoffset]].name; + return palette[blocks[offset + yoffset]].hid; } quint8 ChunkSection::getSkyLight(int x, int y, int z) { diff --git a/chunk.h b/chunk.h index 8eb8b4c2..42755ad9 100644 --- a/chunk.h +++ b/chunk.h @@ -9,20 +9,19 @@ #include "./entity.h" #include "./blockdata.h" -class BlockIdentifier; - class ChunkSection { public: - QString getBlock(int x, int y, int z); - QString getBlock(int offset, int y); - quint8 getSkyLight(int x, int y, int z); - quint8 getSkyLight(int offset, int y); - quint8 getBlockLight(int x, int y, int z); - quint8 getBlockLight(int offset, int y); + uint getBlock(int x, int y, int z); + uint getBlock(int offset, int y); + quint8 getSkyLight(int x, int y, int z); + quint8 getSkyLight(int offset, int y); + quint8 getBlockLight(int x, int y, int z); + quint8 getBlockLight(int offset, int y); BlockData *palette; - int paletteLength; + int paletteLength; + quint16 blocks[16*16*16]; quint8 skyLight[16*16*16/2]; quint8 blockLight[16*16*16/2]; diff --git a/flatteningconverter.cpp b/flatteningconverter.cpp index 13e63a21..e38a4c5c 100644 --- a/flatteningconverter.cpp +++ b/flatteningconverter.cpp @@ -78,10 +78,13 @@ void FlatteningConverter::parseDefinition( flatname = b->at("flatname")->asString(); palette[bid].name = flatname; + palette[bid].hid = qHash(palette[bid].name); if ((parentID == NULL) && (data == 0)) { // spread main block type for data == 0 for (int d=1; d<16; d++) { - palette[bid | (d<<8)].name = flatname; + int sid = bid | (d<<8); + palette[sid].name = flatname; + palette[sid].hid = palette[bid].hid; } } // packs[pack].append(block); @@ -106,6 +109,7 @@ void FlatteningConverter::parseDefinition( int id = bid | (j << 8); int mid = bid | ((j & mask) << 8); palette[id].name = palette[mid].name; + palette[id].hid = palette[mid].hid; } } } diff --git a/mapview.cpp b/mapview.cpp index afb5fb41..b77de3b3 100644 --- a/mapview.cpp +++ b/mapview.cpp @@ -450,7 +450,7 @@ void MapView::renderChunk(Chunk *chunk) { //int data = section->getData(offset, y); // get BlockInfo from block value - BlockInfo &block = blocks->getBlock(section->getBlock(offset, y)); + BlockInfo &block = blocks->getBlockInfo(section->getBlock(offset, y)); if (block.alpha == 0.0) continue; // get light value from one block above @@ -504,8 +504,7 @@ void MapView::renderChunk(Chunk *chunk) { } if (flags & flgMobSpawn) { // get block info from 1 and 2 above and 1 below - QString blid1(""), blid2(""), blidB(""); // default to air - int data1(0), data2(0), dataB(0); // default variant + uint blid1(0), blid2(0), blidB(0); // default to legacy air (todo: better handling of block above) ChunkSection *section2 = NULL; ChunkSection *sectionB = NULL; if (y < 254) @@ -514,20 +513,17 @@ void MapView::renderChunk(Chunk *chunk) { sectionB = chunk->sections[(y-1) >> 4]; if (section1) { blid1 = section1->getBlock(offset, y+1); - // data1 = section1->getData(offset, y+1); } if (section2) { blid2 = section2->getBlock(offset, y+2); - // data2 = section2->getData(offset, y+2); } if (sectionB) { blidB = sectionB->getBlock(offset, y-1); - // dataB = sectionB->getData(offset, y-1); } - BlockInfo &block2 = blocks->getBlock(blid2); - BlockInfo &block1 = blocks->getBlock(blid1); + BlockInfo &block2 = blocks->getBlockInfo(blid2); + BlockInfo &block1 = blocks->getBlockInfo(blid1); BlockInfo &block0 = block; - BlockInfo &blockB = blocks->getBlock(blidB); + BlockInfo &blockB = blocks->getBlockInfo(blidB); int light0 = section->getBlockLight(offset, y); // spawn check #1: on top of solid block @@ -589,7 +585,7 @@ void MapView::renderChunk(Chunk *chunk) { // get data value // int data = section->getData(offset, y); // get BlockInfo from block value - BlockInfo &block = blocks->getBlock(section->getBlock(offset, y)); + BlockInfo &block = blocks->getBlockInfo(section->getBlock(offset, y)); if (block.transparent) { cave_factor -= caveshade[cave_test]; } @@ -635,7 +631,7 @@ void MapView::getToolTip(int x, int z) { int yoffset = (y & 0xf) << 8; //int data = section->data[(offset + yoffset) / 2]; //if (x & 1) data >>= 4; - auto &block = blocks->getBlock(section->getBlock(offset, y)); + auto &block = blocks->getBlockInfo(section->getBlock(offset, y)); if (block.alpha == 0.0) continue; // found block name = block.getName();