From 2009dcd592da10512a2ff74764476bc557399f16 Mon Sep 17 00:00:00 2001 From: Sean Date: Fri, 27 May 2016 15:34:05 -0700 Subject: [PATCH] linted the code, follows google c++ standards --- LICENSE | 24 + README | 80 --- README.md | 117 ++++ biomeidentifier.cpp | 130 ++-- biomeidentifier.h | 67 +- blockidentifier.cpp | 526 +++++++------- blockidentifier.h | 137 ++-- check.sh | 3 + chunk.cpp | 209 +++--- chunk.h | 101 +-- chunkcache.cpp | 155 ++--- chunkcache.h | 95 +-- chunkloader.cpp | 126 ++-- chunkloader.h | 65 +- debian/changelog | 6 + definitionmanager.cpp | 1019 +++++++++++++--------------- definitionmanager.h | 156 ++--- definitionupdater.cpp | 119 ++-- definitionupdater.h | 70 +- dimensionidentifier.cpp | 341 ++++------ dimensionidentifier.h | 101 ++- entity.cpp | 117 ++-- entity.h | 41 +- entityidentifier.cpp | 328 ++++----- entityidentifier.h | 143 ++-- generatedstructure.cpp | 158 ++--- generatedstructure.h | 39 +- json.cpp | 634 ++++++++--------- json.h | 147 ++-- labelledslider.cpp | 122 ++-- labelledslider.h | 84 +-- main.cpp | 171 ++--- make_installer.bat | 6 +- mapview.cpp | 1249 ++++++++++++++++------------------ mapview.h | 190 +++--- minutor.cpp | 1431 ++++++++++++++++++--------------------- minutor.h | 224 +++--- minutor.pro | 1 + minutor.wxs | 4 +- nbt.cpp | 882 +++++++++++------------- nbt.h | 320 ++++----- overlayitem.h | 64 +- properties.cpp | 355 +++++----- properties.h | 42 +- settings.cpp | 159 ++--- settings.h | 77 +-- village.cpp | 70 +- village.h | 21 +- worldsave.cpp | 585 ++++++++-------- worldsave.h | 74 +- zipreader.cpp | 246 +++---- zipreader.h | 63 +- 52 files changed, 5122 insertions(+), 6572 deletions(-) create mode 100644 LICENSE delete mode 100644 README create mode 100644 README.md mode change 100755 => 100644 blockidentifier.cpp mode change 100755 => 100644 blockidentifier.h create mode 100755 check.sh mode change 100755 => 100644 mapview.cpp diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..8cd0cea5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ + Copyright (c) 2016, Sean Kasun + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README b/README deleted file mode 100644 index 5422f9b4..00000000 --- a/README +++ /dev/null @@ -1,80 +0,0 @@ -This is the source code for Minutor 2.0 (beta) -web/ contains the source code for the web-based pack builder. The live version -can be found at http://seancode.com/minutor/packs - -The Makefile inside web/ will use the Closure Compiler to compile all the .js files -into a single editor.min.js. To host the pack builder on your own website, you -only need editor.min.js, index.html, main.css, and the mods/ folder. - -COMPILING: ---------- - -All Platforms: -Use QtCreator (Qt5 version) and open minutor.pro - -Windows: -These are the instructions for doing a static compile on Windows. These are the -same steps I use to make the official versions. - -First you need a static compile of Qt5. Get the Qt5 source from -http://qt-project.org/downloads - -Unzip it whereever you wish, and then edit qtbase\mkspecs\win32-msvc2012\qmake.conf -You'll need to find the CONFIG line and remove embed_manifest_dll and -embed_manifest_exe from that line. -Next find the QMAKE_CFLAGS_* lines and change -MD to -MT, and -MDd to -MTd - -Now open up the Developer Command Prompt -cd into the qtbase folder and run: - -configure -prefix %CD% -debug-and-release -opensource -confirm-license - -platform win32-msvc2012 -nomake tests -nomake examples - -no-angle -no-opengl -static -qt-zlib -nmake - -If nmake complains about python or perl, install ActivePerl and ActivePython and -try again. This compile will take a long time. - -This should make a static Qt5 with both debug and release libraries. Now in -QtCreator, go to Tools->Options... and select Qt Versions from Build & Run. -Add a new Qt Version and locate the qmake.exe that is inside qtbase\bin of -the Qt5 you just compiled. There will be a warning flag because we didn't -compile qmlscene or qmlviewer or any -helpers (we don't need them and by leaving them out we don't have to deal with -Qt OpenGL headaches), you can ignore that. -Then switch over to Kits and make a new kit that uses the Qt version you just -created. Again, there will be a warning flag for the same reasons as before, ignore -it. - -If you get errors with conflicting _z_errmsg: Edit zutil.c and delete the -z_errmsg array (it conflicts with an exported array in Qt5). - -Now compile Minutor using the static Kit. You should end up with a statically -linked minutor.exe which doesn't require any dlls to run. - -Linux: -If you'd rather use the command line, run qmake to generate a Makefile from -minutor.pro, then run make - -To make a package: - - $ debuild - -To make a package for another distribution: - $ pbuilder-dist raring create # called only once to generate environment - $ debuild -S -us - $ pbuilder-dist raring build *.dsc - - - -MacOS: -Make a static compile of Qt by downloading the source code and then - - cd qtbase - ./configure -prefix $PWD -opensource -confirm-license -nomake tests -nomake examples -release -static - make - -Then compile Minutor by: - - ~/path/to/qtbase/bin/qmake - make \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..e26721cf --- /dev/null +++ b/README.md @@ -0,0 +1,117 @@ +This is the source code for Minutor 2.1 +web/ contains the source code for the web-based pack builder. The live version +can be found at http://seancode.com/minutor/packs + +The Makefile inside web/ will use the Closure Compiler to compile all the .js files +into a single editor.min.js. To host the pack builder on your own website, you +only need editor.min.js, index.html, main.css, and the mods/ folder. + +CONVENTIONS: +------------ + +The coding convetion is standardized on the result of Google's cpplint. +https://github.com/google/styleguide/tree/gh-pages/cpplint + +We also use clang's static analyzer. The options tested are in `check.sh`. + + +COMPILING: +--------- + +All Platforms: +Use QtCreator (Qt5 version) and open minutor.pro + + +How to do a static compile on Windows: +------------------------------------- + +Download the qt5.5 sourcecode. + +Unzip it whereever you wish, it's a large file and contains a lot of nested +subdirectories, so you'll probably want to put it in C:\Qt5\src or +something similar since you could end up running into Windows' path-length +limitations otherwise. + +Now edit qtbase\mkspecs\common\msvc-desktop.conf + +Find the CONFIG line and remove `embed_manifest_dll` and `embed_manifest_exe` +from that line. + +Next find `QMAKE_CFLAGS_*` and change `-MD` to `-MT` and `-MDd` to `-MTd`. + +Open your developer command prompt (64-bit), cd into the qtbase folder and +run: + +```bat +configure -prefix %CD% -debug-and-release -opensource -confirm-license + -platform win32-msvc2013 -nomake tests -nomake examples + -opengl desktop -static +nmake +``` + +If nmake complains about python or perl, install ActivePerl and ActivePython and +try again. This compile will take a long time. + +This should make a static Qt5 with both debug and release libraries. Now in +QtCreator, go to Tools → Options... and select Qt Versions from Build & Run. +Add a new Qt Version and locate the `qmake.exe` that is inside +qtbase\bin of the Qt5 you just compiled. +There will be a warning flag because we didn't compile qmlscene or qmlviewer +or any helpers. You can ignore that warning. + +Then switch over to Kits and make a new kit that uses the Qt version you just +created. Again, there will be a warning flag for the same reasons as before, +ignore it. + +Now compile Minutor using the static Kit. You should end up with a statically +linked minutor.exe which doesn't require any dlls to run. + + +Building for Linux: +------------------ + +Use qmake to generate a makefile then run make. Or use QtCreator. + +If you want to make a .deb package, + +```console +$ debuild +``` + +To make a package for another distribution: + +```console +$ pbuilder-dist vivid create # called only once to generate environment +$ debuild -S -us -uc +$ cd .. +$ pbuilder-dist vivid build *.dsc +``` + + +Building on OSX: +---------------- + +Make a static compile of Qt 5.5: + + +```console +$ git clone https://code.qt.io/qt/qt5.git +$ cd qt5 +$ perl init-repository --module-subset=default,-qtwebkit,-qtwebkit-examples,-qtwebengine +(wait forever) +$ git checkout 5.5 +$ ./configure -prefix $PWD -opensource -confirm-license -nomake tests -nomake +examples -release -static +$ make +(wait forever) +``` + +Then compile Minutor: + +```console +$ cd minutor +$ ~/qt5/qtbase/bin/qmake +$ make +``` + +You'll end up with a minutor.app in the current directory. diff --git a/biomeidentifier.cpp b/biomeidentifier.cpp index 0cfb073b..175cf59c 100644 --- a/biomeidentifier.cpp +++ b/biomeidentifier.cpp @@ -1,94 +1,60 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. +/** Copyright (c) 2013, Sean Kasun */ - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "biomeidentifier.h" -#include "json.h" +#include "./biomeidentifier.h" +#include "./json.h" static BiomeInfo unknownBiome; -BiomeIdentifier::BiomeIdentifier() -{ - unknownBiome.name="Unknown"; +BiomeIdentifier::BiomeIdentifier() { + unknownBiome.name = "Unknown"; } -BiomeIdentifier::~BiomeIdentifier() -{ - for (int i=0;i &list=biomes[biome]; - //search backwards for priority sorting to work - for (int i=list.length()-1;i>=0;i--) - if (list[i]->enabled) - return *list[i]; - return unknownBiome; +BiomeInfo &BiomeIdentifier::getBiome(int biome) { + QList &list = biomes[biome]; + // search backwards for priority sorting to work + for (int i = list.length() - 1; i >= 0; i--) + if (list[i]->enabled) + return *list[i]; + return unknownBiome; } -void BiomeIdentifier::enableDefinitions(int pack) -{ - if (pack<0) return; - int len=packs[pack].length(); - for (int i=0;ienabled=true; +void BiomeIdentifier::enableDefinitions(int pack) { + if (pack < 0) return; + int len = packs[pack].length(); + for (int i = 0; i < len; i++) + packs[pack][i]->enabled = true; } -void BiomeIdentifier::disableDefinitions(int pack) -{ - if (pack<0) return; - int len=packs[pack].length(); - for (int i=0;ienabled=false; +void BiomeIdentifier::disableDefinitions(int pack) { + if (pack < 0) return; + int len = packs[pack].length(); + for (int i = 0; i < len; i++) + packs[pack][i]->enabled = false; } -int BiomeIdentifier::addDefinitions(JSONArray *defs,int pack) -{ - if (pack==-1) - { - pack=packs.length(); - packs.append(QList()); - } - - int len=defs->length(); - for (int i=0;i(defs->at(i)); - int id=b->at("id")->asNumber(); - - BiomeInfo *biome=new BiomeInfo(); - biome->enabled=true; - if (b->has("name")) - biome->name=b->at("name")->asString(); - else - biome->name="Unknown"; - biomes[id].append(biome); - packs[pack].append(biome); - } - return pack; +int BiomeIdentifier::addDefinitions(JSONArray *defs, int pack) { + if (pack == -1) { + pack = packs.length(); + packs.append(QList()); + } + + int len = defs->length(); + for (int i = 0; i < len; i++) { + JSONObject *b = dynamic_cast(defs->at(i)); + int id = b->at("id")->asNumber(); + + BiomeInfo *biome = new BiomeInfo(); + biome->enabled = true; + if (b->has("name")) + biome->name = b->at("name")->asString(); + else + biome->name = "Unknown"; + biomes[id].append(biome); + packs[pack].append(biome); + } + return pack; } diff --git a/biomeidentifier.h b/biomeidentifier.h index 9a63dd23..9aaa54c0 100644 --- a/biomeidentifier.h +++ b/biomeidentifier.h @@ -1,57 +1,30 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef __BIOMEIDENTIFIER_H__ -#define __BIOMEIDENTIFIER_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef BIOMEIDENTIFIER_H_ +#define BIOMEIDENTIFIER_H_ #include #include #include class JSONArray; -class BiomeInfo -{ -public: - BiomeInfo() {} - QString name; - bool enabled; +class BiomeInfo { + public: + BiomeInfo() {} + QString name; + bool enabled; }; -class BiomeIdentifier -{ -public: - BiomeIdentifier(); - ~BiomeIdentifier(); - int addDefinitions(JSONArray *,int pack=-1); - void enableDefinitions(int); - void disableDefinitions(int); - BiomeInfo &getBiome(int); -private: - QHash > biomes; - QList > packs; +class BiomeIdentifier { + public: + BiomeIdentifier(); + ~BiomeIdentifier(); + int addDefinitions(JSONArray *, int pack = -1); + void enableDefinitions(int id); + void disableDefinitions(int id); + BiomeInfo &getBiome(int id); + private: + QHash> biomes; + QList > packs; }; -#endif +#endif // BIOMEIDENTIFIER_H_ diff --git a/blockidentifier.cpp b/blockidentifier.cpp old mode 100755 new mode 100644 index 251de926..8f6011f3 --- a/blockidentifier.cpp +++ b/blockidentifier.cpp @@ -1,90 +1,52 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "blockidentifier.h" -#include "json.h" +/** Copyright (c) 2013, Sean Kasun */ + #include +#include "./blockidentifier.h" +#include "./json.h" static BlockInfo unknownBlock; -BlockInfo::BlockInfo() -: transparent(false) -, liquid(false) -, rendernormal(true) -, providepower(false) -, spawninside(false) -{} - -bool BlockInfo::isOpaque() -{ - return !(this->transparent); +BlockInfo::BlockInfo() : transparent(false), liquid(false), rendernormal(true), + providepower(false), spawninside(false) {} + +bool BlockInfo::isOpaque() { + return !(this->transparent); } -bool BlockInfo::isLiquid() -{ - return this->liquid; +bool BlockInfo::isLiquid() { + return this->liquid; } -bool BlockInfo::doesBlockHaveSolidTopSurface(int data) -{ - if (this->isOpaque() && this->renderAsNormalBlock()) return true; - if (this->stairs && ((data&4)==4)) return true; - if (this->halfslab && ((data&8)==8)) return true; - if (this->hopper) return true; - if (this->snow && ((data&7)==7)) return true; - return false; +bool BlockInfo::doesBlockHaveSolidTopSurface(int data) { + if (this->isOpaque() && this->renderAsNormalBlock()) return true; + if (this->stairs && ((data & 4) == 4)) return true; + if (this->halfslab && ((data & 8) == 8)) return true; + if (this->hopper) return true; + if (this->snow && ((data & 7) == 7)) return true; + return false; } -bool BlockInfo::isBlockNormalCube() -{ - return this->isOpaque() && - this->renderAsNormalBlock() && - !this->canProvidePower(); +bool BlockInfo::isBlockNormalCube() { + return this->isOpaque() && this->renderAsNormalBlock() && + !this->canProvidePower(); } -bool BlockInfo::renderAsNormalBlock() -{ -// if (this->name.contains("Redstone Wire")) && powered return true; else return false; - return this->rendernormal; +bool BlockInfo::renderAsNormalBlock() { + return this->rendernormal; } -bool BlockInfo::canProvidePower() -{ - return this->providepower; +bool BlockInfo::canProvidePower() { + return this->providepower; } -void BlockInfo::setName( const QString & newname ) -{ - name = newname; - bedrock = this->name.contains("Bedrock"); - hopper = this->name.contains("Hopper"); - stairs = this->name.contains("Stairs"); - halfslab = this->name.contains("Slab") && !this->name.contains("Double") && !this->name.contains("Full"); - snow = this->name.contains("Snow"); +void BlockInfo::setName(const QString & newname) { + name = newname; + bedrock = this->name.contains("Bedrock"); + hopper = this->name.contains("Hopper"); + stairs = this->name.contains("Stairs"); + halfslab = this->name.contains("Slab") && !this->name.contains("Double") && + !this->name.contains("Full"); + snow = this->name.contains("Snow"); } const QString & BlockInfo::getName() { return name; } @@ -98,246 +60,216 @@ bool BlockInfo::isSnow() { return snow; } -BlockIdentifier::BlockIdentifier() -{ - // clear cache pointers - for (int i=0;i<65536;i++) - cache[i]=NULL; - for (int i=0;i<16;i++) - unknownBlock.colors[i]=0xff00ff; - unknownBlock.alpha=1.0; - unknownBlock.setName("Unknown"); +BlockIdentifier::BlockIdentifier() { + // clear cache pointers + for (int i = 0; i < 65536; i++) + cache[i] = NULL; + for (int i = 0; i < 16; i++) + unknownBlock.colors[i] = 0xff00ff; + unknownBlock.alpha = 1.0; + unknownBlock.setName("Unknown"); } -BlockIdentifier::~BlockIdentifier() -{ - clearCache(); - for (int i=0;imask; - - quint32 bid=id|(data<<12); - //first check the cache - if (cache[bid]!=NULL) - return *cache[bid]; - - //now find the variant - if (blocks.contains(bid)) - { - QList &list=blocks[bid]; - //run backwards for priority sorting - for (int i=list.length()-1;i>=0;i--) - { - if (list[i]->enabled) - { - cache[bid]=list[i]; - return *list[i]; - } - } - } - //no enabled variant found - if (blocks.contains(id)) - { - QList &list=blocks[id]; - for (int i=list.length()-1;i>=0;i--) - { - if (list[i]->enabled) - { - cache[bid]=list[i]; - return *list[i]; - } - } - } - //no blocks at all found.. dammit - return unknownBlock; +BlockInfo &BlockIdentifier::getBlock(int id, int data) { + // first apply the mask + if (blocks.contains(id)) + data &= blocks[id].first()->mask; + + quint32 bid = id | (data << 12); + // first check the cache + if (cache[bid] != NULL) + return *cache[bid]; + + // now find the variant + if (blocks.contains(bid)) { + QList &list = blocks[bid]; + // run backwards for priority sorting + for (int i = list.length() - 1; i >= 0; i--) { + if (list[i]->enabled) { + cache[bid] = list[i]; + return *list[i]; + } + } + } + // no enabled variant found + if (blocks.contains(id)) { + QList &list = blocks[id]; + for (int i = list.length() - 1; i >= 0; i--) { + if (list[i]->enabled) { + cache[bid] = list[i]; + return *list[i]; + } + } + } + // no blocks at all found.. dammit + return unknownBlock; } -void BlockIdentifier::enableDefinitions(int pack) -{ - if (pack<0) return; - int len=packs[pack].length(); - for (int i=0;ienabled=true; - //clear cache - clearCache(); +void BlockIdentifier::enableDefinitions(int pack) { + if (pack < 0) return; + int len = packs[pack].length(); + for (int i = 0; i < len; i++) + packs[pack][i]->enabled = true; + // clear cache + clearCache(); } -void BlockIdentifier::disableDefinitions(int pack) -{ - if (pack<0) return; - int len=packs[pack].length(); - for (int i=0;ienabled=false; - //clear cache - clearCache(); +void BlockIdentifier::disableDefinitions(int pack) { + if (pack < 0) return; + int len = packs[pack].length(); + for (int i = 0; i < len; i++) + packs[pack][i]->enabled = false; + // clear cache + clearCache(); } -int BlockIdentifier::addDefinitions(JSONArray *defs,int pack) -{ - if (pack==-1) - { - pack=packs.length(); - packs.append(QList()); - } - int len=defs->length(); - for (int i=0;i(defs->at(i)),NULL,pack); - //clear cache - clearCache(); - return pack; +int BlockIdentifier::addDefinitions(JSONArray *defs, int pack) { + if (pack == -1) { + pack = packs.length(); + packs.append(QList()); + } + int len = defs->length(); + for (int i = 0; i < len; i++) + parseDefinition(dynamic_cast(defs->at(i)), NULL, pack); + // clear cache + clearCache(); + return pack; } -static int clamp(int v,int min,int max) -{ - return (vmin?v:min):max); +static int clamp(int v, int min, int max) { + return (v < max ? (v > min ? v : min) : max); } -void BlockIdentifier::clearCache() -{ - for (int i=0;i<65536;i++) - { - cache[i]=NULL; - } +void BlockIdentifier::clearCache() { + for (int i = 0; i < 65536; i++) { + cache[i] = NULL; + } } -void BlockIdentifier::parseDefinition(JSONObject *b, BlockInfo *parent, int pack) -{ - int id; - if (parent==NULL) - id=b->at("id")->asNumber(); - else - { - id=parent->id; - int data=b->at("data")->asNumber(); - id|=data<<12; - } - BlockInfo *block=new BlockInfo(); - block->id=id; - - if (b->has("name")) - block->setName(b->at("name")->asString()); - else if (parent!=NULL) - block->setName(parent->getName()); - else - block->setName("Unknown"); - block->enabled=true; - - if (b->has("transparent")) - { - block->transparent=b->at("transparent")->asBool(); - block->rendernormal=false; // for most cases except the following - if (b->has("rendercube")) - block->rendernormal=b->at("rendercube")->asBool(); - block->spawninside=false; // for most cases except the following - if (b->has("spawninside")) - block->spawninside=b->at("spawninside")->asBool(); - } - else if (parent!=NULL) - { - block->transparent=parent->transparent; - block->rendernormal=parent->rendernormal; - block->spawninside=parent->spawninside; - } - else - { - block->transparent=false; - block->rendernormal=true; - block->spawninside=false; - } - - if (b->has("liquid")) - block->liquid=b->at("liquid")->asBool(); - else if (parent!=NULL) - block->liquid=parent->liquid; - else - block->liquid=false; - - if (b->has("canProvidePower")) - block->providepower=b->at("canProvidePower")->asBool(); - else if (parent!=NULL) - block->providepower=parent->providepower; - else - block->providepower=false; - - if (b->has("color")) - { - QString color=b->at("color")->asString(); - quint32 col=0; - for (int h=0;h='0' && c<='9') - col|=c-'0'; - else if (c>='A' && c<='F') - col|=c-'A'+10; - else if (c>='a' && c<='f') - col|=c-'a'+10; - } - int rd=col>>16; - int gn=(col>>8)&0xff; - int bl=col&0xff; - - if (b->has("alpha")) - block->alpha=b->at("alpha")->asNumber(); - else if (parent!=NULL) - block->alpha=parent->alpha; - else - block->alpha=1.0; - - //pre multiply alphas - rd*=block->alpha; - gn*=block->alpha; - bl*=block->alpha; - - //pre-calculate light spectrum - double y=0.299*rd+0.587*gn+0.114*bl; - double u=(bl-y)*0.565; - double v=(rd-y)*0.713; - double delta=y/15; - for (int i=0;i<16;i++) - { - y=i*delta; - rd=(unsigned int)clamp(y+1.403*v,0,255); - gn=(unsigned int)clamp(y-0.344*u-0.714*v,0,255); - bl=(unsigned int)clamp(y+1.770*u,0,255); - block->colors[i]=(rd<<16)|(gn<<8)|bl; - } - - } - else if (parent!=NULL) - { - for (int i=0;i<16;i++) - block->colors[i]=parent->colors[i]; - block->alpha=parent->alpha; - } - else - block->alpha=0.0; - - if (b->has("mask")) - block->mask=b->at("mask")->asNumber(); - else if (b->has("variants")) - block->mask=0x0f; - else - block->mask=0x00; - - if (b->has("variants")) - { - JSONArray *variants=dynamic_cast(b->at("variants")); - int vlen=variants->length(); - for (int j=0;j(variants->at(j)),block,pack); - } - - blocks[id].append(block); - packs[pack].append(block); +void BlockIdentifier::parseDefinition(JSONObject *b, BlockInfo *parent, + int pack) { + int id; + if (parent == NULL) { + id = b->at("id")->asNumber(); + } else { + id = parent->id; + int data = b->at("data")->asNumber(); + id |= data << 12; + } + BlockInfo *block = new BlockInfo(); + block->id = id; + + if (b->has("name")) + block->setName(b->at("name")->asString()); + else if (parent != NULL) + block->setName(parent->getName()); + else + block->setName("Unknown"); + block->enabled = true; + + if (b->has("transparent")) { + block->transparent = b->at("transparent")->asBool(); + block->rendernormal = false; // for most cases except the following + if (b->has("rendercube")) + block->rendernormal = b->at("rendercube")->asBool(); + block->spawninside = false; // for most cases except the following + if (b->has("spawninside")) + block->spawninside = b->at("spawninside")->asBool(); + } else if (parent != NULL) { + block->transparent = parent->transparent; + block->rendernormal = parent->rendernormal; + block->spawninside = parent->spawninside; + } else { + block->transparent = false; + block->rendernormal = true; + block->spawninside = false; + } + + if (b->has("liquid")) + block->liquid = b->at("liquid")->asBool(); + else if (parent != NULL) + block->liquid = parent->liquid; + else + block->liquid = false; + + if (b->has("canProvidePower")) + block->providepower = b->at("canProvidePower")->asBool(); + else if (parent != NULL) + block->providepower = parent->providepower; + else + block->providepower = false; + + if (b->has("color")) { + QString color = b->at("color")->asString(); + quint32 col = 0; + for (int h = 0; h < color.length(); h++) { + ushort c = color.at(h).unicode(); + col <<= 4; + if (c >= '0' && c <= '9') + col |= c - '0'; + else if (c >= 'A' && c <= 'F') + col |= c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + col |= c - 'a' + 10; + } + int rd = col >> 16; + int gn = (col >> 8) & 0xff; + int bl = col & 0xff; + + if (b->has("alpha")) + block->alpha = b->at("alpha")->asNumber(); + else if (parent != NULL) + block->alpha = parent->alpha; + else + block->alpha = 1.0; + + // pre multiply alphas + rd *= block->alpha; + gn *= block->alpha; + bl *= block->alpha; + + // pre-calculate light spectrum + double y = 0.299 * rd + 0.587 * gn + 0.114 * bl; + double u = (bl - y) * 0.565; + double v = (rd - y) * 0.713; + double delta = y / 15; + for (int i = 0; i < 16; i++) { + y = i * delta; + rd = (unsigned int)clamp(y + 1.403 * v, 0, 255); + gn = (unsigned int)clamp(y - 0.344 * u - 0.714 * v, 0, 255); + bl = (unsigned int)clamp(y + 1.770 * u, 0, 255); + block->colors[i] = (rd << 16) | (gn << 8) | bl; + } + } else if (parent != NULL) { + for (int i = 0; i < 16; i++) + block->colors[i] = parent->colors[i]; + block->alpha = parent->alpha; + } else { + block->alpha = 0.0; + } + + if (b->has("mask")) + block->mask = b->at("mask")->asNumber(); + else if (b->has("variants")) + block->mask = 0x0f; + else + block->mask = 0x00; + + if (b->has("variants")) { + JSONArray *variants = dynamic_cast(b->at("variants")); + int vlen = variants->length(); + for (int j = 0; j < vlen; j++) + parseDefinition(dynamic_cast(variants->at(j)), block, pack); + } + + blocks[id].append(block); + packs[pack].append(block); } diff --git a/blockidentifier.h b/blockidentifier.h old mode 100755 new mode 100644 index 418cbd26..be39753a --- a/blockidentifier.h +++ b/blockidentifier.h @@ -1,32 +1,6 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BLOCKIDENTIFIER_H__ -#define __BLOCKIDENTIFIER_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef BLOCKIDENTIFIER_H_ +#define BLOCKIDENTIFIER_H_ #include #include @@ -44,62 +18,61 @@ class JSONObject; // mobs can't spawn on transparent, but need 2 blocks of transparent, // non solid, non liquid above -class BlockInfo -{ -public: - BlockInfo(); - bool isOpaque(); - bool isLiquid(); - bool doesBlockHaveSolidTopSurface(int data); - bool isBlockNormalCube(); - bool renderAsNormalBlock(); - bool canProvidePower(); - - // special blocks used during mob spawning detection - bool isBedrock(); - bool isHopper(); - bool isStairs(); - bool isHalfSlab(); - bool isSnow(); +class BlockInfo { + public: + BlockInfo(); + bool isOpaque(); + bool isLiquid(); + bool doesBlockHaveSolidTopSurface(int data); + bool isBlockNormalCube(); + bool renderAsNormalBlock(); + bool canProvidePower(); + + // special blocks used during mob spawning detection + bool isBedrock(); + bool isHopper(); + bool isStairs(); + bool isHalfSlab(); + bool isSnow(); + + void setName(const QString &newname); + const QString &getName(); - void setName( const QString & newname ); - const QString & getName(); + int id; + double alpha; + quint8 mask; + bool enabled; + bool transparent; + bool liquid; + bool rendernormal; + bool providepower; + bool spawninside; + quint32 colors[16]; - int id; - double alpha; - quint8 mask; - bool enabled; - bool transparent; - bool liquid; - bool rendernormal; - bool providepower; - bool spawninside; - quint32 colors[16]; -private: - QString name; - // cache special blocks used during mob spawning detection - bool bedrock; - bool hopper; - bool stairs; - bool halfslab; - bool snow; + private: + QString name; + // cache special blocks used during mob spawning detection + bool bedrock; + bool hopper; + bool stairs; + bool halfslab; + bool snow; }; -class BlockIdentifier -{ -public: - BlockIdentifier(); - ~BlockIdentifier(); - int addDefinitions(JSONArray *,int pack=-1); - void enableDefinitions(int); - void disableDefinitions(int); - BlockInfo &getBlock(int id,int data); -private: - void clearCache(); - void parseDefinition(JSONObject *block,BlockInfo *parent,int pack); - QMap > blocks; - QList > packs; - BlockInfo *cache[65536]; +class BlockIdentifier { + public: + BlockIdentifier(); + ~BlockIdentifier(); + int addDefinitions(JSONArray *, int pack = -1); + void enableDefinitions(int id); + void disableDefinitions(int id); + BlockInfo &getBlock(int id, int data); + private: + void clearCache(); + void parseDefinition(JSONObject *block, BlockInfo *parent, int pack); + QMap> blocks; + QList > packs; + BlockInfo *cache[65536]; }; -#endif +#endif // BLOCKIDENTIFIER_H_ diff --git a/check.sh b/check.sh new file mode 100755 index 00000000..c05dbdf6 --- /dev/null +++ b/check.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +scan-build -enable-checker alpha.core.BoolAssignment -enable-checker alpha.core.CastSize -enable-checker alpha.core.CastToStruct -enable-checker alpha.core.FixedAddr -enable-checker alpha.core.IdenticalExpr -enable-checker alpha.core.PointerArithm -enable-checker alpha.core.PointerSub -enable-checker alpha.core.SizeofPtr -enable-checker alpha.core.TestAfterDivZero -enable-checker alpha.deadcode.UnreachableCode -enable-checker security.FloatLoopCounter make diff --git a/chunk.cpp b/chunk.cpp index 98e27ef7..d1919b5f 100644 --- a/chunk.cpp +++ b/chunk.cpp @@ -1,136 +1,99 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. +/** Copyright (c) 2013, Sean Kasun */ - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: +#include "./chunk.h" - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "chunk.h" - -Chunk::Chunk() -{ - loaded=false; +Chunk::Chunk() { + loaded = false; } -void Chunk::load(NBT &nbt) -{ - renderedAt=-1; //impossible. - renderedFlags=0; //no flags - memset(this->biomes,127,256); //init to unknown biome - for (int i=0;i<16;i++) - this->sections[i]=NULL; - highest=0; - - Tag *level=nbt.at("Level"); - chunkX = level->at("xPos")->toInt(); - chunkZ = level->at("zPos")->toInt(); - - Tag *biomes=level->at("Biomes"); - memcpy(this->biomes,biomes->toByteArray(),biomes->length()); - Tag *sections=level->at("Sections"); - int numSections=sections->length(); - for (int i=0;iat(i); - ChunkSection *cs=new ChunkSection(); - const quint8 *raw=section->at("Blocks")->toByteArray(); - for (int i=0;i<4096;i++) - cs->blocks[i]=raw[i]; - if (section->has("Add")) - { - raw=section->at("Add")->toByteArray(); - for (int i=0;i<2048;i++) - { - cs->blocks[i*2]|=(raw[i]&0xf)<<8; - cs->blocks[i*2+1]|=(raw[i]&0xf0)<<4; - } - } - memcpy(cs->data,section->at("Data")->toByteArray(),2048); - memcpy(cs->light,section->at("BlockLight")->toByteArray(),2048); - int idx=section->at("Y")->toInt(); - this->sections[idx]=cs; - } - loaded=true; - - - Tag* entitylist = level->at("Entities"); - int numEntities = entitylist->length(); - for (int i = 0; i < numEntities; ++i) - { - QSharedPointer e = Entity::TryParse(entitylist->at(i)); - if (e) - entities.insertMulti(e->type(), e); - } - - - for (int i=15;i>=0;i--) //check for the highest block in this chunk - { - if (this->sections[i]) - for (int j=4095;j>=0;j--) - if (this->sections[i]->blocks[j]) - { - highest=i*16+(j>>8); - return; - } - } +void Chunk::load(const NBT &nbt) { + renderedAt = -1; // impossible. + renderedFlags = 0; // no flags + memset(this->biomes, 127, 256); // init to unknown biome + for (int i = 0; i < 16; i++) + this->sections[i] = NULL; + highest = 0; + + auto level = nbt.at("Level"); + chunkX = level->at("xPos")->toInt(); + chunkZ = level->at("zPos")->toInt(); + + auto biomes = level->at("Biomes"); + memcpy(this->biomes, biomes->toByteArray(), biomes->length()); + auto sections = level->at("Sections"); + int numSections = sections->length(); + for (int i = 0; i < numSections; i++) { + auto section = sections->at(i); + auto cs = new ChunkSection(); + auto raw = section->at("Blocks")->toByteArray(); + for (int i = 0; i < 4096; i++) + cs->blocks[i] = raw[i]; + if (section->has("Add")) { + raw = section->at("Add")->toByteArray(); + for (int i = 0; i < 2048; i++) { + cs->blocks[i * 2] |= (raw[i] & 0xf) << 8; + cs->blocks[i * 2 + 1] |= (raw[i] & 0xf0) << 4; + } + } + memcpy(cs->data, section->at("Data")->toByteArray(), 2048); + memcpy(cs->light, section->at("BlockLight")->toByteArray(), 2048); + int idx = section->at("Y")->toInt(); + this->sections[idx] = cs; + } + loaded = true; + + + auto entitylist = level->at("Entities"); + int numEntities = entitylist->length(); + for (int i = 0; i < numEntities; ++i) { + auto e = Entity::TryParse(entitylist->at(i)); + if (e) + entities.insertMulti(e->type(), e); + } + + for (int i = 15; i >= 0; i--) { // check for the highest block in this chunk + if (this->sections[i]) { + for (int j = 4095; j >= 0; j--) { + if (this->sections[i]->blocks[j]) { + highest = i * 16 + (j >> 8); + return; + } + } + } + } } -Chunk::~Chunk() -{ - if (loaded) - for (int i=0;i<16;i++) - if (sections[i]) - { - delete sections[i]; - sections[i]=NULL; - } +Chunk::~Chunk() { + if (loaded) { + for (int i = 0; i < 16; i++) + if (sections[i]) { + delete sections[i]; + sections[i] = NULL; + } + } } -quint16 ChunkSection::getBlock(int x, int y, int z) -{ - int xoffset = x; - int yoffset = (y&0x0f)<<8; - int zoffset = z<<4; - return blocks[xoffset+yoffset+zoffset]; +quint16 ChunkSection::getBlock(int x, int y, int z) { + int xoffset = x; + int yoffset = (y & 0x0f) << 8; + int zoffset = z << 4; + return blocks[xoffset + yoffset + zoffset]; } -quint8 ChunkSection::getData(int x, int y, int z) -{ - int xoffset = x; - int yoffset = (y&0x0f)<<8; - int zoffset = z<<4; - int value = data[(xoffset+yoffset+zoffset)/2]; - if (x&1) value>>=4; - return value&0x0f; +quint8 ChunkSection::getData(int x, int y, int z) { + int xoffset = x; + int yoffset = (y & 0x0f) << 8; + int zoffset = z << 4; + int value = data[(xoffset + yoffset + zoffset) / 2]; + if (x & 1) value >>= 4; + return value&0x0f; } -quint8 ChunkSection::getLight(int x, int y, int z) -{ - int xoffset = x; - int yoffset = (y&0x0f)<<8; - int zoffset = z<<4; - int value = light[(xoffset+yoffset+zoffset)/2]; - if (x&1) value>>=4; - return value&0x0f; +quint8 ChunkSection::getLight(int x, int y, int z) { + int xoffset = x; + int yoffset = (y & 0x0f) << 8; + int zoffset = z << 4; + int value = light[(xoffset + yoffset + zoffset) / 2]; + if (x & 1) value >>= 4; + return value & 0x0f; } diff --git a/chunk.h b/chunk.h index a45bff32..69110bb2 100644 --- a/chunk.h +++ b/chunk.h @@ -1,76 +1,47 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __CHUNK_H__ -#define __CHUNK_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef CHUNK_H_ +#define CHUNK_H_ #include #include -#include "nbt.h" -#include "entity.h" +#include "./nbt.h" +#include "./entity.h" class BlockIdentifier; -class ChunkSection -{ -public: - quint16 getBlock(int x, int y, int z); - quint8 getData(int x, int y, int z); - quint8 getLight(int x, int y, int z); +class ChunkSection { + public: + quint16 getBlock(int x, int y, int z); + quint8 getData(int x, int y, int z); + quint8 getLight(int x, int y, int z); - quint16 blocks[4096]; - quint8 data[2048]; - quint8 light[2048]; + quint16 blocks[4096]; + quint8 data[2048]; + quint8 light[2048]; }; -class Chunk -{ -public: - Chunk(); - void load(NBT &nbt); - ~Chunk(); -protected: - typedef QMap > EntityMap; - - quint8 biomes[256]; - int highest; - ChunkSection *sections[16]; - int renderedAt; - int renderedFlags; - bool loaded; - uchar image[16*16*4]; //cached render - uchar depth[16*16]; - EntityMap entities; - int chunkX; - int chunkZ; - friend class MapView; - friend class ChunkCache; - friend class WorldSave; +class Chunk { + public: + Chunk(); + void load(const NBT &nbt); + ~Chunk(); + protected: + typedef QMap> EntityMap; + + quint8 biomes[256]; + int highest; + ChunkSection *sections[16]; + int renderedAt; + int renderedFlags; + bool loaded; + uchar image[16 * 16 * 4]; // cached render + uchar depth[16 * 16]; + EntityMap entities; + int chunkX; + int chunkZ; + friend class MapView; + friend class ChunkCache; + friend class WorldSave; }; -#endif +#endif // CHUNK_H_ diff --git a/chunkcache.cpp b/chunkcache.cpp index 04aa0d1f..57f7cac3 100644 --- a/chunkcache.cpp +++ b/chunkcache.cpp @@ -1,123 +1,86 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. +/** Copyright (c) 2013, Sean Kasun */ - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "chunkcache.h" -#include "chunkloader.h" +#include "./chunkcache.h" +#include "./chunkloader.h" #if defined(__unix__) || defined(__unix) || defined(unix) - #include +#include #elif defined(_WIN32) || defined(WIN32) - #include +#include #endif -ChunkID::ChunkID(int x,int z) : x(x),z(z) -{ +ChunkID::ChunkID(int x, int z) : x(x), z(z) { } -bool ChunkID::operator==(const ChunkID &other) const -{ - return (other.x==x) && (other.z==z); +bool ChunkID::operator==(const ChunkID &other) const { + return (other.x == x) && (other.z == z); } -uint qHash(const ChunkID &c) -{ - return (c.x<<16)^(c.z&0xffff); // safe way to hash a pair of integers +uint qHash(const ChunkID &c) { + return (c.x << 16) ^ (c.z & 0xffff); // safe way to hash a pair of integers } -ChunkCache::ChunkCache() -{ - long chunks=10000; // as default 10000 chunks, or 10% more than 1920x1200 blocks +ChunkCache::ChunkCache() { + size_t chunks = 10000; // 10% more than 1920x1200 blocks #if defined(__unix__) || defined(__unix) || defined(unix) - long pages = sysconf(_SC_AVPHYS_PAGES); - long page_size = sysconf(_SC_PAGE_SIZE); - chunks = (pages*page_size) / (sizeof(Chunk) + 16*sizeof(ChunkSection)); - cache.setMaxCost(chunks); + auto pages = sysconf(_SC_AVPHYS_PAGES); + auto page_size = sysconf(_SC_PAGE_SIZE); + chunks = (pages*page_size) / (sizeof(Chunk) + 16*sizeof(ChunkSection)); + cache.setMaxCost(chunks); #elif defined(_WIN32) || defined(WIN32) - MEMORYSTATUSEX status; - status.dwLength = sizeof(status); - GlobalMemoryStatusEx(&status); - DWORDLONG available = std::min(status.ullAvailPhys, status.ullAvailVirtual); - chunks = available / (sizeof(Chunk) + 16*sizeof(ChunkSection)); + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + GlobalMemoryStatusEx(&status); + DWORDLONG available = qmin(status.ullAvailPhys, status.ullAvailVirtual); + chunks = available / (sizeof(Chunk) + 16 * sizeof(ChunkSection)); #endif - cache.setMaxCost(chunks); - maxcache = 2*chunks; //most chunks are only filled less than half with sections + cache.setMaxCost(chunks); + maxcache = 2 * chunks; // most chunks are less than half filled with sections } -ChunkCache::~ChunkCache() -{ +ChunkCache::~ChunkCache() { } -void ChunkCache::clear() -{ - QThreadPool::globalInstance()->waitForDone(); - mutex.lock(); - cache.clear(); - mutex.unlock(); +void ChunkCache::clear() { + QThreadPool::globalInstance()->waitForDone(); + mutex.lock(); + cache.clear(); + mutex.unlock(); } -void ChunkCache::setPath(QString path) -{ - this->path=path; +void ChunkCache::setPath(QString path) { + this->path = path; } -QString ChunkCache::getPath() -{ - return path; +QString ChunkCache::getPath() { + return path; } -Chunk *ChunkCache::fetch(int x, int z) -{ - ChunkID id(x,z); - mutex.lock(); - Chunk *chunk=cache[id]; - mutex.unlock(); - if (chunk!=NULL) - { - if (chunk->loaded) - return chunk; - return NULL; //we're loading this chunk, or it's blank. - } - // launch background process to load this chunk - chunk=new Chunk(); - mutex.lock(); - cache.insert(id,chunk); - mutex.unlock(); - ChunkLoader *loader=new ChunkLoader(path,x,z,cache,mutex); - connect(loader,SIGNAL(loaded(int,int)), - this,SLOT(gotChunk(int,int))); - QThreadPool::globalInstance()->start(loader); - return NULL; +Chunk *ChunkCache::fetch(int x, int z) { + ChunkID id(x, z); + mutex.lock(); + Chunk *chunk = cache[id]; + mutex.unlock(); + if (chunk != NULL) { + if (chunk->loaded) + return chunk; + return NULL; // we're loading this chunk, or it's blank. + } + // launch background process to load this chunk + chunk = new Chunk(); + mutex.lock(); + cache.insert(id, chunk); + mutex.unlock(); + ChunkLoader *loader = new ChunkLoader(path, x, z, cache, &mutex); + connect(loader, SIGNAL(loaded(int, int)), + this, SLOT(gotChunk(int, int))); + QThreadPool::globalInstance()->start(loader); + return NULL; } -void ChunkCache::gotChunk(int x,int z) -{ - emit chunkLoaded(x,z); +void ChunkCache::gotChunk(int x, int z) { + emit chunkLoaded(x, z); } -void ChunkCache::adaptCacheToWindow(int x,int y) -{ - int chunks=((x+15)>>4)*((y+15)>>4); // number of chunks visible in window - chunks *= 1.10; // add 10% - cache.setMaxCost(std::min(chunks,maxcache)); +void ChunkCache::adaptCacheToWindow(int x, int y) { + int chunks = ((x + 15) >> 4) * ((y + 15) >> 4); // number of chunks visible + chunks *= 1.10; // add 10% + cache.setMaxCost(qMin(chunks, maxcache)); } diff --git a/chunkcache.h b/chunkcache.h index 52a71bb2..09cf4805 100644 --- a/chunkcache.h +++ b/chunkcache.h @@ -1,74 +1,45 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __CHUNKCACHE_H__ -#define __CHUNKCACHE_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef CHUNKCACHE_H_ +#define CHUNKCACHE_H_ #include #include -#include "chunk.h" - -class ChunkID -{ -public: - ChunkID(int x,int z); - bool operator==(const ChunkID &) const; - friend uint qHash(const ChunkID &); -protected: - int x,z; +#include "./chunk.h" + +class ChunkID { + public: + ChunkID(int x, int z); + bool operator==(const ChunkID &) const; + friend uint qHash(const ChunkID &); + protected: + int x, z; }; -class ChunkCache : public QObject -{ - Q_OBJECT +class ChunkCache : public QObject { + Q_OBJECT -public: - ChunkCache(); - ~ChunkCache(); - void clear(); - void setPath(QString path); - QString getPath(); - Chunk *fetch(int x,int z); + public: + ChunkCache(); + ~ChunkCache(); + void clear(); + void setPath(QString path); + QString getPath(); + Chunk *fetch(int x, int z); -signals: - void chunkLoaded(int x,int z); + signals: + void chunkLoaded(int x, int z); -public slots: - void adaptCacheToWindow(int x,int y); + public slots: + void adaptCacheToWindow(int x, int y); -private slots: - void gotChunk(int x,int z); + private slots: + void gotChunk(int x, int z); -private: - QString path; - QCache cache; - QMutex mutex; - int maxcache; + private: + QString path; + QCache cache; + QMutex mutex; + int maxcache; }; -#endif +#endif // CHUNKCACHE_H_ diff --git a/chunkloader.cpp b/chunkloader.cpp index bf8cd368..73b61876 100644 --- a/chunkloader.cpp +++ b/chunkloader.cpp @@ -1,82 +1,56 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. +/** Copyright (c) 2013, Sean Kasun */ - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: +#include "./chunkloader.h" +#include "./chunkcache.h" +#include "./chunk.h" - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "chunkloader.h" -#include "chunkcache.h" -#include "chunk.h" - -ChunkLoader::ChunkLoader(QString path,int x,int z,QCache &cache,QMutex &mutex) : path(path),x(x),z(z),cache(cache),mutex(mutex) -{ +ChunkLoader::ChunkLoader(QString path, int x, int z, + const QCache &cache, + QMutex *mutex) : path(path), x(x), z(z), + cache(cache), mutex(mutex) { } -ChunkLoader::~ChunkLoader() -{ +ChunkLoader::~ChunkLoader() { } -void ChunkLoader::run() -{ - int rx=x>>5; - int rz=z>>5; - - QFile f(path+"/region/r."+QString::number(rx)+"."+QString::number(rz)+".mca"); - if (!f.open(QIODevice::ReadOnly)) //no chunks in this region - { - emit loaded(x,z); - return; - } - //map header into memory - uchar *header=f.map(0,4096); - int offset=4*((x&31)+(z&31)*32); - int coffset=(header[offset]<<16)|(header[offset+1]<<8)|header[offset+2]; - int numSectors=header[offset+3]; - f.unmap(header); - - if (coffset==0) // no chunk - { - f.close(); - emit loaded(x,z); - return; - } - - uchar *raw=f.map(coffset*4096,numSectors*4096); - if (raw == NULL) - { - f.close(); - emit loaded(x, z); - return; - } - NBT nbt(raw); - ChunkID id(x,z); - mutex.lock(); - Chunk *chunk=cache[id]; - if (chunk) - chunk->load(nbt); - mutex.unlock(); - f.unmap(raw); - f.close(); - - emit loaded(x,z); +void ChunkLoader::run() { + int rx = x >> 5; + int rz = z >> 5; + + QFile f(path + "/region/r." + QString::number(rx) + "." + + QString::number(rz) + ".mca"); + if (!f.open(QIODevice::ReadOnly)) { // no chunks in this region + emit loaded(x, z); + return; + } + // map header into memory + uchar *header = f.map(0, 4096); + int offset = 4 * ((x & 31) + (z & 31) * 32); + int coffset = (header[offset] << 16) | (header[offset + 1] << 8) | + header[offset + 2]; + int numSectors = header[offset+3]; + f.unmap(header); + + if (coffset == 0) { // no chunk + f.close(); + emit loaded(x, z); + return; + } + + uchar *raw = f.map(coffset * 4096, numSectors * 4096); + if (raw == NULL) { + f.close(); + emit loaded(x, z); + return; + } + NBT nbt(raw); + ChunkID id(x, z); + mutex->lock(); + Chunk *chunk = cache[id]; + if (chunk) + chunk->load(nbt); + mutex->unlock(); + f.unmap(raw); + f.close(); + + emit loaded(x, z); } diff --git a/chunkloader.h b/chunkloader.h index 9aaef11c..16a6c32c 100644 --- a/chunkloader.h +++ b/chunkloader.h @@ -1,32 +1,6 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CHUNKLOADER_H__ -#define __CHUNKLOADER_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef CHUNKLOADER_H_ +#define CHUNKLOADER_H_ #include #include @@ -34,21 +8,22 @@ class Chunk; class ChunkID; class QMutex; -class ChunkLoader : public QObject, public QRunnable -{ - Q_OBJECT -public: - ChunkLoader(QString path,int x,int z,QCache &cache,QMutex &mutex); - ~ChunkLoader(); -signals: - void loaded(int x,int z); -protected: - void run(); -private: - QString path; - int x,z; - QCache &cache; - QMutex &mutex; +class ChunkLoader : public QObject, public QRunnable { + Q_OBJECT + + public: + ChunkLoader(QString path, int x, int z, const QCache &cache, + QMutex *mutex); + ~ChunkLoader(); + signals: + void loaded(int x, int z); + protected: + void run(); + private: + QString path; + int x, z; + const QCache &cache; + QMutex *mutex; }; -#endif +#endif // CHUNKLOADER_H_ diff --git a/debian/changelog b/debian/changelog index a102b903..833024e1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +minutor (2.1.0) vivid; urgency=medium + + * So many changes... + + -- Sean Kasun Fri, 27 May 2016 15:33:01 -0700 + minutor (2.0.1) raring; urgency=low * Fixes for 1.7.2 diff --git a/definitionmanager.cpp b/definitionmanager.cpp index d94a78c8..e4bfb54e 100644 --- a/definitionmanager.cpp +++ b/definitionmanager.cpp @@ -1,33 +1,5 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. +/** Copyright (c) 2013, Sean Kasun */ - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include "definitionmanager.h" #include #include #include @@ -37,549 +9,510 @@ #include #include #include -#include "biomeidentifier.h" -#include "blockidentifier.h" -#include "dimensionidentifier.h" -#include "entityidentifier.h" -#include "mapview.h" -#include "json.h" -#include "zipreader.h" -#include "definitionupdater.h" - -DefinitionManager::DefinitionManager(QWidget *parent) - : QWidget(parent) - , entityManager(EntityIdentifier::Instance()) -{ - setWindowFlags(Qt::Window); - setWindowTitle(tr("Definitions")); - - QVBoxLayout *layout=new QVBoxLayout; - QStringList labels; - labels<setHorizontalHeaderLabels(labels); - table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - table->horizontalHeader()->setSectionResizeMode(0,QHeaderView::Stretch); - table->horizontalHeader()->setHighlightSections(false); - table->verticalHeader()->hide(); - table->setShowGrid(false); - table->setSelectionBehavior(QAbstractItemView::SelectRows); - layout->addWidget(table,1); - - QWidget *buttonBar=new QWidget; - QHBoxLayout *buttons=new QHBoxLayout; - QPushButton *add=new QPushButton(tr("Add Pack...")); - connect(add,SIGNAL(clicked()), - this,SLOT(addPack())); - buttons->addWidget(add); - QPushButton *remove=new QPushButton(tr("Remove Pack")); - connect(remove,SIGNAL(clicked()), - this,SLOT(removePack())); - connect(this,SIGNAL(packSelected(bool)), - remove,SLOT(setEnabled(bool))); - buttons->addWidget(remove); - QPushButton *save=new QPushButton(tr("Export Pack...")); - connect(save,SIGNAL(clicked()), - this,SLOT(exportPack())); - connect(this,SIGNAL(packSelected(bool)), - save,SLOT(setEnabled(bool))); - buttons->addWidget(save); - buttonBar->setLayout(buttons); - layout->addWidget(buttonBar,0); - - emit packSelected(false); - setLayout(layout); - - dimensionList = new DimensionIdentifier; - blocks=new BlockIdentifier; - biomes=new BiomeIdentifier; - - QSettings settings; - sorted=settings.value("packs").toList(); - lastUpdated=settings.value("packupdates").toHash(); - - //copy over built-in definitions if necessary - QString defdir=QStandardPaths::writableLocation(QStandardPaths::DataLocation); - QDir dir; - dir.mkpath(defdir); - QDirIterator it(":/definitions",QDir::Files|QDir::Readable); - while (it.hasNext()) - { - it.next(); - installJson(it.filePath(),false,false); - } - settings.setValue("packs",sorted); - // we load the definitions backwards for priority. - for (int i=sorted.length()-1;i>=0;i--) - loadDefinition(sorted[i].toString()); - - //hook up table selection signal - connect(table,SIGNAL(currentItemChanged(QTableWidgetItem*,QTableWidgetItem*)), - this, SLOT(selectedPack(QTableWidgetItem*,QTableWidgetItem*))); - //fill out table - refresh(); +#include +#include "./definitionmanager.h" +#include "./biomeidentifier.h" +#include "./blockidentifier.h" +#include "./dimensionidentifier.h" +#include "./entityidentifier.h" +#include "./mapview.h" +#include "./json.h" +#include "./zipreader.h" +#include "./definitionupdater.h" + +DefinitionManager::DefinitionManager(QWidget *parent) : QWidget(parent), + entityManager(EntityIdentifier::Instance()) { + setWindowFlags(Qt::Window); + setWindowTitle(tr("Definitions")); + + QVBoxLayout *layout = new QVBoxLayout; + QStringList labels; + labels << tr("Name") << tr("Version") << tr("Type"); + table = new QTableWidget(0, 3); + table->setHorizontalHeaderLabels(labels); + table->horizontalHeader()->setSectionResizeMode( + QHeaderView::ResizeToContents); + table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + table->horizontalHeader()->setHighlightSections(false); + table->verticalHeader()->hide(); + table->setShowGrid(false); + table->setSelectionBehavior(QAbstractItemView::SelectRows); + layout->addWidget(table, 1); + + QWidget *buttonBar = new QWidget; + QHBoxLayout *buttons = new QHBoxLayout; + QPushButton *add = new QPushButton(tr("Add Pack...")); + connect(add, SIGNAL(clicked()), + this, SLOT(addPack())); + buttons->addWidget(add); + QPushButton *remove = new QPushButton(tr("Remove Pack")); + connect(remove, SIGNAL(clicked()), + this, SLOT(removePack())); + connect(this, SIGNAL(packSelected(bool)), + remove, SLOT(setEnabled(bool))); + buttons->addWidget(remove); + QPushButton *save = new QPushButton(tr("Export Pack...")); + connect(save, SIGNAL(clicked()), + this, SLOT(exportPack())); + connect(this, SIGNAL(packSelected(bool)), + save, SLOT(setEnabled(bool))); + buttons->addWidget(save); + buttonBar->setLayout(buttons); + layout->addWidget(buttonBar, 0); + + emit packSelected(false); + setLayout(layout); + + dimensionList = new DimensionIdentifier; + blocks = new BlockIdentifier; + biomes = new BiomeIdentifier; + + QSettings settings; + sorted = settings.value("packs").toList(); + lastUpdated = settings.value("packupdates").toHash(); + + // copy over built-in definitions if necessary + QString defdir = QStandardPaths::writableLocation( + QStandardPaths::DataLocation); + QDir dir; + dir.mkpath(defdir); + QDirIterator it(":/definitions", QDir::Files | QDir::Readable); + while (it.hasNext()) { + it.next(); + installJson(it.filePath(), false, false); + } + settings.setValue("packs", sorted); + // we load the definitions backwards for priority. + for (int i = sorted.length() - 1; i >= 0; i--) + loadDefinition(sorted[i].toString()); + + // hook up table selection signal + connect(table, + SIGNAL(currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)), + this, SLOT(selectedPack(QTableWidgetItem*, QTableWidgetItem*))); + // fill out table + refresh(); } -DefinitionManager::~DefinitionManager() -{ - delete dimensionList; - delete blocks; - delete biomes; +DefinitionManager::~DefinitionManager() { + delete dimensionList; + delete blocks; + delete biomes; } -BlockIdentifier *DefinitionManager::blockIdentifier() -{ - return blocks; +BlockIdentifier *DefinitionManager::blockIdentifier() { + return blocks; } -BiomeIdentifier *DefinitionManager::biomeIdentifier() -{ - return biomes; +BiomeIdentifier *DefinitionManager::biomeIdentifier() { + return biomes; } -DimensionIdentifier *DefinitionManager::dimensionIdentifer() -{ - return dimensionList; +DimensionIdentifier *DefinitionManager::dimensionIdentifer() { + return dimensionList; } -void DefinitionManager::refresh() -{ - table->clearContents(); - table->setRowCount(0); - QStringList types; - types<rowCount(); - table->insertRow(row); - QTableWidgetItem *name=new QTableWidgetItem(def.name); - name->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); - name->setData(Qt::UserRole,def.path); - table->setItem(row,0,name); - QTableWidgetItem *ver=new QTableWidgetItem(def.version); - ver->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); - ver->setData(Qt::UserRole,def.path); - table->setItem(row,1,ver); - QTableWidgetItem *type=new QTableWidgetItem(types[def.type]); - type->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); - type->setData(Qt::UserRole,def.path); - table->setItem(row,2,type); -/* QCheckBox *active=new QCheckBox; - active->setChecked(def.enabled); - connect(active,SIGNAL(toggled(bool)), - this,SLOT(toggledPack(bool))); - checks.append(active); - table->setCellWidget(row,3,active); */ - } +void DefinitionManager::refresh() { + table->clearContents(); + table->setRowCount(0); + QStringList types; + types << tr("block") << tr("biome") << tr("dimension") + << tr("entity") << tr("pack"); + for (int i = 0; i < sorted.length(); i++) { + Definition &def = definitions[sorted[i].toString()]; + int row = table->rowCount(); + table->insertRow(row); + QTableWidgetItem *name = new QTableWidgetItem(def.name); + name->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + name->setData(Qt::UserRole, def.path); + table->setItem(row, 0, name); + QTableWidgetItem *ver = new QTableWidgetItem(def.version); + ver->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ver->setData(Qt::UserRole, def.path); + table->setItem(row, 1, ver); + QTableWidgetItem *type = new QTableWidgetItem(types[def.type]); + type->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + type->setData(Qt::UserRole, def.path); + table->setItem(row, 2, type); + } } -void DefinitionManager::selectedPack(QTableWidgetItem *item,QTableWidgetItem *) -{ - emit packSelected(item!=NULL); - if (item!=NULL) - selected=item->data(Qt::UserRole).toString(); - else - selected=QString(); +void DefinitionManager::selectedPack(QTableWidgetItem *item, + QTableWidgetItem *) { + emit packSelected(item != NULL); + if (item != NULL) + selected = item->data(Qt::UserRole).toString(); + else + selected = QString(); } -void DefinitionManager::toggledPack(bool onoff) -{ - if (definitions.contains(selected)) - { - Definition &def=definitions[selected]; - def.enabled=onoff; - switch (def.type) - { - case Definition::Block: - if (onoff) - blocks->enableDefinitions(def.id); - else - blocks->disableDefinitions(def.id); - break; - case Definition::Biome: - if (onoff) - biomes->enableDefinitions(def.id); - else - biomes->disableDefinitions(def.id); - break; - case Definition::Dimension: - if (onoff) - dimensionList->enableDefinitions(def.id); - else - dimensionList->disableDefinitions(def.id); - break; - case Definition::Entity: - if (onoff) - entityManager.enableDefinitions(def.id); - else - entityManager.disableDefinitions(def.id); - break; - case Definition::Pack: - if (onoff) - { - blocks->enableDefinitions(def.blockid); - biomes->enableDefinitions(def.biomeid); - dimensionList->enableDefinitions(def.dimensionid); - entityManager.enableDefinitions(def.entityid); - } - else - { - blocks->disableDefinitions(def.blockid); - biomes->disableDefinitions(def.biomeid); - dimensionList->disableDefinitions(def.dimensionid); - entityManager.disableDefinitions(def.entityid); - } - break; - } - } - emit packsChanged(); - refresh(); +void DefinitionManager::toggledPack(bool onoff) { + if (definitions.contains(selected)) { + Definition &def = definitions[selected]; + def.enabled = onoff; + switch (def.type) { + case Definition::Block: + if (onoff) + blocks->enableDefinitions(def.id); + else + blocks->disableDefinitions(def.id); + break; + case Definition::Biome: + if (onoff) + biomes->enableDefinitions(def.id); + else + biomes->disableDefinitions(def.id); + break; + case Definition::Dimension: + if (onoff) + dimensionList->enableDefinitions(def.id); + else + dimensionList->disableDefinitions(def.id); + break; + case Definition::Entity: + if (onoff) + entityManager.enableDefinitions(def.id); + else + entityManager.disableDefinitions(def.id); + break; + case Definition::Pack: + if (onoff) { + blocks->enableDefinitions(def.blockid); + biomes->enableDefinitions(def.biomeid); + dimensionList->enableDefinitions(def.dimensionid); + entityManager.enableDefinitions(def.entityid); + } else { + blocks->disableDefinitions(def.blockid); + biomes->disableDefinitions(def.biomeid); + dimensionList->disableDefinitions(def.dimensionid); + entityManager.disableDefinitions(def.entityid); + } + break; + } + } + emit packsChanged(); + refresh(); } -void DefinitionManager::addPack() -{ - QString packName=QFileDialog::getOpenFileName(this,tr("Open Pack"),QString(),tr("Definitions (*.zip *.json)")); - if (!packName.isEmpty()) - { - if (packName.endsWith(".json",Qt::CaseInsensitive)) //raw json - installJson(packName); - else - installZip(packName); - emit packsChanged(); - QSettings settings; - settings.setValue("packs",sorted); - refresh(); - } +void DefinitionManager::addPack() { + QString packName = QFileDialog::getOpenFileName(this, tr("Open Pack"), + QString(), tr("Definitions (*.zip *.json)")); + if (!packName.isEmpty()) { + if (packName.endsWith(".json", Qt::CaseInsensitive)) // raw json + installJson(packName); + else + installZip(packName); + emit packsChanged(); + QSettings settings; + settings.setValue("packs", sorted); + refresh(); + } } -void DefinitionManager::installJson(QString path,bool overwrite,bool install) -{ - QString destdir=QStandardPaths::writableLocation(QStandardPaths::DataLocation); - - JSONData *def; - QFile f(path); - f.open(QIODevice::ReadOnly); - try { - def=JSON::parse(f.readAll()); - f.close(); - } catch (JSONParseException e) { - f.close(); - QMessageBox::warning(this, - tr("Couldn't install %1").arg(path), - e.reason, - QMessageBox::Cancel); - return; - } - - QString key=def->at("name")->asString()+def->at("type")->asString(); - delete def; - QString dest=destdir+"/"+QString("%1").arg(qHash(key))+".json"; - if (!QFile::exists(dest) || overwrite) - { - if (QFile::exists(dest) && install) - removeDefinition(dest); - if (!QFile::copy(path,dest)) - { - QMessageBox::warning(this, - tr("Couldn't install %1").arg(path), - tr("Copy error"), - QMessageBox::Cancel); - return; - } - // fix permissions since we might be copying a readonly resource. - QFile::setPermissions(dest, QFile::ReadOwner|QFile::WriteOwner); - sorted.prepend(dest); - if (install) - loadDefinition(dest); - } +void DefinitionManager::installJson(QString path, bool overwrite, + bool install) { + QString destdir = QStandardPaths::writableLocation( + QStandardPaths::DataLocation); + + JSONData *def; + QFile f(path); + f.open(QIODevice::ReadOnly); + try { + def = JSON::parse(f.readAll()); + f.close(); + } catch (JSONParseException e) { + f.close(); + QMessageBox::warning(this, tr("Couldn't install %1").arg(path), + e.reason, + QMessageBox::Cancel); + return; + } + + QString key = def->at("name")->asString() + def->at("type")->asString(); + delete def; + QString dest = destdir + "/" + QString("%1").arg(qHash(key)) + ".json"; + if (!QFile::exists(dest) || overwrite) { + if (QFile::exists(dest) && install) + removeDefinition(dest); + if (!QFile::copy(path, dest)) { + QMessageBox::warning(this, tr("Couldn't install %1").arg(path), + tr("Copy error"), + QMessageBox::Cancel); + return; + } + // fix permissions since we might be copying a readonly resource. + QFile::setPermissions(dest, QFile::ReadOwner|QFile::WriteOwner); + sorted.prepend(dest); + if (install) + loadDefinition(dest); + } } -void DefinitionManager::installZip(QString path,bool overwrite,bool install) -{ - QString destdir=QStandardPaths::writableLocation(QStandardPaths::DataLocation); - ZipReader zip(path); - if (!zip.open()) - { - QMessageBox::warning(this, - tr("Couldn't install %1").arg(path), - tr("Corrupt zip"), - QMessageBox::Cancel); - return; - } - //fetch the pack info - JSONData *info; - try { - info=JSON::parse(zip.get("pack_info.json")); - } catch (JSONParseException e) { - QMessageBox::warning(this, - tr("Couldn't install %1").arg(path), - tr("pack_info.json : %1").arg(e.reason), - QMessageBox::Cancel); - zip.close(); - return; - } - // let's verify all the jsons in the pack - for (int i=0;iat("data")->length();i++) - { - JSONData *def; - try { - def=JSON::parse(zip.get(info->at("data")->at(i)->asString())); - delete def; - } catch (JSONParseException e) { - QMessageBox::warning(this, - tr("Couldn't install %1").arg(path), - tr("%1: %2").arg(info->at("data")->at(i)->asString(),e.reason), - QMessageBox::Cancel); - delete info; - zip.close(); - return; - } - } - - QString key=info->at("name")->asString()+info->at("type")->asString(); - delete info; - QString dest=destdir+"/"+QString("%1").arg(qHash(key))+".zip"; - if (!QFile::exists(dest) || overwrite) - { - if (QFile::exists(dest) && install) - removeDefinition(dest); - if (!QFile::copy(path,dest)) - { - QMessageBox::warning(this, - tr("Couldn't install %1").arg(path), - tr("Copy error"), - QMessageBox::Cancel); - return; - } - sorted.prepend(dest); - if (install) - loadDefinition(dest); - } +void DefinitionManager::installZip(QString path, bool overwrite, + bool install) { + QString destdir = QStandardPaths::writableLocation( + QStandardPaths::DataLocation); + ZipReader zip(path); + if (!zip.open()) { + QMessageBox::warning(this, tr("Couldn't install %1").arg(path), + tr("Corrupt zip"), + QMessageBox::Cancel); + return; + } + // fetch the pack info + JSONData *info; + try { + info = JSON::parse(zip.get("pack_info.json")); + } catch (JSONParseException e) { + QMessageBox::warning(this, tr("Couldn't install %1").arg(path), + tr("pack_info.json : %1").arg(e.reason), + QMessageBox::Cancel); + zip.close(); + return; + } + // let's verify all the jsons in the pack + for (int i = 0; i < info->at("data")->length(); i++) { + JSONData *def; + try { + def = JSON::parse(zip.get(info->at("data")->at(i)->asString())); + delete def; + } catch (JSONParseException e) { + QMessageBox::warning(this, tr("Couldn't install %1").arg(path), + tr("%1: %2") + .arg(info->at("data")->at(i)->asString(), + e.reason), QMessageBox::Cancel); + delete info; + zip.close(); + return; + } + } + + QString key = info->at("name")->asString() + info->at("type")->asString(); + delete info; + QString dest = destdir + "/" + QString("%1").arg(qHash(key)) + ".zip"; + if (!QFile::exists(dest) || overwrite) { + if (QFile::exists(dest) && install) + removeDefinition(dest); + if (!QFile::copy(path, dest)) { + QMessageBox::warning(this, + tr("Couldn't install %1").arg(path), + tr("Copy error"), + QMessageBox::Cancel); + return; + } + sorted.prepend(dest); + if (install) + loadDefinition(dest); + } } -void DefinitionManager::removePack() -{ - //find selected pack - if (definitions.contains(selected)) - { - int ret=QMessageBox::question(this, - tr("Delete Pack"), - tr("Are you sure you want to delete %1?").arg(definitions[selected].name), - QMessageBox::Yes|QMessageBox::No, - QMessageBox::No); - if (ret==QMessageBox::Yes) - removeDefinition(selected); - } +void DefinitionManager::removePack() { + // find selected pack + if (definitions.contains(selected)) { + int ret = QMessageBox::question(this, tr("Delete Pack"), + tr("Are you sure you want to delete %1?") + .arg(definitions[selected].name), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No); + if (ret == QMessageBox::Yes) + removeDefinition(selected); + } } -void DefinitionManager::exportPack() -{ - //find selected pack - if (definitions.contains(selected)) - { - QString fname=definitions[selected].name; - switch (definitions[selected].type) - { - case Definition::Block: fname+="_blocks"; break; - case Definition::Biome: fname+="_biomes"; break; - case Definition::Dimension: fname+="_dims"; break; - default: break; - } - if (selected.endsWith(".zip")) - fname+=".zip"; - else - fname+=".json"; - QString dest=QFileDialog::getSaveFileName(this,tr("Save Pack As"),fname,tr("Definitions (*.zip *.json)")); - if (!dest.isEmpty()) - { - if (!QFile::copy(selected,dest)) - { - QMessageBox::warning(this, - tr("Couldn't write to %1").arg(dest), - tr("Copy error"), - QMessageBox::Cancel); - } - } - } +void DefinitionManager::exportPack() { + // find selected pack + if (definitions.contains(selected)) { + QString fname = definitions[selected].name; + switch (definitions[selected].type) { + case Definition::Block: fname+="_blocks"; break; + case Definition::Biome: fname+="_biomes"; break; + case Definition::Dimension: fname+="_dims"; break; + default: break; + } + if (selected.endsWith(".zip")) + fname += ".zip"; + else + fname += ".json"; + QString dest = QFileDialog::getSaveFileName(this, tr("Save Pack As"), + fname, tr("Definitions (*.zip *.json)")); + if (!dest.isEmpty()) { + if (!QFile::copy(selected, dest)) { + QMessageBox::warning(this, + tr("Couldn't write to %1").arg(dest), + tr("Copy error"), + QMessageBox::Cancel); + } + } + } } -QSize DefinitionManager::minimumSizeHint() const -{ - return QSize(300,300); +QSize DefinitionManager::minimumSizeHint() const { + return QSize(300, 300); } -QSize DefinitionManager::sizeHint() const -{ - return QSize(400,300); +QSize DefinitionManager::sizeHint() const { + return QSize(400, 300); } -void DefinitionManager::loadDefinition(QString path) -{ - //determine if we're loading a single json or a pack - if (path.endsWith(".json",Qt::CaseInsensitive)) - { - JSONData *def; - QFile f(path); - f.open(QIODevice::ReadOnly); - try { - def=JSON::parse(f.readAll()); - f.close(); - } catch (JSONParseException e) { - f.close(); - return; - } - Definition d; - d.name=def->at("name")->asString(); - d.version=def->at("version")->asString(); - d.path=path; - d.update=def->at("update")->asString(); - QString type=def->at("type")->asString(); - QString key=d.name+type; - d.enabled=true; //should look this up - if (type=="block") - { - d.id=blocks->addDefinitions(dynamic_cast(def->at("data"))); - d.type=Definition::Block; - } else if (type=="biome") { - d.id=biomes->addDefinitions(dynamic_cast(def->at("data"))); - d.type=Definition::Biome; - } else if (type=="dimension") { - d.id=dimensionList->addDefinitions(dynamic_cast(def->at("data"))); - d.type=Definition::Dimension; - } else if (type=="entity") { - d.id=entityManager.addDefinitions(dynamic_cast(def->at("data"))); - d.type=Definition::Entity; - } - definitions.insert(path,d); - delete def; - } - else - { - ZipReader zip(path); - if (!zip.open()) - return; - JSONData *info; - try { - info=JSON::parse(zip.get("pack_info.json")); - } catch (JSONParseException e) { - zip.close(); - return; - } - Definition d; - d.name=info->at("name")->asString(); - d.version=info->at("version")->asString(); - d.update=info->at("update")->asString(); - d.path=path; - d.enabled=true; - d.id=0; - d.type=Definition::Pack; - d.blockid=-1; - d.biomeid=-1; - d.dimensionid=-1; - d.entityid=-1; - QString key=d.name+"pack"; - for (int i=0;iat("data")->length();i++) - { - JSONData *def; - try { - def=JSON::parse(zip.get(info->at("data")->at(i)->asString())); - } catch (JSONParseException e) { - continue; - } - QString type=def->at("type")->asString(); - if (type=="block") - d.blockid=blocks->addDefinitions(dynamic_cast(def->at("data")),d.blockid); - else if (type=="biome") - d.biomeid=biomes->addDefinitions(dynamic_cast(def->at("data")),d.biomeid); - else if (type=="dimension") - d.dimensionid=dimensionList->addDefinitions(dynamic_cast(def->at("data")),d.dimensionid); - else if (type=="entity") - d.entityid=entityManager.addDefinitions(dynamic_cast(def->at("data")),d.entityid); - delete def; - } - definitions.insert(path,d); - delete info; - zip.close(); - } +void DefinitionManager::loadDefinition(QString path) { + // determine if we're loading a single json or a pack + if (path.endsWith(".json", Qt::CaseInsensitive)) { + JSONData *def; + QFile f(path); + f.open(QIODevice::ReadOnly); + try { + def = JSON::parse(f.readAll()); + f.close(); + } catch (JSONParseException e) { + f.close(); + return; + } + Definition d; + d.name = def->at("name")->asString(); + d.version = def->at("version")->asString(); + d.path = path; + d.update = def->at("update")->asString(); + QString type = def->at("type")->asString(); + QString key = d.name + type; + d.enabled = true; // should look this up + if (type == "block") { + d.id = blocks->addDefinitions( + dynamic_cast(def->at("data"))); + d.type = Definition::Block; + } else if (type == "biome") { + d.id = biomes->addDefinitions( + dynamic_cast(def->at("data"))); + d.type = Definition::Biome; + } else if (type == "dimension") { + d.id = dimensionList->addDefinitions( + dynamic_cast(def->at("data"))); + d.type = Definition::Dimension; + } else if (type == "entity") { + d.id = entityManager.addDefinitions( + dynamic_cast(def->at("data"))); + d.type = Definition::Entity; + } + definitions.insert(path, d); + delete def; + } else { + ZipReader zip(path); + if (!zip.open()) + return; + JSONData *info; + try { + info = JSON::parse(zip.get("pack_info.json")); + } catch (JSONParseException e) { + zip.close(); + return; + } + Definition d; + d.name = info->at("name")->asString(); + d.version = info->at("version")->asString(); + d.update = info->at("update")->asString(); + d.path = path; + d.enabled = true; + d.id = 0; + d.type = Definition::Pack; + d.blockid = -1; + d.biomeid = -1; + d.dimensionid = -1; + d.entityid = -1; + QString key = d.name+"pack"; + for (int i = 0; i < info->at("data")->length(); i++) { + JSONData *def; + try { + def = JSON::parse(zip.get(info->at("data")->at(i)->asString())); + } catch (JSONParseException e) { + continue; + } + QString type = def->at("type")->asString(); + if (type == "block") + d.blockid = blocks->addDefinitions( + dynamic_cast(def->at("data")), d.blockid); + else if (type == "biome") + d.biomeid = biomes->addDefinitions( + dynamic_cast(def->at("data")), d.biomeid); + else if (type == "dimension") + d.dimensionid = dimensionList->addDefinitions( + dynamic_cast(def->at("data")), d.dimensionid); + else if (type == "entity") + d.entityid = entityManager.addDefinitions( + dynamic_cast(def->at("data")), d.entityid); + delete def; + } + definitions.insert(path, d); + delete info; + zip.close(); + } } -void DefinitionManager::removeDefinition(QString path) -{ - - //find the definition and remove it from disk - Definition &def=definitions[path]; - if (def.path==path) - { - switch (def.type) - { - case Definition::Block: - blocks->disableDefinitions(def.id); - break; - case Definition::Biome: - biomes->disableDefinitions(def.id); - break; - case Definition::Dimension: - dimensionList->disableDefinitions(def.id); - break; - case Definition::Entity: - entityManager.disableDefinitions(def.id); - break; - case Definition::Pack: - blocks->disableDefinitions(def.blockid); - biomes->disableDefinitions(def.biomeid); - dimensionList->disableDefinitions(def.dimensionid); - entityManager.disableDefinitions(def.entityid); - break; - } - definitions.remove(path); - QFile::remove(path); - sorted.removeOne(path); - QSettings settings; - settings.setValue("packs",sorted); - emit packsChanged(); - refresh(); - } - +void DefinitionManager::removeDefinition(QString path) { + // find the definition and remove it from disk + Definition &def = definitions[path]; + if (def.path == path) { + switch (def.type) { + case Definition::Block: + blocks->disableDefinitions(def.id); + break; + case Definition::Biome: + biomes->disableDefinitions(def.id); + break; + case Definition::Dimension: + dimensionList->disableDefinitions(def.id); + break; + case Definition::Entity: + entityManager.disableDefinitions(def.id); + break; + case Definition::Pack: + blocks->disableDefinitions(def.blockid); + biomes->disableDefinitions(def.biomeid); + dimensionList->disableDefinitions(def.dimensionid); + entityManager.disableDefinitions(def.entityid); + break; + } + definitions.remove(path); + QFile::remove(path); + sorted.removeOne(path); + QSettings settings; + settings.setValue("packs", sorted); + emit packsChanged(); + refresh(); + } } -void DefinitionManager::checkForUpdates() -{ - // show update dialog - if (!isUpdating) - autoUpdate(); - if (!isUpdating) // nothing needs updating - { - //hide update dialog - //show completion - } +void DefinitionManager::checkForUpdates() { + // show update dialog + if (!isUpdating) + autoUpdate(); + if (!isUpdating) { // nothing needs updating + // hide update dialog + // show completion + } } -void DefinitionManager::autoUpdate() -{ - for (int i=0;iupdate(); - } - } +void DefinitionManager::autoUpdate() { + for (int i = 0; i < sorted.length(); i++) { + QString name = sorted[i].toString(); + Definition &def = definitions[name]; + if (!def.update.isEmpty()) { + isUpdating = true; + QDateTime last; + last.setMSecsSinceEpoch(0); + if (lastUpdated.contains(name)) + last = lastUpdated[name].toDateTime(); + auto updater = new DefinitionUpdater(name, def.update, last); + connect(updater, + SIGNAL(updated(DefinitionUpdater *, QString, QDateTime)), + this, + SLOT(updatePack(DefinitionUpdater *, QString, QDateTime))); + updateQueue.append(updater); + updater->update(); + } + } } -void DefinitionManager::updatePack(DefinitionUpdater *updater,QString filename, QDateTime timestamp) -{ - updateQueue.removeOne(updater); - delete updater; - if (lastUpdated[filename]!=timestamp) - { - lastUpdated[filename]=timestamp; - QSettings settings; - settings.setValue("packupdates",lastUpdated); - } - if (updateQueue.isEmpty()) - emit updateFinished(); +void DefinitionManager::updatePack(DefinitionUpdater *updater, + QString filename, QDateTime timestamp) { + updateQueue.removeOne(updater); + delete updater; + if (lastUpdated[filename] != timestamp) { + lastUpdated[filename] = timestamp; + QSettings settings; + settings.setValue("packupdates", lastUpdated); + } + if (updateQueue.isEmpty()) + emit updateFinished(); } diff --git a/definitionmanager.h b/definitionmanager.h index 4a2c2369..efac1900 100644 --- a/definitionmanager.h +++ b/definitionmanager.h @@ -1,33 +1,6 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __DEFINITIONMANAGER_H__ -#define __DEFINITIONMANAGER_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef DEFINITIONMANAGER_H_ +#define DEFINITIONMANAGER_H_ #include #include @@ -47,69 +20,68 @@ class MapView; class JSONData; class DefinitionUpdater; -struct Definition -{ - QString name; - QString version; - QString path; - QString update; - enum {Block,Biome,Dimension,Entity,Pack} type; - int id; - bool enabled; - // for packs only - int blockid,biomeid,dimensionid,entityid; +struct Definition { + QString name; + QString version; + QString path; + QString update; + enum {Block, Biome, Dimension, Entity, Pack} type; + int id; + bool enabled; + // for packs only + int blockid, biomeid, dimensionid, entityid; }; -class DefinitionManager : public QWidget -{ - Q_OBJECT -public: - explicit DefinitionManager(QWidget *parent = 0); - ~DefinitionManager(); - void attachMapView(MapView *mapview); - QSize minimumSizeHint() const; - QSize sizeHint() const; - - BlockIdentifier *blockIdentifier(); - BiomeIdentifier *biomeIdentifier(); - DimensionIdentifier *dimensionIdentifer(); - - void autoUpdate(); - -signals: - void packSelected(bool); - void packsChanged(); - void updateFinished(); - -public slots: - void selectedPack(QTableWidgetItem *,QTableWidgetItem *); - void toggledPack(bool); - void addPack(); - void removePack(); - void exportPack(); - void checkForUpdates(); - void updatePack(DefinitionUpdater *updater,QString filename,QDateTime timestamp); - -private: - QTableWidget *table; - QListchecks; - void installJson(QString path,bool overwrite=true,bool install=true); - void installZip(QString path,bool overwrite=true,bool install=true); - void loadDefinition(QString path); - void loadDefinition(JSONData *,int pack=-1); - void removeDefinition(QString path); - void refresh(); - QHash definitions; - BiomeIdentifier *biomes; - BlockIdentifier *blocks; - DimensionIdentifier *dimensionList; - EntityIdentifier & entityManager; - QString selected; - QList sorted; - - bool isUpdating; - QList updateQueue; - QHash lastUpdated; +class DefinitionManager : public QWidget { + Q_OBJECT + + public: + explicit DefinitionManager(QWidget *parent = 0); + ~DefinitionManager(); + void attachMapView(MapView *mapview); + QSize minimumSizeHint() const; + QSize sizeHint() const; + + BlockIdentifier *blockIdentifier(); + BiomeIdentifier *biomeIdentifier(); + DimensionIdentifier *dimensionIdentifer(); + void autoUpdate(); + + signals: + void packSelected(bool on); + void packsChanged(); + void updateFinished(); + + public slots: + void selectedPack(QTableWidgetItem *, QTableWidgetItem *); + void toggledPack(bool on); + void addPack(); + void removePack(); + void exportPack(); + void checkForUpdates(); + void updatePack(DefinitionUpdater *updater, QString filename, + QDateTime timestamp); + + private: + QTableWidget *table; + QListchecks; + void installJson(QString path, bool overwrite = true, bool install = true); + void installZip(QString path, bool overwrite = true, bool install = true); + void loadDefinition(QString path); + void loadDefinition(JSONData *, int pack = -1); + void removeDefinition(QString path); + void refresh(); + QHash definitions; + BiomeIdentifier *biomes; + BlockIdentifier *blocks; + DimensionIdentifier *dimensionList; + EntityIdentifier &entityManager; + QString selected; + QList sorted; + + bool isUpdating; + QList updateQueue; + QHash lastUpdated; }; -#endif +#endif // DEFINITIONMANAGER_H_ diff --git a/definitionupdater.cpp b/definitionupdater.cpp index 904ed496..76310e14 100644 --- a/definitionupdater.cpp +++ b/definitionupdater.cpp @@ -1,88 +1,57 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. +/** Copyright (c) 2013, Sean Kasun */ - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "definitionupdater.h" #include #include #include #include +#include "./definitionupdater.h" -DefinitionUpdater::DefinitionUpdater(QString filename, - QString url, - QDateTime timestamp) : filename(filename), url(url), timestamp(timestamp) -{ - save=NULL; +DefinitionUpdater::DefinitionUpdater(QString filename, QString url, + QDateTime timestamp) : + filename(filename), url(url), timestamp(timestamp) { + save = NULL; } -void DefinitionUpdater::update() -{ - reply=qnam.head(QNetworkRequest(url)); - connect(reply,SIGNAL(finished()), - this,SLOT(checkTime())); +void DefinitionUpdater::update() { + reply = qnam.head(QNetworkRequest(url)); + connect(reply, SIGNAL(finished()), + this, SLOT(checkTime())); } -void DefinitionUpdater::checkTime() -{ - QVariant redir=reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - if (!redir.isNull()) - { - reply->deleteLater(); - url=redir.toUrl(); - update(); - return; - } - QVariant lmod=reply->header(QNetworkRequest::LastModifiedHeader); - if (lmod.isValid() && lmod.toDateTime()>timestamp) - { - timestamp=lmod.toDateTime(); - reply->deleteLater(); - reply=qnam.get(QNetworkRequest(url)); - save=new QFile(filename); - save->open(QIODevice::WriteOnly|QIODevice::Truncate); - connect(reply,SIGNAL(finished()), - this,SLOT(didUpdate())); - connect(reply,SIGNAL(readyRead()), - this,SLOT(saveFile())); - return; - } - reply->deleteLater(); - // no need to update - emit updated(this,filename,timestamp); +void DefinitionUpdater::checkTime() { + QVariant redir = + reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (!redir.isNull()) { + reply->deleteLater(); + url = redir.toUrl(); + update(); + return; + } + QVariant lmod = reply->header(QNetworkRequest::LastModifiedHeader); + if (lmod.isValid() && lmod.toDateTime() > timestamp) { + timestamp = lmod.toDateTime(); + reply->deleteLater(); + reply = qnam.get(QNetworkRequest(url)); + save = new QFile(filename); + save->open(QIODevice::WriteOnly | QIODevice::Truncate); + connect(reply, SIGNAL(finished()), + this, SLOT(didUpdate())); + connect(reply, SIGNAL(readyRead()), + this, SLOT(saveFile())); + return; + } + reply->deleteLater(); + // no need to update + emit updated(this, filename, timestamp); } -void DefinitionUpdater::didUpdate() -{ - save->flush(); - save->close(); - delete save; - save=NULL; - emit updated(this,filename,timestamp); +void DefinitionUpdater::didUpdate() { + save->flush(); + save->close(); + delete save; + save = NULL; + emit updated(this, filename, timestamp); } -void DefinitionUpdater::saveFile() -{ - if (save) - save->write(reply->readAll()); +void DefinitionUpdater::saveFile() { + if (save) + save->write(reply->readAll()); } diff --git a/definitionupdater.h b/definitionupdater.h index 10f1970d..d6ebf278 100644 --- a/definitionupdater.h +++ b/definitionupdater.h @@ -1,31 +1,6 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef __DEFINITIONUPDATER_H__ -#define __DEFINITIONUPDATER_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef DEFINITIONUPDATER_H_ +#define DEFINITIONUPDATER_H_ #include #include @@ -35,25 +10,24 @@ class QFile; class QNetworkReply; -class DefinitionUpdater : public QObject -{ - Q_OBJECT -public: - DefinitionUpdater(QString filename,QString url,QDateTime timestamp); - void update(); -signals: - void updated(DefinitionUpdater *,QString filename,QDateTime timestamp); -private slots: - void checkTime(); - void didUpdate(); - void saveFile(); -private: - QString filename; - QUrl url; - QDateTime timestamp; - QNetworkAccessManager qnam; - QNetworkReply *reply; - QFile *save; +class DefinitionUpdater : public QObject { + Q_OBJECT + public: + DefinitionUpdater(QString filename, QString url, QDateTime timestamp); + void update(); + signals: + void updated(DefinitionUpdater *, QString filename, QDateTime timestamp); + private slots: + void checkTime(); + void didUpdate(); + void saveFile(); + private: + QString filename; + QUrl url; + QDateTime timestamp; + QNetworkAccessManager qnam; + QNetworkReply *reply; + QFile *save; }; -#endif +#endif // DEFINITIONUPDATER_H_ diff --git a/dimensionidentifier.cpp b/dimensionidentifier.cpp index 1211395f..0f46a538 100644 --- a/dimensionidentifier.cpp +++ b/dimensionidentifier.cpp @@ -1,212 +1,167 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. +/** Copyright (c) 2013, Sean Kasun */ - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "dimensionidentifier.h" #include #include -#include "json.h" - -class DimensionDef -{ -public: - DimensionDef() {} - QString name; - QString path; - int scale; - bool regex; - bool enabled; +#include "./dimensionidentifier.h" +#include "./json.h" + +class DimensionDef { + public: + DimensionDef() {} + QString name; + QString path; + int scale; + bool regex; + bool enabled; }; -DimensionIdentifier::DimensionIdentifier() -{ - group=NULL; +DimensionIdentifier::DimensionIdentifier() { + group = NULL; } -DimensionIdentifier::~DimensionIdentifier() -{ - for (int i=0;ienabled=true; +void DimensionIdentifier::enableDefinitions(int pack) { + if (pack < 0) return; + int len = packs[pack].length(); + for (int i = 0; i < len; i++) + packs[pack][i]->enabled = true; } -void DimensionIdentifier::disableDefinitions(int pack) -{ - if (pack<0) return; - int len=packs[pack].length(); - for (int i=0;ienabled=false; +void DimensionIdentifier::disableDefinitions(int pack) { + if (pack < 0) return; + int len = packs[pack].length(); + for (int i = 0; i < len; i++) + packs[pack][i]->enabled = false; } -int DimensionIdentifier::addDefinitions(JSONArray *defs,int pack) -{ - if (pack==-1) - { - pack=packs.length(); - packs.append(QList()); - } - - int len=defs->length(); - for (int i=0;i(defs->at(i)); - DimensionDef *dim=new DimensionDef(); - dim->enabled=true; - if (d->has("name")) - dim->name=d->at("name")->asString(); - else - dim->name="Unknown"; - if (d->has("path")) - dim->path=d->at("path")->asString(); - else - dim->path="."; - if (d->has("scale")) - dim->scale=d->at("scale")->asNumber(); - else - dim->scale=1; - if (d->has("regex")) - dim->regex=d->at("regex")->asBool(); - else - dim->regex=false; - definitions.append(dim); - packs[pack].append(dim); - } - return pack; +int DimensionIdentifier::addDefinitions(JSONArray *defs, int pack) { + if (pack == -1) { + pack = packs.length(); + packs.append(QList()); + } + + int len = defs->length(); + for (int i = 0; i < len; i++) { + JSONObject *d = dynamic_cast(defs->at(i)); + DimensionDef *dim = new DimensionDef(); + dim->enabled = true; + if (d->has("name")) + dim->name = d->at("name")->asString(); + else + dim->name = "Unknown"; + if (d->has("path")) + dim->path = d->at("path")->asString(); + else + dim->path = "."; + if (d->has("scale")) + dim->scale = d->at("scale")->asNumber(); + else + dim->scale = 1; + if (d->has("regex")) + dim->regex = d->at("regex")->asBool(); + else + dim->regex = false; + definitions.append(dim); + packs[pack].append(dim); + } + return pack; } -void DimensionIdentifier::removeDimensions(QMenu *menu) -{ - for (int i=0;iremoveAction(items[i]); - delete items[i]; - } - items.clear(); - dimensions.clear(); - foundDimensions.clear(); - menu->setEnabled(false); - if (group!=NULL) - { - delete group; - group=NULL; - } +void DimensionIdentifier::removeDimensions(QMenu *menu) { + for (int i = 0; i < items.count(); i++) { + menu->removeAction(items[i]); + delete items[i]; + } + items.clear(); + dimensions.clear(); + foundDimensions.clear(); + menu->setEnabled(false); + if (group != NULL) { + delete group; + group = NULL; + } } -void DimensionIdentifier::getDimensions(QDir path,QMenu *menu,QObject *parent) -{ - //first get the currently selected dimension so it doesn't change - QString current; - for (int i=0;iisChecked()) - current=dimensions[i].path; - removeDimensions(menu); - group=new QActionGroup(parent); - - for (int i=0;ienabled) - { - //check path for regex - if (definitions[i]->regex) - { - QDirIterator it(path.absolutePath(),QDir::Dirs); - QRegExp rx(definitions[i]->path); - while (it.hasNext()) - { - it.next(); - if (rx.indexIn(it.fileName())!=-1) - { - QString name=definitions[i]->name; - for (int c=0;cscale,parent); - } - } - } - else - addDimension(path,definitions[i]->path,definitions[i]->name,definitions[i]->scale,parent); - } - } - menu->addActions(items); - if (items.count()>0) - { - bool changed=true; - //locate our old selected item - for (int i=0;idata().toInt()].path==current) - { - items[i]->setChecked(true); - changed=false; - break; - } - if (changed) - { - items.first()->setChecked(true); - emit dimensionChanged(dimensions[items.first()->data().toInt()]); - } - menu->setEnabled(true); - } +void DimensionIdentifier::getDimensions(QDir path, QMenu *menu, + QObject *parent) { + // first get the currently selected dimension so it doesn't change + QString current; + for (int i = 0; i < items.length(); i++) + if (items[i]->isChecked()) + current = dimensions[i].path; + removeDimensions(menu); + group = new QActionGroup(parent); + + for (int i = 0; i < definitions.length(); i++) { + if (definitions[i]->enabled) { + // check path for regex + if (definitions[i]->regex) { + QDirIterator it(path.absolutePath(), QDir::Dirs); + QRegExp rx(definitions[i]->path); + while (it.hasNext()) { + it.next(); + if (rx.indexIn(it.fileName()) != -1) { + QString name = definitions[i]->name; + for (int c = 0; c < rx.captureCount(); c++) + name = name.arg(rx.cap(c + 1)); + addDimension(path, it.fileName(), name, definitions[i]->scale, + parent); + } + } + } else { + addDimension(path, definitions[i]->path, definitions[i]->name, + definitions[i]->scale, parent); + } + } + } + menu->addActions(items); + if (items.count() > 0) { + bool changed = true; + // locate our old selected item + for (int i = 0; i < items.length(); i++) { + if (dimensions[items[i]->data().toInt()].path == current) { + items[i]->setChecked(true); + changed = false; + break; + } + } + if (changed) { + items.first()->setChecked(true); + emit dimensionChanged(dimensions[items.first()->data().toInt()]); + } + menu->setEnabled(true); + } } -void DimensionIdentifier::addDimension(QDir path,QString dir,QString name,int scale,QObject *parent) -{ - if (!path.exists(dir)) - return; - - if (foundDimensions.contains(dir)) - return; - - path.cd(dir); - if (path.exists("region")) //is it a used dimension? - { - QAction *d=new QAction(parent); - d->setText(name); - d->setData(dimensions.count()); - dimensions.append(DimensionInfo(path.absolutePath(),scale, name)); - d->setCheckable(true); - parent->connect(d, SIGNAL(triggered()), - this, SLOT(viewDimension())); - group->addAction(d); - items.append(d); - foundDimensions.insert(dir,true); - } - path.cdUp(); +void DimensionIdentifier::addDimension(QDir path, QString dir, QString name, + int scale, QObject *parent) { + if (!path.exists(dir)) + return; + + if (foundDimensions.contains(dir)) + return; + + path.cd(dir); + if (path.exists("region")) { // is it a used dimension? + QAction *d = new QAction(parent); + d->setText(name); + d->setData(dimensions.count()); + dimensions.append(DimensionInfo(path.absolutePath(), scale, name)); + d->setCheckable(true); + parent->connect(d, SIGNAL(triggered()), + this, SLOT(viewDimension())); + group->addAction(d); + items.append(d); + foundDimensions.insert(dir, true); + } + path.cdUp(); } -void DimensionIdentifier::viewDimension() -{ - QAction *action=qobject_cast(sender()); - if (action) - emit dimensionChanged(dimensions[action->data().toInt()]); +void DimensionIdentifier::viewDimension() { + QAction *action = qobject_cast(sender()); + if (action) + emit dimensionChanged(dimensions[action->data().toInt()]); } diff --git a/dimensionidentifier.h b/dimensionidentifier.h index 5eb804a5..2df49e40 100644 --- a/dimensionidentifier.h +++ b/dimensionidentifier.h @@ -1,33 +1,6 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __DIMENSIONIDENTIFIER_H__ -#define __DIMENSIONIDENTIFIER_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef DIMENSIONIDENTIFIER_H_ +#define DIMENSIONIDENTIFIER_H_ #include #include @@ -39,41 +12,45 @@ class QAction; class QActionGroup; class JSONArray; -class DimensionInfo -{ -public: - DimensionInfo(QString path,int scale, QString name):path(path),scale(scale),name(name) {} - QString path; - int scale; - QString name; +class DimensionInfo { + public: + DimensionInfo(QString path, int scale, QString name) : path(path), + scale(scale), name(name) {} + QString path; + int scale; + QString name; }; class DimensionDef; -class DimensionIdentifier : public QObject -{ - Q_OBJECT -public: - DimensionIdentifier(); - ~DimensionIdentifier(); - int addDefinitions(JSONArray *,int pack=-1); - void enableDefinitions(int); - void disableDefinitions(int); - void getDimensions(QDir path,QMenu *menu,QObject *parent); - void removeDimensions(QMenu *menu); -signals: - void dimensionChanged(DimensionInfo &dim); -private slots: - void viewDimension(); -private: - void addDimension(QDir path,QString dir,QString name,int scale,QObject *parent); - QList items; - QList dimensions; - QList definitions; - QList > packs; - QActionGroup *group; - - QHash foundDimensions; +class DimensionIdentifier : public QObject { + Q_OBJECT + + public: + DimensionIdentifier(); + ~DimensionIdentifier(); + int addDefinitions(JSONArray *, int pack = -1); + void enableDefinitions(int id); + void disableDefinitions(int id); + void getDimensions(QDir path, QMenu *menu, QObject *parent); + void removeDimensions(QMenu *menu); + + signals: + void dimensionChanged(const DimensionInfo &dim); + + private slots: + void viewDimension(); + + private: + void addDimension(QDir path, QString dir, QString name, int scale, + QObject *parent); + QList items; + QList dimensions; + QList definitions; + QList > packs; + QActionGroup *group; + + QHash foundDimensions; }; -#endif +#endif // DIMENSIONIDENTIFIER_H_ diff --git a/entity.cpp b/entity.cpp index 76416820..f1885b91 100644 --- a/entity.cpp +++ b/entity.cpp @@ -1,79 +1,70 @@ -#include "entity.h" -#include "entityidentifier.h" - -#include "nbt.h" - +/** Copyright 2014 Mc_Etlam */ #include +#include "./entity.h" +#include "./entityidentifier.h" +#include "./nbt.h" -QSharedPointer Entity::TryParse(Tag* tag) -{ - EntityIdentifier& ei = EntityIdentifier::Instance(); +QSharedPointer Entity::TryParse(const Tag* tag) { + EntityIdentifier& ei = EntityIdentifier::Instance(); - QSharedPointer ret; - Tag* pos = tag->at("Pos"); - if (pos && pos != &NBT::Null) - { - Entity* entity = new Entity(); - entity->pos.x = pos->at(0)->toDouble(); - entity->pos.y = pos->at(1)->toDouble(); - entity->pos.z = pos->at(2)->toDouble(); - Tag* id = tag->at("id"); - if (id && id != &NBT::Null) - { - QString type = id->toString(); - EntityInfo const & info = ei.getEntityInfo(type); + QSharedPointer ret; + auto pos = tag->at("Pos"); + if (pos && pos != &NBT::Null) { + Entity* entity = new Entity(); + entity->pos.x = pos->at(0)->toDouble(); + entity->pos.y = pos->at(1)->toDouble(); + entity->pos.z = pos->at(2)->toDouble(); + auto id = tag->at("id"); + if (id && id != &NBT::Null) { + QString type = id->toString(); + EntityInfo const & info = ei.getEntityInfo(type); - QMap props = tag->getData().toMap(); + QMap props = tag->getData().toMap(); - //get something more descriptive if its an item - if (type == "Item") - { - Tag* itemId = tag->at("Item")->at("id"); + // get something more descriptive if its an item + if (type == "Item") { + auto itemId = tag->at("Item")->at("id"); - QString itemtype = itemId->toString(); - entity->setDisplay(itemtype.mid(itemtype.indexOf(':') + 1)); - } - else - {// or just use the Entity's name - entity->setDisplay(info.name); - } - entity->setType("Entity."+info.category); - entity->setColor( info.brushColor ); - entity->setExtraColor( info.penColor ); - entity->setProperties(props); - ret.reset(entity); - } - } - return ret; + QString itemtype = itemId->toString(); + entity->setDisplay(itemtype.mid(itemtype.indexOf(':') + 1)); + } else { // or just use the Entity's name + entity->setDisplay(info.name); + } + entity->setType("Entity." + info.category); + entity->setColor(info.brushColor); + entity->setExtraColor(info.penColor); + entity->setProperties(props); + ret.reset(entity); + } + } + return ret; } -bool Entity::intersects(const Point& min, const Point& max) const -{ - return min.x <= pos.x && max.x >= pos.x && - min.y <= pos.y && max.y >= pos.y && - min.z <= pos.z && max.z >= pos.z; +bool Entity::intersects(const Point& min, const Point& max) const { + return min.x <= pos.x && max.x >= pos.x && + min.y <= pos.y && max.y >= pos.y && + min.z <= pos.z && max.z >= pos.z; } -void Entity::draw(double offsetX, double offsetZ, double scale, QPainter& canvas) const -{ - QPoint center((pos.x - offsetX) * scale, - (pos.z - offsetZ) * scale); +void Entity::draw(double offsetX, double offsetZ, double scale, + QPainter *canvas) const { + QPoint center((pos.x - offsetX) * scale, + (pos.z - offsetZ) * scale); - QColor penColor = extraColor; - penColor.setAlpha(192); - QPen pen = canvas.pen(); - pen.setColor(penColor); - pen.setWidth(2); - canvas.setPen(pen); + QColor penColor = extraColor; + penColor.setAlpha(192); + QPen pen = canvas->pen(); + pen.setColor(penColor); + pen.setWidth(2); + canvas->setPen(pen); - QColor brushColor = color(); - brushColor.setAlpha(128); - canvas.setBrush(brushColor); - canvas.drawEllipse(center, RADIUS, RADIUS); + QColor brushColor = color(); + brushColor.setAlpha(128); + canvas->setBrush(brushColor); + canvas->drawEllipse(center, RADIUS, RADIUS); } -Entity::Point Entity::midpoint() const -{ - return pos; +Entity::Point Entity::midpoint() const { + return pos; } diff --git a/entity.h b/entity.h index 1075b5ae..a7b16757 100644 --- a/entity.h +++ b/entity.h @@ -1,32 +1,31 @@ -#ifndef ENTITY_H -#define ENTITY_H - -#include "overlayitem.h" +/** Copyright 2014 Mc_Etlam */ +#ifndef ENTITY_H_ +#define ENTITY_H_ #include +#include "./overlayitem.h" class Tag; -class Entity: public OverlayItem -{ -public: - static QSharedPointer TryParse(Tag* tag); - - virtual bool intersects(const Point& min, const Point& max) const; - virtual void draw(double offsetX, double offsetZ, double scale, QPainter& canvas) const; - virtual Point midpoint() const; - void setExtraColor(const QColor& c) {extraColor = c;} +class Entity: public OverlayItem { + public: + static QSharedPointer TryParse(const Tag* tag); - static const int RADIUS = 5; + virtual bool intersects(const Point& min, const Point& max) const; + virtual void draw(double offsetX, double offsetZ, double scale, + QPainter *canvas) const; + virtual Point midpoint() const; + void setExtraColor(const QColor& c) {extraColor = c;} -protected: - Entity() {} + static const int RADIUS = 5; -private: + protected: + Entity() {} - QColor extraColor; - Point pos; - QString display; + private: + QColor extraColor; + Point pos; + QString display; }; -#endif // ENTITY_H +#endif // ENTITY_H_ diff --git a/entityidentifier.cpp b/entityidentifier.cpp index ae1c2fbe..5d6fc5b7 100644 --- a/entityidentifier.cpp +++ b/entityidentifier.cpp @@ -1,229 +1,165 @@ -/* - Copyright (c) 2014, Mc_Etlam - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "entityidentifier.h" -#include "json.h" +/** Copyright (c) 2014, Mc_Etlam */ #include #include +#include "./entityidentifier.h" +#include "./json.h" -// ---------- ---------- ---------- ---------- +EntityInfo::EntityInfo(QString name, QString category, QColor brushColor, + QColor penColor) : name(name), category(category), + brushColor(brushColor), penColor(penColor) {} -EntityInfo::EntityInfo( QString name, QString category, QColor brushColor, QColor penColor ) - : name(name) - , category(category) - , brushColor(brushColor) - , penColor(penColor) -{} +static EntityInfo entityDummy("Name unknown", "Entity.Unknown", Qt::black, + Qt::black); -static EntityInfo entityDummy("Name unknown","Entity.Unknown",Qt::black,Qt::black); +EntityIdentifier::EntityIdentifier() {} +EntityIdentifier::~EntityIdentifier() {} -// ---------- ---------- ---------- ---------- - -EntityIdentifier::EntityIdentifier() -{} - -EntityIdentifier::~EntityIdentifier() -{} - -EntityIdentifier& EntityIdentifier::Instance() -{ - static EntityIdentifier singleton; - return singleton; +EntityIdentifier& EntityIdentifier::Instance() { + static EntityIdentifier singleton; + return singleton; } -void EntityIdentifier::enableDefinitions(int packID) -{ - if (packID<0) return; - for (QList::iterator it = packs.begin(); it != packs.end(); ++it) - { - if (it->packID == packID) - { - it->enabled = true; - return; - } - } +void EntityIdentifier::enableDefinitions(int packID) { + if (packID < 0) return; + for (auto it = packs.begin(); it != packs.end(); ++it) { + if (it->packID == packID) { + it->enabled = true; + return; + } + } } -void EntityIdentifier::disableDefinitions(int packID) -{ - if (packID<0) return; - for (QList::iterator it = packs.begin(); it != packs.end(); ++it) - { - if (it->packID == packID) - it->enabled = false; - } +void EntityIdentifier::disableDefinitions(int packID) { + if (packID < 0) return; + for (auto it = packs.begin(); it != packs.end(); ++it) { + if (it->packID == packID) + it->enabled = false; + } } -int EntityIdentifier::addDefinitions(JSONArray *defs,int packID) -{ - if (packID==-1) - { - // find largest used packID - for (QList::const_iterator it = packs.begin(); it != packs.end(); ++it) - { - if (it->packID > packID) - packID = it->packID; - } - packID++; // use one higher than largest found - packs.append(TpackInfo(packID)); - } - int len=defs->length(); - for (int i=0;i(defs->at(i)),packID); - return packID; +int EntityIdentifier::addDefinitions(JSONArray *defs, int packID) { + if (packID == -1) { + // find largest used packID + for (auto it = packs.constBegin(); it != packs.constEnd(); ++it) { + if (it->packID > packID) + packID = it->packID; + } + packID++; // use one higher than largest found + packs.append(TpackInfo(packID)); + } + int len = defs->length(); + for (int i = 0; i < len; i++) + parseCategoryDefinition(dynamic_cast(defs->at(i)), packID); + return packID; } -EntityIdentifier::TentityMap& EntityIdentifier::getMapForPackID(int packID) -{ - for (QList::iterator it = packs.begin(); it != packs.end(); ++it) - { - if (it->packID == packID) - return it->map; - } - return dummyMap; +EntityIdentifier::TentityMap& EntityIdentifier::getMapForPackID(int packID) { + for (auto it = packs.begin(); it != packs.end(); ++it) { + if (it->packID == packID) + return it->map; + } + return dummyMap; } -void EntityIdentifier::parseCategoryDefinition( JSONObject *data, int packID ) -{ - QString category; - if (data->has("category")) - category = data->at("category")->asString(); - else - category = "Unknown"; - - QColor catcolor; - if (data->has("catcolor")) - { - QString colorname = data->at("catcolor")->asString(); - catcolor.setNamedColor( colorname ); - assert(catcolor.isValid()); - } else {// use hashed by name instead - quint32 hue = qHash(category); - catcolor.setHsv(hue % 360, 255, 255); - } - addCategory(qMakePair(category,catcolor)); - - if (data->has("entity")) { - JSONArray *entities=dynamic_cast(data->at("entity")); - int len=entities->length(); - - for (int e=0;e(entities->at(e)), category, catcolor, packID); - } +void EntityIdentifier::parseCategoryDefinition(JSONObject *data, int packID) { + QString category; + if (data->has("category")) + category = data->at("category")->asString(); + else + category = "Unknown"; + + QColor catcolor; + if (data->has("catcolor")) { + QString colorname = data->at("catcolor")->asString(); + catcolor.setNamedColor(colorname); + assert(catcolor.isValid()); + } else { // use hashed by name instead + quint32 hue = qHash(category); + catcolor.setHsv(hue % 360, 255, 255); + } + addCategory(qMakePair(category, catcolor)); + + if (data->has("entity")) { + JSONArray *entities = dynamic_cast(data->at("entity")); + int len = entities->length(); + + for (int e = 0; e < len; e++) + parseEntityDefinition(dynamic_cast(entities->at(e)), + category, catcolor, packID); + } } -void EntityIdentifier::parseEntityDefinition( JSONObject *entity, QString const & category, QColor catcolor, int packID ) -{ - QString id; - if (entity->has("id")) - id = entity->at("id")->asString(); - else - id = "Unknown"; - - if (entity->has("catcolor")) - { - QString colorname = entity->at("catcolor")->asString(); - catcolor.setNamedColor( colorname ); - assert(catcolor.isValid()); - } - - QColor color; - if (entity->has("color")) - { - QString colorname = entity->at("color")->asString(); - color.setNamedColor( colorname ); - assert(color.isValid()); - } - else - {// use hashed by name instead - quint32 hue = qHash(id); - color.setHsv(hue % 360, 255, 255); - } - - // enter entity into manager - TentityMap& map = getMapForPackID(packID); - map.insert( id, EntityInfo(id,category,catcolor,color) ); +void EntityIdentifier::parseEntityDefinition(JSONObject *entity, + QString const &category, + QColor catcolor, int packID) { + QString id; + if (entity->has("id")) + id = entity->at("id")->asString(); + else + id = "Unknown"; + + if (entity->has("catcolor")) { + QString colorname = entity->at("catcolor")->asString(); + catcolor.setNamedColor(colorname); + assert(catcolor.isValid()); + } + + QColor color; + if (entity->has("color")) { + QString colorname = entity->at("color")->asString(); + color.setNamedColor(colorname); + assert(color.isValid()); + } else { // use hashed by name instead + quint32 hue = qHash(id); + color.setHsv(hue % 360, 255, 255); + } + + // enter entity into manager + TentityMap& map = getMapForPackID(packID); + map.insert(id, EntityInfo(id, category, catcolor, color)); } -bool EntityIdentifier::addCategory(QPair cat) -{ - TcatList::const_iterator it = categories.begin(); - for (; it != categories.end(); ++it) - { - if (it->first == cat.first) - return false; - } - categories.append(cat); - return true; +bool EntityIdentifier::addCategory(QPair cat) { + for (auto it = categories.constBegin(); it != categories.constEnd(); ++it) { + if (it->first == cat.first) + return false; + } + categories.append(cat); + return true; } -int EntityIdentifier::getNumCategories() const -{ - return categories.size(); +int EntityIdentifier::getNumCategories() const { + return categories.size(); } -EntityIdentifier::TcatList const & EntityIdentifier::getCategoryList() const -{ - return categories; +EntityIdentifier::TcatList const &EntityIdentifier::getCategoryList() const { + return categories; } -QColor EntityIdentifier::getCategoryColor(QString name) const -{ - for (TcatList::const_iterator it = categories.begin(); it != categories.end() ;++it) - { - if (it->first==name) - return it->second; - } - return Qt::black; // dummy +QColor EntityIdentifier::getCategoryColor(QString name) const { + for (auto it = categories.constBegin(); it != categories.constEnd(); ++it) { + if (it->first == name) + return it->second; + } + return Qt::black; // dummy } -EntityInfo const & EntityIdentifier::getEntityInfo( QString id ) const -{ - for (QList::const_iterator it = packs.begin(); it != packs.end(); ++it) - { - if (it->enabled) - { - TentityMap::const_iterator info = it->map.find(id); - if (info != it->map.end()) - { // found it - return info.value(); - } - } - } - - return entityDummy; +EntityInfo const &EntityIdentifier::getEntityInfo(QString id) const { + for (auto it = packs.constBegin(); it != packs.constEnd(); ++it) { + if (it->enabled) { + TentityMap::const_iterator info = it->map.find(id); + if (info != it->map.end()) { // found it + return info.value(); + } + } + } + return entityDummy; } -QColor EntityIdentifier::getBrushColor( QString id ) const -{ - return getEntityInfo(id).brushColor; +QColor EntityIdentifier::getBrushColor(QString id) const { + return getEntityInfo(id).brushColor; } -QColor EntityIdentifier::getPenColor( QString id ) const -{ - return getEntityInfo(id).penColor; +QColor EntityIdentifier::getPenColor(QString id) const { + return getEntityInfo(id).penColor; } diff --git a/entityidentifier.h b/entityidentifier.h index a17035fe..436367d4 100644 --- a/entityidentifier.h +++ b/entityidentifier.h @@ -1,32 +1,6 @@ -/* - Copyright (c) 2014, Mc_Etlam - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ENTITYIDENTIFIER_H__ -#define __ENTITYIDENTIFIER_H__ +/** Copyright (c) 2014, Mc_Etlam */ +#ifndef ENTITYIDENTIFIER_H_ +#define ENTITYIDENTIFIER_H_ #include #include @@ -37,63 +11,62 @@ class JSONArray; class JSONObject; -class EntityInfo -{ -public: - EntityInfo( QString name, QString category, QColor brushColor, QColor penColor ); - QString name; - QString category; - QColor brushColor; - QColor penColor; +class EntityInfo { + public: + EntityInfo(QString name, QString category, QColor brushColor, + QColor penColor); + QString name; + QString category; + QColor brushColor; + QColor penColor; }; -class EntityIdentifier -{ -public: - // singleton: access to global usable instance - static EntityIdentifier& Instance(); - - int addDefinitions(JSONArray *,int packID=-1); - void enableDefinitions(int); - void disableDefinitions(int); - - // interface to list of main categories - typedef QList > TcatList; - int getNumCategories() const; - TcatList const & getCategoryList() const; - QColor getCategoryColor(QString name) const; - - // interface to single EntityInfo objects - EntityInfo const & getEntityInfo( QString id ) const; - QColor getBrushColor( QString id ) const; - QColor getPenColor ( QString id ) const; - -private: - // singleton: prevent access to constructor and copyconstructor - EntityIdentifier(); - ~EntityIdentifier(); - EntityIdentifier( const EntityIdentifier& ); - EntityIdentifier & operator= (const EntityIdentifier &); - - void parseCategoryDefinition( JSONObject *data, int packID ); - void parseEntityDefinition ( JSONObject *entity, QString const & category, QColor catcolor, int packID ); - - TcatList categories; // main categories for entities - bool addCategory(QPair cat); - - typedef QMap TentityMap; // key:id_name value:EntityInfo - TentityMap dummyMap; - - class TpackInfo - { - public: - int packID; - bool enabled; - TentityMap map; - TpackInfo(int packID) : packID(packID), enabled(true) {} - }; - QList< TpackInfo > packs; - TentityMap& getMapForPackID(int packID); +class EntityIdentifier { + public: + // singleton: access to global usable instance + static EntityIdentifier &Instance(); + + int addDefinitions(JSONArray *, int packID = -1); + void enableDefinitions(int id); + void disableDefinitions(int id); + + // interface to list of main categories + typedef QList> TcatList; + int getNumCategories() const; + TcatList const &getCategoryList() const; + QColor getCategoryColor(QString name) const; + + // interface to single EntityInfo objects + EntityInfo const &getEntityInfo(QString id) const; + QColor getBrushColor(QString id) const; + QColor getPenColor(QString id) const; + + private: + // singleton: prevent access to constructor and copyconstructor + EntityIdentifier(); + ~EntityIdentifier(); + EntityIdentifier(const EntityIdentifier &); + EntityIdentifier &operator=(const EntityIdentifier &); + + void parseCategoryDefinition(JSONObject *data, int packID); + void parseEntityDefinition(JSONObject *entity, QString const &category, + QColor catcolor, int packID); + + TcatList categories; // main categories for entities + bool addCategory(QPair cat); + + typedef QMap TentityMap; // key:id_name value:EntityInfo + TentityMap dummyMap; + + class TpackInfo { + public: + int packID; + bool enabled; + TentityMap map; + explicit TpackInfo(int packID) : packID(packID), enabled(true) {} + }; + QList< TpackInfo > packs; + TentityMap& getMapForPackID(int packID); }; -#endif +#endif // ENTITYIDENTIFIER_H_ diff --git a/generatedstructure.cpp b/generatedstructure.cpp index 6603e062..0855387d 100644 --- a/generatedstructure.cpp +++ b/generatedstructure.cpp @@ -1,100 +1,82 @@ -#include "generatedstructure.h" - -#include "nbt.h" - +/** Copyright 2014 Rian Shelley */ #include +#include "./generatedstructure.h" +#include "./nbt.h" -QList > GeneratedStructure::tryParse(Tag* data) -{ - QList > ret; - if (data && data != &NBT::Null) - { - Tag* features = data->at("Features"); - if (features && data != &NBT::Null) - { - //convert the features to a qvariant here - QVariant maybeFeatureMap = features->getData(); - if ((QMetaType::Type)maybeFeatureMap.type() == QMetaType::QVariantMap) - { - QMap featureMap = maybeFeatureMap.toMap(); - foreach(const QVariant& feature, featureMap) - { - if ((QMetaType::Type)feature.type() == QMetaType::QVariantMap) - { - QMap featureProperties = feature.toMap(); - //check for required properties - if (featureProperties.contains("BB") //bounding box... gives us the position - && (QMetaType::Type)featureProperties["BB"].type() == QMetaType::QVariantList - && featureProperties.contains("id") //name of the feature type - ) - { - QList bb = featureProperties["BB"].toList(); - if (bb.size() == 6) - { - GeneratedStructure* structure = new GeneratedStructure(); - structure->setBounds( - Point(bb[0].toInt(), bb[1].toInt(), bb[2].toInt()), - Point(bb[3].toInt(), bb[4].toInt(), bb[5].toInt()) - ); - structure->setType("Structure." + featureProperties["id"].toString()); - structure->setDisplay(featureProperties["id"].toString()); - structure->setProperties(featureProperties); +QList> +GeneratedStructure::tryParse(const Tag* data) { + QList> ret; + if (data && data != &NBT::Null) { + auto features = data->at("Features"); + if (features && data != &NBT::Null) { + // convert the features to a qvariant here + QVariant maybeFeatureMap = features->getData(); + if ((QMetaType::Type)maybeFeatureMap.type() == QMetaType::QVariantMap) { + QMap featureMap = maybeFeatureMap.toMap(); + for (auto &feature : featureMap) { + if ((QMetaType::Type)feature.type() == QMetaType::QVariantMap) { + QMap featureProperties = feature.toMap(); + // check for required properties + if (featureProperties.contains("BB") && + (QMetaType::Type)featureProperties["BB"].type() == + QMetaType::QVariantList && featureProperties.contains("id")) { + QList bb = featureProperties["BB"].toList(); + if (bb.size() == 6) { + GeneratedStructure* structure = new GeneratedStructure(); + structure->setBounds( + Point(bb[0].toInt(), bb[1].toInt(), bb[2].toInt()), + Point(bb[3].toInt(), bb[4].toInt(), bb[5].toInt())); + structure->setType("Structure." + + featureProperties["id"].toString()); + structure->setDisplay(featureProperties["id"].toString()); + structure->setProperties(featureProperties); - //base the color on a hash of its type - quint32 hue = qHash(featureProperties["id"].toString()); - QColor color; - color.setHsv(hue % 360, 255, 255, 64); - structure->setColor(color); + // base the color on a hash of its type + quint32 hue = qHash(featureProperties["id"].toString()); + QColor color; + color.setHsv(hue % 360, 255, 255, 64); + structure->setColor(color); - //this will have to be maintained if new structures are added - if (structure->type() == "Structure.Fortress") - { - structure->setDimension("nether"); - } - else - { - structure->setDimension("overworld"); - } - ret.append(QSharedPointer(structure)); - } - } - } - } - } - } - } - return ret; + // this will have to be maintained if new structures are added + if (structure->type() == "Structure.Fortress") { + structure->setDimension("nether"); + } else { + structure->setDimension("overworld"); + } + ret.append(QSharedPointer(structure)); + } + } + } + } + } + } + } + return ret; } -bool GeneratedStructure::intersects(const Point& min, const Point& max) const -{ - return min.x <= p2.x && - p1.x <= max.x && - min.y <= p2.y && - p1.y <= max.y && - min.z <= p2.z && - p1.z <= max.z; +bool GeneratedStructure::intersects(const Point& min, + const Point& max) const { + return min.x <= p2.x && p1.x <= max.x && min.y <= p2.y && + p1.y <= max.y && min.z <= p2.z && p1.z <= max.z; } -void GeneratedStructure::draw(double offsetX, double offsetZ, double scale, QPainter& canvas) const -{ - int left = (int)((p1.x - offsetX) * scale);// + MIN_SIZE/4; - int top = (int)((p1.z - offsetZ) * scale);// + MIN_SIZE/4; - int w = (int)((p2.x - p1.x + 1) * scale);// - MIN_SIZE/2; - int h = (int)((p2.z - p1.z + 1) * scale);// - MIN_SIZE/2; +void GeneratedStructure::draw(double offsetX, double offsetZ, double scale, + QPainter *canvas) const { + int left = static_cast((p1.x - offsetX) * scale); + int top = static_cast((p1.z - offsetZ) * scale); + int w = static_cast((p2.x - p1.x + 1) * scale); + int h = static_cast((p2.z - p1.z + 1) * scale); - canvas.setPen(Qt::transparent); - canvas.setBrush(QBrush(color())); - canvas.drawRoundedRect(left, top, w, h, RADIUS, RADIUS); - QSize labelsize = canvas.fontMetrics().size(0, display()); - canvas.setPen(Qt::black); - if (labelsize.height() < h && labelsize.width() < w) - { - canvas.drawText(left, top, w, h, Qt::AlignCenter, display()); - } + canvas->setPen(Qt::transparent); + canvas->setBrush(QBrush(color())); + canvas->drawRoundedRect(left, top, w, h, RADIUS, RADIUS); + QSize labelsize = canvas->fontMetrics().size(0, display()); + canvas->setPen(Qt::black); + if (labelsize.height() < h && labelsize.width() < w) { + canvas->drawText(left, top, w, h, Qt::AlignCenter, display()); + } } -GeneratedStructure::Point GeneratedStructure::midpoint() const -{ - return Point((p1.x + p2.x)/2, (p1.y + p2.y)/2, (p1.z + p2.z)/2); +GeneratedStructure::Point GeneratedStructure::midpoint() const { + return Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2, (p1.z + p2.z) / 2); } diff --git a/generatedstructure.h b/generatedstructure.h index 6be3d14c..664dc719 100644 --- a/generatedstructure.h +++ b/generatedstructure.h @@ -1,33 +1,34 @@ -#ifndef GENERATEDSTRUCTURE_H -#define GENERATEDSTRUCTURE_H +/** Copyright 2014 Rian Shelley */ +#ifndef GENERATEDSTRUCTURE_H_ +#define GENERATEDSTRUCTURE_H_ -#include "overlayitem.h" #include #include +#include "./overlayitem.h" class Tag; class QColor; -class GeneratedStructure: public OverlayItem -{ -public: - static QList > tryParse(Tag* tag); +class GeneratedStructure: public OverlayItem { + public: + static QList> tryParse(const Tag* tag); - virtual bool intersects(const Point& min, const Point& max) const; - virtual void draw(double offsetX, double offsetZ, double scale, QPainter& canvas) const; - virtual Point midpoint() const; + virtual bool intersects(const Point& min, const Point& max) const; + virtual void draw(double offsetX, double offsetZ, double scale, + QPainter *canvas) const; + virtual Point midpoint() const; -protected: - GeneratedStructure() {} + protected: + GeneratedStructure() {} - //these are used to draw a rounded rect. If you want to draw something - //else, override draw() - void setBounds(const Point& min, const Point& max) {p1 = min; p2 = max;} + // these are used to draw a rounded rect. If you want to draw something + // else, override draw() + void setBounds(const Point& min, const Point& max) {p1 = min; p2 = max;} - static const int RADIUS = 10; + static const int RADIUS = 10; -private: - Point p1, p2; + private: + Point p1, p2; }; -#endif // GENERATEDSTRUCTURE_H +#endif // GENERATEDSTRUCTURE_H_ diff --git a/json.cpp b/json.cpp index 17038caa..175468a0 100644 --- a/json.cpp +++ b/json.cpp @@ -1,380 +1,330 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - +/** Copyright (c) 2013, Sean Kasun */ #include -#include "json.h" #include +#include "./json.h" enum Token { - TokenNULL, - TokenTRUE, - TokenFALSE, - TokenString, - TokenNumber, - TokenObject, - TokenArray, - TokenObjectClose, - TokenArrayClose, - TokenKeySeparator, - TokenValueSeparator + TokenNULL, + TokenTRUE, + TokenFALSE, + TokenString, + TokenNumber, + TokenObject, + TokenArray, + TokenObjectClose, + TokenArrayClose, + TokenKeySeparator, + TokenValueSeparator }; -class JSONHelper -{ -public: - JSONHelper(QString data) : data(data) {pos=0;len=data.length();} - ~JSONHelper() {} - Token nextToken() - { - while (pos='0' && c<='9') - num|=c-'0'; - else if (c>='a' && c<='f') - num|=c-'a'+10; - else if (c>='A' && c<='F') - num|=c-'A'+10; - else throw JSONParseException("Invalid hex code",location()); - } - r+=QChar(num); - } - break; - default: throw JSONParseException("Unknown escape sequence",location()); - } - } - else - r+=data.at(pos++); - } - pos++; - return r; - } - double readDouble() - { - double sign=1.0; - if (data.at(pos)=='-') - { - sign=-1.0; - pos++; - } - else if (data.at(pos)=='+') - pos++; - double value=0.0; - while (pos308) expon=308; - while (expon>=50) {scale *= 1E50; expon-=50; } - while (expon>=8) {scale *=1E8; expon-=8; } - while (expon>0) {scale*=10.0; expon-=1;} - } - return sign*(frac?(value/scale):(value*scale)); - } - QString location() - { - int line=1; - int col=0; - int cpos=pos; - bool doneCol=false; - while (cpos>=0) - { - if (data.at(cpos)=='\n') - { - doneCol=true; - line++; - } - if (!doneCol) col++; - cpos--; - } - return QString("Line: %1, Offset: %2").arg(line).arg(col); - } -private: - int pos,len; - QString data; +class JSONHelper { + public: + explicit JSONHelper(QString data) : data(data) { + pos = 0; + len = data.length(); + } + ~JSONHelper() {} + Token nextToken() { + while (pos < len && data.at(pos).isSpace()) + pos++; + if (pos == len) + throw JSONParseException("Unexpected EOF", location()); + QChar c = data.at(pos++); + if (c.isLetter()) { // keyword like NULL,TRUE or FALSE + int start = pos - 1; + while (pos < len && data.at(pos).isLetter()) + pos++; + QStringRef ref = data.midRef(start, pos - start); + if (ref.compare("null", Qt::CaseInsensitive) == 0) + return TokenNULL; + if (ref.compare("true", Qt::CaseInsensitive) == 0) + return TokenTRUE; + if (ref.compare("false", Qt::CaseInsensitive) == 0) + return TokenFALSE; + throw JSONParseException("Unquoted string", location()); + } + if (c.isDigit() || c == '-') { // double or hex + pos--; + return TokenNumber; + } + switch (c.unicode()) { + case '"': return TokenString; + case '{': return TokenObject; + case '}': return TokenObjectClose; + case '[': return TokenArray; + case ']': return TokenArrayClose; + case ':': return TokenKeySeparator; + case ',': return TokenValueSeparator; + default: + throw JSONParseException(QString("Unexpected character: %1").arg(c), + location()); + } + } + QString readString() { + QString r; + while (pos < len && data.at(pos) != '"') { + if (data.at(pos) == '\\') { + pos++; + if (pos == len) + throw JSONParseException("Unexpected EOF", location()); + switch (data.at(pos++).unicode()) { + case '"': r += '"'; break; + case '\\': r += '\\'; break; + case '/': r += '/'; break; + case 'b': r += '\b'; break; + case 'f': r += '\f'; break; + case 'n': r += '\n'; break; + case 'r': r += '\r'; break; + case 't': r += '\t'; break; + case 'u': { // hex + int num = 0; + for (int i = 0; i < 4; i++) { + if (pos == len) + throw JSONParseException("Unexpected EOF", location()); + num <<= 4; + char c = data.at(pos++).unicode(); + if (c >= '0' && c <= '9') + num |= c - '0'; + else if (c >= 'a' && c <= 'f') + num |= c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + num |= c - 'A' + 10; + else + throw JSONParseException("Invalid hex code", location()); + } + r += QChar(num); + } + break; + default: + throw JSONParseException("Unknown escape sequence", location()); + } + } else { + r += data.at(pos++); + } + } + pos++; + return r; + } + double readDouble() { + double sign = 1.0; + if (data.at(pos) == '-') { + sign = -1.0; + pos++; + } else if (data.at(pos) == '+') { + pos++; + } + double value = 0.0; + while (pos < len && data.at(pos).isDigit()) { + value *= 10.0; + value += data.at(pos++).unicode() - '0'; + } + if (pos == len) + throw JSONParseException("Unexpected EOF", location()); + if (data.at(pos) == '.') { + double pow10 = 10.0; + pos++; + while (pos < len && data.at(pos).isDigit()) { + value += (data.at(pos++).unicode() - '0') / pow10; + pow10 *= 10.0; + } + } + if (pos == len) + throw JSONParseException("Unexpected EOF", location()); + double scale = 1.0; + bool frac = false; + if (data.at(pos) == 'e' || data.at(pos) == 'E') { + pos++; + if (pos == len) + throw JSONParseException("Unexpected EOF", location()); + if (data.at(pos) == '-') { + frac = true; + pos++; + } else if (data.at(pos) == '+') { + pos++; + } + unsigned int expon = 0; + while (pos < len && data.at(pos).isDigit()) { + expon *= 10.0; + expon += data.at(pos++).unicode() - '0'; + } + if (expon > 308) + expon = 308; + while (expon >= 50) { + scale *= 1E50; + expon -= 50; + } + while (expon >= 8) { + scale *= 1E8; + expon -= 8; + } + while (expon > 0) { + scale *= 10.0; + expon -= 1; + } + } + return sign * (frac ? (value / scale) : (value * scale)); + } + QString location() { + int line = 1; + int col = 0; + int cpos = pos; + bool doneCol = false; + while (cpos >= 0) { + if (data.at(cpos) == '\n') { + doneCol = true; + line++; + } + if (!doneCol) col++; + cpos--; + } + return QString("Line: %1, Offset: %2").arg(line).arg(col); + } + + private: + int pos, len; + QString data; }; -JSONData *JSON::parse(const QString data) -{ - JSONHelper reader(data); - Token type=reader.nextToken(); - switch (type) - { - case TokenObject: //hash - return new JSONObject(reader); - case TokenArray: //array - return new JSONArray(reader); - default: - throw JSONParseException("Doesn't start with object or array",reader.location()); - break; - } - return NULL; +JSONData *JSON::parse(const QString data) { + JSONHelper reader(data); + Token type = reader.nextToken(); + switch (type) { + case TokenObject: // hash + return new JSONObject(reader); + case TokenArray: // array + return new JSONArray(reader); + default: + throw JSONParseException("Doesn't start with object or array", + reader.location()); + break; + } + return NULL; } static JSONData Null; -JSONData::JSONData() -{ +JSONData::JSONData() { } -JSONData::~JSONData() -{ +JSONData::~JSONData() { } -bool JSONData::has(const QString) -{ - return false; +bool JSONData::has(const QString) { + return false; } -JSONData *JSONData::at(const QString) -{ - return &Null; +JSONData *JSONData::at(const QString) { + return &Null; } -JSONData *JSONData::at(int) -{ - return &Null; +JSONData *JSONData::at(int /* idx */) { + return &Null; } -int JSONData::length() -{ - return 0; +int JSONData::length() { + return 0; } -QString JSONData::asString() -{ - return ""; +QString JSONData::asString() { + return ""; } -double JSONData::asNumber() -{ - return 0.0; +double JSONData::asNumber() { + return 0.0; } -bool JSONData::asBool() -{ - return false; +bool JSONData::asBool() { + return false; } -JSONBool::JSONBool(bool val) -{ - data=val; +JSONBool::JSONBool(bool val) { + data = val; } -bool JSONBool::asBool() -{ - return data; +bool JSONBool::asBool() { + return data; } -JSONString::JSONString(QString val) -{ - data=val; +JSONString::JSONString(QString val) { + data = val; } -QString JSONString::asString() -{ - return data; +QString JSONString::asString() { + return data; } -JSONNumber::JSONNumber(double val) -{ - data=val; +JSONNumber::JSONNumber(double val) { + data = val; } -double JSONNumber::asNumber() -{ - return data; +double JSONNumber::asNumber() { + return data; } -JSONObject::JSONObject(JSONHelper &reader) -{ - while (true) - { - Token type=reader.nextToken(); - if (type==TokenObjectClose) - break; - if (type!=TokenString) - throw JSONParseException("Expected quoted string",reader.location()); - QString key=reader.readString(); - if (key.length()==0) throw JSONParseException("Empty object key",reader.location()); - if (reader.nextToken()!=TokenKeySeparator) throw JSONParseException("Expected ':'",reader.location()); - JSONData *value; - switch (reader.nextToken()) - { - case TokenNULL: value=NULL; break; - case TokenTRUE: value=new JSONBool(true); break; - case TokenFALSE: value=new JSONBool(false); break; - case TokenString: value=new JSONString(reader.readString()); break; - case TokenNumber: value=new JSONNumber(reader.readDouble()); break; - case TokenObject: value=new JSONObject(reader); break; - case TokenArray: value=new JSONArray(reader); break; - default: throw JSONParseException("Expected value",reader.location()); - } - children[key]=value; - type=reader.nextToken(); //comma or end - if (type==TokenObjectClose) - break; - if (type!=TokenValueSeparator) - throw JSONParseException("Expected ',' or '}'",reader.location()); - } +JSONObject::JSONObject(JSONHelper &reader) { + while (true) { + Token type = reader.nextToken(); + if (type == TokenObjectClose) + break; + if (type != TokenString) + throw JSONParseException("Expected quoted string", reader.location()); + QString key = reader.readString(); + if (key.length() == 0) + throw JSONParseException("Empty object key", reader.location()); + if (reader.nextToken() != TokenKeySeparator) + throw JSONParseException("Expected ':'", reader.location()); + JSONData *value; + switch (reader.nextToken()) { + case TokenNULL: value = NULL; break; + case TokenTRUE: value = new JSONBool(true); break; + case TokenFALSE: value = new JSONBool(false); break; + case TokenString: value = new JSONString(reader.readString()); break; + case TokenNumber: value = new JSONNumber(reader.readDouble()); break; + case TokenObject: value = new JSONObject(reader); break; + case TokenArray: value = new JSONArray(reader); break; + default: throw JSONParseException("Expected value", reader.location()); + } + children[key] = value; + type = reader.nextToken(); // comma or end + if (type == TokenObjectClose) + break; + if (type != TokenValueSeparator) + throw JSONParseException("Expected ',' or '}'", reader.location()); + } } -JSONObject::~JSONObject() -{ - QHash::const_iterator i; - for (i=children.constBegin();i!=children.constEnd();i++) - delete i.value(); +JSONObject::~JSONObject() { + for (auto i = children.constBegin(); i != children.constEnd(); i++) + delete i.value(); } -bool JSONObject::has(QString key) -{ - return children.contains(key); +bool JSONObject::has(QString key) { + return children.contains(key); } -JSONData *JSONObject::at(QString key) -{ - if (children.contains(key)) - return children[key]; - return &Null; +JSONData *JSONObject::at(QString key) { + if (children.contains(key)) + return children[key]; + return &Null; } -JSONArray::JSONArray(JSONHelper &reader) -{ - while (true) - { - Token type=reader.nextToken(); - if (type==TokenArrayClose) - break; - JSONData *value; - switch (type) - { - case TokenNULL: value=NULL; break; - case TokenTRUE: value=new JSONBool(true); break; - case TokenFALSE: value=new JSONBool(false); break; - case TokenString: value=new JSONString(reader.readString()); break; - case TokenNumber: value=new JSONNumber(reader.readDouble()); break; - case TokenObject: value=new JSONObject(reader); break; - case TokenArray: value=new JSONArray(reader); break; - default: throw JSONParseException("Expected Value",reader.location()); - } - data.append(value); - type=reader.nextToken(); //comma or end - if (type==TokenArrayClose) - break; - if (type!=TokenValueSeparator) - throw JSONParseException("Expected ',' or ']'",reader.location()); - } +JSONArray::JSONArray(JSONHelper &reader) { + while (true) { + Token type = reader.nextToken(); + if (type == TokenArrayClose) + break; + JSONData *value; + switch (type) { + case TokenNULL: value = NULL; break; + case TokenTRUE: value = new JSONBool(true); break; + case TokenFALSE: value = new JSONBool(false); break; + case TokenString: value = new JSONString(reader.readString()); break; + case TokenNumber: value = new JSONNumber(reader.readDouble()); break; + case TokenObject: value = new JSONObject(reader); break; + case TokenArray: value = new JSONArray(reader); break; + default: throw JSONParseException("Expected Value", reader.location()); + } + data.append(value); + type = reader.nextToken(); // comma or end + if (type == TokenArrayClose) + break; + if (type != TokenValueSeparator) + throw JSONParseException("Expected ',' or ']'", reader.location()); + } } -JSONArray::~JSONArray() -{ - QList::const_iterator i; - for (i=data.constBegin();i!=data.constEnd();i++) - delete *i; +JSONArray::~JSONArray() { + for (auto i = data.constBegin(); i != data.constEnd(); i++) + delete *i; } -int JSONArray::length() -{ - return data.length(); +int JSONArray::length() { + return data.length(); } -JSONData *JSONArray::at(int index) -{ - if (index #include class JSONHelper; -class JSONData -{ -public: - JSONData(); - virtual ~JSONData(); - virtual bool has(const QString key); - virtual JSONData *at(const QString key); - virtual JSONData *at(int index); - virtual int length(); - virtual QString asString(); - virtual double asNumber(); - virtual bool asBool(); +class JSONData { + public: + JSONData(); + virtual ~JSONData(); + virtual bool has(const QString key); + virtual JSONData *at(const QString key); + virtual JSONData *at(int index); + virtual int length(); + virtual QString asString(); + virtual double asNumber(); + virtual bool asBool(); }; -class JSONBool : public JSONData -{ -public: - JSONBool(bool val); - bool asBool(); -private: - bool data; +class JSONBool : public JSONData { + public: + explicit JSONBool(bool val); + bool asBool(); + private: + bool data; }; -class JSONString : public JSONData -{ -public: - JSONString(QString val); - QString asString(); -private: - QString data; +class JSONString : public JSONData { + public: + explicit JSONString(QString val); + QString asString(); + private: + QString data; }; -class JSONNumber : public JSONData -{ -public: - JSONNumber(double val); - double asNumber(); -private: - double data; +class JSONNumber : public JSONData { + public: + explicit JSONNumber(double val); + double asNumber(); + private: + double data; }; -class JSONObject : public JSONData -{ -public: - JSONObject(JSONHelper &); - ~JSONObject(); - bool has(const QString key); - JSONData *at(const QString key); -private: - QHashchildren; +class JSONObject : public JSONData { + public: + explicit JSONObject(JSONHelper &); + ~JSONObject(); + bool has(const QString key); + JSONData *at(const QString key); + private: + QHashchildren; }; -class JSONArray : public JSONData -{ -public: - JSONArray(JSONHelper &); - ~JSONArray(); - JSONData *at(int index); - int length(); -private: - QListdata; +class JSONArray : public JSONData { + public: + explicit JSONArray(JSONHelper &); + ~JSONArray(); + JSONData *at(int index); + int length(); + private: + QListdata; }; -class JSONParseException -{ -public: - JSONParseException(QString reason,QString at) : reason(QString("%1 at %2").arg(reason).arg(at)) {} - QString reason; +class JSONParseException { + public: + JSONParseException(QString reason, QString at) : + reason(QString("%1 at %2").arg(reason).arg(at)) {} + QString reason; }; -class JSON -{ -public: - static JSONData *parse(const QString data); +class JSON { + public: + static JSONData *parse(const QString data); }; -#endif +#endif // JSON_H_ diff --git a/labelledslider.cpp b/labelledslider.cpp index 342497fb..cb471a29 100644 --- a/labelledslider.cpp +++ b/labelledslider.cpp @@ -1,96 +1,62 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "labelledslider.h" +/** Copyright (c) 2013, Sean Kasun */ #include - -LabelledSlider::LabelledSlider(Qt::Orientation orientation, QWidget *parent) : QWidget(parent) -{ - slider = new MSlider(orientation); - slider->setRange(0,255); - - label = new QLabel(); - label->setAlignment(Qt::AlignCenter|Qt::AlignVCenter); - label->setFixedWidth(label->fontMetrics().width("888")); - label->setNum(255); - - connect(slider, SIGNAL(valueChanged(int)), - this, SLOT(intValueChange(int))); - - QBoxLayout *myLayout; - if (orientation==Qt::Vertical){ - myLayout = new QVBoxLayout; - myLayout->addWidget(label); - myLayout->addWidget(slider); - } else { - myLayout = new QHBoxLayout; - myLayout->addWidget(slider); - myLayout->addWidget(label); - } - setLayout(myLayout); - setFocusProxy(slider); +#include "./labelledslider.h" + +LabelledSlider::LabelledSlider(Qt::Orientation orientation, QWidget *parent) : + QWidget(parent) { + slider = new MSlider(orientation); + slider->setRange(0, 255); + + label = new QLabel(); + label->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); + label->setFixedWidth(label->fontMetrics().width("888")); + label->setNum(255); + + connect(slider, SIGNAL(valueChanged(int)), + this, SLOT(intValueChange(int))); + + QBoxLayout *myLayout; + if (orientation == Qt::Vertical) { + myLayout = new QVBoxLayout; + myLayout->addWidget(label); + myLayout->addWidget(slider); + } else { + myLayout = new QHBoxLayout; + myLayout->addWidget(slider); + myLayout->addWidget(label); + } + setLayout(myLayout); + setFocusProxy(slider); } -int LabelledSlider::value() const -{ - return slider->value(); +int LabelledSlider::value() const { + return slider->value(); } // public slot -void LabelledSlider::setValue(int v) -{ - slider->setValue(v); +void LabelledSlider::setValue(int v) { + slider->setValue(v); } // public slot -void LabelledSlider::changeValue(int v) -{ - slider->setValue(slider->value()+v); +void LabelledSlider::changeValue(int v) { + slider->setValue(slider->value() + v); } // private slot -void LabelledSlider::intValueChange(int v) -{ - label->setNum(v); - emit valueChanged(v); +void LabelledSlider::intValueChange(int v) { + label->setNum(v); + emit valueChanged(v); } -void LabelledSlider::wheelEvent( QWheelEvent* event ) -{ - slider->wheelEvent( event ); +void LabelledSlider::wheelEvent(QWheelEvent* event) { + slider->wheelEvent(event); } -MSlider::MSlider(Qt::Orientation orientation, QWidget* parent) - : QSlider(orientation, parent) -{} +MSlider::MSlider(Qt::Orientation orientation, QWidget* parent) : + QSlider(orientation, parent) {} -void MSlider::wheelEvent( QWheelEvent* event ) -{ - int delta = event->delta() / 120; // in order to make wheel intuitive - this->setValue(this->value()+delta); +void MSlider::wheelEvent(QWheelEvent* event) { + int delta = event->delta() / 120; // in order to make wheel intuitive + this->setValue(this->value() + delta); } diff --git a/labelledslider.h b/labelledslider.h index 86b251eb..13d19dcd 100644 --- a/labelledslider.h +++ b/labelledslider.h @@ -1,33 +1,6 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __LABELLEDSLIDER_H__ -#define __LABELLEDSLIDER_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef LABELLEDSLIDER_H_ +#define LABELLEDSLIDER_H_ #include #include @@ -35,41 +8,40 @@ #include #include -class MSlider : public QSlider -{ - Q_OBJECT +class MSlider : public QSlider { + Q_OBJECT -public: - MSlider(Qt::Orientation orientation, QWidget * parent = 0); + public: + explicit MSlider(Qt::Orientation orientation, QWidget *parent = 0); -public slots: - void wheelEvent( QWheelEvent* event ); + public slots: + void wheelEvent(QWheelEvent *event); }; -class LabelledSlider : public QWidget -{ - Q_OBJECT -public: - explicit LabelledSlider(Qt::Orientation orientation, QWidget *parent = 0); - int value() const; +class LabelledSlider : public QWidget { + Q_OBJECT + + public: + explicit LabelledSlider(Qt::Orientation orientation, QWidget *parent = 0); + int value() const; -signals: - void valueChanged(int); + signals: + void valueChanged(int val); -public slots: - void setValue(int); // set absolute - void changeValue(int); // change relative + public slots: + void setValue(int val); // set absolute + void changeValue(int val); // change relative -private slots: - void intValueChange(int); + private slots: + void intValueChange(int val); -protected: - void wheelEvent( QWheelEvent* event ); + protected: + void wheelEvent(QWheelEvent *event); -private: - MSlider *slider; - QLabel *label; + private: + MSlider *slider; + QLabel *label; }; -#endif +#endif // LABELLEDSLIDER_H_ diff --git a/main.cpp b/main.cpp index f565f62b..963e63fb 100644 --- a/main.cpp +++ b/main.cpp @@ -1,118 +1,79 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - +/** Copyright (c) 2013, Sean Kasun */ #include #include #include -#include "minutor.h" - -int main(int argc,char *argv[]) -{ - QApplication app(argc,argv); +#include "./minutor.h" - QString locale = QLocale::system().name(); +int main(int argc, char *argv[]) { + QApplication app(argc, argv); - QTranslator translator; - translator.load(QString("minutor_")+locale); - app.installTranslator(&translator); + QString locale = QLocale::system().name(); - app.setApplicationName("Minutor"); - app.setApplicationVersion("2.0.1"); - app.setOrganizationName("seancode"); + QTranslator translator; + translator.load(QString("minutor_")+locale); + app.installTranslator(&translator); - Minutor minutor; + app.setApplicationName("Minutor"); + app.setApplicationVersion("2.1.0"); + app.setOrganizationName("seancode"); - // Process the cmdline arguments: - QStringList args = app.arguments(); - int numArgs = args.size(); - bool regionChecker=false; - bool chunkChecker=false; - for (int i = 0; i < numArgs; i++) - { - if (args[i].length()>2) - { - // convert long variants to lower case - args[i]=args[i].toLower(); - } - if (((args[i] == "-w") || (args[i] == "--world")) && (i + 1 < numArgs)) - { - minutor.loadWorld(args[i + 1]); - i += 1; - continue; - } - if (args[i] == "--regionchecker") - { - regionChecker=true; - continue; - } - if (args[i] == "--chunkchecker") - { - chunkChecker=true; - continue; - } - if (((args[i] == "-s") || (args[i] == "--savepng")) && (i + 1 < numArgs)) - { - minutor.savePNG( args[i + 1], true, regionChecker, chunkChecker ); - i += 1; - continue; - } - if (((args[i] == "-j") || (args[i] == "--jump")) && (i + 2 < numArgs)) - { - minutor.jumpToXZ(args[i + 1].toInt(), args[i + 2].toInt()); - i += 2; - continue; - } - if (((args[i] == "-y") || (args[i] == "--depth")) && (i + 1 < numArgs)) - { - minutor.setDepth( args[i + 1].toInt() ); - i += 1; - continue; - } + Minutor minutor; - // menu View-> - if ((args[i] == "-L") || (args[i] == "--lighting")) - { - minutor.setViewLighting(true); - continue; - } - if ((args[i] == "-M") || (args[i] == "--mobspawning")) - { - minutor.setViewMobspawning(true); - continue; - } - if ((args[i] == "-D") || (args[i] == "--depthshading")) - { - minutor.setViewDepthshading(true); - continue; - } + // Process the cmdline arguments: + QStringList args = app.arguments(); + int numArgs = args.size(); + bool regionChecker = false; + bool chunkChecker = false; + for (int i = 0; i < numArgs; i++) { + if (args[i].length() > 2) { + // convert long variants to lower case + args[i] = args[i].toLower(); + } + if ((args[i] == "-w" || args[i] == "--world") && i + 1 < numArgs) { + minutor.loadWorld(args[i + 1]); + i += 1; + continue; + } + if (args[i] == "--regionchecker") { + regionChecker = true; + continue; + } + if (args[i] == "--chunkchecker") { + chunkChecker = true; + continue; + } + if ((args[i] == "-s" || args[i] == "--savepng") && i + 1 < numArgs) { + minutor.savePNG(args[i + 1], true, regionChecker, chunkChecker); + i += 1; + continue; + } + if ((args[i] == "-j" || args[i] == "--jump") && i + 2 < numArgs) { + minutor.jumpToXZ(args[i + 1].toInt(), args[i + 2].toInt()); + i += 2; + continue; + } + if ((args[i] == "-y" || args[i] == "--depth") && i + 1 < numArgs) { + minutor.setDepth(args[i + 1].toInt()); + i += 1; + continue; + } - } // for itr - args[] + // menu View-> + if (args[i] == "-L" || args[i] == "--lighting") { + minutor.setViewLighting(true); + continue; + } + if (args[i] == "-M" || args[i] == "--mobspawning") { + minutor.setViewMobspawning(true); + continue; + } + if (args[i] == "-D" || args[i] == "--depthshading") { + minutor.setViewDepthshading(true); + continue; + } + } - minutor.show(); - return app.exec(); + minutor.show(); + return app.exec(); } diff --git a/make_installer.bat b/make_installer.bat index 4ef42a10..d5ffb8b6 100644 --- a/make_installer.bat +++ b/make_installer.bat @@ -1,4 +1,4 @@ -"c:\Program Files (x86)\Windows Installer XML v3.5\bin\candle.exe" MyWixUI_InstallDir.wxs -"c:\Program Files (x86)\Windows Installer XML v3.5\bin\candle.exe" minutor.wxs -"c:\Program Files (x86)\Windows Installer XML v3.5\bin\light.exe" -ext WixUIExtension -o minutor.msi minutor.wixobj MyWixUI_InstallDir.wixobj +"c:\Program Files (x86)\WiX Toolset v3.10\bin\candle.exe" MyWixUI_InstallDir.wxs +"c:\Program Files (x86)\WiX Toolset v3.10\bin\candle.exe" minutor.wxs +"c:\Program Files (x86)\WiX Toolset v3.10\bin\light.exe" -ext WixUIExtension -o minutor.msi minutor.wixobj MyWixUI_InstallDir.wixobj @pause diff --git a/mapview.cpp b/mapview.cpp old mode 100755 new mode 100644 index 3b860986..66592e03 --- a/mapview.cpp +++ b/mapview.cpp @@ -1,737 +1,632 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "mapview.h" -#include "definitionmanager.h" -#include "blockidentifier.h" -#include "biomeidentifier.h" +/** Copyright (c) 2013, Sean Kasun */ #include #include #include - #include -MapView::MapView(QWidget *parent) : QWidget(parent) -{ - depth=255; - scale=1; - zoom=1.0; - connect(&cache, SIGNAL(chunkLoaded(int,int)), - this, SLOT(chunkUpdated(int,int))); - setMouseTracking(true); - setFocusPolicy(Qt::StrongFocus); - - int offset=0; - for (int y=0;y<16;y++) - for (int x=0;x<16;x++) - { - uchar color=((x&8)^(y&8))==0?0x44:0x88; - placeholder[offset++]=color; - placeholder[offset++]=color; - placeholder[offset++]=color; - placeholder[offset++]=0xff; - } +#include "./mapview.h" +#include "./definitionmanager.h" +#include "./blockidentifier.h" +#include "./biomeidentifier.h" + +MapView::MapView(QWidget *parent) : QWidget(parent) { + depth = 255; + scale = 1; + zoom = 1.0; + connect(&cache, SIGNAL(chunkLoaded(int, int)), + this, SLOT(chunkUpdated(int, int))); + setMouseTracking(true); + setFocusPolicy(Qt::StrongFocus); + + int offset = 0; + for (int y = 0; y < 16; y++) + for (int x = 0; x < 16; x++) { + uchar color = ((x & 8) ^ (y & 8)) == 0 ? 0x44 : 0x88; + placeholder[offset++] = color; + placeholder[offset++] = color; + placeholder[offset++] = color; + placeholder[offset++] = 0xff; + } } -QSize MapView::minimumSizeHint() const -{ - return QSize(300,300); +QSize MapView::minimumSizeHint() const { + return QSize(300, 300); } -QSize MapView::sizeHint() const -{ - return QSize(400,400); +QSize MapView::sizeHint() const { + return QSize(400, 400); } -void MapView::attach(DefinitionManager *dm) -{ - this->dm=dm; - connect(dm,SIGNAL(packsChanged()), - this,SLOT(redraw())); - this->blocks=dm->blockIdentifier(); - this->biomes=dm->biomeIdentifier(); +void MapView::attach(DefinitionManager *dm) { + this->dm = dm; + connect(dm, SIGNAL(packsChanged()), + this, SLOT(redraw())); + this->blocks = dm->blockIdentifier(); + this->biomes = dm->biomeIdentifier(); } -void MapView::setLocation(double x, double z) -{ - this->x=x/scale; - this->z=z/scale; +void MapView::setLocation(double x, double z) { + this->x = x / scale; + this->z = z / scale; - redraw(); + redraw(); } -void MapView::setDimension(QString path, int scale) -{ - if (scale>0) - { - this->x*=this->scale; - this->z*=this->scale; //undo current scale transform - this->scale=scale; - this->x/=scale; //and do the new scale transform - this->z/=scale; - } - else - { - this->scale=1; //no scaling because no relation to overworld - this->x=0; //and we jump to the center spawn automatically - this->z=0; - } - cache.clear(); - cache.setPath(path); - redraw(); +void MapView::setDimension(QString path, int scale) { + if (scale > 0) { + this->x *= this->scale; + this->z *= this->scale; // undo current scale transform + this->scale = scale; + this->x /= scale; // and do the new scale transform + this->z /= scale; + } else { + this->scale = 1; // no scaling because no relation to overworld + this->x = 0; // and we jump to the center spawn automatically + this->z = 0; + } + cache.clear(); + cache.setPath(path); + redraw(); } -void MapView::setDepth(int depth) -{ - this->depth=depth; - redraw(); +void MapView::setDepth(int depth) { + this->depth = depth; + redraw(); } -void MapView::setFlags(int flags) -{ - this->flags=flags; +void MapView::setFlags(int flags) { + this->flags = flags; } -void MapView::chunkUpdated(int x, int z) -{ - drawChunk(x,z); - update(); +void MapView::chunkUpdated(int x, int z) { + drawChunk(x, z); + update(); } -QString MapView::getWorldPath() -{ - return cache.getPath(); +QString MapView::getWorldPath() { + return cache.getPath(); } -void MapView::clearCache() -{ - cache.clear(); - //TODO: clear overlay items? - redraw(); +void MapView::clearCache() { + cache.clear(); + redraw(); } -static int lastX=-1,lastY=-1; -static bool dragging=false; -void MapView::mousePressEvent(QMouseEvent *event) -{ - lastX=event->x(); - lastY=event->y(); - dragging=true; +static int lastX = -1, lastY = -1; +static bool dragging = false; +void MapView::mousePressEvent(QMouseEvent *event) { + lastX = event->x(); + lastY = event->y(); + dragging = true; } -void MapView::mouseMoveEvent(QMouseEvent *event) -{ - if (!dragging) - { - int centerblockx=floor(this->x); - int centerblockz=floor(this->z); - - int centerx=image.width()/2; - int centery=image.height()/2; - - centerx-=(this->x-centerblockx)*zoom; - centery-=(this->z-centerblockz)*zoom; - - int mx=floor(centerblockx-(centerx-event->x())/zoom); - int mz=floor(centerblockz-(centery-event->y())/zoom); - - getToolTip(mx,mz); - return; - } - x+=(lastX-event->x())/zoom; - z+=(lastY-event->y())/zoom; - lastX=event->x(); - lastY=event->y(); - redraw(); +void MapView::mouseMoveEvent(QMouseEvent *event) { + if (!dragging) { + int centerblockx = floor(this->x); + int centerblockz = floor(this->z); + + int centerx = image.width() / 2; + int centery = image.height() / 2; + + centerx -= (this->x - centerblockx) * zoom; + centery -= (this->z - centerblockz) * zoom; + + int mx = floor(centerblockx - (centerx - event->x()) / zoom); + int mz = floor(centerblockz - (centery - event->y()) / zoom); + + getToolTip(mx, mz); + return; + } + x += (lastX-event->x()) / zoom; + z += (lastY-event->y()) / zoom; + lastX = event->x(); + lastY = event->y(); + redraw(); } -void MapView::mouseReleaseEvent(QMouseEvent *) -{ - dragging=false; +void MapView::mouseReleaseEvent(QMouseEvent * /* event */) { + dragging = false; } -void MapView::mouseDoubleClickEvent(QMouseEvent*event) -{ - int centerblockx=floor(this->x); - int centerblockz=floor(this->z); +void MapView::mouseDoubleClickEvent(QMouseEvent *event) { + int centerblockx = floor(this->x); + int centerblockz = floor(this->z); - int centerx=image.width()/2; - int centery=image.height()/2; + int centerx = image.width() / 2; + int centery = image.height() / 2; - centerx-=(this->x-centerblockx)*zoom; - centery-=(this->z-centerblockz)*zoom; + centerx -= (this->x - centerblockx) * zoom; + centery -= (this->z - centerblockz) * zoom; - int mx=floor(centerblockx-(centerx-event->x())/zoom); - int mz=floor(centerblockz-(centery-event->y())/zoom); + int mx = floor(centerblockx - (centerx - event->x()) / zoom); + int mz = floor(centerblockz - (centery - event->y()) / zoom); - //get the y coordinate - int my = getY(mx, mz); + // get the y coordinate + int my = getY(mx, mz); - QList properties; - foreach(const QSharedPointer& item, getItems(mx, my, mz)) - { - properties.append(item->properties()); - } + QList properties; + for (auto &item : getItems(mx, my, mz)) { + properties.append(item->properties()); + } - if (!properties.isEmpty()) - { - emit showProperties(properties); - } + if (!properties.isEmpty()) { + emit showProperties(properties); + } } -void MapView::wheelEvent(QWheelEvent *event) -{ - if ((event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier) // change depth - { - emit demandDepthChange(event->delta()/120); - } - else // change zoom - { - zoom+=floor(event->delta()/90.0); - if (zoom<1.0) zoom=1.0; - if (zoom>20.0) zoom=20.0; - redraw(); - } +void MapView::wheelEvent(QWheelEvent *event) { + if ((event->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier) { + // change depth + emit demandDepthChange(event->delta() / 120); + } else { // change zoom + zoom += floor(event->delta() / 90.0); + if (zoom < 1.0) zoom = 1.0; + if (zoom > 20.0) zoom = 20.0; + redraw(); + } } -void MapView::keyPressEvent(QKeyEvent *event) -{ - switch (event->key()) - { - case Qt::Key_Up: - case Qt::Key_W: - z-=10.0/zoom; - redraw(); - break; - case Qt::Key_Down: - case Qt::Key_S: - z+=10.0/zoom; - redraw(); - break; - case Qt::Key_Left: - case Qt::Key_A: - x-=10.0/zoom; - redraw(); - break; - case Qt::Key_Right: - case Qt::Key_D: - x+=10.0/zoom; - redraw(); - break; - case Qt::Key_PageUp: - case Qt::Key_Q: - zoom++; - if (zoom>20.0) zoom=20.0; - redraw(); - break; - case Qt::Key_PageDown: - case Qt::Key_E: - zoom--; - if (zoom<1.0) zoom=1.0; - redraw(); - break; - case Qt::Key_Home: - case Qt::Key_Plus: - case Qt::Key_BracketLeft: - emit demandDepthChange(+1); - break; - case Qt::Key_End: - case Qt::Key_Minus: - case Qt::Key_BracketRight: - emit demandDepthChange(-1); - break; - } +void MapView::keyPressEvent(QKeyEvent *event) { + switch (event->key()) { + case Qt::Key_Up: + case Qt::Key_W: + z -= 10.0 / zoom; + redraw(); + break; + case Qt::Key_Down: + case Qt::Key_S: + z += 10.0 / zoom; + redraw(); + break; + case Qt::Key_Left: + case Qt::Key_A: + x -= 10.0 / zoom; + redraw(); + break; + case Qt::Key_Right: + case Qt::Key_D: + x += 10.0 / zoom; + redraw(); + break; + case Qt::Key_PageUp: + case Qt::Key_Q: + zoom++; + if (zoom > 20.0) zoom = 20.0; + redraw(); + break; + case Qt::Key_PageDown: + case Qt::Key_E: + zoom--; + if (zoom < 1.0) zoom = 1.0; + redraw(); + break; + case Qt::Key_Home: + case Qt::Key_Plus: + case Qt::Key_BracketLeft: + emit demandDepthChange(+1); + break; + case Qt::Key_End: + case Qt::Key_Minus: + case Qt::Key_BracketRight: + emit demandDepthChange(-1); + break; + } } -void MapView::resizeEvent(QResizeEvent *event) -{ - image=QImage(event->size(),QImage::Format_RGB32); - redraw(); +void MapView::resizeEvent(QResizeEvent *event) { + image = QImage(event->size(), QImage::Format_RGB32); + redraw(); } -void MapView::paintEvent(QPaintEvent *) -{ - QPainter p(this); - p.drawImage(QPoint(0,0),image); - p.end(); +void MapView::paintEvent(QPaintEvent * /* event */) { + QPainter p(this); + p.drawImage(QPoint(0, 0), image); + p.end(); } -void MapView::redraw() -{ - if (!this->isEnabled()) - { - // blank - uchar *bits=image.bits(); - int imgstride=image.bytesPerLine(); - int imgoffset=0; - for (int y=0;y range = chunk->entities.equal_range(type); - for (Chunk::EntityMap::iterator it = range.first; it != range.second; ++it) - { - //don't show entities above our depth - int entityY = (*it)->midpoint().y; - if (entityY < depth+1) // everything below the current block, but also inside the current block - { - int entityX = ((int)(*it)->midpoint().x) & 0x0f; - int entityZ = ((int)(*it)->midpoint().z) & 0x0f ; - int index = entityX + (entityZ<<4); - int highY = chunk->depth[index]; - if ( (entityY+10 >= highY) || - (entityY+10 >= depth) ) - (*it)->draw(x1, z1, zoom, canvas); - } - } - } - } - } - } - - - //draw the generated structures - foreach(const QString& type, overlayItemTypes) - { - foreach(const QSharedPointer& item, overlayItems[type]) - { - if (item->intersects( - OverlayItem::Point(x1-1, 0, z1-1), - OverlayItem::Point(x2+1, depth, z2+1))) - { - item->draw(x1, z1, zoom, canvas); - } - } - } - - update(); +void MapView::redraw() { + if (!this->isEnabled()) { + // blank + uchar *bits = image.bits(); + int imgstride = image.bytesPerLine(); + int imgoffset = 0; + for (int y = 0; y < image.height(); y++, imgoffset += imgstride) + memset(bits + imgoffset, 0xee, imgstride); + update(); + return; + } + + double chunksize = 16 * zoom; + + // first find the center block position + int centerchunkx = floor(x / 16); + int centerchunkz = floor(z / 16); + // and the center of the screen + int centerx = image.width() / 2; + int centery = image.height() / 2; + // and align for panning + centerx -= (x - centerchunkx * 16) * zoom; + centery -= (z - centerchunkz * 16) * zoom; + // now calculate the topleft block on the screen + int startx = centerchunkx - floor(centerx / chunksize) - 1; + int startz = centerchunkz - floor(centery / chunksize) - 1; + // and the dimensions of the screen in blocks + int blockswide = image.width() / chunksize + 3; + int blockstall = image.height() / chunksize + 3; + + for (int cz = startz; cz < startz + blockstall; cz++) + for (int cx = startx; cx < startx + blockswide; cx++) + drawChunk(cx, cz); + + // add on the entity layer + QPainter canvas(&image); + double halfviewwidth = image.width() / 2 / zoom; + double halvviewheight = image.height() / 2 / zoom; + double x1 = x - halfviewwidth; + double z1 = z - halvviewheight; + double x2 = x + halfviewwidth; + double z2 = z + halvviewheight; + + // draw the entities + for (int cz = startz; cz < startz + blockstall; cz++) { + for (int cx = startx; cx < startx + blockswide; cx++) { + for (auto &type : overlayItemTypes) { + Chunk *chunk = cache.fetch(cx, cz); + if (chunk) { + auto range = chunk->entities.equal_range(type); + for (auto it = range.first; it != range.second; ++it) { + // don't show entities above our depth + int entityY = (*it)->midpoint().y; + // everything below the current block, + // but also inside the current block + if (entityY < depth + 1) { + int entityX = static_cast((*it)->midpoint().x) & 0x0f; + int entityZ = static_cast((*it)->midpoint().z) & 0x0f; + int index = entityX + (entityZ << 4); + int highY = chunk->depth[index]; + if ( (entityY+10 >= highY) || + (entityY+10 >= depth) ) + (*it)->draw(x1, z1, zoom, &canvas); + } + } + } + } + } + } + + + // draw the generated structures + for (auto &type : overlayItemTypes) { + for (auto &item : overlayItems[type]) { + if (item->intersects(OverlayItem::Point(x1 - 1, 0, z1 - 1), + OverlayItem::Point(x2 + 1, depth, z2 + 1))) { + item->draw(x1, z1, zoom, &canvas); + } + } + } + + update(); } -void MapView::drawChunk(int x, int z) -{ - if (!this->isEnabled()) - return; - - uchar *src=placeholder; - //fetch the chunk - Chunk *chunk=cache.fetch(x,z); - - if (chunk && (chunk->renderedAt!=depth || chunk->renderedFlags!=flags)) - { - renderChunk(chunk); - } - - //this figures out where on the screen this chunk should be drawn - - - // first find the center chunk - int centerchunkx=floor(this->x/16); - int centerchunkz=floor(this->z/16); - // and the center chunk screen coordinates - int centerx=image.width()/2; - int centery=image.height()/2; - // which need to be shifted to account for panning inside that chunk - centerx-=(this->x-centerchunkx*16)*zoom; - centery-=(this->z-centerchunkz*16)*zoom; - // centerx,y now points to the top left corner of the center chunk - // so now calculate our x,y in relation - double chunksize=16*zoom; - centerx+=(x-centerchunkx)*chunksize; - centery+=(z-centerchunkz)*chunksize; - - int srcoffset=0; - uchar *bits=image.bits(); - int imgstride=image.bytesPerLine(); - - int skipx=0,skipy=0; - int blockwidth=chunksize,blockheight=chunksize; - // now if we're off the screen we need to crop - if (centerx<0) - { - skipx=-centerx; - centerx=0; - } - if (centery<0) - { - skipy=-centery; - centery=0; - } - // or the other side, we need to trim - if (centerx+blockwidth>image.width()) - blockwidth=image.width()-centerx; - if (centery+blockheight>image.height()) - blockheight=image.height()-centery; - if (blockwidth<=0 || skipx>=blockwidth) return; - int imgoffset=centerx*4+centery*imgstride; - if (chunk) - src=chunk->image; - //blit (or scale blit) - for (int z=skipy;zisEnabled()) + return; + + uchar *src = placeholder; + // fetch the chunk + Chunk *chunk = cache.fetch(x, z); + + if (chunk && (chunk->renderedAt != depth || + chunk->renderedFlags != flags)) { + renderChunk(chunk); + } + + // this figures out where on the screen this chunk should be drawn + + // first find the center chunk + int centerchunkx = floor(this->x / 16); + int centerchunkz = floor(this->z / 16); + // and the center chunk screen coordinates + int centerx = image.width() / 2; + int centery = image.height() / 2; + // which need to be shifted to account for panning inside that chunk + centerx -= (this->x - centerchunkx * 16) * zoom; + centery -= (this->z - centerchunkz * 16) * zoom; + // centerx,y now points to the top left corner of the center chunk + // so now calculate our x,y in relation + double chunksize = 16 * zoom; + centerx += (x - centerchunkx) * chunksize; + centery += (z - centerchunkz) * chunksize; + + int srcoffset = 0; + uchar *bits = image.bits(); + int imgstride = image.bytesPerLine(); + + int skipx = 0, skipy = 0; + int blockwidth = chunksize, blockheight = chunksize; + // now if we're off the screen we need to crop + if (centerx < 0) { + skipx = -centerx; + centerx = 0; + } + if (centery < 0) { + skipy = -centery; + centery = 0; + } + // or the other side, we need to trim + if (centerx + blockwidth > image.width()) + blockwidth = image.width() - centerx; + if (centery + blockheight > image.height()) + blockheight = image.height() - centery; + if (blockwidth <= 0 || skipx >= blockwidth) return; + int imgoffset = centerx * 4 + centery * imgstride; + if (chunk) + src = chunk->image; + // blit (or scale blit) + for (int z = skipy; z < blockheight; z++, imgoffset += imgstride) { + srcoffset = floor(z / zoom) * 16 * 4; + if (zoom == 1.0) { + memcpy(bits + imgoffset, src + srcoffset + skipx * 4, + (blockwidth - skipx) * 4); + } else { + int xofs = 0; + for (int x = skipx; x < blockwidth; x++, xofs += 4) + memcpy(bits + imgoffset + xofs, src + srcoffset + + static_cast(floor(x / zoom) * 4), 4); + } + } } -void MapView::renderChunk(Chunk *chunk) -{ - int offset=0; - uchar *bits=chunk->image; - uchar *depthbits=chunk->depth; - for (int z=0;z<16;z++) //n->s - { - int lasty=-1; - for (int x=0;x<16;x++,offset++) //e->w - { - uchar r=0,g=0,b=0; - double alpha=0.0; - int top=depth; - if (top>chunk->highest) - top=chunk->highest; - int highest=0; - for (int y=top;y>=0;y--) - { - int sec=y>>4; - ChunkSection *section=chunk->sections[sec]; - if (!section) - { - y=(sec<<4)-1; //skip whole section - continue; - } - - // get data value - int data = section->getData(x,y,z); - - // get BlockInfo from block value - BlockInfo &block=blocks->getBlock(section->getBlock(x,y,z),data); - if (block.alpha==0.0) continue; - - // get light value from one block above - int light = 0; - ChunkSection *section1=NULL; - if (y<255) - section1 = chunk->sections[(y+1)>>4]; - if (section1) - light = section1->getLight(x,y+1,z); - int light1 = light; - if (!(flags & flgLighting)) - light = 13; - if ((alpha==0.0)&&(lasty!=-1)) - { - if (lastyy) - light-=2; - } - if (light<0) light=0; - if (light>15) light=15; - - // define the color - quint32 color=block.colors[light]; - quint32 colr = color >> 16; - quint32 colg = (color >> 8) & 0xff; - quint32 colb = color & 0xff; - if (flags & flgDepthShading) - { - // Use a table to define depth-relative shade: - static const quint32 shadeTable[] = {0, 12, 18, 22, 24, 26, 28, 29, 30, 31, 32}; - size_t idx = std::min(static_cast(depth - y), sizeof(shadeTable) / sizeof(*shadeTable) - 1); - quint32 shade = shadeTable[idx]; - colr = colr - std::min(shade, colr); - colg = colg - std::min(shade, colg); - colb = colb - std::min(shade, colb); - } - if (flags & flgMobSpawn) - { - // get block info from 1 and 2 above and 1 below - quint16 blid1(0), blid2(0), blidB(0); // default to air - int data1(0), data2(0), dataB(0); // default variant - ChunkSection *section2=NULL; - ChunkSection *sectionB=NULL; - if (y<254) - section2 = chunk->sections[(y+2)>>4]; - if (y>0) - sectionB = chunk->sections[(y-1)>>4]; - if (section1) - { - blid1 = section1->getBlock(x,y+1,z); - data1 = section1->getData(x,y+1,z); - } - if (section2) - { - blid2 = section2->getBlock(x,y+2,z); - data2 = section2->getData(x,y+2,z); - } - if (sectionB) - { - blidB = sectionB->getBlock(x,y-1,z); - dataB = sectionB->getData(x,y-1,z); - } - BlockInfo &block2=blocks->getBlock(blid2,data2); - BlockInfo &block1=blocks->getBlock(blid1,data1); - BlockInfo &block0=block; - BlockInfo &blockB=blocks->getBlock(blidB,dataB); - int light0 = section->getLight(x,y,z); - - // spawn check #1: on top of solid block - if ( block0.doesBlockHaveSolidTopSurface(data) && - !block0.isBedrock() && - (light1<8) && - !block1.isBlockNormalCube() && block1.spawninside && !block1.isLiquid() && - !block2.isBlockNormalCube() && block2.spawninside ) - { - colr = (colr+256)/2; - colg = (colg+0)/2; - colb = (colb+192)/2; - } - // spawn check #2: current block is transparent, but mob can spawn through (e.g. snow) - if ( blockB.doesBlockHaveSolidTopSurface(dataB) && - !blockB.isBedrock() && - (light0<8) && - !block0.isBlockNormalCube() && block0.spawninside && !block0.isLiquid() && - !block1.isBlockNormalCube() && block1.spawninside ) - { - colr = (colr+192)/2; - colg = (colg+0)/2; - colb = (colb+256)/2; - } - } - if (alpha==0.0) - { - alpha = block.alpha; - r = colr; - g = colg; - b = colb; - highest = y; - } - else - { - r =(quint8)(alpha*r + (1.0-alpha)*(colr)); - g =(quint8)(alpha*g + (1.0-alpha)*(colg)); - b =(quint8)(alpha*b + (1.0-alpha)*(colb)); - alpha+=block.alpha*(1.0-alpha); - } - - // finish deepth (Y) scanning when color is saturated enough - if (block.alpha==1.0 || alpha>0.9) - break; - } - *depthbits++=lasty=highest; - *bits++=b; - *bits++=g; - *bits++=r; - *bits++=0xff; - } - } - chunk->renderedAt=depth; - chunk->renderedFlags=flags; +void MapView::renderChunk(Chunk *chunk) { + int offset = 0; + uchar *bits = chunk->image; + uchar *depthbits = chunk->depth; + for (int z = 0; z < 16; z++) { // n->s + int lasty = -1; + for (int x = 0; x < 16; x++, offset++) { // e->w + uchar r = 0, g = 0, b = 0; + double alpha = 0.0; + int top = depth; + if (top > chunk->highest) + top = chunk->highest; + int highest = 0; + for (int y = top; y >= 0; y--) { + int sec = y >> 4; + ChunkSection *section = chunk->sections[sec]; + if (!section) { + y = (sec << 4) - 1; // skip whole section + continue; + } + + // get data value + int data = section->getData(x, y, z); + + // get BlockInfo from block value + BlockInfo &block = blocks->getBlock(section->getBlock(x, y, z), + data); + if (block.alpha == 0.0) continue; + + // get light value from one block above + int light = 0; + ChunkSection *section1 = NULL; + if (y < 255) + section1 = chunk->sections[(y + 1) >> 4]; + if (section1) + light = section1->getLight(x, y + 1, z); + int light1 = light; + if (!(flags & flgLighting)) + light = 13; + if (alpha == 0.0 && lasty != -1) { + if (lasty < y) + light += 2; + else if (lasty > y) + light -= 2; + } + if (light < 0) light = 0; + if (light > 15) light = 15; + + // define the color + quint32 color = block.colors[light]; + quint32 colr = color >> 16; + quint32 colg = (color >> 8) & 0xff; + quint32 colb = color & 0xff; + if (flags & flgDepthShading) { + // Use a table to define depth-relative shade: + static const quint32 shadeTable[] = { + 0, 12, 18, 22, 24, 26, 28, 29, 30, 31, 32}; + size_t idx = qMin(static_cast(depth - y), + sizeof(shadeTable) / sizeof(*shadeTable) - 1); + quint32 shade = shadeTable[idx]; + colr = colr - qMin(shade, colr); + colg = colg - qMin(shade, colg); + colb = colb - qMin(shade, colb); + } + if (flags & flgMobSpawn) { + // get block info from 1 and 2 above and 1 below + quint16 blid1(0), blid2(0), blidB(0); // default to air + int data1(0), data2(0), dataB(0); // default variant + ChunkSection *section2 = NULL; + ChunkSection *sectionB = NULL; + if (y < 254) + section2 = chunk->sections[(y + 2) >> 4]; + if (y > 0) + sectionB = chunk->sections[(y - 1) >> 4]; + if (section1) { + blid1 = section1->getBlock(x, y + 1, z); + data1 = section1->getData(x, y + 1, z); + } + if (section2) { + blid2 = section2->getBlock(x, y + 2, z); + data2 = section2->getData(x, y + 2, z); + } + if (sectionB) { + blidB = sectionB->getBlock(x, y - 1, z); + dataB = sectionB->getData(x, y - 1, z); + } + BlockInfo &block2 = blocks->getBlock(blid2, data2); + BlockInfo &block1 = blocks->getBlock(blid1, data1); + BlockInfo &block0 = block; + BlockInfo &blockB = blocks->getBlock(blidB, dataB); + int light0 = section->getLight(x, y, z); + + // spawn check #1: on top of solid block + if (block0.doesBlockHaveSolidTopSurface(data) && + !block0.isBedrock() && light1 < 8 && + !block1.isBlockNormalCube() && block1.spawninside && + !block1.isLiquid() && + !block2.isBlockNormalCube() && block2.spawninside) { + colr = (colr + 256) / 2; + colg = (colg + 0) / 2; + colb = (colb + 192) / 2; + } + // spawn check #2: current block is transparent, + // but mob can spawn through (e.g. snow) + if (blockB.doesBlockHaveSolidTopSurface(dataB) && + !blockB.isBedrock() && light0 < 8 && + !block0.isBlockNormalCube() && block0.spawninside && + !block0.isLiquid() && + !block1.isBlockNormalCube() && block1.spawninside) { + colr = (colr + 192) / 2; + colg = (colg + 0) / 2; + colb = (colb + 256) / 2; + } + } + if (alpha == 0.0) { + alpha = block.alpha; + r = colr; + g = colg; + b = colb; + highest = y; + } else { + r = (quint8)(alpha * r + (1.0 - alpha) * colr); + g = (quint8)(alpha * g + (1.0 - alpha) * colg); + b = (quint8)(alpha * b + (1.0 - alpha) * colb); + alpha+=block.alpha * (1.0 - alpha); + } + + // finish deepth (Y) scanning when color is saturated enough + if (block.alpha == 1.0 || alpha > 0.9) + break; + } + *depthbits++ = lasty = highest; + *bits++ = b; + *bits++ = g; + *bits++ = r; + *bits++ = 0xff; + } + } + chunk->renderedAt = depth; + chunk->renderedFlags = flags; } -void MapView::getToolTip(int x, int z) -{ - int cx=floor(x/16.0); - int cz=floor(z/16.0); - Chunk *chunk=cache.fetch(cx,cz); - int offset=(x&0xf)+(z&0xf)*16; - int id=0,bd=0; - - QString name="Unknown"; - QString biome="Unknown Biome"; - QMap entityIds; - - if (chunk) - { - int top=depth; - if (top>chunk->highest) - top=chunk->highest; - int y = 0; - for (y=top;y>=0;y--) - { - int sec=y>>4; - ChunkSection *section=chunk->sections[sec]; - if (!section) - { - y=(sec<<4)-1; //skip entire section - continue; - } - int yoffset=(y&0xf)<<8; - int data=section->data[(offset+yoffset)/2]; - if (x&1) data>>=4; - BlockInfo &block=blocks->getBlock(section->blocks[offset+yoffset],data&0xf); - if (block.alpha==0.0) continue; - //found block - name=block.getName(); - id=section->blocks[offset+yoffset]; - bd=data&0xf; - break; - } - BiomeInfo &bi=biomes->getBiome(chunk->biomes[(x&0xf)+(z&0xf)*16]); - biome=bi.name; - - foreach (const QSharedPointer& item, getItems(x, y, z)) - { - entityIds[item->display()]++; - } - } - - QString entityStr; - if (!entityIds.empty()) - { - QStringList entities; - QMap::iterator it, itEnd = entityIds.end(); - for (it = entityIds.begin(); it != itEnd; ++it) - { - if (it.value() > 1) - { - entities << it.key() + ":" + QString::number(it.value()); - } - else - { - entities << it.key(); - } - } - entityStr = entities.join(", "); - } - - emit hoverTextChanged(tr("X:%1 Z:%2 - %3 - %4 (%5:%6) %7") - .arg(x) - .arg(z) - .arg(biome) - .arg(name) - .arg(id) - .arg(bd) - .arg(entityStr)); +void MapView::getToolTip(int x, int z) { + int cx = floor(x / 16.0); + int cz = floor(z / 16.0); + Chunk *chunk = cache.fetch(cx, cz); + int offset = (x & 0xf) + (z & 0xf) * 16; + int id = 0, bd = 0; + + QString name = "Unknown"; + QString biome = "Unknown Biome"; + QMap entityIds; + + if (chunk) { + int top = qMin(depth, chunk->highest); + int y = 0; + for (y = top; y >= 0; y--) { + int sec = y >> 4; + ChunkSection *section = chunk->sections[sec]; + if (!section) { + y = (sec << 4) - 1; // skip entire section + continue; + } + int yoffset = (y & 0xf) << 8; + int data = section->data[(offset + yoffset) / 2]; + if (x & 1) data >>= 4; + auto &block = blocks->getBlock(section->blocks[offset + yoffset], + data & 0xf); + if (block.alpha == 0.0) continue; + // found block + name = block.getName(); + id = section->blocks[offset + yoffset]; + bd = data & 0xf; + break; + } + auto &bi = biomes->getBiome(chunk->biomes[(x & 0xf) + (z & 0xf) * 16]); + biome = bi.name; + + for (auto &item : getItems(x, y, z)) { + entityIds[item->display()]++; + } + } + + QString entityStr; + if (!entityIds.empty()) { + QStringList entities; + QMap::iterator it, itEnd = entityIds.end(); + for (it = entityIds.begin(); it != itEnd; ++it) { + if (it.value() > 1) { + entities << it.key() + ":" + QString::number(it.value()); + } else { + entities << it.key(); + } + } + entityStr = entities.join(", "); + } + + emit hoverTextChanged(tr("X:%1 Z:%2 - %3 - %4 (%5:%6) %7") + .arg(x) + .arg(z) + .arg(biome) + .arg(name) + .arg(id) + .arg(bd) + .arg(entityStr)); } -void MapView::addOverlayItem(QSharedPointer item) -{ - overlayItems[item->type()].push_back(item); +void MapView::addOverlayItem(QSharedPointer item) { + overlayItems[item->type()].push_back(item); } -void MapView::showOverlayItemTypes(const QSet& itemTypes) -{ - overlayItemTypes = itemTypes; +void MapView::showOverlayItemTypes(const QSet& itemTypes) { + overlayItemTypes = itemTypes; } -int MapView::getY(int x, int z) -{ - int cx=floor(x/16.0); - int cz=floor(z/16.0); - Chunk *chunk=cache.fetch(cx,cz); - return chunk ? chunk->depth[(x&0xf)+(z&0xf)*16] : -1; +int MapView::getY(int x, int z) { + int cx = floor(x / 16.0); + int cz = floor(z / 16.0); + Chunk *chunk = cache.fetch(cx, cz); + return chunk ? chunk->depth[(x & 0xf) + (z & 0xf) * 16] : -1; } -QList > MapView::getItems(int x, int y, int z) -{ - QList > ret; - int cx=floor(x/16.0); - int cz=floor(z/16.0); - Chunk *chunk=cache.fetch(cx,cz); - - if (chunk) - { - double invzoom = 10.0/zoom; - foreach (const QString& type, overlayItemTypes) - { - //generated structures - foreach (const QSharedPointer& item, overlayItems[type]) - { - double ymin = 0; - double ymax = depth; - //TODO: handle depth? - if (item->intersects( - OverlayItem::Point(x, ymin, z), - OverlayItem::Point(x, ymax, z))) - { - ret.append(item); - } - } - - //entities - QPair itemRange = chunk->entities.equal_range(type); - for(Chunk::EntityMap::iterator itItem = itemRange.first; itItem != itemRange.second; ++itItem) - { - double ymin = y - 4; - double ymax = depth + 4; - - if ((*itItem)->intersects( - OverlayItem::Point(x - invzoom/2, ymin, z - invzoom/2), - OverlayItem::Point(x + 1 + invzoom/2, ymax, z + 1 + invzoom/2))) - { - ret.append(*itItem); - } - } - } - } - return ret; +QList> MapView::getItems(int x, int y, int z) { + QList> ret; + int cx = floor(x / 16.0); + int cz = floor(z / 16.0); + Chunk *chunk = cache.fetch(cx, cz); + + if (chunk) { + double invzoom = 10.0 / zoom; + for (auto &type : overlayItemTypes) { + // generated structures + for (auto &item : overlayItems[type]) { + double ymin = 0; + double ymax = depth; + if (item->intersects(OverlayItem::Point(x, ymin, z), + OverlayItem::Point(x, ymax, z))) { + ret.append(item); + } + } + + // entities + auto itemRange = chunk->entities.equal_range(type); + for (auto itItem = itemRange.first; itItem != itemRange.second; + ++itItem) { + double ymin = y - 4; + double ymax = depth + 4; + + if ((*itItem)->intersects( + OverlayItem::Point(x - invzoom/2, ymin, z - invzoom/2), + OverlayItem::Point(x + 1 + invzoom/2, ymax, z + 1 + invzoom/2))) { + ret.append(*itItem); + } + } + } + } + return ret; } diff --git a/mapview.h b/mapview.h index 6d9ded58..fb8dd955 100644 --- a/mapview.h +++ b/mapview.h @@ -1,120 +1,90 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __MAPVIEW_H__ -#define __MAPVIEW_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef MAPVIEW_H_ +#define MAPVIEW_H_ #include #include -#include "chunkcache.h" +#include "./chunkcache.h" class DefinitionManager; class BiomeIdentifier; class BlockIdentifier; class OverlayItem; -class MapView : public QWidget -{ - Q_OBJECT -public: - - /// Values for the individual flags - enum - { - flgLighting = 1, - flgMobSpawn = 2, - flgCaveMode = 4, - flgDepthShading = 8, - flgShowEntities = 16 - }; - - - MapView(QWidget *parent=0); - - QSize minimumSizeHint() const; - QSize sizeHint() const; - - void attach(DefinitionManager *); - - void setLocation(double x,double z); - void setDimension(QString path,int scale); - void setFlags(int flags); - void addOverlayItem(QSharedPointer item); - void showOverlayItemTypes(const QSet& itemTypes); - - // public for saving the png - void renderChunk(Chunk *chunk); - QString getWorldPath(); - - -public slots: - void setDepth(int depth); - void chunkUpdated(int x,int z); - void redraw(); - - /// Clears the cache and redraws, causing all chunks to be re-loaded; but keeps the viewport - void clearCache(); - -signals: - void hoverTextChanged(QString text); - void demandDepthChange(int value); - void showProperties(QVariant properties); - void addOverlayItemType(QString type, QColor color); - -protected: - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *); - void mouseDoubleClickEvent(QMouseEvent*event); - void wheelEvent(QWheelEvent *event); - void keyPressEvent(QKeyEvent *event); - void resizeEvent(QResizeEvent *); - void paintEvent(QPaintEvent *); - -private: - - void drawChunk(int x,int z); - void getToolTip(int x,int z); - int getY(int x, int z); - QList > getItems(int x, int y, int z); - - int depth; - double x,z; - int scale; - double zoom; - int flags; - ChunkCache cache; - QImage image; - DefinitionManager *dm; - BlockIdentifier *blocks; - BiomeIdentifier *biomes; - uchar placeholder[16*16*4]; // no chunk found placeholder - QSet overlayItemTypes; - QMap > > overlayItems; +class MapView : public QWidget { + Q_OBJECT + + public: + /// Values for the individual flags + enum { + flgLighting = 1, + flgMobSpawn = 2, + flgCaveMode = 4, + flgDepthShading = 8, + flgShowEntities = 16 + }; + + explicit MapView(QWidget *parent = 0); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + + void attach(DefinitionManager *dm); + + void setLocation(double x, double z); + void setDimension(QString path, int scale); + void setFlags(int flags); + void addOverlayItem(QSharedPointer item); + void showOverlayItemTypes(const QSet& itemTypes); + + // public for saving the png + void renderChunk(Chunk *chunk); + QString getWorldPath(); + + + public slots: + void setDepth(int depth); + void chunkUpdated(int x, int z); + void redraw(); + + // Clears the cache and redraws, causing all chunks to be re-loaded; + // but keeps the viewport + void clearCache(); + + signals: + void hoverTextChanged(QString text); + void demandDepthChange(int value); + void showProperties(QVariant properties); + void addOverlayItemType(QString type, QColor color); + + protected: + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + void keyPressEvent(QKeyEvent *event); + void resizeEvent(QResizeEvent *event); + void paintEvent(QPaintEvent *event); + + private: + void drawChunk(int x, int z); + void getToolTip(int x, int z); + int getY(int x, int z); + QList> getItems(int x, int y, int z); + + int depth; + double x, z; + int scale; + double zoom; + int flags; + ChunkCache cache; + QImage image; + DefinitionManager *dm; + BlockIdentifier *blocks; + BiomeIdentifier *biomes; + uchar placeholder[16 * 16 * 4]; // no chunk found placeholder + QSet overlayItemTypes; + QMap>> overlayItems; }; -#endif +#endif // MAPVIEW_H_ diff --git a/minutor.cpp b/minutor.cpp index acb72626..72d86329 100644 --- a/minutor.cpp +++ b/minutor.cpp @@ -1,31 +1,4 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - +/** Copyright (c) 2013, Sean Kasun */ #include #include #include @@ -37,741 +10,675 @@ #include #include #include -#include "minutor.h" -#include "mapview.h" -#include "labelledslider.h" -#include "nbt.h" -#include "json.h" -#include "definitionmanager.h" -#include "entityidentifier.h" -#include "settings.h" -#include "dimensionidentifier.h" -#include "worldsave.h" -#include "properties.h" -#include "generatedstructure.h" -#include "village.h" - -Minutor::Minutor(): - maxentitydistance(0) -{ - mapview = new MapView; - connect(mapview, SIGNAL(hoverTextChanged(QString)), - statusBar(), SLOT(showMessage(QString))); - connect(mapview, SIGNAL(showProperties(QVariant)), - this, SLOT(showProperties(QVariant))); - connect(mapview, SIGNAL(addOverlayItemType(QString,QColor)), - this, SLOT(addOverlayItemType(QString,QColor))); - dm=new DefinitionManager(this); - mapview->attach(dm); - connect(dm, SIGNAL(packsChanged()), - this, SLOT(updateDimensions())); - dimensions=dm->dimensionIdentifer(); - connect(dimensions, SIGNAL(dimensionChanged(DimensionInfo &)), - this, SLOT(viewDimension(DimensionInfo &))); - settings = new Settings(this); - connect(settings, SIGNAL(settingsUpdated()), - this, SLOT(rescanWorlds())); - - - if (settings->autoUpdate) - dm->autoUpdate(); - - createActions(); - createMenus(); - createStatusBar(); - - QBoxLayout *mainLayout; - if (settings->verticalDepth) - { - mainLayout = new QHBoxLayout; - depth = new LabelledSlider(Qt::Vertical); - mainLayout->addWidget(mapview,1); - mainLayout->addWidget(depth); - } else { - mainLayout = new QVBoxLayout; - depth = new LabelledSlider(Qt::Horizontal); - mainLayout->addWidget(depth); - mainLayout->addWidget(mapview,1); - } - depth->setValue(255); - mainLayout->setSpacing(0); - mainLayout->setContentsMargins(0,0,0,0); - - connect(depth, SIGNAL(valueChanged(int)), - mapview, SLOT(setDepth(int))); - connect(mapview, SIGNAL(demandDepthChange(int)), - depth, SLOT(changeValue(int))); - connect(this, SIGNAL(worldLoaded(bool)), - mapview, SLOT(setEnabled(bool))); - connect(this, SIGNAL(worldLoaded(bool)), - depth, SLOT(setEnabled(bool))); - - QWidget *central=new QWidget; - central->setLayout(mainLayout); - - setCentralWidget(central); - layout()->setContentsMargins(0,0,0,0); - - setWindowTitle(qApp->applicationName()); - - propView = new Properties(this); - - emit worldLoaded(false); -} - -void Minutor::openWorld() -{ - QAction *action=qobject_cast(sender()); - if (action) - loadWorld(action->data().toString()); -} - -void Minutor::open() -{ - QString dirName = QFileDialog::getExistingDirectory(this,tr("Open World")); - if (!dirName.isEmpty()) - { - QDir path(dirName); - if (!path.exists("level.dat")) - { - QMessageBox::warning(this, - tr("Couldn't open world"), - tr("%1 is not a valid Minecraft world").arg(dirName), - QMessageBox::Cancel); - return; - } - loadWorld(dirName); - } -} - -void Minutor::reload() -{ - loadWorld(currentWorld); -} - -void Minutor::save() -{ - QFileDialog fileDialog(this); - fileDialog.setDefaultSuffix("png"); - QString filename = fileDialog.getSaveFileName(this,tr("Save world as PNG"),QString(),"*.png"); - - savePNG( filename, false, false, false ); -} - -void Minutor::savePNG( QString filename, bool autoclose, bool regionChecker, bool chunkChecker ) -{ - progressAutoclose = autoclose; - if (!filename.isEmpty()) - { - WorldSave *ws=new WorldSave(filename,mapview,regionChecker,chunkChecker); - progress=new QProgressDialog(); - progress->setCancelButton(NULL); - progress->setMaximum(100); - progress->show(); - connect(ws, SIGNAL(progress(QString,double)), - this, SLOT(saveProgress(QString,double))); - connect(ws, SIGNAL(finished()), - this, SLOT(saveFinished())); - QThreadPool::globalInstance()->start(ws); - } -} - - -void Minutor::saveProgress(QString status, double value) -{ - progress->setValue(value*100); - progress->setLabelText(status); -} - -void Minutor::saveFinished() -{ - progress->hide(); - delete progress; - if (progressAutoclose) - this->close(); -} - -void Minutor::closeWorld() -{ - locations.clear(); - for (int i=0;iremoveAction(players[i]); - delete players[i]; - } - players.clear(); - jumpMenu->setEnabled(false); - dimensions->removeDimensions(dimMenu); - currentWorld=QString(); - emit worldLoaded(false); -} - -void Minutor::jumpToLocation() -{ - QAction *action=qobject_cast(sender()); - if (action) - { - Location loc=locations[action->data().toInt()]; - mapview->setLocation(loc.x,loc.z); - } -} - -void Minutor::jumpToXZ(int blockX, int blockZ) -{ - mapview->setLocation(blockX, blockZ); -} - -void Minutor::setViewLighting( bool value ) -{ - lightingAct->setChecked( value ); - toggleFlags(); -} - -void Minutor::setViewMobspawning( bool value ) -{ - mobSpawnAct->setChecked( value ); - toggleFlags(); -} - -void Minutor::setViewCavemode( bool value ) -{ - depthShadingAct->setChecked( value ); - toggleFlags(); -} - -void Minutor::setViewDepthshading( bool value ) -{ - lightingAct->setChecked( value ); - toggleFlags(); -} - -void Minutor::setDepth( int value ) -{ - depth->setValue( value ); -} - -void Minutor::toggleFlags() -{ - int flags = 0; - - if (lightingAct->isChecked()) flags |= MapView::flgLighting; - if (mobSpawnAct->isChecked()) flags |= MapView::flgMobSpawn; - if (caveModeAct->isChecked()) flags |= MapView::flgCaveMode; - if (depthShadingAct->isChecked()) flags |= MapView::flgDepthShading; - mapview->setFlags(flags); - - QSet overlayTypes; - foreach(QAction*action, structureActions) - { - if (action->isChecked()) - { - overlayTypes.insert(action->data().toMap()["type"].toString()); - } - } - foreach(QAction*action, entityActions) - { - if (action->isChecked()) - { - overlayTypes.insert(action->data().toString()); - } - } - mapview->showOverlayItemTypes(overlayTypes); - mapview->redraw(); -} - -void Minutor::viewDimension(DimensionInfo &dim) -{ - foreach(QAction*action, structureActions) - { - QString dimension = action->data().toMap()["dimension"].toString(); - if (dimension.isEmpty() || !dimension.compare(dim.name, Qt::CaseInsensitive)) - { - action->setVisible(true); - } - else - { - action->setVisible(false); - } - } - - mapview->setDimension(dim.path,dim.scale); -} - -void Minutor::about() -{ - QMessageBox::about(this,tr("About %1").arg(qApp->applicationName()), - tr("%1 v%2
\n" - "© Copyright %3, %4").arg(qApp->applicationName()) - .arg(qApp->applicationVersion()) - .arg(2013) - .arg(qApp->organizationName())); -} - -void Minutor::updateDimensions() -{ - dimensions->getDimensions(currentWorld,dimMenu,this); -} - -void Minutor::createActions() -{ - getWorldList(); - - // [File] - openAct = new QAction(tr("&Open..."),this); - openAct->setShortcut(tr("Ctrl+O")); - openAct->setStatusTip(tr("Open a world")); - connect(openAct, SIGNAL(triggered()), - this, SLOT(open())); - - reloadAct = new QAction(tr("&Reload"),this); - reloadAct->setShortcut(tr("F5")); - reloadAct->setStatusTip(tr("Reload current world")); - connect(reloadAct, SIGNAL(triggered()), - this, SLOT(reload())); - connect(this, SIGNAL(worldLoaded(bool)), - reloadAct, SLOT(setEnabled(bool))); - - saveAct = new QAction(tr("&Save PNG..."),this); - saveAct->setShortcut(tr("Ctrl+S")); - saveAct->setStatusTip(tr("Save as PNG")); - connect(saveAct, SIGNAL(triggered()), - this, SLOT(save())); - connect(this, SIGNAL(worldLoaded(bool)), - saveAct, SLOT(setEnabled(bool))); - - exitAct = new QAction(tr("E&xit"),this); - exitAct->setShortcut(tr("Ctrl+Q")); - exitAct->setStatusTip(tr("Exit %1").arg(qApp->applicationName())); - connect(exitAct, SIGNAL(triggered()), - this, SLOT(close())); - - // [View] - jumpSpawnAct = new QAction(tr("Jump to &Spawn"),this); - jumpSpawnAct->setShortcut(tr("F1")); - jumpSpawnAct->setStatusTip(tr("Jump to world spawn")); - connect(jumpSpawnAct, SIGNAL(triggered()), - this, SLOT(jumpToLocation())); - connect(this, SIGNAL(worldLoaded(bool)), - jumpSpawnAct, SLOT(setEnabled(bool))); - - - lightingAct = new QAction(tr("&Lighting"),this); - lightingAct->setCheckable(true); - lightingAct->setShortcut(tr("Ctrl+L")); - lightingAct->setStatusTip(tr("Toggle lighting on/off")); - connect(lightingAct, SIGNAL(triggered()), - this, SLOT(toggleFlags())); - - depthShadingAct = new QAction(tr("&Depth shading"), this); - depthShadingAct->setCheckable(true); - depthShadingAct->setShortcut(tr("Ctrl+D")); - depthShadingAct->setStatusTip(tr("Toggle shading based on relative depth")); - connect(depthShadingAct, SIGNAL(triggered()), - this, SLOT(toggleFlags())); - - mobSpawnAct = new QAction(tr("&Mob spawning"),this); - mobSpawnAct->setCheckable(true); - mobSpawnAct->setShortcut(tr("Ctrl+M")); - mobSpawnAct->setStatusTip(tr("Toggle show mob spawning on/off")); - connect(mobSpawnAct, SIGNAL(triggered()), - this, SLOT(toggleFlags())); - - caveModeAct = new QAction(tr("&Cave Mode"),this); - caveModeAct->setCheckable(true); - caveModeAct->setShortcut(tr("Ctrl+C")); - caveModeAct->setStatusTip(tr("Toggle cave mode on/off")); - connect(caveModeAct, SIGNAL(triggered()), - this, SLOT(toggleFlags())); - caveModeAct->setEnabled(false); - - // [View->Entity Overlay] - - manageDefsAct = new QAction(tr("Manage &Definitions..."),this); - manageDefsAct->setStatusTip(tr("Manage block and biome definitions")); - connect(manageDefsAct, SIGNAL(triggered()), - dm, SLOT(show())); - - refreshAct = new QAction(tr("Refresh"), this); - refreshAct->setShortcut(tr("F2")); - refreshAct->setStatusTip(tr("Reloads all chunks, but keeps the same position / dimension")); - connect(refreshAct, SIGNAL(triggered()), - mapview, SLOT(clearCache())); - - // [Help] - aboutAct = new QAction(tr("&About"),this); - aboutAct->setStatusTip(tr("About %1").arg(qApp->applicationName())); - connect(aboutAct, SIGNAL(triggered()), - this, SLOT(about())); - - settingsAct = new QAction(tr("Settings..."),this); - settingsAct->setStatusTip(tr("Change %1 Settings").arg(qApp->applicationName())); - connect(settingsAct, SIGNAL(triggered()), - settings, SLOT(show())); - - updatesAct = new QAction(tr("Check for updates..."),this); - updatesAct->setStatusTip(tr("Check for updated packs")); - connect(updatesAct, SIGNAL(triggered()), - dm, SLOT(checkForUpdates())); +#include "./minutor.h" +#include "./mapview.h" +#include "./labelledslider.h" +#include "./nbt.h" +#include "./json.h" +#include "./definitionmanager.h" +#include "./entityidentifier.h" +#include "./settings.h" +#include "./dimensionidentifier.h" +#include "./worldsave.h" +#include "./properties.h" +#include "./generatedstructure.h" +#include "./village.h" + +Minutor::Minutor(): maxentitydistance(0) { + mapview = new MapView; + connect(mapview, SIGNAL(hoverTextChanged(QString)), + statusBar(), SLOT(showMessage(QString))); + connect(mapview, SIGNAL(showProperties(QVariant)), + this, SLOT(showProperties(QVariant))); + connect(mapview, SIGNAL(addOverlayItemType(QString, QColor)), + this, SLOT(addOverlayItemType(QString, QColor))); + dm = new DefinitionManager(this); + mapview->attach(dm); + connect(dm, SIGNAL(packsChanged()), + this, SLOT(updateDimensions())); + dimensions = dm->dimensionIdentifer(); + connect(dimensions, SIGNAL(dimensionChanged(const DimensionInfo &)), + this, SLOT(viewDimension(const DimensionInfo &))); + settings = new Settings(this); + connect(settings, SIGNAL(settingsUpdated()), + this, SLOT(rescanWorlds())); + + + if (settings->autoUpdate) + dm->autoUpdate(); + + createActions(); + createMenus(); + createStatusBar(); + + QBoxLayout *mainLayout; + if (settings->verticalDepth) { + mainLayout = new QHBoxLayout; + depth = new LabelledSlider(Qt::Vertical); + mainLayout->addWidget(mapview, 1); + mainLayout->addWidget(depth); + } else { + mainLayout = new QVBoxLayout; + depth = new LabelledSlider(Qt::Horizontal); + mainLayout->addWidget(depth); + mainLayout->addWidget(mapview, 1); + } + depth->setValue(255); + mainLayout->setSpacing(0); + mainLayout->setContentsMargins(0, 0, 0, 0); + + connect(depth, SIGNAL(valueChanged(int)), + mapview, SLOT(setDepth(int))); + connect(mapview, SIGNAL(demandDepthChange(int)), + depth, SLOT(changeValue(int))); + connect(this, SIGNAL(worldLoaded(bool)), + mapview, SLOT(setEnabled(bool))); + connect(this, SIGNAL(worldLoaded(bool)), + depth, SLOT(setEnabled(bool))); + + QWidget *central = new QWidget; + central->setLayout(mainLayout); + + setCentralWidget(central); + layout()->setContentsMargins(0, 0, 0, 0); + + setWindowTitle(qApp->applicationName()); + + propView = new Properties(this); + + emit worldLoaded(false); +} + +void Minutor::openWorld() { + QAction *action = qobject_cast(sender()); + if (action) + loadWorld(action->data().toString()); +} + +void Minutor::open() { + QString dirName = QFileDialog::getExistingDirectory(this, tr("Open World")); + if (!dirName.isEmpty()) { + QDir path(dirName); + if (!path.exists("level.dat")) { + QMessageBox::warning(this, + tr("Couldn't open world"), + tr("%1 is not a valid Minecraft world") + .arg(dirName), + QMessageBox::Cancel); + return; + } + loadWorld(dirName); + } +} + +void Minutor::reload() { + loadWorld(currentWorld); +} + +void Minutor::save() { + QFileDialog fileDialog(this); + fileDialog.setDefaultSuffix("png"); + QString filename = fileDialog.getSaveFileName(this, tr("Save world as PNG"), + QString(), "*.png"); + + savePNG(filename, false, false, false); +} + +void Minutor::savePNG(QString filename, bool autoclose, bool regionChecker, + bool chunkChecker) { + progressAutoclose = autoclose; + if (!filename.isEmpty()) { + WorldSave *ws = new WorldSave(filename, mapview, regionChecker, + chunkChecker); + progress = new QProgressDialog(); + progress->setCancelButton(NULL); + progress->setMaximum(100); + progress->show(); + connect(ws, SIGNAL(progress(QString, double)), + this, SLOT(saveProgress(QString, double))); + connect(ws, SIGNAL(finished()), + this, SLOT(saveFinished())); + QThreadPool::globalInstance()->start(ws); + } +} + + +void Minutor::saveProgress(QString status, double value) { + progress->setValue(value*100); + progress->setLabelText(status); +} + +void Minutor::saveFinished() { + progress->hide(); + delete progress; + if (progressAutoclose) + this->close(); +} + +void Minutor::closeWorld() { + locations.clear(); + for (int i = 0; i < players.size(); i++) { + jumpMenu->removeAction(players[i]); + delete players[i]; + } + players.clear(); + jumpMenu->setEnabled(false); + dimensions->removeDimensions(dimMenu); + currentWorld = QString(); + emit worldLoaded(false); +} + +void Minutor::jumpToLocation() { + QAction *action = qobject_cast(sender()); + if (action) { + Location loc = locations[action->data().toInt()]; + mapview->setLocation(loc.x, loc.z); + } +} + +void Minutor::jumpToXZ(int blockX, int blockZ) { + mapview->setLocation(blockX, blockZ); +} + +void Minutor::setViewLighting(bool value) { + lightingAct->setChecked(value); + toggleFlags(); +} + +void Minutor::setViewMobspawning(bool value) { + mobSpawnAct->setChecked(value); + toggleFlags(); +} + +void Minutor::setViewCavemode(bool value) { + depthShadingAct->setChecked(value); + toggleFlags(); +} + +void Minutor::setViewDepthshading(bool value) { + lightingAct->setChecked(value); + toggleFlags(); +} + +void Minutor::setDepth(int value) { + depth->setValue(value); +} + +void Minutor::toggleFlags() { + int flags = 0; + + if (lightingAct->isChecked()) flags |= MapView::flgLighting; + if (mobSpawnAct->isChecked()) flags |= MapView::flgMobSpawn; + if (caveModeAct->isChecked()) flags |= MapView::flgCaveMode; + if (depthShadingAct->isChecked()) flags |= MapView::flgDepthShading; + mapview->setFlags(flags); + + QSet overlayTypes; + for (auto action : structureActions) { + if (action->isChecked()) { + overlayTypes.insert(action->data().toMap()["type"].toString()); + } + } + for (auto action : entityActions) { + if (action->isChecked()) { + overlayTypes.insert(action->data().toString()); + } + } + mapview->showOverlayItemTypes(overlayTypes); + mapview->redraw(); +} + +void Minutor::viewDimension(const DimensionInfo &dim) { + for (auto action : structureActions) { + QString dimension = action->data().toMap()["dimension"].toString(); + if (dimension.isEmpty() || + !dimension.compare(dim.name, Qt::CaseInsensitive)) { + action->setVisible(true); + } else { + action->setVisible(false); + } + } + mapview->setDimension(dim.path, dim.scale); +} + +void Minutor::about() { + QMessageBox::about(this, tr("About %1").arg(qApp->applicationName()), + tr("%1 v%2
\n" + "© Copyright %3, %4") + .arg(qApp->applicationName()) + .arg(qApp->applicationVersion()) + .arg(2016) + .arg(qApp->organizationName())); +} + +void Minutor::updateDimensions() { + dimensions->getDimensions(currentWorld, dimMenu, this); +} + +void Minutor::createActions() { + getWorldList(); + + // [File] + openAct = new QAction(tr("&Open..."), this); + openAct->setShortcut(tr("Ctrl+O")); + openAct->setStatusTip(tr("Open a world")); + connect(openAct, SIGNAL(triggered()), + this, SLOT(open())); + + reloadAct = new QAction(tr("&Reload"), this); + reloadAct->setShortcut(tr("F5")); + reloadAct->setStatusTip(tr("Reload current world")); + connect(reloadAct, SIGNAL(triggered()), + this, SLOT(reload())); + connect(this, SIGNAL(worldLoaded(bool)), + reloadAct, SLOT(setEnabled(bool))); + + saveAct = new QAction(tr("&Save PNG..."), this); + saveAct->setShortcut(tr("Ctrl+S")); + saveAct->setStatusTip(tr("Save as PNG")); + connect(saveAct, SIGNAL(triggered()), + this, SLOT(save())); + connect(this, SIGNAL(worldLoaded(bool)), + saveAct, SLOT(setEnabled(bool))); + + exitAct = new QAction(tr("E&xit"), this); + exitAct->setShortcut(tr("Ctrl+Q")); + exitAct->setStatusTip(tr("Exit %1").arg(qApp->applicationName())); + connect(exitAct, SIGNAL(triggered()), + this, SLOT(close())); + + // [View] + jumpSpawnAct = new QAction(tr("Jump to &Spawn"), this); + jumpSpawnAct->setShortcut(tr("F1")); + jumpSpawnAct->setStatusTip(tr("Jump to world spawn")); + connect(jumpSpawnAct, SIGNAL(triggered()), + this, SLOT(jumpToLocation())); + connect(this, SIGNAL(worldLoaded(bool)), + jumpSpawnAct, SLOT(setEnabled(bool))); + + + lightingAct = new QAction(tr("&Lighting"), this); + lightingAct->setCheckable(true); + lightingAct->setShortcut(tr("Ctrl+L")); + lightingAct->setStatusTip(tr("Toggle lighting on/off")); + connect(lightingAct, SIGNAL(triggered()), + this, SLOT(toggleFlags())); + + depthShadingAct = new QAction(tr("&Depth shading"), this); + depthShadingAct->setCheckable(true); + depthShadingAct->setShortcut(tr("Ctrl+D")); + depthShadingAct->setStatusTip(tr("Toggle shading based on relative depth")); + connect(depthShadingAct, SIGNAL(triggered()), + this, SLOT(toggleFlags())); + + mobSpawnAct = new QAction(tr("&Mob spawning"), this); + mobSpawnAct->setCheckable(true); + mobSpawnAct->setShortcut(tr("Ctrl+M")); + mobSpawnAct->setStatusTip(tr("Toggle show mob spawning on/off")); + connect(mobSpawnAct, SIGNAL(triggered()), + this, SLOT(toggleFlags())); + + caveModeAct = new QAction(tr("&Cave Mode"), this); + caveModeAct->setCheckable(true); + caveModeAct->setShortcut(tr("Ctrl+C")); + caveModeAct->setStatusTip(tr("Toggle cave mode on/off")); + connect(caveModeAct, SIGNAL(triggered()), + this, SLOT(toggleFlags())); + caveModeAct->setEnabled(false); + + // [View->Entity Overlay] + + manageDefsAct = new QAction(tr("Manage &Definitions..."), this); + manageDefsAct->setStatusTip(tr("Manage block and biome definitions")); + connect(manageDefsAct, SIGNAL(triggered()), + dm, SLOT(show())); + + refreshAct = new QAction(tr("Refresh"), this); + refreshAct->setShortcut(tr("F2")); + refreshAct->setStatusTip(tr("Reloads all chunks, " + "but keeps the same position / dimension")); + connect(refreshAct, SIGNAL(triggered()), + mapview, SLOT(clearCache())); + + // [Help] + aboutAct = new QAction(tr("&About"), this); + aboutAct->setStatusTip(tr("About %1").arg(qApp->applicationName())); + connect(aboutAct, SIGNAL(triggered()), + this, SLOT(about())); + + settingsAct = new QAction(tr("Settings..."), this); + settingsAct->setStatusTip(tr("Change %1 Settings") + .arg(qApp->applicationName())); + connect(settingsAct, SIGNAL(triggered()), + settings, SLOT(show())); + + updatesAct = new QAction(tr("Check for updates..."), this); + updatesAct->setStatusTip(tr("Check for updated packs")); + connect(updatesAct, SIGNAL(triggered()), + dm, SLOT(checkForUpdates())); } // actionName will be modified, a "&" is added -QKeySequence Minutor::generateUniqueKeyboardShortcut( QString & actionName ) -{ - //generate a unique keyboard shortcut - QKeySequence sequence; - // test all letters in given name - QString testName(actionName); - for (int ampPos=0; ampPosfindChildren()) - { - foreach (const QAction* a, m->actions()) - { - if (a->shortcut() == sequence) - { - sequence = QKeySequence(); - break; - } - } - if (sequence.isEmpty()) - break; // already eliminated this as a possbility - } - if (!sequence.isEmpty()) - {// not eliminated, this one is ok - actionName = testName.mid(0, ampPos) + "&" + testName.mid(ampPos); - break; - } - } - return sequence; -} - -void Minutor::populateEntityOverlayMenu() -{ - EntityIdentifier& ei = EntityIdentifier::Instance(); - EntityIdentifier::TcatList::const_iterator it = ei.getCategoryList().begin(); - for (; it != ei.getCategoryList().end(); ++it) - { - QString category = it->first; - QColor catcolor = it->second; - - QString actionName = category; - QKeySequence sequence = generateUniqueKeyboardShortcut(actionName); - - QPixmap pixmap(16,16); - QColor solidColor(catcolor); - solidColor.setAlpha(255); - pixmap.fill(solidColor); - - entityActions.push_back(new QAction(pixmap, actionName, this)); - entityActions.last()->setShortcut(sequence); - entityActions.last()->setStatusTip(QString(tr("Toggle viewing of %1").arg(category))); - entityActions.last()->setEnabled(true); - entityActions.last()->setData("Entity."+category); - entityActions.last()->setCheckable(true); - entityOverlayMenu->addAction(entityActions.last()); - connect(entityActions.last(), SIGNAL(triggered()), this, SLOT(toggleFlags())); - } -} - - -void Minutor::createMenus() -{ - // [File] - fileMenu=menuBar()->addMenu(tr("&File")); - worldMenu=fileMenu->addMenu(tr("&Open World")); - - worldMenu->addActions(worlds); - if (worlds.size()==0) //no worlds found - worldMenu->setEnabled(false); - - fileMenu->addAction(openAct); - fileMenu->addAction(reloadAct); - fileMenu->addSeparator(); - fileMenu->addAction(saveAct); - fileMenu->addSeparator(); - fileMenu->addAction(exitAct); - - // [View] - viewMenu=menuBar()->addMenu(tr("&View")); - viewMenu->addAction(jumpSpawnAct); - jumpMenu=viewMenu->addMenu(tr("&Jump to Player")); - jumpMenu->setEnabled(false); - dimMenu=viewMenu->addMenu(tr("&Dimension")); - dimMenu->setEnabled(false); - viewMenu->addSeparator(); - viewMenu->addAction(lightingAct); - viewMenu->addAction(mobSpawnAct); - viewMenu->addAction(caveModeAct); - viewMenu->addAction(depthShadingAct); - // [View->Overlay] - structureOverlayMenu = viewMenu->addMenu(tr("&Structure Overlay")); - entityOverlayMenu = viewMenu->addMenu(tr("&Entity Overlay")); - populateEntityOverlayMenu(); - - viewMenu->addSeparator(); - viewMenu->addAction(refreshAct); - viewMenu->addSeparator(); - viewMenu->addAction(manageDefsAct); - - menuBar()->addSeparator(); - - // [Help] - helpMenu=menuBar()->addMenu(tr("&Help")); - helpMenu->addAction(aboutAct); - helpMenu->addSeparator(); - helpMenu->addAction(settingsAct); - helpMenu->addAction(updatesAct); -} - -void Minutor::createStatusBar() -{ - statusBar()->showMessage(tr("Ready")); -} - -QString Minutor::getWorldName(QDir path) -{ - if (!path.exists("level.dat")) //no level.dat? no world - return QString(); - - NBT level(path.filePath("level.dat")); - return level.at("Data")->at("LevelName")->toString(); -} - - -void Minutor::getWorldList() -{ - QDir mc(settings->mcpath); - if (!mc.cd("saves")) - return; - - QDirIterator it(mc); - int key=1; - while (it.hasNext()) - { - it.next(); - if (it.fileInfo().isDir()) - { - QString name=getWorldName(it.filePath()); - if (!name.isNull()) - { - QAction *w=new QAction(this); - w->setText(name); - w->setData(it.filePath()); - if (key<10) - { - w->setShortcut("Ctrl+"+QString::number(key)); - key++; - } - connect(w, SIGNAL(triggered()), - this, SLOT(openWorld())); - worlds.append(w); - } - } - } -} - -void Minutor::loadWorld(QDir path) -{ - closeWorld(); //just in case - currentWorld=path; - - NBT level(path.filePath("level.dat")); - - Tag *data=level.at("Data"); - //add level name to window title - setWindowTitle(qApp->applicationName()+" - "+data->at("LevelName")->toString()); - //save world spawn - jumpSpawnAct->setData(locations.count()); - locations.append(Location(data->at("SpawnX")->toDouble(), - data->at("SpawnZ")->toDouble())); - //show saved players - if (path.cd("playerdata") || path.cd("players")) - { - QDirIterator it(path); - bool hasPlayers=false; - while (it.hasNext()) - { - it.next(); - if (it.fileInfo().isFile()) - { - hasPlayers=true; - NBT player(it.filePath()); - Tag *pos=player.at("Pos"); - double posX=pos->at(0)->toDouble(); - double posZ=pos->at(2)->toDouble(); - Tag *dim=player.at("Dimension"); - if (dim && (dim->toInt() == -1)) - { - posX *= 8; - posZ *= 8; - } - QString playerName = it.fileInfo().completeBaseName(); - QRegExp id("[0-9a-z]{8,8}\\-[0-9a-z]{4,4}\\-[0-9a-z]{4,4}\\-[0-9a-z]{4,4}\\-[0-9a-z]{12,12}"); - if (id.exactMatch(playerName)) - { - playerName = QString("Player %1").arg(players.length()); - } - - QAction *p=new QAction(this); - p->setText(playerName); - p->setData(locations.count()); - locations.append(Location(posX, posZ)); - connect(p, SIGNAL(triggered()), - this, SLOT(jumpToLocation())); - players.append(p); - if (player.has("SpawnX")) //player has a bed - { - p=new QAction(this); - - - p->setText(playerName+"'s Bed"); - p->setData(locations.count()); - locations.append(Location(player.at("SpawnX")->toDouble(), - player.at("SpawnZ")->toDouble())); - connect(p, SIGNAL(triggered()), - this, SLOT(jumpToLocation())); - players.append(p); - } - } - } - jumpMenu->addActions(players); - jumpMenu->setEnabled(hasPlayers); - path.cdUp(); - } - - if (path.cd("data")) - { - loadStructures(path); - path.cdUp(); - } - - //show dimensions - dimensions->getDimensions(path,dimMenu,this); - emit worldLoaded(true); - mapview->setLocation(locations.first().x,locations.first().z); - toggleFlags(); -} - -void Minutor::rescanWorlds() -{ - worlds.clear(); - getWorldList(); - worldMenu->clear(); - worldMenu->addActions(worlds); - worldMenu->setEnabled(worlds.count()!=0); - //we don't care about the auto-update toggle, since that only happens - //on startup anyway. -} - -void Minutor::addOverlayItemType(QString type, QColor color, QString dimension) -{ - if (!overlayItemTypes.contains(type)) - { - overlayItemTypes.insert(type); - QList path = type.split('.'); - QList::const_iterator pathIt, nextIt, endPathIt = path.end(); - nextIt = path.begin(); - nextIt++; // skip first part - pathIt = nextIt++; - QMenu* cur = structureOverlayMenu; - - //generate a nested menu structure to match the path - while(nextIt != endPathIt) - { - QList results = cur->findChildren(*pathIt, Qt::FindDirectChildrenOnly); - if (results.empty()) - { - cur = cur->addMenu("&" + *pathIt); - cur->setObjectName(*pathIt); - } - else - { - cur = results.front(); - } - pathIt = ++nextIt; - } - - //generate a unique keyboard shortcut - QString actionName = path.last(); - QKeySequence sequence = generateUniqueKeyboardShortcut(actionName); - - QPixmap pixmap(16,16); - QColor solidColor(color); - solidColor.setAlpha(255); - pixmap.fill(solidColor); - - QMap entityData; - entityData["type"] = type; - entityData["dimension"] = dimension; - - structureActions.push_back(new QAction(pixmap, actionName, this)); - structureActions.last()->setShortcut(sequence); - structureActions.last()->setStatusTip(QString(tr("Toggle viewing of %1").arg(type))); - structureActions.last()->setEnabled(true); - structureActions.last()->setData(entityData); - structureActions.last()->setCheckable(true); - cur->addAction(structureActions.last()); - connect(structureActions.last(), SIGNAL(triggered()), this, SLOT(toggleFlags())); - } -} - -void Minutor::addOverlayItem(QSharedPointer item) -{ - addOverlayItemType(item->type(), item->color(), item->dimension()); - - //TODO: don't guess this - maxentitydistance = 50; - - const OverlayItem::Point& p = item->midpoint(); - overlayItems[item->type()].insertMulti(QPair(p.x, p.z), item); - - mapview->addOverlayItem(item); -} - -void Minutor::showProperties(QVariant props) -{ - if (!props.isNull()) - { - propView->DisplayProperties(props); - propView->show(); - } -} - -void Minutor::loadStructures(const QDir& dataPath) -{ - //attempt to parse all of the files in the data directory, looking for - //generated structures - foreach(const QString& fileName, dataPath.entryList(QStringList() << "*.dat")) - { - NBT file(dataPath.filePath(fileName)); - Tag* data = file.at("data"); - - //TODO: factory? - QList > items = GeneratedStructure::tryParse(data); - - foreach (const QSharedPointer& item, items) - { - addOverlayItem(item); - } - - if (items.isEmpty()) - { - //try parsing it as a village.dat file - int underidx = fileName.lastIndexOf('_'); - int dotidx = fileName.lastIndexOf('.'); - QString dimension = "overworld"; - if (underidx > 0) - { - dimension = fileName.mid(underidx + 1, dotidx - underidx - 1); - } - items = Village::tryParse(data, dimension); - - foreach (const QSharedPointer& item, items) - { - addOverlayItem(item); - } - } - } +QKeySequence Minutor::generateUniqueKeyboardShortcut(QString *actionName) { + // generate a unique keyboard shortcut + QKeySequence sequence; + // test all letters in given name + QString testName(*actionName); + for (int ampPos=0; ampPos < testName.length(); ++ampPos) { + QChar c = testName[ampPos]; + sequence = QKeySequence(QString("Ctrl+")+c); + for (auto m : menuBar()->findChildren()) { + for (auto a : m->actions()) { + if (a->shortcut() == sequence) { + sequence = QKeySequence(); + break; + } + } + if (sequence.isEmpty()) + break; // already eliminated this as a possbility + } + if (!sequence.isEmpty()) { // not eliminated, this one is ok + *actionName = testName.mid(0, ampPos) + "&" + testName.mid(ampPos); + break; + } + } + return sequence; +} + +void Minutor::populateEntityOverlayMenu() { + EntityIdentifier &ei = EntityIdentifier::Instance(); + for (auto it = ei.getCategoryList().constBegin(); + it != ei.getCategoryList().constEnd(); it++) { + QString category = it->first; + QColor catcolor = it->second; + + QString actionName = category; + QKeySequence sequence = generateUniqueKeyboardShortcut(&actionName); + + QPixmap pixmap(16, 16); + QColor solidColor(catcolor); + solidColor.setAlpha(255); + pixmap.fill(solidColor); + + entityActions.push_back(new QAction(pixmap, actionName, this)); + entityActions.last()->setShortcut(sequence); + entityActions.last()->setStatusTip(tr("Toggle viewing of %1") + .arg(category)); + entityActions.last()->setEnabled(true); + entityActions.last()->setData("Entity."+category); + entityActions.last()->setCheckable(true); + entityOverlayMenu->addAction(entityActions.last()); + connect(entityActions.last(), SIGNAL(triggered()), + this, SLOT(toggleFlags())); + } +} + + +void Minutor::createMenus() { + // [File] + fileMenu = menuBar()->addMenu(tr("&File")); + worldMenu = fileMenu->addMenu(tr("&Open World")); + + worldMenu->addActions(worlds); + if (worlds.size() == 0) // no worlds found + worldMenu->setEnabled(false); + + fileMenu->addAction(openAct); + fileMenu->addAction(reloadAct); + fileMenu->addSeparator(); + fileMenu->addAction(saveAct); + fileMenu->addSeparator(); + fileMenu->addAction(exitAct); + + // [View] + viewMenu = menuBar()->addMenu(tr("&View")); + viewMenu->addAction(jumpSpawnAct); + jumpMenu = viewMenu->addMenu(tr("&Jump to Player")); + jumpMenu->setEnabled(false); + dimMenu = viewMenu->addMenu(tr("&Dimension")); + dimMenu->setEnabled(false); + viewMenu->addSeparator(); + viewMenu->addAction(lightingAct); + viewMenu->addAction(mobSpawnAct); + viewMenu->addAction(caveModeAct); + viewMenu->addAction(depthShadingAct); + // [View->Overlay] + structureOverlayMenu = viewMenu->addMenu(tr("&Structure Overlay")); + entityOverlayMenu = viewMenu->addMenu(tr("&Entity Overlay")); + populateEntityOverlayMenu(); + + viewMenu->addSeparator(); + viewMenu->addAction(refreshAct); + viewMenu->addSeparator(); + viewMenu->addAction(manageDefsAct); + + menuBar()->addSeparator(); + + // [Help] + helpMenu = menuBar()->addMenu(tr("&Help")); + helpMenu->addAction(aboutAct); + helpMenu->addSeparator(); + helpMenu->addAction(settingsAct); + helpMenu->addAction(updatesAct); +} + +void Minutor::createStatusBar() { + statusBar()->showMessage(tr("Ready")); +} + +QString Minutor::getWorldName(QDir path) { + if (!path.exists("level.dat")) // no level.dat? no world + return QString(); + + NBT level(path.filePath("level.dat")); + return level.at("Data")->at("LevelName")->toString(); +} + + +void Minutor::getWorldList() { + QDir mc(settings->mcpath); + if (!mc.cd("saves")) + return; + + QDirIterator it(mc); + int key = 1; + while (it.hasNext()) { + it.next(); + if (it.fileInfo().isDir()) { + QString name = getWorldName(it.filePath()); + if (!name.isNull()) { + QAction *w = new QAction(this); + w->setText(name); + w->setData(it.filePath()); + if (key < 10) { + w->setShortcut("Ctrl+"+QString::number(key)); + key++; + } + connect(w, SIGNAL(triggered()), + this, SLOT(openWorld())); + worlds.append(w); + } + } + } +} + +void Minutor::loadWorld(QDir path) { + closeWorld(); // just in case + currentWorld = path; + + NBT level(path.filePath("level.dat")); + + auto data = level.at("Data"); + // add level name to window title + setWindowTitle(qApp->applicationName() + " - " + + data->at("LevelName")->toString()); + // save world spawn + jumpSpawnAct->setData(locations.count()); + locations.append(Location(data->at("SpawnX")->toDouble(), + data->at("SpawnZ")->toDouble())); + // show saved players + if (path.cd("playerdata") || path.cd("players")) { + QDirIterator it(path); + bool hasPlayers = false; + while (it.hasNext()) { + it.next(); + if (it.fileInfo().isFile()) { + hasPlayers = true; + NBT player(it.filePath()); + auto pos = player.at("Pos"); + double posX = pos->at(0)->toDouble(); + double posZ = pos->at(2)->toDouble(); + auto dim = player.at("Dimension"); + if (dim && (dim->toInt() == -1)) { + posX *= 8; + posZ *= 8; + } + QString playerName = it.fileInfo().completeBaseName(); + QRegExp id("[0-9a-z]{8,8}\\-[0-9a-z]{4,4}\\-[0-9a-z]{4,4}" + "\\-[0-9a-z]{4,4}\\-[0-9a-z]{12,12}"); + if (id.exactMatch(playerName)) { + playerName = QString("Player %1").arg(players.length()); + } + + QAction *p = new QAction(this); + p->setText(playerName); + p->setData(locations.count()); + locations.append(Location(posX, posZ)); + connect(p, SIGNAL(triggered()), + this, SLOT(jumpToLocation())); + players.append(p); + if (player.has("SpawnX")) { // player has a bed + p = new QAction(this); + p->setText(playerName+"'s Bed"); + p->setData(locations.count()); + locations.append(Location(player.at("SpawnX")->toDouble(), + player.at("SpawnZ")->toDouble())); + connect(p, SIGNAL(triggered()), + this, SLOT(jumpToLocation())); + players.append(p); + } + } + } + jumpMenu->addActions(players); + jumpMenu->setEnabled(hasPlayers); + path.cdUp(); + } + + if (path.cd("data")) { + loadStructures(path); + path.cdUp(); + } + + // show dimensions + dimensions->getDimensions(path, dimMenu, this); + emit worldLoaded(true); + mapview->setLocation(locations.first().x, locations.first().z); + toggleFlags(); +} + +void Minutor::rescanWorlds() { + worlds.clear(); + getWorldList(); + worldMenu->clear(); + worldMenu->addActions(worlds); + worldMenu->setEnabled(worlds.count() != 0); + // we don't care about the auto-update toggle, since that only happens + // on startup anyway. +} + +void Minutor::addOverlayItemType(QString type, QColor color, + QString dimension) { + if (!overlayItemTypes.contains(type)) { + overlayItemTypes.insert(type); + QList path = type.split('.'); + QList::const_iterator pathIt, nextIt, endPathIt = path.end(); + nextIt = path.begin(); + nextIt++; // skip first part + pathIt = nextIt++; + QMenu* cur = structureOverlayMenu; + + // generate a nested menu structure to match the path + while (nextIt != endPathIt) { + QList results = + cur->findChildren(*pathIt, Qt::FindDirectChildrenOnly); + if (results.empty()) { + cur = cur->addMenu("&" + *pathIt); + cur->setObjectName(*pathIt); + } else { + cur = results.front(); + } + pathIt = ++nextIt; + } + + // generate a unique keyboard shortcut + QString actionName = path.last(); + QKeySequence sequence = generateUniqueKeyboardShortcut(&actionName); + + QPixmap pixmap(16, 16); + QColor solidColor(color); + solidColor.setAlpha(255); + pixmap.fill(solidColor); + + QMap entityData; + entityData["type"] = type; + entityData["dimension"] = dimension; + + structureActions.push_back(new QAction(pixmap, actionName, this)); + structureActions.last()->setShortcut(sequence); + structureActions.last()->setStatusTip(tr("Toggle viewing of %1") + .arg(type)); + structureActions.last()->setEnabled(true); + structureActions.last()->setData(entityData); + structureActions.last()->setCheckable(true); + cur->addAction(structureActions.last()); + connect(structureActions.last(), SIGNAL(triggered()), + this, SLOT(toggleFlags())); + } +} + +void Minutor::addOverlayItem(QSharedPointer item) { + addOverlayItemType(item->type(), item->color(), item->dimension()); + + maxentitydistance = 50; + + const OverlayItem::Point& p = item->midpoint(); + overlayItems[item->type()].insertMulti(QPair(p.x, p.z), item); + + mapview->addOverlayItem(item); +} + +void Minutor::showProperties(QVariant props) { + if (!props.isNull()) { + propView->DisplayProperties(props); + propView->show(); + } +} + +void Minutor::loadStructures(const QDir &dataPath) { + // attempt to parse all of the files in the data directory, looking for + // generated structures + for (auto &fileName : dataPath.entryList(QStringList() << "*.dat")) { + NBT file(dataPath.filePath(fileName)); + auto data = file.at("data"); + + auto items = GeneratedStructure::tryParse(data); + for (auto &item : items) { + addOverlayItem(item); + } + + if (items.isEmpty()) { + // try parsing it as a village.dat file + int underidx = fileName.lastIndexOf('_'); + int dotidx = fileName.lastIndexOf('.'); + QString dimension = "overworld"; + if (underidx > 0) { + dimension = fileName.mid(underidx + 1, dotidx - underidx - 1); + } + items = Village::tryParse(data, dimension); + + for (auto &item : items) { + addOverlayItem(item); + } + } + } } diff --git a/minutor.h b/minutor.h index 63160e04..6ba72d0c 100644 --- a/minutor.h +++ b/minutor.h @@ -1,33 +1,6 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __MINUTOR_H__ -#define __MINUTOR_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef MINUTOR_H_ +#define MINUTOR_H_ #include #include @@ -49,103 +22,102 @@ class WorldSave; class Properties; class OverlayItem; -class Location -{ -public: - Location(double x,double z):x(x),z(z) {} - double x,z; +class Location { + public: + Location(double x, double z) : x(x), z(z) {} + double x, z; }; -class Minutor : public QMainWindow -{ - Q_OBJECT -public: - Minutor(); - - void loadWorld( QDir path ); - - void savePNG( QString filename, bool autoclose=false, bool regionChecker=false, bool chunkChecker=false ); - - void jumpToXZ( int blockX, int blockZ ); // jumps to the block coords provided - - void setViewLighting( bool value ); // set View->Ligthing - void setViewMobspawning( bool value ); // set View->Mob_Spawning - void setViewCavemode( bool value ); // set View->Cave_Mode - void setViewDepthshading( bool value ); // set View->Depth_Shading - - void setDepth( int value ); // set Depth-Slider - -private slots: - void openWorld(); - void open(); - void closeWorld(); - void reload(); - void save(); - - void jumpToLocation(); - void viewDimension(DimensionInfo &dim); - void toggleFlags(); - - void about(); - - void updateDimensions(); - void rescanWorlds(); - void saveProgress(QString status,double value); - void saveFinished(); - void addOverlayItem(QSharedPointer item); - void addOverlayItemType(QString type, QColor color, QString dimension = ""); - void showProperties(QVariant props); - -signals: - void worldLoaded(bool isLoaded); - -private: - void createActions(); - void createMenus(); - void createStatusBar(); - void loadStructures(const QDir &dataPath); - void populateEntityOverlayMenu(); - QKeySequence generateUniqueKeyboardShortcut( QString & actionName ); - - QString getWorldName(QDir path); - void getWorldList(); - - MapView *mapview; - LabelledSlider *depth; - QProgressDialog *progress; - bool progressAutoclose; - - QMenu *fileMenu, *worldMenu; - QMenu *viewMenu, *jumpMenu, *dimMenu; - QMenu *helpMenu; - QMenu *structureOverlayMenu, *entityOverlayMenu; - - QListworlds; - QAction *openAct, *reloadAct, *saveAct, *exitAct; - QAction *jumpSpawnAct; - QListplayers; - QAction *lightingAct, *mobSpawnAct, *caveModeAct, *depthShadingAct; - QAction *manageDefsAct; - QAction *refreshAct; - QAction *aboutAct; - QAction *settingsAct; - QAction *updatesAct; - QList structureActions; - QList entityActions; - - //loaded world data - QList locations; - DefinitionManager *dm; - Settings *settings; - DimensionIdentifier *dimensions; - QDir currentWorld; - - // type x z - typedef QMap, QSharedPointer > > OverlayMap; - OverlayMap overlayItems; - QSet overlayItemTypes; - int maxentitydistance; - Properties * propView; +class Minutor : public QMainWindow { + Q_OBJECT + + public: + Minutor(); + + void loadWorld(QDir path); + + void savePNG(QString filename, bool autoclose = false, + bool regionChecker = false, bool chunkChecker = false); + + void jumpToXZ(int blockX, int blockZ); // jumps to the block coords + void setViewLighting(bool value); // set View->Ligthing + void setViewMobspawning(bool value); // set View->Mob_Spawning + void setViewCavemode(bool value); // set View->Cave_Mode + void setViewDepthshading(bool value); // set View->Depth_Shading + void setDepth(int value); // set Depth-Slider + + private slots: + void openWorld(); + void open(); + void closeWorld(); + void reload(); + void save(); + + void jumpToLocation(); + void viewDimension(const DimensionInfo &dim); + void toggleFlags(); + + void about(); + + void updateDimensions(); + void rescanWorlds(); + void saveProgress(QString status, double value); + void saveFinished(); + void addOverlayItem(QSharedPointer item); + void addOverlayItemType(QString type, QColor color, QString dimension = ""); + void showProperties(QVariant props); + + signals: + void worldLoaded(bool isLoaded); + + private: + void createActions(); + void createMenus(); + void createStatusBar(); + void loadStructures(const QDir &dataPath); + void populateEntityOverlayMenu(); + QKeySequence generateUniqueKeyboardShortcut(QString *actionName); + + QString getWorldName(QDir path); + void getWorldList(); + + MapView *mapview; + LabelledSlider *depth; + QProgressDialog *progress; + bool progressAutoclose; + + QMenu *fileMenu, *worldMenu; + QMenu *viewMenu, *jumpMenu, *dimMenu; + QMenu *helpMenu; + QMenu *structureOverlayMenu, *entityOverlayMenu; + + QListworlds; + QAction *openAct, *reloadAct, *saveAct, *exitAct; + QAction *jumpSpawnAct; + QListplayers; + QAction *lightingAct, *mobSpawnAct, *caveModeAct, *depthShadingAct; + QAction *manageDefsAct; + QAction *refreshAct; + QAction *aboutAct; + QAction *settingsAct; + QAction *updatesAct; + QList structureActions; + QList entityActions; + + // loaded world data + QList locations; + DefinitionManager *dm; + Settings *settings; + DimensionIdentifier *dimensions; + QDir currentWorld; + + // type x z + typedef QMap, + QSharedPointer>> OverlayMap; + OverlayMap overlayItems; + QSet overlayItemTypes; + int maxentitydistance; + Properties * propView; }; -#endif +#endif // MINUTOR_H_ diff --git a/minutor.pro b/minutor.pro index 87a7f4e5..88a29244 100644 --- a/minutor.pro +++ b/minutor.pro @@ -2,6 +2,7 @@ TEMPLATE = app TARGET = minutor DEPENDPATH += . INCLUDEPATH += . +CONFIG += c++11 QT += widgets network QMAKE_INFO_PLIST = minutor.plist unix:LIBS += -lz diff --git a/minutor.wxs b/minutor.wxs index 8c05088f..0b60000a 100644 --- a/minutor.wxs +++ b/minutor.wxs @@ -1,6 +1,6 @@ - + @@ -52,4 +52,4 @@ INSTALLDIR - \ No newline at end of file + diff --git a/nbt.cpp b/nbt.cpp index dfd5a614..bbce7fd9 100644 --- a/nbt.cpp +++ b/nbt.cpp @@ -1,602 +1,474 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - +/** Copyright (c) 2013, Sean Kasun */ #include #include #include #include -#include "nbt.h" +#include "./nbt.h" #include "zlib/zlib.h" // this handles decoding the gzipped level.dat -NBT::NBT(const QString level) -{ - root=&NBT::Null; //just in case we die - - QFile f(level); - f.open(QIODevice::ReadOnly); - QByteArray data=f.readAll(); - f.close(); - - QByteArray nbt; - z_stream strm; - static const int CHUNK_SIZE = 8192; - char out[CHUNK_SIZE]; - strm.zalloc=Z_NULL; - strm.zfree=Z_NULL; - strm.opaque=Z_NULL; - strm.avail_in=data.size(); - strm.next_in=(Bytef*)data.data(); - - inflateInit2(&strm,15+32); - do { - strm.avail_out=CHUNK_SIZE; - strm.next_out=(Bytef*)out; - inflate(&strm,Z_NO_FLUSH); - nbt.append(out,CHUNK_SIZE-strm.avail_out); - } while (strm.avail_out==0); - inflateEnd(&strm); - - TagDataStream s(nbt.constData(),nbt.size()); - - if (s.r8()==10) //compound - { - s.skip(s.r16()); //skip name - root=new Tag_Compound(s); - } -} - - -//this handles decoding a compressed() section of a region file -NBT::NBT(const uchar *chunk) -{ - root=&NBT::Null; //just in case - - // find chunk size - int length=(chunk[0]<<24)|(chunk[1]<<16)|(chunk[2]<<8)|chunk[3]; - if (chunk[4]!=2) //rfc1950 - return; - - z_stream strm; - static const int CHUNK_SIZE = 8192; - char out[CHUNK_SIZE]; - strm.zalloc=Z_NULL; - strm.zfree=Z_NULL; - strm.opaque=Z_NULL; - strm.avail_in=length-1; - strm.next_in=(Bytef*)chunk+5; - - QByteArray nbt; - - inflateInit(&strm); - do { - strm.avail_out=CHUNK_SIZE; - strm.next_out=(Bytef*)out; - inflate(&strm,Z_NO_FLUSH); - nbt.append(out,CHUNK_SIZE-strm.avail_out); - } while (strm.avail_out==0); - inflateEnd(&strm); - - TagDataStream s(nbt.constData(),nbt.size()); - - if (s.r8()==10) //compound - { - s.skip(s.r16()); //skip name - root=new Tag_Compound(s); - } +NBT::NBT(const QString level) { + root = &NBT::Null; // just in case we die + + QFile f(level); + f.open(QIODevice::ReadOnly); + QByteArray data = f.readAll(); + f.close(); + + QByteArray nbt; + z_stream strm; + static const int CHUNK_SIZE = 8192; + char out[CHUNK_SIZE]; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = data.size(); + strm.next_in = reinterpret_cast(data.data()); + + inflateInit2(&strm, 15 + 32); + do { + strm.avail_out = CHUNK_SIZE; + strm.next_out = reinterpret_cast(out); + inflate(&strm, Z_NO_FLUSH); + nbt.append(out, CHUNK_SIZE - strm.avail_out); + } while (strm.avail_out == 0); + inflateEnd(&strm); + + TagDataStream s(nbt.constData(), nbt.size()); + + if (s.r8() == 10) { // compound + s.skip(s.r16()); // skip name + root = new Tag_Compound(&s); + } +} + +// this handles decoding a compressed() section of a region file +NBT::NBT(const uchar *chunk) { + root = &NBT::Null; // just in case + + // find chunk size + int length = (chunk[0] << 24) | (chunk[1] << 16) | (chunk[2] << 8) | + chunk[3]; + if (chunk[4] != 2) // rfc1950 + return; + + z_stream strm; + static const int CHUNK_SIZE = 8192; + char out[CHUNK_SIZE]; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = length - 1; + strm.next_in = (Bytef *)chunk + 5; + + QByteArray nbt; + + inflateInit(&strm); + do { + strm.avail_out = CHUNK_SIZE; + strm.next_out = reinterpret_cast(out); + inflate(&strm, Z_NO_FLUSH); + nbt.append(out, CHUNK_SIZE - strm.avail_out); + } while (strm.avail_out == 0); + inflateEnd(&strm); + + TagDataStream s(nbt.constData(), nbt.size()); + + if (s.r8() == 10) { // compound + s.skip(s.r16()); // skip name + root = new Tag_Compound(&s); + } } Tag NBT::Null; -bool NBT::has(const QString key) -{ - return root->has(key); +bool NBT::has(const QString key) const { + return root->has(key); } -Tag *NBT::at(const QString key) -{ - return root->at(key); +const Tag *NBT::at(const QString key) const { + return root->at(key); } -NBT::~NBT() -{ - if (root!=&NBT::Null) - delete root; +NBT::~NBT() { + if (root != &NBT::Null) + delete root; } /********** TAGS ****************/ -Tag::Tag() -{ +Tag::Tag() { } -Tag::~Tag() -{ +Tag::~Tag() { } -int Tag::length() -{ - qWarning()<<"Unhandled length"; - return 0; +int Tag::length() const { + qWarning() << "Unhandled length"; + return 0; } -bool Tag::has(const QString) -{ - return false; +bool Tag::has(const QString) const { + return false; } -Tag *Tag::at(const QString) -{ - return &NBT::Null; +const Tag *Tag::at(const QString) const { + return &NBT::Null; } -Tag *Tag::at(int) -{ - return &NBT::Null; +const Tag *Tag::at(int /* idx */) const { + return &NBT::Null; } -QString Tag::toString() -{ - qWarning()<<"Unhandled toString"; - return ""; +const QString Tag::toString() const { + qWarning() << "Unhandled toString"; + return ""; } -qint32 Tag::toInt() -{ - qWarning()<<"Unhandled toInt"; - return 0; +qint32 Tag::toInt() const { + qWarning() << "Unhandled toInt"; + return 0; } -double Tag::toDouble() -{ - qWarning()<<"Unhandled toDouble"; - return 0.0; +double Tag::toDouble() const { + qWarning() << "Unhandled toDouble"; + return 0.0; } -const quint8 *Tag::toByteArray() -{ - qWarning()<<"Unhandled toByteArray"; - return NULL; +const quint8 *Tag::toByteArray() const { + qWarning() << "Unhandled toByteArray"; + return NULL; } -const qint32 *Tag::toIntArray() -{ - qWarning()<<"Unhandled toIntArray"; - return NULL; +const qint32 *Tag::toIntArray() const { + qWarning() << "Unhandled toIntArray"; + return NULL; } -QVariant Tag::getData() -{ - qWarning()<<"Unhandled getData"; - return QVariant(); +const QVariant Tag::getData() const { + qWarning() << "Unhandled getData"; + return QVariant(); } -Tag_Byte::Tag_Byte(TagDataStream &s) -{ - data=s.r8(); +Tag_Byte::Tag_Byte(TagDataStream *s) { + data = s->r8(); } -int Tag_Byte::toInt() -{ - return data; +int Tag_Byte::toInt() const { + return data; } -QString Tag_Byte::toString() -{ - return QString::number(data); +const QString Tag_Byte::toString() const { + return QString::number(data); } -QVariant Tag_Byte::getData() -{ - return data; +const QVariant Tag_Byte::getData() const { + return data; } -Tag_Short::Tag_Short(TagDataStream &s) -{ - data=s.r16(); +Tag_Short::Tag_Short(TagDataStream *s) { + data = s->r16(); } -int Tag_Short::toInt() -{ - return data; +int Tag_Short::toInt() const { + return data; } +const QString Tag_Short::toString() const { + return QString::number(data); +} -QString Tag_Short::toString() -{ - return QString::number(data); +const QVariant Tag_Short::getData() const { + return data; } -QVariant Tag_Short::getData() -{ - return data; +Tag_Int::Tag_Int(TagDataStream *s) { + data = s->r32(); +} +qint32 Tag_Int::toInt() const { + return data; } -Tag_Int::Tag_Int(TagDataStream &s) -{ - data=s.r32(); +const QString Tag_Int::toString() const { + return QString::number(data); } -qint32 Tag_Int::toInt() -{ - return data; + +const QVariant Tag_Int::getData() const { + return data; } -QString Tag_Int::toString() -{ - return QString::number(data); +double Tag_Int::toDouble() const { + return static_cast(data); } -QVariant Tag_Int::getData() -{ - return data; +Tag_Long::Tag_Long(TagDataStream *s) { + data = s->r64(); } -double Tag_Int::toDouble() -{ - return (double)data; +double Tag_Long::toDouble() const { + return static_cast(data); } +qint32 Tag_Long::toInt() const { + return static_cast(data); +} -Tag_Long::Tag_Long(TagDataStream &s) -{ - data=s.r64(); +const QString Tag_Long::toString() const { + return QString::number(data); } -double Tag_Long::toDouble() -{ - return (double)data; +const QVariant Tag_Long::getData() const { + return data; } -qint32 Tag_Long::toInt() -{ - return (double)data; +Tag_Float::Tag_Float(TagDataStream *s) { + union {qint32 d; float f;} fl; + fl.d = s->r32(); + data = fl.f; +} +double Tag_Float::toDouble() const { + return data; } -QString Tag_Long::toString() -{ - return QString::number(data); +const QString Tag_Float::toString() const { + return QString::number(data); } -QVariant Tag_Long::getData() -{ - return data; +const QVariant Tag_Float::getData() const { + return data; } -Tag_Float::Tag_Float(TagDataStream &s) -{ - union {qint32 d; float f;} fl; - fl.d=s.r32(); - data=fl.f; +Tag_Double::Tag_Double(TagDataStream *s) { + union {qint64 d; double f;} fl; + fl.d = s->r64(); + data = fl.f; } -double Tag_Float::toDouble() -{ - return data; +double Tag_Double::toDouble() const { + return data; } -QString Tag_Float::toString() -{ - return QString::number(data); +const QVariant Tag_Double::getData() const { + return data; } -QVariant Tag_Float::getData() -{ - return data; +const QString Tag_Double::toString() const { + return QString::number(data); } -Tag_Double::Tag_Double(TagDataStream &s) -{ - union {qint64 d; double f;} fl; - fl.d=s.r64(); - data=fl.f; +Tag_Byte_Array::Tag_Byte_Array(TagDataStream *s) { + len = s->r32(); + data = s->r(len); } -double Tag_Double::toDouble() -{ - return data; +Tag_Byte_Array::~Tag_Byte_Array() { + delete[] data; } - -QVariant Tag_Double::getData() -{ - return data; +int Tag_Byte_Array::length() const { + return len; +} +const quint8 *Tag_Byte_Array::toByteArray() const { + return data; } -QString Tag_Double::toString() -{ - return QString::number(data); +const QVariant Tag_Byte_Array::getData() const { + return QByteArray(reinterpret_cast(data), len); } -Tag_Byte_Array::Tag_Byte_Array(TagDataStream &s) -{ - len=s.r32(); - data=s.r(len); +const QString Tag_Byte_Array::toString() const { + try { + return QString::fromLatin1(reinterpret_cast(data)); + } catch(...) {} + + return ""; } -Tag_Byte_Array::~Tag_Byte_Array() -{ - delete[] data; + +Tag_String::Tag_String(TagDataStream *s) { + int len = s->r16(); + data = s->utf8(len); } -int Tag_Byte_Array::length() -{ - return len; +const QString Tag_String::toString() const { + return data; } -const quint8 *Tag_Byte_Array::toByteArray() -{ - return data; + +const QVariant Tag_String::getData() const { + return data; } -QVariant Tag_Byte_Array::getData() -{ - return QByteArray(reinterpret_cast(data), len); +template +static void setListData(QList *data, int len, + TagDataStream *s) { + for (int i = 0; i < len; i++) + data->append(new T(s)); } -QString Tag_Byte_Array::toString() -{ - try - { - return QString::fromLatin1((char*)data); - } - catch(...) - { +Tag_List::Tag_List(TagDataStream *s) { + quint8 type = s->r8(); + int len = s->r32(); + if (len == 0) // empty list, type is invalid + return; + + switch (type) { + case 1: setListData(&data, len, s); break; + case 2: setListData(&data, len, s); break; + case 3: setListData(&data, len, s); break; + case 4: setListData(&data, len, s); break; + case 5: setListData(&data, len, s); break; + case 6: setListData(&data, len, s); break; + case 7: setListData(&data, len, s); break; + case 8: setListData(&data, len, s); break; + case 9: setListData(&data, len, s); break; + case 10: setListData(&data, len, s); break; + case 11: setListData(&data, len, s); break; + default: throw "Unknown type"; + } +} - } +Tag_List::~Tag_List() { + for (auto i = data.constBegin(); i != data.constEnd(); i++) + delete *i; +} +int Tag_List::length() const { + return data.count(); +} +const Tag *Tag_List::at(int index) const { + return data[index]; +} - return ""; +const QString Tag_List::toString() const { + QStringList ret; + ret << "["; + for (auto i = data.constBegin(); i != data.constEnd(); i++) { + ret << (*i)->toString(); + ret << ", "; + } + ret.last() = "]"; + return ret.join(""); } -Tag_String::Tag_String(TagDataStream &s) -{ - int len=s.r16(); - data=s.utf8(len); +const QVariant Tag_List::getData() const { + QList lst; + for (auto i = data.constBegin(); i != data.constEnd(); i++) { + lst << (*i)->getData(); + } + return lst; } -QString Tag_String::toString() -{ - return data; -} - -QVariant Tag_String::getData() -{ - return data; -} - - template -static void setListData(QList &data,int len,TagDataStream &s) -{ - for (int i=0;i(data,len,s); break; - case 2: setListData(data,len,s); break; - case 3: setListData(data,len,s); break; - case 4: setListData(data,len,s); break; - case 5: setListData(data,len,s); break; - case 6: setListData(data,len,s); break; - case 7: setListData(data,len,s); break; - case 8: setListData(data,len,s); break; - case 9: setListData(data,len,s); break; - case 10: setListData(data,len,s); break; - case 11: setListData(data,len,s); break; - default: - throw "Unknown type"; - } -} - -Tag_List::~Tag_List() -{ - QList::const_iterator i; - for (i=data.constBegin();i!=data.constEnd();i++) - delete *i; -} -int Tag_List::length() -{ - return data.count(); -} -Tag *Tag_List::at(int index) -{ - return data[index]; -} - -QString Tag_List::toString() -{ - QStringList ret; - ret << "["; - QList::iterator it, end = data.end(); - for (it = data.begin(); it != end; ++it) - { - ret << (*it)->toString(); - ret << ", "; - } - ret.last() = "]"; - return ret.join(""); -} - -QVariant Tag_List::getData() -{ - QList list; - QList::iterator it, end = data.end(); - for (it = data.begin(); it != end; ++it) - { - list << (*it)->getData(); - } - return list; -} - -Tag_Compound::Tag_Compound(TagDataStream &s) -{ - quint8 type; - while ((type=s.r8())!=0) //until tag_end - { - quint16 len=s.r16(); - QString key=s.utf8(len); - Tag *child; - switch (type) - { - case 1: child=new Tag_Byte(s); break; - case 2: child=new Tag_Short(s); break; - case 3: child=new Tag_Int(s); break; - case 4: child=new Tag_Long(s); break; - case 5: child=new Tag_Float(s); break; - case 6: child=new Tag_Double(s); break; - case 7: child=new Tag_Byte_Array(s); break; - case 8: child=new Tag_String(s); break; - case 9: child=new Tag_List(s); break; - case 10: child=new Tag_Compound(s); break; - case 11: child=new Tag_Int_Array(s); break; - default: throw "Unknown tag"; - } - children[key]=child; - } -} -Tag_Compound::~Tag_Compound() -{ - QHash::const_iterator i; - for (i=children.constBegin();i!=children.constEnd();i++) - delete i.value(); -} -bool Tag_Compound::has(const QString key) -{ - return children.contains(key); -} -Tag *Tag_Compound::at(const QString key) -{ - if (!children.contains(key)) - return &NBT::Null; - return children[key]; -} - -QString Tag_Compound::toString() -{ - QStringList ret; - ret << "{\n"; - QHash::iterator it, end = children.end(); - for (it = children.begin(); it != end; ++it) - { - ret << "\t" << it.key() << " = '" << it.value()->toString() << "',\n"; - } - ret.last() = "}"; - return ret.join(""); -} - -QVariant Tag_Compound::getData() -{ - QMap map; - QHash::iterator it, end = children.end(); - for (it = children.begin(); it != end; ++it) - { - map.insert(it.key(), it.value()->getData()); - } - return map; -} - -Tag_Int_Array::Tag_Int_Array(TagDataStream &s) -{ - len=s.r32(); - data=new qint32[len]; - for (int i=0;i ret; - for (int i = 0; i < len; ++i) - { - ret.push_back(data[i]); + +Tag_Compound::Tag_Compound(TagDataStream *s) { + quint8 type; + while ((type = s->r8()) != 0) { + // until tag_end + quint16 len = s->r16(); + QString key = s->utf8(len); + Tag *child; + switch (type) { + case 1: child = new Tag_Byte(s); break; + case 2: child = new Tag_Short(s); break; + case 3: child = new Tag_Int(s); break; + case 4: child = new Tag_Long(s); break; + case 5: child = new Tag_Float(s); break; + case 6: child = new Tag_Double(s); break; + case 7: child = new Tag_Byte_Array(s); break; + case 8: child = new Tag_String(s); break; + case 9: child = new Tag_List(s); break; + case 10: child = new Tag_Compound(s); break; + case 11: child = new Tag_Int_Array(s); break; + default: throw "Unknown tag"; } + children[key] = child; + } +} +Tag_Compound::~Tag_Compound() { + for (auto i = children.constBegin(); i != children.constEnd(); i++) + delete i.value(); +} +bool Tag_Compound::has(const QString key) const { + return children.contains(key); +} +const Tag *Tag_Compound::at(const QString key) const { + if (!children.contains(key)) + return &NBT::Null; + return children[key]; +} - return ret; -} - -TagDataStream::TagDataStream(const char *data,int len) -{ - this->data=(const quint8 *)data; - this->len=len; - pos=0; -} - -quint8 TagDataStream::r8() -{ - return data[pos++]; -} -quint16 TagDataStream::r16() -{ - quint16 r=data[pos++]<<8; - r|=data[pos++]; - return r; -} -quint32 TagDataStream::r32() -{ - quint32 r=data[pos++]<<24; - r|=data[pos++]<<16; - r|=data[pos++]<<8; - r|=data[pos++]; - return r; -} -quint64 TagDataStream::r64() -{ - quint64 r=(quint64)r32()<<32; - r|=r32(); - return r; -} -quint8 *TagDataStream::r(int len) //you need to free anything read with this -{ - quint8 *r=new quint8[len]; - memcpy(r,data+pos,len); - pos+=len; - return r; -} -QString TagDataStream::utf8(int len) -{ - int old=pos; - pos+=len; - return QString::fromUtf8((const char *)data+old,len); -} -void TagDataStream::skip(int len) -{ - pos+=len; +const QString Tag_Compound::toString() const { + QStringList ret; + ret << "{\n"; + for (auto i = children.constBegin(); i != children.constEnd(); i++) { + ret << "\t" << i.key() << " = '" << i.value()->toString() << "',\n"; + } + ret.last() = "}"; + return ret.join(""); +} + +const QVariant Tag_Compound::getData() const { + QMap map; + for (auto i = children.constBegin(); i != children.constEnd(); i++) { + map.insert(i.key(), i.value()->getData()); + } + return map; +} + +Tag_Int_Array::Tag_Int_Array(TagDataStream *s) { + len = s->r32(); + data = new qint32[len]; + for (int i = 0; i < len; i++) + data[i] = s->r32(); +} +Tag_Int_Array::~Tag_Int_Array() { + delete[] data; +} +const qint32 *Tag_Int_Array::toIntArray() const { + return data; +} +int Tag_Int_Array::length() const { + return len; +} + +const QString Tag_Int_Array::toString() const { + QStringList ret; + ret << "["; + for (int i = 0; i < len; ++i) { + ret << QString::number(data[i]) << ","; + } + ret.last() = "]"; + return ret.join(""); +} + +const QVariant Tag_Int_Array::getData() const { + QList ret; + for (int i = 0; i < len; ++i) { + ret.push_back(data[i]); + } + + return ret; +} + +TagDataStream::TagDataStream(const char *data, int len) { + this->data = (const quint8 *)data; + this->len = len; + pos = 0; +} + +quint8 TagDataStream::r8() { + return data[pos++]; +} +quint16 TagDataStream::r16() { + quint16 r = data[pos++] << 8; + r |= data[pos++]; + return r; +} +quint32 TagDataStream::r32() { + quint32 r = data[pos++] << 24; + r |= data[pos++] << 16; + r |= data[pos++] << 8; + r |= data[pos++]; + return r; +} +quint64 TagDataStream::r64() { + quint64 r = (quint64)r32() << 32; + r |= r32(); + return r; +} +quint8 *TagDataStream::r(int len) { + // you need to free anything read with this + quint8 *r = new quint8[len]; + memcpy(r, data + pos, len); + pos += len; + return r; +} +QString TagDataStream::utf8(int len) { + int old = pos; + pos += len; + return QString::fromUtf8((const char *)data + old, len); +} +void TagDataStream::skip(int len) { + pos += len; } diff --git a/nbt.h b/nbt.h index 8f4a037f..7f76bde3 100644 --- a/nbt.h +++ b/nbt.h @@ -1,32 +1,6 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __NBT_H__ -#define __NBT_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef NBT_H_ +#define NBT_H_ class QString; class QByteArray; @@ -35,186 +9,172 @@ class QByteArray; #include #include -class TagDataStream -{ -public: - TagDataStream(const char *data,int len); - quint8 r8(); - quint16 r16(); - quint32 r32(); - quint64 r64(); - quint8 *r(int len); - QString utf8(int len); - void skip(int len); -private: - const quint8 *data; - int pos,len; +class TagDataStream { + public: + TagDataStream(const char *data, int len); + quint8 r8(); + quint16 r16(); + quint32 r32(); + quint64 r64(); + quint8 *r(int len); + QString utf8(int len); + void skip(int len); + private: + const quint8 *data; + int pos, len; }; -class Tag -{ -public: - Tag(); - virtual ~Tag(); - virtual bool has(const QString key); - virtual int length(); - virtual Tag *at(const QString key); - virtual Tag *at(int index); - virtual QString toString(); - virtual qint32 toInt(); - virtual double toDouble(); - virtual const quint8 *toByteArray(); - virtual const qint32 *toIntArray(); - virtual QVariant getData(); +class Tag { + public: + Tag(); + virtual ~Tag(); + virtual bool has(const QString key) const; + virtual int length() const; + virtual const Tag *at(const QString key) const; + virtual const Tag *at(int index) const; + virtual const QString toString() const; + virtual qint32 toInt() const; + virtual double toDouble() const; + virtual const quint8 *toByteArray() const; + virtual const qint32 *toIntArray() const; + virtual const QVariant getData() const; }; -class NBT -{ -public: - NBT(const QString level); - NBT(const uchar *chunk); - ~NBT(); +class NBT { + public: + explicit NBT(const QString level); + explicit NBT(const uchar *chunk); + ~NBT(); - bool has(const QString key); - Tag *at(const QString key); + bool has(const QString key) const; + const Tag *at(const QString key) const; - static Tag Null; -private: - Tag *root; + static Tag Null; + private: + Tag *root; }; -class Tag_Byte : public Tag -{ -public: - Tag_Byte(TagDataStream &s); - int toInt(); - virtual QString toString(); - virtual QVariant getData(); -private: - quint8 data; +class Tag_Byte : public Tag { + public: + explicit Tag_Byte(TagDataStream *s); + int toInt() const; + virtual const QString toString() const; + virtual const QVariant getData() const; + private: + quint8 data; }; -class Tag_Short : public Tag -{ -public: - Tag_Short(TagDataStream &s); - int toInt(); - virtual QString toString(); - virtual QVariant getData(); -private: - qint16 data; +class Tag_Short : public Tag { + public: + explicit Tag_Short(TagDataStream *s); + int toInt() const; + virtual const QString toString() const; + virtual const QVariant getData() const; + private: + qint16 data; }; -class Tag_Int : public Tag -{ -public: - Tag_Int(TagDataStream &s); - qint32 toInt(); - double toDouble(); - virtual QString toString(); - virtual QVariant getData(); -private: - qint32 data; +class Tag_Int : public Tag { + public: + explicit Tag_Int(TagDataStream *s); + qint32 toInt() const; + double toDouble() const; + virtual const QString toString() const; + virtual const QVariant getData() const; + private: + qint32 data; }; -class Tag_Long : public Tag -{ -public: - Tag_Long(TagDataStream &s); - qint32 toInt(); - double toDouble(); - virtual QString toString(); - virtual QVariant getData(); -private: - qint64 data; +class Tag_Long : public Tag { + public: + explicit Tag_Long(TagDataStream *s); + qint32 toInt() const; + double toDouble() const; + virtual const QString toString() const; + virtual const QVariant getData() const; + private: + qint64 data; }; -class Tag_Float : public Tag -{ -public: - Tag_Float(TagDataStream &s); +class Tag_Float : public Tag { + public: + explicit Tag_Float(TagDataStream *s); - virtual double toDouble(); - virtual QString toString(); - virtual QVariant getData(); + virtual double toDouble() const; + virtual const QString toString() const; + virtual const QVariant getData() const; -private: - float data; + private: + float data; }; -class Tag_Double : public Tag -{ -public: - Tag_Double(TagDataStream &s); - double toDouble(); - virtual QString toString(); - virtual QVariant getData(); -private: - double data; +class Tag_Double : public Tag { + public: + explicit Tag_Double(TagDataStream *s); + double toDouble() const; + virtual const QString toString() const; + virtual const QVariant getData() const; + private: + double data; }; -class Tag_Byte_Array : public Tag -{ -public: - Tag_Byte_Array(TagDataStream &s); - ~Tag_Byte_Array(); - int length(); - const quint8 *toByteArray(); - virtual QString toString(); - virtual QVariant getData(); -private: - const quint8 *data; - int len; +class Tag_Byte_Array : public Tag { + public: + explicit Tag_Byte_Array(TagDataStream *s); + ~Tag_Byte_Array(); + int length() const; + const quint8 *toByteArray() const; + virtual const QString toString() const; + virtual const QVariant getData() const; + private: + const quint8 *data; + int len; }; -class Tag_String : public Tag -{ -public: - Tag_String(TagDataStream &s); - QString toString(); - virtual QVariant getData(); -private: - QString data; +class Tag_String : public Tag { + public: + explicit Tag_String(TagDataStream *s); + const QString toString() const; + virtual const QVariant getData() const; + private: + QString data; }; -class Tag_List : public Tag -{ -public: - Tag_List(TagDataStream &s); - ~Tag_List(); - Tag *at(int index); - int length(); - virtual QString toString(); - virtual QVariant getData(); -private: - QList data; +class Tag_List : public Tag { + public: + explicit Tag_List(TagDataStream *s); + ~Tag_List(); + const Tag *at(int index) const; + int length() const; + virtual const QString toString() const; + virtual const QVariant getData() const; + private: + QList data; }; -class Tag_Compound : public Tag -{ -public: - Tag_Compound(TagDataStream &s); - ~Tag_Compound(); - bool has(const QString key); - Tag *at(const QString key); - virtual QString toString(); - virtual QVariant getData(); -private: - QHash children; +class Tag_Compound : public Tag { + public: + explicit Tag_Compound(TagDataStream *s); + ~Tag_Compound(); + bool has(const QString key) const; + const Tag *at(const QString key) const; + virtual const QString toString() const; + virtual const QVariant getData() const; + private: + QHash children; }; -class Tag_Int_Array : public Tag -{ -public: - Tag_Int_Array(TagDataStream &s); - ~Tag_Int_Array(); - int length(); - const qint32 *toIntArray(); - virtual QString toString(); - virtual QVariant getData(); -private: - int len; - qint32 *data; +class Tag_Int_Array : public Tag { + public: + explicit Tag_Int_Array(TagDataStream *s); + ~Tag_Int_Array(); + int length() const; + const qint32 *toIntArray() const; + virtual const QString toString() const; + virtual const QVariant getData() const; + private: + int len; + qint32 *data; }; -#endif +#endif // NBT_H_ diff --git a/overlayitem.h b/overlayitem.h index 5d6cf0fa..0530c99b 100644 --- a/overlayitem.h +++ b/overlayitem.h @@ -1,5 +1,6 @@ -#ifndef OVERLAYITEM_H -#define OVERLAYITEM_H +/** Copyright 2014 Rian Shelley */ +#ifndef OVERLAYITEM_H_ +#define OVERLAYITEM_H_ #include #include @@ -7,38 +8,37 @@ class QPainter; -class OverlayItem -{ -public: - virtual ~OverlayItem() {} - struct Point - { - Point(double x=0, double y=0, double z=0):x(x), y(y), z(z) {} - double x, y, z; - }; +class OverlayItem { + public: + virtual ~OverlayItem() {} + struct Point { + explicit Point(double x = 0, double y = 0, double z = 0):x(x), y(y), z(z) {} + double x, y, z; + }; - virtual bool intersects(const Point& min, const Point& max) const = 0; - virtual void draw(double offsetX, double offsetZ, double scale, QPainter& canvas) const = 0; - virtual Point midpoint() const = 0; - const QString& type() const {return itemType;} - const QString& display() const { return itemDescription;} - const QVariant& properties() const { return itemProperties;} - const QColor& color() const { return itemColor; } - const QString& dimension() const { return itemDimension; } + virtual bool intersects(const Point& min, const Point& max) const = 0; + virtual void draw(double offsetX, double offsetZ, double scale, + QPainter *canvas) const = 0; + virtual Point midpoint() const = 0; + const QString& type() const {return itemType;} + const QString& display() const { return itemDescription;} + const QVariant& properties() const { return itemProperties;} + const QColor& color() const { return itemColor; } + const QString& dimension() const { return itemDimension; } -protected: - void setProperties(const QVariant& props) {itemProperties = props;} - void setColor(const QColor& c) {itemColor = c;} - void setDimension(const QString& d) {itemDimension = d;} - void setDisplay(const QString& d) {itemDescription = d;} - void setType(const QString& t) {itemType = t;} + protected: + void setProperties(const QVariant& props) {itemProperties = props;} + void setColor(const QColor& c) {itemColor = c;} + void setDimension(const QString& d) {itemDimension = d;} + void setDisplay(const QString& d) {itemDescription = d;} + void setType(const QString& t) {itemType = t;} -private: - QVariant itemProperties; - QColor itemColor; - QString itemDimension; - QString itemType; - QString itemDescription; + private: + QVariant itemProperties; + QColor itemColor; + QString itemDimension; + QString itemType; + QString itemDescription; }; -#endif // OVERLAYITEM_H +#endif // OVERLAYITEM_H_ diff --git a/properties.cpp b/properties.cpp index e63bd0d7..761bb83d 100644 --- a/properties.cpp +++ b/properties.cpp @@ -1,218 +1,183 @@ -#include "properties.h" -#include "ui_properties.h" +/** Copyright 2014 Rian Shelley */ #include +#include "./properties.h" +#include "./ui_properties.h" -Properties::Properties(QWidget *parent) : - QDialog(parent), - ui(new Ui::Properties) -{ - ui->setupUi(this); +Properties::Properties(QWidget *parent) : QDialog(parent), + ui(new Ui::Properties) { + ui->setupUi(this); - //TODO: populate this from a config file? - summary.insert("", "{id} ({Pos.[0]}, {Pos.[1]}, {Pos.[2]})"); - summary.insert("Pos", "({[0]}, {[1]}, {[2]})"); - summary.insert("Attributes[]", "{Name} = {Base}"); + summary.insert("", "{id} ({Pos.[0]}, {Pos.[1]}, {Pos.[2]})"); + summary.insert("Pos", "({[0]}, {[1]}, {[2]})"); + summary.insert("Attributes[]", "{Name} = {Base}"); } -Properties::~Properties() -{ - delete ui; +Properties::~Properties() { + delete ui; } template -void Properties::ParseIterable(QTreeWidgetItem* node, const IterableT& seq) -{ - typename IterableT::const_iterator it, itEnd = seq.end(); - for(it = seq.begin(); it != itEnd; ++it) - { - QTreeWidgetItem* child = new QTreeWidgetItem(); - child->setData(0, Qt::DisplayRole, it.key()); - child->setData(1, Qt::DisplayRole, GetSummary(it.key(), it.value())); - CreateTree(child, it.value()); - if (node) - node->addChild(child); - else - ui->propertyView->addTopLevelItem(child); - } +void Properties::ParseIterable(QTreeWidgetItem* node, const IterableT& seq) { + typename IterableT::const_iterator it, itEnd = seq.end(); + for (it = seq.begin(); it != itEnd; ++it) { + QTreeWidgetItem* child = new QTreeWidgetItem(); + child->setData(0, Qt::DisplayRole, it.key()); + child->setData(1, Qt::DisplayRole, GetSummary(it.key(), it.value())); + CreateTree(child, it.value()); + if (node) + node->addChild(child); + else + ui->propertyView->addTopLevelItem(child); + } } template -void Properties::ParseList(QTreeWidgetItem* node, const IterableT& seq) -{ - typename IterableT::const_iterator it, itEnd = seq.end(); - int i = 0; - //skip 1 sized arrays - if (seq.size() == 0) - { - //empty - if (node) - node->setData(1, Qt::DisplayRole, ""); - } - else if (seq.size() == 1) - { - CreateTree(node, seq.first()); - if (node) - node->setData(1, Qt::DisplayRole, GetSummary("[0]", seq.first())); - } - else - { - for(it = seq.begin(); it != itEnd; ++it) - { - QTreeWidgetItem* child = new QTreeWidgetItem(); - QString key = QString("[%1]").arg(i++); - child->setData(0, Qt::DisplayRole, key); - child->setData(1, Qt::DisplayRole, GetSummary(key, *it)); - CreateTree(child, *it); - - if (node) - node->addChild(child); - else - ui->propertyView->addTopLevelItem(child); - } - } +void Properties::ParseList(QTreeWidgetItem* node, const IterableT& seq) { + typename IterableT::const_iterator it, itEnd = seq.end(); + int i = 0; + // skip 1 sized arrays + if (seq.size() == 0) { + // empty + if (node) + node->setData(1, Qt::DisplayRole, ""); + } else if (seq.size() == 1) { + CreateTree(node, seq.first()); + if (node) + node->setData(1, Qt::DisplayRole, GetSummary("[0]", seq.first())); + } else { + for (it = seq.begin(); it != itEnd; ++it) { + QTreeWidgetItem* child = new QTreeWidgetItem(); + QString key = QString("[%1]").arg(i++); + child->setData(0, Qt::DisplayRole, key); + child->setData(1, Qt::DisplayRole, GetSummary(key, *it)); + CreateTree(child, *it); + + if (node) + node->addChild(child); + else + ui->propertyView->addTopLevelItem(child); + } + } } -void Properties::DisplayProperties(QVariant p) -{ - //get current property - QString propertyName; - QTreeWidgetItem* item = ui->propertyView->currentItem(); - if (item) - { - propertyName = item->data(0, Qt::DisplayRole).toString(); - } - - ui->propertyView->clear(); - - //only support QVariantMap or QVariantHash at this level - switch (p.type()) - { - case QMetaType::QVariantMap: - ParseIterable(NULL, p.toMap()); - break; - case QMetaType::QVariantHash: - ParseIterable(NULL, p.toHash()); - break; - case QMetaType::QVariantList: - ParseList(NULL, p.toList()); - break; - default: - qWarning("Trying to display scalar value as a property"); - break; - } - - //expand at least the first level - ui->propertyView->expandToDepth(0); - - if (propertyName.size() != 0) - { - //try to restore the path - QList items = ui->propertyView->findItems(propertyName, Qt::MatchRecursive); - if (items.size()) - items.front()->setSelected(true); - } +void Properties::DisplayProperties(QVariant p) { + // get current property + QString propertyName; + QTreeWidgetItem* item = ui->propertyView->currentItem(); + if (item) { + propertyName = item->data(0, Qt::DisplayRole).toString(); + } + + ui->propertyView->clear(); + + // only support QVariantMap or QVariantHash at this level + switch (p.type()) { + case QMetaType::QVariantMap: + ParseIterable(NULL, p.toMap()); + break; + case QMetaType::QVariantHash: + ParseIterable(NULL, p.toHash()); + break; + case QMetaType::QVariantList: + ParseList(NULL, p.toList()); + break; + default: + qWarning("Trying to display scalar value as a property"); + break; + } + + // expand at least the first level + ui->propertyView->expandToDepth(0); + + if (propertyName.size() != 0) { + // try to restore the path + QList items = + ui->propertyView->findItems(propertyName, Qt::MatchRecursive); + if (items.size()) + items.front()->setSelected(true); + } } -void Properties::CreateTree(QTreeWidgetItem* node, const QVariant& v) -{ - switch (v.type()) - { - case QMetaType::QVariantMap: - ParseIterable(node, v.toMap()); - break; - case QMetaType::QVariantHash: - ParseIterable(node, v.toHash()); - break; - case QMetaType::QVariantList: - ParseList(node, v.toList()); - break; - default: - if(node) - node->setData(1, Qt::DisplayRole, v.toString()); - break; - } +void Properties::CreateTree(QTreeWidgetItem* node, const QVariant& v) { + switch (v.type()) { + case QMetaType::QVariantMap: + ParseIterable(node, v.toMap()); + break; + case QMetaType::QVariantHash: + ParseIterable(node, v.toHash()); + break; + case QMetaType::QVariantList: + ParseList(node, v.toList()); + break; + default: + if (node) + node->setData(1, Qt::DisplayRole, v.toString()); + break; + } } -QString EvaluateSubExpression(const QString& subexpr, const QVariant& v) -{ - if (subexpr.size() == 0) - { - //limit the displayed decimal places - if ((QMetaType::Type)v.type() == QMetaType::Double) - { - return QString::number(v.toDouble(), 'f', 2); - } - return v.toString(); - } - else if (subexpr.at(0) == '[') - { - int rightbracket = subexpr.indexOf(']'); - if (rightbracket > 0) - { - bool ok = false; - int index = subexpr.mid(1, rightbracket-1).toInt(&ok); - if (ok && (QMetaType::Type)v.type() == QMetaType::QVariantList) - { - return EvaluateSubExpression(subexpr.mid(rightbracket + 1), v.toList().at(index)); - } - } - } - else - { - int dot = subexpr.indexOf('.'); - QString key = subexpr.mid(0, dot); - if ((QMetaType::Type)v.type() == QMetaType::QVariantHash) - { - QHash h = v.toHash(); - QHash::const_iterator it = h.find(key); - if (it != h.end()) - return EvaluateSubExpression(subexpr.mid(key.length() + 1), *it); - } - else if ((QMetaType::Type)v.type() == QMetaType::QVariantMap) - { - QMap h = v.toMap(); - QMap::const_iterator it = h.find(key); - if (it != h.end()) - return EvaluateSubExpression(subexpr.mid(key.length() + 1), *it); - } - } - - return ""; +QString EvaluateSubExpression(const QString& subexpr, const QVariant& v) { + if (subexpr.size() == 0) { + // limit the displayed decimal places + if ((QMetaType::Type)v.type() == QMetaType::Double) { + return QString::number(v.toDouble(), 'f', 2); + } + return v.toString(); + } else if (subexpr.at(0) == '[') { + int rightbracket = subexpr.indexOf(']'); + if (rightbracket > 0) { + bool ok = false; + int index = subexpr.mid(1, rightbracket-1).toInt(&ok); + if (ok && (QMetaType::Type)v.type() == QMetaType::QVariantList) { + return EvaluateSubExpression(subexpr.mid(rightbracket + 1), + v.toList().at(index)); + } + } + } else { + int dot = subexpr.indexOf('.'); + QString key = subexpr.mid(0, dot); + if ((QMetaType::Type)v.type() == QMetaType::QVariantHash) { + QHash h = v.toHash(); + QHash::const_iterator it = h.find(key); + if (it != h.end()) + return EvaluateSubExpression(subexpr.mid(key.length() + 1), *it); + } else if ((QMetaType::Type)v.type() == QMetaType::QVariantMap) { + QMap h = v.toMap(); + QMap::const_iterator it = h.find(key); + if (it != h.end()) + return EvaluateSubExpression(subexpr.mid(key.length() + 1), *it); + } + } + + return ""; } -QString Properties::GetSummary(const QString& key, const QVariant& v) -{ - QString ret; - QMap::const_iterator it = summary.find(key); - if (it != summary.end()) - { - ret = *it; - QRegularExpression re("(\\{.*?\\})"); - QRegularExpressionMatchIterator matches = re.globalMatch(*it); - while (matches.hasNext()) - { - QRegularExpressionMatch m = matches.next(); - QString pattern = m.captured(0); - QString evaluated = EvaluateSubExpression(pattern.mid(1, pattern.size()-2), v); - //if a lookup fails, then don't return anything - if (evaluated.size() == 0) - { - ret = ""; - break; - } - ret.replace(pattern, evaluated); - } - } - else if ((QMetaType::Type)v.type() == QMetaType::QVariantList) - { - ret = QString("(%1 items)").arg(v.toList().size()); - } - else if ((QMetaType::Type)v.type() == QMetaType::QVariantMap) - { - ret = GetSummary("", v); - } - return ret; +QString Properties::GetSummary(const QString& key, const QVariant& v) { + QString ret; + QMap::const_iterator it = summary.find(key); + if (it != summary.end()) { + ret = *it; + QRegularExpression re("(\\{.*?\\})"); + QRegularExpressionMatchIterator matches = re.globalMatch(*it); + while (matches.hasNext()) { + QRegularExpressionMatch m = matches.next(); + QString pattern = m.captured(0); + QString evaluated = + EvaluateSubExpression(pattern.mid(1, pattern.size() - 2), v); + // if a lookup fails, then don't return anything + if (evaluated.size() == 0) { + ret = ""; + break; + } + ret.replace(pattern, evaluated); + } + } else if ((QMetaType::Type)v.type() == QMetaType::QVariantList) { + ret = QString("(%1 items)").arg(v.toList().size()); + } else if ((QMetaType::Type)v.type() == QMetaType::QVariantMap) { + ret = GetSummary("", v); + } + return ret; } diff --git a/properties.h b/properties.h index 83d3036b..83959598 100644 --- a/properties.h +++ b/properties.h @@ -1,5 +1,6 @@ -#ifndef PROPERTIES_H -#define PROPERTIES_H +/** Copyright 2014 Rian Shelley */ +#ifndef PROPERTIES_H_ +#define PROPERTIES_H_ #include #include @@ -10,28 +11,27 @@ class Properties; class QTreeWidgetItem; -class Properties : public QDialog -{ - Q_OBJECT +class Properties : public QDialog { + Q_OBJECT -public: - explicit Properties(QWidget *parent = 0); - ~Properties(); + public: + explicit Properties(QWidget *parent = 0); + ~Properties(); - void DisplayProperties(QVariant p); - -protected: - void CreateTree(QTreeWidgetItem *node, const QVariant& v); - QString GetSummary(const QString& key, const QVariant& v); + void DisplayProperties(QVariant p); - template - void ParseIterable(QTreeWidgetItem* node, const IterableT& seq); - template - void ParseList(QTreeWidgetItem* node, const IterableT& seq); + protected: + void CreateTree(QTreeWidgetItem *node, const QVariant& v); + QString GetSummary(const QString& key, const QVariant& v); -private: - Ui::Properties *ui; - QMap summary; + template + void ParseIterable(QTreeWidgetItem* node, const IterableT& seq); + template + void ParseList(QTreeWidgetItem* node, const IterableT& seq); + + private: + Ui::Properties *ui; + QMap summary; }; -#endif // PROPERTIES_H +#endif // PROPERTIES_H_ diff --git a/settings.cpp b/settings.cpp index 81736528..5237e436 100644 --- a/settings.cpp +++ b/settings.cpp @@ -1,121 +1,94 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "settings.h" - +/** Copyright (c) 2013, Sean Kasun */ #include #include #include -Settings::Settings(QWidget *parent) : QDialog(parent) -{ - m_ui.setupUi(this); +#include "./settings.h" + +Settings::Settings(QWidget *parent) : QDialog(parent) { + m_ui.setupUi(this); - setWindowTitle(tr("%1 Settings").arg(qApp->applicationName())); + setWindowTitle(tr("%1 Settings").arg(qApp->applicationName())); - connect(m_ui.checkBox_DefaultLocation, SIGNAL(toggled(bool)), - this, SLOT(toggleDefaultLocation(bool))); - connect(m_ui.checkBox_DefaultLocation, SIGNAL(toggled(bool)), - m_ui.lineEdit_Location, SLOT(setDisabled(bool))); + connect(m_ui.checkBox_DefaultLocation, SIGNAL(toggled(bool)), + this, SLOT(toggleDefaultLocation(bool))); + connect(m_ui.checkBox_DefaultLocation, SIGNAL(toggled(bool)), + m_ui.lineEdit_Location, SLOT(setDisabled(bool))); - connect(this, SIGNAL(locationChanged(QString)), - m_ui.lineEdit_Location, SLOT(setText(const QString &))); + connect(this, SIGNAL(locationChanged(const QString)), + m_ui.lineEdit_Location, SLOT(setText(const QString &))); - connect(m_ui.lineEdit_Location, SIGNAL(textChanged(const QString &)), - this, SLOT(pathChanged(const QString &))); + connect(m_ui.lineEdit_Location, SIGNAL(textChanged(const QString &)), + this, SLOT(pathChanged(const QString &))); - connect(m_ui.pushButton_Browse, SIGNAL(clicked(bool)), - this, SLOT(browseLocation(bool))); + connect(m_ui.pushButton_Browse, SIGNAL(clicked(bool)), + this, SLOT(browseLocation(bool))); - connect(m_ui.checkBox_VerticalDepth, SIGNAL(toggled(bool)), - this, SLOT(toggleVerticalDepth(bool))); + connect(m_ui.checkBox_VerticalDepth, SIGNAL(toggled(bool)), + this, SLOT(toggleVerticalDepth(bool))); - connect(m_ui.checkBox_AutoUpdate, SIGNAL(toggled(bool)), - this, SLOT(toggleAutoUpdate(bool))); + connect(m_ui.checkBox_AutoUpdate, SIGNAL(toggled(bool)), + this, SLOT(toggleAutoUpdate(bool))); - //set stored settings - QSettings info; - m_ui.checkBox_AutoUpdate ->setChecked(info.value("autoupdate",true).toBool()); - m_ui.lineEdit_Location ->setText (info.value("mcdir","").toString()); - m_ui.lineEdit_Location ->setDisabled(m_ui.checkBox_DefaultLocation->isChecked()); - m_ui.checkBox_DefaultLocation->setChecked(info.value("usedefault",true).toBool()); - m_ui.checkBox_VerticalDepth ->setChecked(info.value("verticaldepth",true).toBool()); + // set stored settings + QSettings info; + m_ui.checkBox_AutoUpdate->setChecked(info.value("autoupdate", + true).toBool()); + m_ui.lineEdit_Location->setText(info.value("mcdir", "").toString()); + m_ui.lineEdit_Location->setDisabled( + m_ui.checkBox_DefaultLocation->isChecked()); + m_ui.checkBox_DefaultLocation->setChecked(info.value("usedefault", + true).toBool()); + m_ui.checkBox_VerticalDepth->setChecked(info.value("verticaldepth", + true).toBool()); } -void Settings::toggleAutoUpdate(bool up) -{ - autoUpdate=up; - QSettings info; - info.setValue("autoupdate",up); - emit settingsUpdated(); +void Settings::toggleAutoUpdate(bool up) { + autoUpdate = up; + QSettings info; + info.setValue("autoupdate", up); + emit settingsUpdated(); } -void Settings::browseLocation(bool) -{ - QString dirName=QFileDialog::getExistingDirectory(this,tr("Find Minecraft")); - if (!dirName.isEmpty()) - emit locationChanged(dirName); +void Settings::browseLocation(bool /* on */) { + QString dirName = QFileDialog::getExistingDirectory(this, + tr("Find Minecraft")); + if (!dirName.isEmpty()) + emit locationChanged(dirName); } -void Settings::pathChanged(const QString &path) -{ - mcpath=path; - QSettings info; - info.setValue("mcdir",path); - //save settings - emit settingsUpdated(); +void Settings::pathChanged(const QString &path) { + mcpath = path; + QSettings info; + info.setValue("mcdir", path); + // save settings + emit settingsUpdated(); } -void Settings::toggleDefaultLocation(bool def) -{ - QSettings info; - info.setValue("usedefault",def); - if (!def) //we unchecked default.. but we're still technically default - return; +void Settings::toggleDefaultLocation(bool def) { + QSettings info; + info.setValue("usedefault", def); + if (!def) // we unchecked default.. but we're still technically default + return; - QString mc; + QString mc; #ifdef Q_OS_MAC - mc=QDir::homePath()+QDir::toNativeSeparators("/Library/Application Support/minecraft"); + mc = QDir::homePath() + + QDir::toNativeSeparators("/Library/Application Support/minecraft"); #elif defined Q_OS_WIN32 - //pretend to be minecraft - QSettings ini(QSettings::IniFormat,QSettings::UserScope, - ".minecraft","minecraft1"); - mc=QFileInfo(ini.fileName()).absolutePath(); + // pretend to be minecraft + QSettings ini(QSettings::IniFormat, QSettings::UserScope, + ".minecraft", "minecraft1"); + mc = QFileInfo(ini.fileName()).absolutePath(); #else - mc=QDir::homePath()+QDir::toNativeSeparators("/.minecraft"); + mc = QDir::homePath()+QDir::toNativeSeparators("/.minecraft"); #endif - - emit locationChanged(mc); + emit locationChanged(mc); } -void Settings::toggleVerticalDepth(bool value) -{ - verticalDepth=value; - QSettings info; - info.setValue("verticaldepth",value); - emit settingsUpdated(); +void Settings::toggleVerticalDepth(bool value) { + verticalDepth = value; + QSettings info; + info.setValue("verticaldepth", value); + emit settingsUpdated(); } diff --git a/settings.h b/settings.h index bd79d136..9bf1d5bc 100644 --- a/settings.h +++ b/settings.h @@ -1,64 +1,33 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SETTINGS_H -#define SETTINGS_H +/** Copyright (c) 2013, Sean Kasun */ +#ifndef SETTINGS_H_ +#define SETTINGS_H_ #include +#include "./ui_settings.h" -#include "ui_settings.h" - - -class Settings : public QDialog -{ - Q_OBJECT -public: - explicit Settings(QWidget *parent = 0); - - bool autoUpdate; - bool verticalDepth; - QString mcpath; -signals: - void settingsUpdated(); +class Settings : public QDialog { + Q_OBJECT + public: + explicit Settings(QWidget *parent = 0); -signals: - void locationChanged(const QString &); + bool autoUpdate; + bool verticalDepth; + QString mcpath; -private slots: - void toggleAutoUpdate(bool); - void browseLocation(bool); - void toggleDefaultLocation(bool); - void pathChanged(const QString &); - void toggleVerticalDepth(bool); + signals: + void settingsUpdated(); + void locationChanged(const QString &loc); -private: - Ui::Settings m_ui; + private slots: + void toggleAutoUpdate(bool on); + void browseLocation(bool on); + void toggleDefaultLocation(bool on); + void pathChanged(const QString &path); + void toggleVerticalDepth(bool on); + private: + Ui::Settings m_ui; }; -#endif // SETTINGS_H +#endif // SETTINGS_H_ diff --git a/village.cpp b/village.cpp index 86c15a10..fc66890e 100644 --- a/village.cpp +++ b/village.cpp @@ -1,42 +1,38 @@ -#include "village.h" +/** Copyright 2014 Rian Shelley */ +#include "./village.h" +#include "./nbt.h" -#include "nbt.h" +QList> +Village::tryParse(const Tag* tag, const QString& dimension) { + QList > ret; -QList > Village::tryParse(Tag* tag, const QString& dimension) -{ - QList > ret; + if (tag && tag != &NBT::Null) { + auto villages = tag->at("Villages"); + if (villages && villages != &NBT::Null) { + for (int i = 0; i < villages->length(); ++i) { + Village* newVillage = new Village(); + auto village = villages->at(i); + int radius = village->at("Radius")->toInt(); + int cx = village->at("CX")->toInt(); + int cy = village->at("CY")->toInt(); + int cz = village->at("CZ")->toInt(); + newVillage->setBounds( + Point(cx - radius, cy - radius, cz - radius), + Point(cx + radius, cy + radius, cz + radius)); + newVillage->setDisplay("Village"); + newVillage->setType("Structure.Village"); - if (tag && tag != &NBT::Null) - { - Tag* villages = tag->at("Villages"); - if (villages && villages != &NBT::Null) - { - for (int i = 0; i < villages->length(); ++i) - { - Village* newVillage = new Village(); - Tag* village = villages->at(i); - int radius = village->at("Radius")->toInt(); - int cx = village->at("CX")->toInt(); - int cy = village->at("CY")->toInt(); - int cz = village->at("CZ")->toInt(); - newVillage->setBounds( - Point(cx - radius, cy - radius, cz - radius), - Point(cx + radius, cy + radius, cz + radius) - ); - newVillage->setDisplay("Village"); - newVillage->setType("Structure.Village"); + // color is based on the hash + quint32 hue = qHash("Village"); + QColor color; + color.setHsv(hue % 360, 255, 255, 64); + newVillage->setColor(color); - //color is based on the hash - quint32 hue = qHash("Village"); - QColor color; - color.setHsv(hue % 360, 255, 255, 64); - newVillage->setColor(color); - - newVillage->setProperties(village->getData()); - newVillage->setDimension(dimension); - ret.append(QSharedPointer(newVillage)); - } - } - } - return ret; + newVillage->setProperties(village->getData()); + newVillage->setDimension(dimension); + ret.append(QSharedPointer(newVillage)); + } + } + } + return ret; } diff --git a/village.h b/village.h index 49629dfb..ecd05ccb 100644 --- a/village.h +++ b/village.h @@ -1,15 +1,16 @@ -#ifndef VILLAGE_H -#define VILLAGE_H +/** Copyright 2014 Rian Shelley */ +#ifndef VILLAGE_H_ +#define VILLAGE_H_ -#include "generatedstructure.h" +#include "./generatedstructure.h" -class Village : public GeneratedStructure -{ -public: - static QList > tryParse(Tag* tag, const QString &dimension); +class Village : public GeneratedStructure { + public: + static QList> + tryParse(const Tag* tag, const QString &dimension); -protected: - Village() {} + protected: + Village() {} }; -#endif // VILLAGE_H +#endif // VILLAGE_H_ diff --git a/worldsave.cpp b/worldsave.cpp index fa105494..c84304a1 100644 --- a/worldsave.cpp +++ b/worldsave.cpp @@ -1,29 +1,4 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ +/** Copyright (c) 2013, Sean Kasun */ /* Saves the world to PNG. It doesn't use stock PNG code because @@ -32,324 +7,294 @@ make less-than-optimal PNGs. */ -#include "worldsave.h" -#include "mapview.h" +#include "./worldsave.h" +#include "./mapview.h" #include "zlib/zlib.h" -WorldSave::WorldSave(QString filename, MapView *map, bool regionChecker, bool chunkChecker) - : filename(filename) - , map(map) - , regionChecker(regionChecker) - , chunkChecker(chunkChecker) -{ +WorldSave::WorldSave(QString filename, MapView *map, bool regionChecker, + bool chunkChecker) : filename(filename), map(map), + regionChecker(regionChecker), chunkChecker(chunkChecker) { } -WorldSave::~WorldSave() -{ +WorldSave::~WorldSave() { } -static inline void w32(char *p,quint32 v) -{ - *p++=v>>24; - *p++=(v>>16)&0xff; - *p++=(v>>8)&0xff; - *p++=v&0xff; +static inline void w32(char *p, quint32 v) { + *p++ = v >> 24; + *p++ = (v >> 16) & 0xff; + *p++ = (v >> 8) & 0xff; + *p++ = v & 0xff; } -static void writeChunk(QFile &f,const char *tag,const char *data,int len) -{ - char dword[4]; - w32(dword,len); - f.write(dword,4); - f.write(tag,4); - if (len!=0) - f.write(data,len); - quint32 crc=crc32(0,Z_NULL,0); - crc=crc32(crc,(const Bytef *)tag,4); - if (len!=0) - crc=crc32(crc,(const Bytef *)data,len); - w32(dword,crc); - f.write(dword,4); +static void writeChunk(QFile *f, const char *tag, const char *data, + int len) { + char dword[4]; + w32(dword, len); + f->write(dword, 4); + f->write(tag, 4); + if (len != 0) + f->write(data, len); + quint32 crc = crc32(0, Z_NULL, 0); + crc = crc32(crc, (const Bytef *)tag, 4); + if (len != 0) + crc = crc32(crc, (const Bytef *)data, len); + w32(dword, crc); + f->write(dword, 4); } -void WorldSave::run() -{ - emit progress(tr("Calculating world bounds"),0.0); - QString path=map->getWorldPath(); - - int top,left,right,bottom; - findBounds(path,&top,&left,&bottom,&right); - - int width=(right+1-left)*16; - int height=(bottom+1-top)*16; - - QFile png(filename); - png.open(QIODevice::WriteOnly); - - //output PNG signature - const char *sig="\x89PNG\x0d\x0a\x1a\x0a"; - png.write(sig,8); - //output PNG header - const char *ihdrdata="\x00\x00\x00\x00" //width - "\x00\x00\x00\x00" //height - "\x08" //bit depth - "\x06" //color type (rgba) - "\x00" //compresion method (deflate) - "\x00" //filter method (standard) - "\x00"; //interlace method (none) - char ihdr[13]; - memcpy(ihdr,ihdrdata,13); - w32(ihdr,width); - w32(ihdr+4,height); - writeChunk(png,"IHDR",ihdr,13); - - int insize=width*16*4+16; - int outsize=insize*2; - - uchar *scanlines=new uchar[insize]; - for (int i=0;i<16;i++) //set scanline filters to off - scanlines[i*(width*4+1)]=0; - - uchar *compressed=new uchar[outsize]; - z_stream strm; - strm.zalloc=Z_NULL; - strm.zfree=Z_NULL; - strm.opaque=Z_NULL; - deflateInit2(&strm,6,Z_DEFLATED,15,8,Z_DEFAULT_STRATEGY); - - double maximum=(bottom+1-top)*(right+1-left); - double step=0.0; - for (int z=top;z<=bottom;z++) - { - for (int x=left;x<=right;x++,step+=1.0) - { - emit progress(tr("Rendering world"),step/maximum); - int rx=x>>5; - int rz=z>>5; - QFile f(path+"/region/r."+QString::number(rx)+"."+QString::number(rz)+".mca"); - if (!f.open(QIODevice::ReadOnly)) - { - blankChunk(scanlines,width*4+1,x-left); - continue; - } - uchar *header=f.map(0,4096); - int offset=4*((x&31)+(z&31)*32); - int coffset=(header[offset]<<16)|(header[offset+1]<<8)|header[offset+2]; - int numSectors=header[offset+3]; - f.unmap(header); - if (coffset==0) //no chunk here - blankChunk(scanlines,width*4+1,x-left); - else - { - uchar *raw=f.map(coffset*4096,numSectors*4096); - NBT nbt(raw); - Chunk *chunk=new Chunk(); - chunk->load(nbt); - f.unmap(raw); - drawChunk(scanlines,width*4+1,x-left,chunk); - delete chunk; - } - f.close(); - } - //write out scanlines to disk - strm.avail_in=insize; - strm.next_in=scanlines; - do { - strm.avail_out=outsize; - strm.next_out=compressed; - deflate(&strm,(z==bottom)?Z_FINISH:Z_NO_FLUSH); - writeChunk(png,"IDAT",(const char *)compressed,outsize-strm.avail_out); - } while (strm.avail_out==0); - } - deflateEnd(&strm); - delete [] scanlines; - delete [] compressed; - - writeChunk(png,"IEND",NULL,0); - png.close(); - emit finished(); +void WorldSave::run() { + emit progress(tr("Calculating world bounds"), 0.0); + QString path = map->getWorldPath(); + + int top, left, right, bottom; + findBounds(path, &top, &left, &bottom, &right); + + int width = (right + 1 - left) * 16; + int height = (bottom + 1 - top) * 16; + + QFile png(filename); + png.open(QIODevice::WriteOnly); + + // output PNG signature + const char *sig = "\x89PNG\x0d\x0a\x1a\x0a"; + png.write(sig, 8); + // output PNG header + const char *ihdrdata = "\x00\x00\x00\x00" // width + "\x00\x00\x00\x00" // height + "\x08" // bit depth + "\x06" // color type (rgba) + "\x00" // compresion method (deflate) + "\x00" // filter method (standard) + "\x00"; // interlace method (none) + char ihdr[13]; + memcpy(ihdr, ihdrdata, 13); + w32(ihdr, width); + w32(ihdr + 4, height); + writeChunk(&png, "IHDR", ihdr, 13); + + int insize = width * 16 * 4 + 16; + int outsize = insize * 2; + + uchar *scanlines = new uchar[insize]; + for (int i = 0; i < 16; i++) // set scanline filters to off + scanlines[i * (width * 4 + 1)] = 0; + + uchar *compressed = new uchar[outsize]; + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + deflateInit2(&strm, 6, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY); + + double maximum = (bottom + 1 - top) * (right + 1 - left); + double step = 0.0; + for (int z = top; z <= bottom; z++) { + for (int x = left; x <= right; x++, step += 1.0) { + emit progress(tr("Rendering world"), step / maximum); + int rx = x >> 5; + int rz = z >> 5; + QFile f(path + "/region/r." + QString::number(rx) + "." + + QString::number(rz) + ".mca"); + if (!f.open(QIODevice::ReadOnly)) { + blankChunk(scanlines, width * 4 + 1, x - left); + continue; + } + uchar *header = f.map(0, 4096); + int offset = 4 * ((x & 31) + (z & 31) * 32); + int coffset = (header[offset] << 16) | (header[offset + 1] << 8) | + header[offset + 2]; + int numSectors = header[offset + 3]; + f.unmap(header); + if (coffset == 0) { + // no chunk here + blankChunk(scanlines, width * 4 + 1, x - left); + } else { + uchar *raw = f.map(coffset * 4096, numSectors * 4096); + NBT nbt(raw); + Chunk *chunk = new Chunk(); + chunk->load(nbt); + f.unmap(raw); + drawChunk(scanlines, width * 4 + 1, x - left, chunk); + delete chunk; + } + f.close(); + } + // write out scanlines to disk + strm.avail_in = insize; + strm.next_in = scanlines; + do { + strm.avail_out = outsize; + strm.next_out = compressed; + deflate(&strm, (z == bottom) ? Z_FINISH : Z_NO_FLUSH); + writeChunk(&png, "IDAT", (const char *)compressed, + outsize - strm.avail_out); + } while (strm.avail_out == 0); + } + deflateEnd(&strm); + delete [] scanlines; + delete [] compressed; + + writeChunk(&png, "IEND", NULL, 0); + png.close(); + emit finished(); } typedef struct { - int x,z; + int x, z; } ChunkPos; -//helper functions for the findBounds function - -static bool outside(int side,ChunkPos &edge,ChunkPos &p) -{ - switch (side) - { - case 0: //top - return edge.z>p.z; - case 1: //left - return edge.x>p.x; - case 2: //bottom - return edge.z p.z; + case 1: // left + return edge.x > p.x; + case 2: // bottom + return edge.z < p.z; + default: // right + return edge.x < p.x; + } } -static bool onside(int side,ChunkPos &edge,ChunkPos &p) -{ - switch (side) - { - case 0: //top or bottom - case 2: - return edge.z==p.z; - default: //left or right - return edge.x==p.x; - } +static bool onside(int side, const ChunkPos &edge, const ChunkPos &p) { + switch (side) { + case 0: // top or bottom + case 2: + return edge.z == p.z; + default: // left or right + return edge.x == p.x; + } } /* - This routine loops through all the region filenames and constructs a list - of regions that lie along the edges of the map. Then it loops through - those region headers and finds the furthest chunks. The end result is - the boundary chunks for the entire world. - - Because we only check at the chunk level, there could be up to 15 pixels - of padding around the edge of the final image. However, if we just - went by regions, there could be 511 pixels of padding. - */ -void WorldSave::findBounds(QString path, int *top, int *left, int *bottom, int *right) -{ - QStringList filters; - filters<<"*.mca"; - - QDirIterator it(path+"/region",filters); - QList edges[4]; - ChunkPos cur; - bool hasOne=false; - - //loop through all region files and find the extremes - while (it.hasNext()) - { - it.next(); - QString fn=it.fileName(); - int len=fn.length()-4; // length of filename - - //figure out the X of the region - int posX=2; // position after "r." - int posE=posX; - while ( posEoffset/128) minz=offset/128; - break; - case 1: //smallest X - if (minx>(offset&127)/4) minx=(offset&127)/4; - break; - case 2: //largest Z - if (maxz edges[4]; + ChunkPos cur; + bool hasOne = false; + + // loop through all region files and find the extremes + while (it.hasNext()) { + it.next(); + QString fn = it.fileName(); + int len = fn.length() - 4; // length of filename + + // figure out the X of the region + int posX = 2; // position after "r." + int posE = posX; + while (posE < len && (fn.at(posE) == '+' || fn.at(posE) == '-' || + fn.at(posE).isDigit())) { + posE++; + } + QStringRef numX(&fn, posX, posE-posX); + cur.x = numX.toInt(); + + // figure out the Z of the region + int posZ = ++posE; + while (posE < len && (fn.at(posE) == '+' || fn.at(posE) == '-' || + fn.at(posE).isDigit())) { + posE++; + } + QStringRef numZ(&fn, posZ, posE - posZ); + cur.z = numZ.toInt(); + + if (!hasOne) { + for (int e = 0; e < 4; e++) + edges[e].append(cur); + hasOne = true; + } + for (int e = 0; e < 4; e++) + if (outside(e, edges[e].front(), cur)) { + edges[e].clear(); + edges[e].append(cur); + } else if (onside(e, edges[e].front(), cur)) { + edges[e].append(cur); + } + } + // find image bounds + int minz = 32, maxz = 0, minx = 32, maxx = 0; + for (int e = 0; e < 4; e++) { + for (int i = 0; i < edges[e].length(); i++) { + QFile f(path+"/region/r." + + QString::number(edges[e].at(i).x) + "." + + QString::number(edges[e].at(i).z) + ".mca"); + f.open(QIODevice::ReadOnly); + uchar *header = f.map(0, 4096); + // loop through all chunk headers. + for (int offset = 0; offset < 4096; offset += 4) { + int coffset = (header[offset] << 16) | (header[offset + 1] << 8) | + header[offset + 2]; + if (coffset != 0) { + switch (e) { + case 0: // smallest Z + minz = qMin(minz, offset / 128); + break; + case 1: // smallest X + minx = qMin(minx, (offset & 127) / 4); + break; + case 2: // largest Z + maxz = qMax(maxz, offset / 128); + break; + case 3: // largest X + maxx = qMax(maxx, (offset & 127) / 4); + break; + } + } + } + f.unmap(header); + f.close(); + } + } + *top = (edges[0].front().z * 32) + minz; + *left = (edges[1].front().x * 32) + minx; + *bottom = (edges[2].front().z * 32) + maxz; + *right = (edges[3].front().x * 32) + maxx; } // sets chunk to transparent -void WorldSave::blankChunk(uchar *scanlines, int stride, int x) -{ - int offset=x*16*4+1; - for (int y=0;y<16;y++,offset+=stride) - memset(scanlines+offset,0,16*4); +void WorldSave::blankChunk(uchar *scanlines, int stride, int x) { + int offset = x * 16 * 4 + 1; + for (int y = 0; y < 16; y++, offset += stride) + memset(scanlines + offset, 0, 16 * 4); } -void WorldSave::drawChunk(uchar *scanlines, int stride, int x, Chunk *chunk) -{ - // calculate attenuation - float attenuation=1.0f; - if ((this->regionChecker) && 0!=(int(floor(chunk->chunkX/32.0f)+floor(chunk->chunkZ/32.0f))%2)) - attenuation *= 0.9f; - if ((this->chunkChecker) && 0!=((chunk->chunkX+chunk->chunkZ)%2)) - attenuation *= 0.9f; - - //render chunk with current settings - map->renderChunk(chunk); - //we can't memcpy each scanline because it's in BGRA format. - int offset=x*16*4+1; - int ioffset=0; - for (int y=0;y<16;y++,offset+=stride) - { - int xofs=offset; - for (int x=0;x<16;x++,xofs+=4) - { - scanlines[xofs+2]=attenuation*chunk->image[ioffset++]; - scanlines[xofs+1]=attenuation*chunk->image[ioffset++]; - scanlines[xofs+0]=attenuation*chunk->image[ioffset++]; - scanlines[xofs+3]=attenuation*chunk->image[ioffset++]; - } - } +void WorldSave::drawChunk(uchar *scanlines, int stride, int x, Chunk *chunk) { + // calculate attenuation + float attenuation = 1.0f; + if (this->regionChecker && static_cast(floor(chunk->chunkX / 32.0f) + + floor(chunk->chunkZ / 32.0f)) % 2 != 0) + attenuation *= 0.9f; + if (this->chunkChecker && ((chunk->chunkX + chunk->chunkZ) % 2) != 0) + attenuation *= 0.9f; + + // render chunk with current settings + map->renderChunk(chunk); + // we can't memcpy each scanline because it's in BGRA format. + int offset = x * 16 * 4 + 1; + int ioffset = 0; + for (int y = 0; y < 16; y++, offset += stride) { + int xofs = offset; + for (int x = 0; x < 16; x++, xofs += 4) { + scanlines[xofs+2] = attenuation * chunk->image[ioffset++]; + scanlines[xofs+1] = attenuation * chunk->image[ioffset++]; + scanlines[xofs+0] = attenuation * chunk->image[ioffset++]; + scanlines[xofs+3] = attenuation * chunk->image[ioffset++]; + } + } } diff --git a/worldsave.h b/worldsave.h index 16e3029d..15153947 100644 --- a/worldsave.h +++ b/worldsave.h @@ -1,32 +1,6 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __WORLDSAVE_H__ -#define __WORLDSAVE_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef WORLDSAVE_H_ +#define WORLDSAVE_H_ #include #include @@ -34,26 +8,26 @@ class MapView; class Chunk; -class WorldSave : public QObject, public QRunnable -{ - Q_OBJECT -public: - WorldSave(QString filename,MapView *map, bool regionChecker=false, bool chunkChecker=false); - ~WorldSave(); -signals: - void progress(QString status,double amount); - void finished(); -protected: - void run(); -private: - void findBounds(QString path,int *top,int *left,int *bottom,int *right); - void blankChunk(uchar *scanlines,int stride,int x); - void drawChunk(uchar *scanlines,int stride,int x,Chunk *chunk); - - QString filename; - MapView *map; - bool regionChecker; - bool chunkChecker; +class WorldSave : public QObject, public QRunnable { + Q_OBJECT + public: + WorldSave(QString filename, MapView *map, bool regionChecker = false, + bool chunkChecker = false); + ~WorldSave(); + signals: + void progress(QString status, double amount); + void finished(); + protected: + void run(); + private: + void findBounds(QString path, int *top, int *left, int *bottom, int *right); + void blankChunk(uchar *scanlines, int stride, int x); + void drawChunk(uchar *scanlines, int stride, int x, Chunk *chunk); + + QString filename; + MapView *map; + bool regionChecker; + bool chunkChecker; }; -#endif +#endif // WORLDSAVE_H_ diff --git a/zipreader.cpp b/zipreader.cpp index d6ad009d..5cebefee 100644 --- a/zipreader.cpp +++ b/zipreader.cpp @@ -1,145 +1,115 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "zipreader.h" +/** Copyright (c) 2013, Sean Kasun */ +#include "./zipreader.h" #include "zlib/zlib.h" -ZipReader::ZipReader(const QString filename) : f(filename) -{ +ZipReader::ZipReader(const QString filename) : f(filename) { } -bool ZipReader::open() -{ - if (!f.open(QIODevice::ReadOnly)) - return false; - - //locate end of central directory record - qint64 ziplen=f.size(); - qint64 maxECDlen=0xffff+22; //max comment len + ECD - if (maxECDlen>ziplen) //zip is shorter? - maxECDlen=ziplen; - - f.seek(ziplen-maxECDlen); //ECD must be after this - - QByteArray data=f.read(maxECDlen); - const quint8 *p=(const quint8 *)data.constData(); - - bool found=false; - //now scan this data for the ECD signature - for (qint64 i=0;i ziplen) // zip is shorter? + maxECDlen = ziplen; + + f.seek(ziplen - maxECDlen); // ECD must be after this + + QByteArray data = f.read(maxECDlen); + const quint8 *p = (const quint8 *)data.constData(); + + bool found = false; + // now scan this data for the ECD signature + for (qint64 i = 0; i < maxECDlen - 20; i++, p++) { + if (p[0] == 0x50 && p[1] == 0x4b && p[2] == 0x05 && p[3] == 0x06) { + found = true; + break; + } + } + if (!found) { + // no ecd found, probably not a zip + f.close(); + return false; + } + + // awesome, now to find the central directory + qint32 cdnum = p[0xa] | (p[0xb] << 8); + qint32 cdsize = p[0xc] | (p[0xd] << 8) | (p[0xe] << 16) | (p[0xf] << 24); + qint64 cdoffset = p[0x10] | (p[0x11] << 8) | (p[0x12] << 16) | + (p[0x13] << 24); + + f.seek(cdoffset); + data = f.read(cdsize); + p = (const quint8 *)data.constData(); + + // loop through all the files + for (int i = 0; i < cdnum; i++) { + if (p[0] != 0x50 || p[1] != 0x4b || p[2] != 0x01 || p[3] != 0x02) { + // not a central file header? + f.close(); // screw this zip + return false; + } + qint16 namelen = p[0x1c] | (p[0x1d] << 8); + qint16 extralen = p[0x1e] | (p[0x1f] << 8); + qint16 commentlen = p[0x20] | (p[0x21] << 8); + QString key = QString::fromUtf8(reinterpret_cast(p + 0x2e), + namelen); + ZipFileHeader &zfh = files[key]; + zfh.compressed = p[0x14] | (p[0x15] << 8) | (p[0x16] << 16) | + (p[0x17] << 24); + zfh.uncompressed = p[0x18] | (p[0x19] << 8) | (p[0x1a] << 16) | + (p[0x1b] << 24); + zfh.compression = p[0xa] | (p[0xb] << 8); + zfh.offset = p[0x2a] | (p[0x2b] << 8) | (p[0x2c] << 16) | (p[0x2d] << 24); + p += 0x2e + namelen + extralen + commentlen; // next file + } + return true; } -QByteArray ZipReader::get(const QString filename) -{ - if (!files.contains(filename)) - return QByteArray(); - ZipFileHeader &zfh=files[filename]; - if (zfh.compression!=0 && zfh.compression!=8) //unsupported compression - return QByteArray(); - f.seek(zfh.offset); - QByteArray lfh=f.read(0x1e); //read local file header - const quint8 *p=(const quint8 *)lfh.constData(); - - //make sure we got a local file header - if (p[0]!=0x50 || p[1]!=0x4b || p[2]!=0x03 || p[3]!=0x04) - return QByteArray(); - - qint32 namelen=p[0x1a]|(p[0x1b]<<8); - qint32 extralen=p[0x1c]|(p[0x1d]<<8); - f.seek(zfh.offset+namelen+extralen+0x1e); //skip header - - QByteArray comp=f.read(zfh.compressed); - if (zfh.compression==0) //no compression - return comp; - QByteArray result; - - z_stream strm; - static const int CHUNK_SIZE = 8192; - char out[CHUNK_SIZE]; - strm.zalloc=Z_NULL; - strm.zfree=Z_NULL; - strm.opaque=Z_NULL; - strm.avail_in=comp.size(); - strm.next_in=(Bytef*)comp.data(); - - inflateInit2(&strm,-MAX_WBITS); - do { - strm.avail_out=CHUNK_SIZE; - strm.next_out=(Bytef*)out; - inflate(&strm,Z_NO_FLUSH); - result.append(out,CHUNK_SIZE-strm.avail_out); - } while (strm.avail_out==0); - inflateEnd(&strm); - return result; +QByteArray ZipReader::get(const QString filename) { + if (!files.contains(filename)) + return QByteArray(); + ZipFileHeader &zfh = files[filename]; + if (zfh.compression != 0 && zfh.compression != 8) // unsupported compression + return QByteArray(); + f.seek(zfh.offset); + QByteArray lfh = f.read(0x1e); // read local file header + const quint8 *p = (const quint8 *)lfh.constData(); + + // make sure we got a local file header + if (p[0] != 0x50 || p[1] != 0x4b || p[2] != 0x03 || p[3] != 0x04) + return QByteArray(); + + qint32 namelen = p[0x1a] | (p[0x1b] << 8); + qint32 extralen = p[0x1c] | (p[0x1d] << 8); + f.seek(zfh.offset + namelen + extralen + 0x1e); // skip header + + QByteArray comp = f.read(zfh.compressed); + if (zfh.compression == 0) // no compression + return comp; + QByteArray result; + + z_stream strm; + static const int CHUNK_SIZE = 8192; + char out[CHUNK_SIZE]; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = comp.size(); + strm.next_in = reinterpret_cast(comp.data()); + + inflateInit2(&strm, -MAX_WBITS); + do { + strm.avail_out = CHUNK_SIZE; + strm.next_out = reinterpret_cast(out); + inflate(&strm, Z_NO_FLUSH); + result.append(out, CHUNK_SIZE - strm.avail_out); + } while (strm.avail_out == 0); + inflateEnd(&strm); + return result; } -void ZipReader::close() -{ - files.clear(); //erase all headers - f.close(); +void ZipReader::close() { + files.clear(); // erase all headers + f.close(); } diff --git a/zipreader.h b/zipreader.h index b1fd7047..ff991747 100644 --- a/zipreader.h +++ b/zipreader.h @@ -1,56 +1,27 @@ -/* - Copyright (c) 2013, Sean Kasun - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __ZIPREADER_H__ -#define __ZIPREADER_H__ +/** Copyright (c) 2013, Sean Kasun */ +#ifndef ZIPREADER_H_ +#define ZIPREADER_H_ #include #include #include #include -struct ZipFileHeader -{ - qint32 compressed,uncompressed; - qint16 compression; - qint64 offset; +struct ZipFileHeader { + qint32 compressed, uncompressed; + qint16 compression; + qint64 offset; }; -class ZipReader -{ -public: - ZipReader(const QString filename); - bool open(); - void close(); - QByteArray get(const QString filename); -private: - QFile f; - QHash files; +class ZipReader { + public: + explicit ZipReader(const QString filename); + bool open(); + void close(); + QByteArray get(const QString filename); + private: + QFile f; + QHash files; }; -#endif +#endif // ZIPREADER_H_