[
  {
    "path": ".gitignore",
    "content": "*~\n*.pyc\nbuild\n*.cmake\n*.a\nMakefile\nCMakeFiles\n*.orig\n*.rej\nsrc/config.hpp\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"libs/unc\"]\n\tpath = libs/unc\n\turl = git://github.com/udoprog/unc.git\n  branch = stable\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.6)\nproject(c10t)\n\nset(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\")\n\n# attempt to find out which revision we are building from\nexecute_process(COMMAND git rev-list HEAD -n1 --abbrev-commit\n        OUTPUT_STRIP_TRAILING_WHITESPACE\n        OUTPUT_VARIABLE C10T_REVISION)\n\nOPTION(BUILD_DEV_LIBS \"Attempt to build libraries under ./libs\" ON)\n\nset(C10T_VERSION \"git ${C10T_REVISION}\")\nset(C10T_SITE \"http://github.com/udoprog/c10t\")\nset(C10T_CONTACT \"Udoprog <johnjohn.tedro@gmail.com> et. al (see README)\")\nset(C10T_COMMENT \"Created using c10t (http://github.com/udoprog/c10t)\")\n\nconfigure_file(${CMAKE_SOURCE_DIR}/src/config.hpp.cmake\n  ${CMAKE_BINARY_DIR}/src/config.hpp)\n\ninclude_directories(${CMAKE_BINARY_DIR}/src)\n# output the binary to the build directory instead of in src/\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})\n\nOPTION(Boost_USE_STATIC_LIBS \"Use static boost libs\" TRUE)\n\nfind_package(ZLIB REQUIRED)\nfind_package(PNG 1.2 REQUIRED)\nfind_package(Freetype 2 REQUIRED)\nfind_package(Threads REQUIRED)\nfind_package(Boost 1.46 COMPONENTS thread filesystem system REQUIRED)\n\ninclude_directories(${CMAKE_SOURCE_DIR}/src)\ninclude_directories(${ZLIB_INCLUDE_DIR})\ninclude_directories(${PNG_INCLUDE_DIR})\ninclude_directories(${FREETYPE_INCLUDE_DIR_freetype2})\ninclude_directories(${FREETYPE_INCLUDE_DIR_ft2build})\ninclude_directories(${Boost_INCLUDE_DIR})\n\nset(c10t_LIBRARIES\n  dl\n  # internal libraries that could/should be externalized\n  c10t-image\n  c10t-nbt\n  c10t-mc\n  c10t-engine\n  # external libraries\n  ${ZLIB_LIBRARIES}\n  ${PNG_LIBRARIES}\n  ${CMAKE_THREAD_LIBS_INIT}\n  ${Boost_LIBRARIES}\n  ${FREETYPE_LIBRARY}\n  )\n\nif (BUILD_DEV_LIBS)\n  include_directories(\"${CMAKE_SOURCE_DIR}/libs/unc/src\")\n  add_subdirectory(libs/unc)\n  set(c10t_LIBRARIES ${c10t_LIBRARIES}\n    unc\n    uncdata\n    )\nelse (BUILD_DEV_LIBS)\n  find_package(PkgConfig)\n  pkg_check_modules(UNC unc)\n  set(c10t_LIBRARIES ${c10t_LIBRARIES} ${UNC_LIBRARIES})\nendif (BUILD_DEV_LIBS)\n\nadd_subdirectory(src/image)\nadd_subdirectory(src/engine)\nadd_subdirectory(src/nbt)\nadd_subdirectory(src/mc)\n\nadd_subdirectory(test)\n\nset(c10t_SOURCES \n  src/main.cpp\n  src/dlopen.cpp\n  src/main_utils.cpp\n  src/algorithm.cpp\n  src/players.cpp\n  src/fileutils.cpp\n  src/dirlist.cpp\n  src/altitude_graph.cpp\n  src/warps.cpp\n  src/text.cpp\n  src/json.cpp\n  src/generate_map.cpp\n  src/generate_statistics.cpp\n  src/marker.cpp\n  src/nullstream.cpp\n  src/settings_t.cpp\n  )\n\nadd_executable(c10t ${c10t_SOURCES})\nadd_executable(c10t-debug EXCLUDE_FROM_ALL ${c10t_SOURCES})\nadd_executable(nbt-inspect EXCLUDE_FROM_ALL src/nbt/nbt_inspect.cpp src/nbt/nbt.cpp)\nadd_executable(region-inspect EXCLUDE_FROM_ALL src/mc/region_inspect.cpp)\n\nset_target_properties(c10t PROPERTIES COMPILE_FLAGS \"-O3 -Wall -pedantic\")\nset_target_properties(c10t-debug PROPERTIES COMPILE_FLAGS \"-Wall -pedantic -g\")\nset_target_properties(nbt-inspect PROPERTIES COMPILE_FLAGS \"-O3 -Wall -pedantic\")\nset_target_properties(region-inspect PROPERTIES COMPILE_FLAGS \"-O3 -Wall -pedantic\")\n\ntarget_link_libraries(c10t ${c10t_LIBRARIES})\ntarget_link_libraries(c10t-debug ${c10t_LIBRARIES})\ntarget_link_libraries(nbt-inspect ${ZLIB_LIBRARIES})\ntarget_link_libraries(region-inspect ${c10t_LIBRARIES})\n"
  },
  {
    "path": "ChangeLog",
    "content": "Wed Nov 17 21:23:38 CET 2010\n\t- By popular demand, including the google-api scripts by the following\n\tindividuals from minecraftforum:\n\tRendrik - php\n\tKochu - powershell\n\nWed Nov  3 15:16:21 CET 2010\n\t- Show warp positions, by phlip at minecraftforum\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "// BSD license. Copyright (c) 2010, John-John Tedro et al.\n// All rights reserved.\n// \n// Redistribution and use in source and binary forms, with or without \n// modification, are permitted provided that the following conditions are met:\n// \n//  * Redistributions of source code must retain the above copyright notice, \n// this list of conditions and the following disclaimer.\n//  * Redistributions in binary form must reproduce the above copyright notice, \n// this list of conditions and the following disclaimer in the documentation \n// and/or other materials provided with the distribution.\n//  * Neither the name of the minecraft community nor the names of its \n// contributors may be used to endorse or promote products derived from this \n// software without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" \n// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \n// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE \n// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR \n// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF \n// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) \n// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE \n// POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "c10t - a cartography tool for Minecraft\r\n=======================================\r\n\r\nI wrote c10t entirely because i liked the tool Cartograph by ZomBuster, but I wasn't too fond of a couple of aspects about how rendering was performed.\r\n\r\nRequirements\r\n------------\r\n\r\n  * libz (?)\r\n  * libpng (>= 1.2)\r\n  * libfreetype (>= 2)\r\n  * libboost (thread, filesystem, system and test) (>= 1.46)\r\n\r\nFeatures\r\n--------\r\n\r\n  * Pipelined rendering process (using image compositioning) which allows for\r\n    multithreaded rendering.\r\n  * Very memory friendly, you can specify a memory limit and it will switch caching to file.\r\n  * Uses proper command line options.\r\n  * Clean code, for easing further development.\r\n  * Multiplatform - yes, it does compile properly on windows and mac.\r\n  * A gui wrapper, see: http://github.com/udoprog/c10t-swt (native gui with java bindings)\r\n\r\nI would not have done this were it not for the excellent inspiration by\r\nZomBuster and Firemark (the linux port of cartograph). Thank you for the\r\ninspiration.\r\n\r\nBuilding from Source (using cmake)\r\n----------------------------------\r\n\r\n### Ubuntu ###\r\n\r\n 1. Install dependencies:\r\n\r\n        $ sudo apt-get install build-essential cmake libpng-dev zlib1g-dev libboost-all-dev libfreetype6-dev\r\n\r\n    If libboost >= 1.46 is not available by using your package manager, you need to install it from source. To do so download and untar it from www.boost.org and perform the following operations as root:\r\n\r\n        $ ./bootstrap --prefix=/usr\r\n        $ ./b2 install\r\n\r\n    If you have troubles installing boost, consult the Getting Started Guide on the website of the boost library.\r\n\r\n 2. Clone repository\r\n\r\n        $ git clone git://github.com/udoprog/c10t.git\r\n        $ cd c10t\r\n\r\n    You need to clone the repository in order to successfully execute the commands in step three. You can get support for git on the following web page:\r\n    http://schacon.github.com/git/gittutorial.html\r\n    Just scroll to the section \"Using git for collaboration\".\r\n\r\n 3. Update submodules which contains some required dependencies (./libs):\r\n\r\n        $ git submodule init\r\n        $ git submodule update\r\n\r\n 4. Run:\r\n\r\n        $ mkdir build\r\n        $ cd build\r\n        $ cmake ..\r\n        $ make c10t\r\n\r\n * CMake should generate a file called src/config.h from the input file src/config.h.cmake\r\n  \r\n * There are several targets you can make.  c10t, c10t-lib, c10t-debug, and c10t-test.\r\n   * If you wish to build all of these simply run `make` which defaults to target `all`.\r\n   * If you wish to build any individual one run `make <target>` e.g. `make c10t-test`.\r\n\r\n4. The executable `c10t` should be in the current directory.\r\n\r\nThere are a couple of available targets\r\n\r\n * ___c10t-debug___ - debug build with symbols, nice for debugging\r\n * ___c10t-lib___ - library that contains all c10t functions not in main or nbt_inspect\r\n * ___nbt-inspect___ - dumps the content of an nbt data file (basically anything in the world directory). Useful for writing tools.\r\n * ___region-inspect___ - dumps the content of a mcr region file.\r\n\r\nIssues\r\n------\r\n\r\n * Issues should be posted on http://github.com/udoprog/c10t/issues\r\n * Run the program in debug mode (c10t --debug), this will print useful information, but be much slower.\r\n * ALWAYS include `c10t --version` information when posting issues, that way it can be determined weither the issue already has been resolved or not, if this information is missing, the issue probably cannot be resolved.\r\n * ALWAYS include the following information: Platform (e.g. Windows, Linux, Mac) and Architecture (x86, x86_64)\r\n * IF POSSIBLE include information which can help us reproduce the problem.\r\n\r\nContributors\r\n------------\r\n    UniversE - for epic center calculation, and saving the api!\r\n\r\nContributions\r\n-------------\r\n    ZomBuster and Firemark - for their original work\r\n    Guardian9979 - for his continual nagging for improvements\r\n    acleone - for his work with cmake [85e980a]\r\n    j005u - for explaining how cocoa works\r\n    jnnnnn - for limit options which are helpful when debugging (and quite cool)\r\n    mudaltsov - for mapping out the Mac OS X building process and creating a splendid package!\r\n    frozencow - for fixing boost_thread configuration for cmake\r\n    reportingjsr - for pointing out build issues\r\n    Dim-Dul - for providing a nice map to render\r\n    vostok4 - for implementing google API support\r\n    rmmh - for figuring out png compression and encouraging people to build properly.\r\n    Athemis - for fixing beta 1.2 compatibility.\r\n    sn4kebite - for implementing Wool colors.\r\n    ekryyn - for implementing the altitude graph!\r\n"
  },
  {
    "path": "dist/Makefile.osx",
    "content": "ARCH=intel\nOS=osx\nVERSION=SNAPSHOT\n\nUSR=/opt/local\nCXXFLAGS=-arch i386 -arch x86_64 -Isrc -I/opt/local/include\nLDFLAGS=-pthread\nLDFLAGS+=\"/opt/local/lib/libpng.a\"\nLDFLAGS+=\"/opt/local/lib/libz.a\"\nLDFLAGS+=\"/opt/local/lib/libboost_thread-mt.a\"\nLDFLAGS+=\"/opt/local/lib/libboost_system-mt.a\"\nLDFLAGS+=\"/opt/local/lib/libboost_filesystem-mt.a\"\nLDFLAGS+=\"/opt/local/lib/libfreetype.a\"\nDIST=c10t\nBIN=c10t\nTARGET_DEBUG=c10t-debug\n\ninclude config.mk\n\nlocal-package:\n\tcp LICENSE.txt ${PACKAGE}/LICENSE.txt\n\tcp README.md ${PACKAGE}/README\n\tcp -R scripts/google-api/ ${PACKAGE}/\n\tcp -R res/libc10t.js ${PACKAGE}/\n\tcp -R res/example.html ${PACKAGE}/\n\t\n\tzip -r ${PACKAGE}-${OS}-${ARCH}.zip ${PACKAGE}\n\tmv ${PACKAGE}-${OS}-${ARCH}.zip ${BUILD}/${PACKAGE}-${OS}-${ARCH}.zip\n\tsha1sum ${BUILD}/${PACKAGE}-${OS}-${ARCH}.zip > ${BUILD}/${PACKAGE}-${OS}-${ARCH}.zip.sha1\n"
  },
  {
    "path": "dist/README.md",
    "content": "This little setup came out of me wanting to setup my server to build SNAPSHOTS about once very day.\nThese scripts generate static binaries, and they require you to have all required libraries pre-installed.\n\nThis is not meant to be used by a broad set of users, therefore it is very specialized to my system setup, but still might be useful if you want to setup something similar yourself.\n\nThis is what I do for building static binary for windows:\n  i686-mingw32-g++ -DBOOST_THREAD_USE_LIB -I./contrib/include \\\n       -static-libgcc $(find src -name \"*.cpp\") \\\n      ./contrib/boost_thread/src/win32/thread.cpp \\\n      ./contrib/boost_thread/src/win32/tss_pe.cpp \\\n      ./contrib/tss_dummy.cpp \\\n      -static -lpng14 -lz -lpthreadGC2 \\\n      -o c10t.exe\n\nNow, the only thing I havent gotten down yet is mac. I have no experience and no means to test it, so if someone would like to inform me on how it's done, I'm all ears.\n\nIf you want to run these manually, you have to be in the root directory, and issue the following command:\n\n  make -f dist/Makefile.<target-os> clean all\n\nPlease not that the 'clean' is basically compulsary, since it will probably otherwise break when doing multiple targets due to output format.\n\nThis also assumes that you've already generated the src/config.h, you do this by typing:\n\n  cmake .\n\nMy cross development setup is base of gentoo crossdev, this allows me to have multiple comilers and library setups without conflicts:\n\n  http://en.gentoo-wiki.com/wiki/Crossdev\n\nGood luck, this is me sharing my experiences\n\n-- Udoprog\n"
  },
  {
    "path": "dist/all.sh",
    "content": "#!/bin/sh\n\nfor dist in $(ls -1 dist/targets); do\n  if ! dist/make.sh $dist \"$@\"; then\n    echo \"TARGET FAILED: $dist\"\n    exit 1\n  fi\ndone\n"
  },
  {
    "path": "dist/config.mk",
    "content": "USR?=/usr/${TARGET}/usr\nLIB?=${USR}/lib\n\nSOURCES+=src/algorithm.cpp\nSOURCES+=src/altitude_graph.cpp\nSOURCES+=src/dirlist.cpp\nSOURCES+=src/dlopen.cpp\nSOURCES+=src/engine/block_rotation.cpp\nSOURCES+=src/engine/fatiso_engine.cpp\nSOURCES+=src/engine/flat_base.cpp\nSOURCES+=src/engine/functions.cpp\nSOURCES+=src/engine/isometric_base.cpp\nSOURCES+=src/engine/isometric_engine.cpp\nSOURCES+=src/engine/obliqueangle_engine.cpp\nSOURCES+=src/engine/oblique_engine.cpp\nSOURCES+=src/engine/topdown_engine.cpp\nSOURCES+=src/fileutils.cpp\nSOURCES+=src/generate_map.cpp\nSOURCES+=src/generate_statistics.cpp\nSOURCES+=src/image/algorithms.cpp\nSOURCES+=src/image/cached_image.cpp\nSOURCES+=src/image/color.cpp\nSOURCES+=src/image/image_base.cpp\nSOURCES+=src/image/image_operations.cpp\nSOURCES+=src/image/memory_image.cpp\nSOURCES+=src/json.cpp\nSOURCES+=src/main.cpp\nSOURCES+=src/main_utils.cpp\nSOURCES+=src/marker.cpp\nSOURCES+=src/mc/blocks.cpp\nSOURCES+=src/mc/dynamic_buffer.cpp\nSOURCES+=src/mc/level.cpp\nSOURCES+=src/mc/level_info.cpp\nSOURCES+=src/mc/marker.cpp\nSOURCES+=src/mc/region.cpp\nSOURCES+=src/mc/region_inspect.cpp\nSOURCES+=src/mc/region_iterator.cpp\nSOURCES+=src/mc/rotated_level_info.cpp\nSOURCES+=src/mc/utils.cpp\nSOURCES+=src/mc/world.cpp\nSOURCES+=src/nbt/nbt.cpp\nSOURCES+=src/nbt/nbt_inspect.cpp\nSOURCES+=src/nullstream.cpp\nSOURCES+=src/players.cpp\nSOURCES+=src/settings_t.cpp\nSOURCES+=src/text.cpp\nSOURCES+=src/warps.cpp\nSOURCES+=src/win32/tss_cleanup_implemented.cpp\n\nLDFLAGS+=${LIB}/libpng.a\nLDFLAGS+=${LIB}/libboost_thread.a\nLDFLAGS+=${LIB}/libboost_system.a\nLDFLAGS+=${LIB}/libboost_filesystem.a\nLDFLAGS+=${LIB}/libfreetype.a\nLDFLAGS+=${LIB}/libz.a\nLDFLAGS+=${LIB}/libbz2.a\nLDFLAGS+=${LIB}/libdl.a\nLDFLAGS+=${LIB}/libunc.a\nLDFLAGS+=${LIB}/libuncdata.a\n\nOBJECTS=${SOURCES:.cpp=.o}\nCXXFLAGS+=-Isrc -I${USR}/include/freetype2 -Wall -fomit-frame-pointer -O2\n\nCXX=${TARGET}-g++\nSTRIP=${TARGET}-strip\n\nVERSION?=SNAPSHOT\nPACKAGE=c10t-${VERSION}-${OS}-${ARCH}\n\nBUILD=./build\n\nall: package\n\n.SUFFIXES: .cpp .o\n\n.cpp.o:\n\t${CXX} ${CXXFLAGS} -c $< -o $@\n\n${BIN}: ${OBJECTS}\n\t${CXX} ${CXXFLAGS} ${OBJECTS} ${LDFLAGS} -o ${BIN}\n\t${STRIP} ${BIN}\n\nclean:\n\t${RM} ${OBJECTS}\n\t${RM} -rf ${PACKAGE}\n\npre-package: ${BIN}\n\techo \"pre-package: ${PACKAGE}\"\n\tmkdir -p ${PACKAGE}\n\tcp ${BIN} ${PACKAGE}/${BIN}\n\trm -rf ${BUILD}\n\tmkdir -p ${BUILD}\n\npost-package:\n\techo \"post-package: ${PACKAGE}\"\n\t${RM} -rf ${PACKAGE}\n\npackage: pre-package local-package post-package\n\n%.sha1:\n\tsha1sum $* > $*.sha1\n\tcp $@ ${BUILD}/$@\n\n%.tar.gz:\n\ttar -cvf $*.tar $*\n\tgzip -f $*.tar\n\tcp $@ ${BUILD}/$@\n\n%.zip:\n\tzip -r $*.zip $*\n\tcp $@ ${BUILD}/$@\n"
  },
  {
    "path": "dist/make.sh",
    "content": "#!/bin/bash\n\ntarget=$1\n\nshift\n\ndist_target=dist/targets/$target\nbuild_target=build/$target\ndist_config=dist/config.mk\ndist_src=src\ndist_scripts=scripts\ndist_res=res\n\nexit_usage() {\n  echo \"Usage: dist/dist.sh <target> [make-opts]\"\n  echo \"<target> is one of:\"\n  ls -1 dist/targets\n  exit 1\n}\n\ndo_cp() {\n  if test $1 -nt $2; then\n    printf \"cp %-37s -> %s\\n\" \"$1\" \"$2\"\n    cp $1 $2\n  fi\n\n  return 0\n}\n\ndo_sync() {\n  src=$1\n  dir=$2\n\n  shift 2\n\n  echo \"Syncing $src to $dir/$src \\\"$@\\\"\"\n\n  while read file; do\n    target=\"$dir/$file\"\n    mkdir -p $(dirname \"$target\")\n\n    if test $file -nt $target; then\n      printf \"%-40s -> %s\\n\" \"$file\" \"$target\"\n      cp -p \"$file\" \"$target\"\n    fi\n  done < <(find $src -type f \"$@\")\n}\n\n[[ ! -d dist/targets ]] && echo \"Not in build directory\" && exit 1\n[[ -z $target ]] && exit_usage\n[[ ! -f $dist_target ]] && exit_usage\n\nif ! cmake .; then\n  echo \"cmake: failed\"\n  exit 1\nfi\n\nmkdir -p $build_target\ndo_cp $dist_target $build_target/Makefile\ndo_cp $dist_config $build_target/config.mk\ndo_cp LICENSE.txt $build_target/LICENSE.txt\ndo_cp README.md $build_target/README.md\ndo_sync $dist_src $build_target -name \"*.cpp\"\ndo_sync $dist_src $build_target -name \"*.hpp\"\ndo_sync $dist_scripts $build_target\ndo_sync $dist_res $build_target\n\necho \"cd $build_target && make $@\"\ncd $build_target && make \"$@\"\nexit $?\n"
  },
  {
    "path": "dist/targets/x86-linux",
    "content": "ARCH=x86\nOS=linux\n\nTARGET=i686-linux-gnu\n\nLDFLAGS=-pthread -static -static-libgcc\nBIN=c10t\n\ninclude config.mk\n\nlocal-package:\n\tcp LICENSE.txt ${PACKAGE}/LICENSE.txt\n\tcp README.md ${PACKAGE}/README\n\tcp -R scripts/google-api ${PACKAGE}/\n\tcp -R res/libc10t.js ${PACKAGE}/\n\tcp -R res/example.html ${PACKAGE}/\n\tmake ${PACKAGE}.tar.gz\n\tmake ${PACKAGE}.tar.gz.sha1\n"
  },
  {
    "path": "dist/targets/x86-windows",
    "content": "ARCH=x86\nOS=windows\n\nTARGET=i686-mingw32\n\nBIN=c10t.exe\nCXXFLAGS=-DBOOST_THREAD_USE_LIB=1\nLDFLAGS=-static -static-libgcc\n\ninclude config.mk\n\nlocal-package:\n\tcp LICENSE.txt ${PACKAGE}/LICENSE.txt\n\tcp README.md ${PACKAGE}/README.txt\n\tcp -R scripts/google-api ${PACKAGE}/\n\tcp -R res/libc10t.js ${PACKAGE}/\n\tcp -R res/example.html ${PACKAGE}/\n\tmake ${PACKAGE}.zip\n\tmake ${PACKAGE}.zip.sha1\n"
  },
  {
    "path": "dist/targets/x86_64-linux",
    "content": "ARCH=x86_64\nOS=linux\n\nLDFLAGS=-pthread -static -static-libgcc\nBIN=c10t\n\ninclude config.mk\n\nTARGET=x86_64-linux-gnu\nUSR=/usr\n\nlocal-package:\n\tcp LICENSE.txt ${PACKAGE}/LICENSE.txt\n\tcp README.md ${PACKAGE}/README\n\tcp -R scripts/google-api ${PACKAGE}/\n\tcp -R res/libc10t.js ${PACKAGE}/\n\tcp -R res/example.html ${PACKAGE}/\n\tmake ${PACKAGE}.tar.gz\n\tmake ${PACKAGE}.tar.gz.sha1\n"
  },
  {
    "path": "dist/targets/x86_64-windows",
    "content": "ARCH=x86_64\nOS=windows\n\nTARGET=x86_64-w64-mingw32\n\nBIN=c10t.exe\nCXXFLAGS=-m64 -O3 -DBOOST_THREAD_USE_LIB=1 -DBOOST_USE_WINDOWS_H\nLDFLAGS=-static -static-libgcc\nSOURCES=src/win32/tss_cleanup_implemented.cpp\n\ninclude config.mk\n\nlocal-package:\n\tcp LICENSE.txt ${PACKAGE}/LICENSE.txt\n\tcp README.md ${PACKAGE}/README.txt\n\tcp -R scripts/google-api ${PACKAGE}/\n\tcp -R res/libc10t.js ${PACKAGE}/\n\tcp -R res/example.html ${PACKAGE}/\n\tmake ${PACKAGE}.zip\n\tmake ${PACKAGE}.zip.sha1\n"
  },
  {
    "path": "docs/NBT.txt",
    "content": "Named Binary Tag specification\n\nNBT (Named Binary Tag) is a tag based binary format designed to carry large amounts of binary data with smaller amounts of additional data.\nAn NBT file consists of a single GZIPped Named Tag of type TAG_Compound.\n\nA Named Tag has the following format:\n\n    byte tagType\n    TAG_String name\n    [payload]\n    \nThe tagType is a single byte defining the contents of the payload of the tag.\n\nThe name is a descriptive name, and can be anything (eg \"cat\", \"banana\", \"Hello World!\"). It has nothing to do with the tagType.\nThe purpose for this name is to name tags so parsing is easier and can be made to only look for certain recognized tag names.\nException: If tagType is TAG_End, the name is skipped and assumed to be \"\".\n\nThe [payload] varies by tagType.\n\nNote that ONLY Named Tags carry the name and tagType data. Explicitly identified Tags (such as TAG_String above) only contains the payload. \n\n\nThe tag types and respective payloads are:\n\n    TYPE: 0  NAME: TAG_End\n    Payload: None.\n    Note:    This tag is used to mark the end of a list.\n             Cannot be named! If type 0 appears where a Named Tag is expected, the name is assumed to be \"\".\n             (In other words, this Tag is always just a single 0 byte when named, and nothing in all other cases)\n    \n    TYPE: 1  NAME: TAG_Byte\n    Payload: A single signed byte (8 bits)\n\n    TYPE: 2  NAME: TAG_Short\n    Payload: A signed short (16 bits, big endian)\n\n    TYPE: 3  NAME: TAG_Int\n    Payload: A signed short (32 bits, big endian)\n\n    TYPE: 4  NAME: TAG_Long\n    Payload: A signed long (64 bits, big endian)\n\n    TYPE: 5  NAME: TAG_Float\n    Payload: A floating point value (32 bits, big endian, IEEE 754-2008, binary32)\n\n    TYPE: 6  NAME: TAG_Double\n    Payload: A floating point value (64 bits, big endian, IEEE 754-2008, binary64)\n    \n    TYPE: 7  NAME: TAG_Byte_Array\n    Payload: TAG_Int length \n             An array of bytes of unspecified format. The length of this array is <length> bytes\n\n    TYPE: 8  NAME: TAG_String\n    Payload: TAG_Short length \n             An array of bytes defining a string in UTF-8 format. The length of this array is <length> bytes\n\n    TYPE: 9  NAME: TAG_List\n    Payload: TAG_Byte tagId\n             TAG_Int length\n             A sequential list of Tags (not Named Tags), of type <typeId>. The length of this array is <length> Tags\n    Notes:   All tags share the same type.\n             \n    TYPE: 10 NAME: TAG_Compound\n    Payload: A sequential list of Named Tags. This array keeps going until a TAG_End is found.\n             TAG_End end\n    Notes:   If there's a nested TAG_Compound within this tag, that one will also have a TAG_End, so simply reading until the next TAG_End will not work.\n             The names of the named tags have to be unique within each TAG_Compound\n             The order of the tags is not guaranteed.\n             \n             \n\n\n\nDecoding example:\n(Use http://www.minecraft.net/docs/test.nbt to test your implementation)\n\n\nFirst we start by reading a Named Tag.\nAfter unzipping the stream, the first byte is a 10. That means the tag is a TAG_Compound (as expected by the specification).\n\nThe next two bytes are 0 and 11, meaning the name string consists of 11 UTF-8 characters. In this case, they happen to be \"hello world\".\nThat means our root tag is named \"hello world\". We can now move on to the payload.\n\nFrom the specification, we see that TAG_Compound consists of a series of Named Tags, so we read another byte to find the tagType.\nIt happens to be an 8. The name is 4 letters long, and happens to be \"name\". Type 8 is TAG_String, meaning we read another two bytes to get the length,\nthen read that many bytes to get the contents. In this case, it's \"Bananrama\".\n\nSo now we know the TAG_Compound contains a TAG_String named \"name\" with the content \"Bananrama\"\n\nWe move on to reading the next Named Tag, and get a 0. This is TAG_End, which always has an implied name of \"\". That means that the list of entries\nin the TAG_Compound is over, and indeed all of the NBT file.\n\nSo we ended up with this:\n\n\tTAG_Compound(\"hello world\"): 1 entries\n\t{\n\t   TAG_String(\"name\"): Bananrama\n\t}\n\n\n\nFor a slightly longer test, download http://www.minecraft.net/docs/bigtest.nbt\nYou should end up with this:\n\n\tTAG_Compound(\"Level\"): 11 entries\n\t{\n\t   TAG_Short(\"shortTest\"): 32767\n\t   TAG_Long(\"longTest\"): 9223372036854775807\n\t   TAG_Float(\"floatTest\"): 0.49823147\n\t   TAG_String(\"stringTest\"): HELLO WORLD THIS IS A TEST STRING !\n\t   TAG_Int(\"intTest\"): 2147483647\n\t   TAG_Compound(\"nested compound test\"): 2 entries\n\t   {\n\t      TAG_Compound(\"ham\"): 2 entries\n\t      {\n\t         TAG_String(\"name\"): Hampus\n\t         TAG_Float(\"value\"): 0.75\n\t      }\n\t      TAG_Compound(\"egg\"): 2 entries\n\t      {\n\t         TAG_String(\"name\"): Eggbert\n\t         TAG_Float(\"value\"): 0.5\n\t      }\n\t   }\n\t   TAG_List(\"listTest (long)\"): 5 entries of type TAG_Long\n\t   {\n\t      TAG_Long: 11\n\t      TAG_Long: 12\n\t      TAG_Long: 13\n\t      TAG_Long: 14\n\t      TAG_Long: 15\n\t   }\n\t   TAG_Byte(\"byteTest\"): 127\n\t   TAG_List(\"listTest (compound)\"): 2 entries of type TAG_Compound\n\t   {\n\t      TAG_Compound: 2 entries\n\t      {\n\t         TAG_String(\"name\"): Compound tag #0\n\t         TAG_Long(\"created-on\"): 1264099775885\n\t      }\n\t      TAG_Compound: 2 entries\n\t      {\n\t         TAG_String(\"name\"): Compound tag #1\n\t         TAG_Long(\"created-on\"): 1264099775885\n\t      }\n\t   }\n\t   TAG_Byte_Array(\"byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))\"): [1000 bytes]\n\t   TAG_Double(\"doubleTest\"): 0.4931287132182315\n\t}\n"
  },
  {
    "path": "gui/c10t-tk/README",
    "content": "This is a simple GUI using Python and Tkinter.\n\nI know Tkinter is ugly and it sucks... But it is available on the standard Python library, so this GUI works out-of-the-box on Linux and Windows and Mac (but I don't have a Mac to test).\n\nThe image previewing feature requires PIL (Python Imaging Library). If it is not available, the GUI will still work, the image will be saved to disk, but it won't be displayed.\n\nHow to run:\n* cd to the project root dir (the one which will contain the c10t executable)\n* run ./gui/c10t-tk/c10t-tk.py\nNotice: in fact, you can run the GUI from whatever directory you want, but the suggestion above will make everything work by default.\n\nThis is what it does:\n* Graphical interface to select the most common c10t options\n* Runs c10t with such options\n* Shows the final command-line, so it's easy to copy-paste that onto scripts\n* Previews the rendered image, with zoom\n\nWhat it still doesn't do:\n* It don't show any output from c10t\n* There is no error checking when c10t runs\n* There is no progress bar (the program just hangs while c10t is running)\n* The program also hangs briefly while zooming in/out the image\n\nPossible improvements:\n* Some kind of interface to select blocks\n* Some kind of interface to select files/directories\n* Auto-detect the correct minecraft save path on other systems\n* Use a checkbutton for threads (when off, use the built-in auto-detection) instead of the quick-and-dirty hack of selecting zero threads\n* Use radiobuttons (intead of checkbuttons) for selecting the rendering mode (group by (normal, oblique, obliqueangle, isometric) (normal, night, heightmap) )\n* Add support for --no-alpha and --striped-terrain\n* Improve the packaging?\n"
  },
  {
    "path": "gui/c10t-tk/c10t-tk.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# vi:ts=4 sw=4 et\n\nimport re\nimport os.path\nimport subprocess\nfrom mainwindow import MainWindow\n\n\ndef default_c10t_executable():\n    return \"./c10t\"\n\ndef default_minecraft_world():\n    return \"~/.minecraft/saves/World1\"\n\ndef default_output_image():\n    return os.path.abspath(\"out.png\")\n\n\ndef quote_arg_if_needed(arg):\n    \"\"\"Add quotes if the argument has 'weird' characters.\n\n    This function is extremely simple, and it is not fool-proof.\n    Improvements are quite welcome!\n    \n    WARNING: single-quotes inside the argument will break this!\"\"\"\n\n    if re.search(r'''[^-a-zA-Z0-9_.,/+=]''', arg):\n        return \"'%s'\" % (arg,)\n    else:\n        return arg\n\ndef args_to_string(args):\n    \"\"\"Converts a list of arguments to one string that can be copy-pasted\n    into a terminal and will work (hopefully).\"\"\"\n\n    return \" \".join(quote_arg_if_needed(arg) for arg in args)\n\n\nclass Program(object):\n    def __init__(self):\n        self.win = MainWindow()\n        self.args = []\n\n        # Files\n        self.win.ui.exepath = default_c10t_executable()\n        self.win.ui.world = default_minecraft_world()\n        self.win.ui.output = default_output_image()\n\n        self.update_ui_commandline()\n\n        self.win.update_button_callback = self.update_ui_commandline\n        self.win.run_button_callback = self.run_command\n        self.win.load_button_callback = self.load_image\n\n    def run_command(self):\n        self.update_ui_commandline()\n        proc = subprocess.Popen(self.args, shell=False)\n        # TODO: Add a progress window/progress bar\n        # Meanwhile... let's just block this program until c10t finishes...\n        # Ugly, but better than nothing.\n        proc.communicate() # TODO: Check process returncode\n        self.load_image()\n\n    def load_image(self):\n        self.win.load_image_from_file(os.path.expanduser(self.win.ui.output))\n\n    def update_ui_commandline(self):\n        self.build_commandline()\n        self.win.ui.command = args_to_string(self.args)\n\n    def build_commandline(self):\n        ui = self.win.ui\n\n        args = [os.path.expanduser(ui.exepath)]\n\n        # Filtering\n        if ui.topcheck   : args.extend([\"--top\"   , str(ui.top   )])\n        if ui.bottomcheck: args.extend([\"--bottom\", str(ui.bottom)])\n        if ui.limitscheck:\n            args.extend([\n                \"--limits\",\n                \",\".join(str(x) for x in (\n                    ui.limitsnorth,\n                    ui.limitssouth,\n                    ui.limitseast,\n                    ui.limitswest,\n                ))\n            ])\n        if ui.cavemodecheck: args.append(\"--cave-mode\")\n        if ui.excludecheck:\n            for block in re.split(\"[ \\t,;/]+\", ui.exclude):\n                args.extend([\"-e\", str(block)])\n        if ui.includecheck:\n            args.append(\"--hide-all\")\n            for block in re.split(\"[ \\t,;/]+\", ui.include):\n                args.extend([\"-i\", str(block)])\n\n        # Rendering\n        if ui.obliquecheck     : args.append(\"--oblique\")\n        if ui.obliqueanglecheck: args.append(\"--oblique-angle\")\n        if ui.isometriccheck   : args.append(\"--isometric\")\n        if ui.nightcheck       : args.append(\"--night\")\n        if ui.heightmapcheck   : args.append(\"--heightmap\")\n        if ui.rotate           : args.extend([\"-r\", str(ui.rotate)])\n        if int(ui.threads) != 0: args.extend([\"--threads\", str(ui.threads)])\n\n        # Text and fonts\n        args.extend([\"--ttf-size\" , str(ui.ttfsize)])\n        args.extend([\"--ttf-color\", str(ui.ttfcolor)])\n        if ui.showplayerscheck: args.append(\"--show-players\")\n        if ui.showsignscheck  : args.append(\"--show-signs\")\n        if ui.showcoordscheck : args.append(\"--show-coordinates\")\n        if ui.playercolorcheck: args.extend([\"--player-color\", str(ui.playercolor)])\n        if ui.signcolorcheck  : args.extend([\"--sign-color\", str(ui.signcolor)])\n        if ui.coordcolorcheck : args.extend([\"--coordinate-color\", str(ui.coordcolor)])\n\n        # Adding the \"Files\" section to the end for readability reasons\n        args.extend([\n            \"-w\", os.path.expanduser(ui.world),\n            \"-o\", os.path.expanduser(ui.output),\n        ])\n\n        self.args = args\n\n    def main(self):\n        self.win.mainloop()\n\n\nif __name__ == \"__main__\":\n    p = Program()\n    p.main()\n"
  },
  {
    "path": "gui/c10t-tk/mainwindow.py",
    "content": "# -*- coding: utf-8 -*-\n# vi:ts=4 sw=4 et\n\n# Let me warn you... Tkinter sucks!\n# It's so... crude... and ugly...\n# But the *only* reason I'm using it is that\n# it is available on the standard Python library.\n#\n# Also, be aware that most of this code is ugly because all it does is\n# setting up the widgets at the window.\n\nfrom Tkinter import *\nfrom tooltip import ToolTip\n\ntry:\n    import PIL.Image\n    import PIL.ImageTk\n    PIL_NOT_AVAILABLE = False\nexcept ImportError as e:\n    PIL_NOT_AVAILABLE = True\n    PIL_NOT_AVAILABLE_MESSAGE = repr(e)\n\n\ndef add_tooltip(text, widgets):\n    \"\"\"Adds a tooltip to multiple elements at once. Useful for setting the\n    same tooltip for the label/checkbox and the associated entry/spinbox.\n    \n    The tooltip widget is also stored at the \"tooltip\" attribute.\"\"\"\n\n    for w in widgets:\n        w.tooltip = ToolTip(w, text=text)\n\n\ndef cross_platform_mouse_wheel(event):\n    \"\"\"Abstracts all Windows/Linux/Mac differences when handling the\n    mouse wheel. Receives an 'event' object, and returns:\n     negative value ==> scrolling down\n     positive value ==> scrolling up\n     zero           ==> something went wrong...\n\n    This function should be called from within \"<MouseWheel>\",\n    \"<Button-4>\" and \"<Button-5>\" event handlers.\n    \"\"\"\n    # http://infohost.nmt.edu/tcc/help/pubs/tkinter/events.html#event-handlers\n\n    # Linux maps scrolling to mouse buttons 4 and 5\n    if event.num == 4:  # scroll up\n        return 1\n    elif event.num == 5:  # scroll down\n        return -1\n    # Windows and MacOs have a MouseWheel event\n    elif event.delta:\n        # In Windows, delta is a multiple of 120\n        if abs(event.delta) >= 120:\n            return event.delta // 120\n        # In MacOS, delta is a multiples of 1\n        else:\n            return event.delta\n\n    return 0\n\n\nclass XCheckbutton(Checkbutton):\n    \"\"\"Tkinter requires a Tk variable for Checkbutton. This class\n    automatically creates such variable (as IntVar), stores it at the\n    widget's \"var\" attribute, and adds get/set methods to access that var.\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        self.var = IntVar()\n        Checkbutton.__init__(self, variable=self.var, *args, **kwargs)\n\n    def get(self):\n        return self.var.get()\n\n    def set(self, value):\n        self.var.set(value)\n\n\nclass XEntry(Entry):\n    \"\"\"For some reason, Entry supplies .get() but doesn't have a .set()\n    method. This class adds such simple and useful method.\"\"\"\n\n    def set(self, value):\n        # When the state is disabled or readonly, then .delete() and\n        # .insert() methods do nothing. So, I change the state to NORMAL\n        # before calling them, and restore the state afterwards.\n        state = self[\"state\"]\n        self[\"state\"] = NORMAL\n        self.delete(0, END)\n        self.insert(0, value)\n        self[\"state\"] = state\n\n\nclass XSpinbox(Spinbox):\n    \"\"\"As the Entry widget, Tkinter doesn't provide a .set() method to\n    Spinbox. This class adds that method.\n    \n    In addition, it adds support for mouse-wheel.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        Spinbox.__init__(self, *args, **kwargs)\n\n        self.bind(\"<MouseWheel>\", self.mouse_wheel_handler)\n        self.bind(\"<Button-4>\", self.mouse_wheel_handler)\n        self.bind(\"<Button-5>\", self.mouse_wheel_handler)\n\n    def set(self, value):\n        # Adding a simple \".set()\" method to spinboxes...\n        # http://stackoverflow.com/questions/3019800/tkinter-spinbox-widget/3024931#3024931\n        # So simple solution... WHY doesn't Tkinter have it already?!\n        self.delete(0, END)\n        self.insert(0, value)\n\n    def mouse_wheel_handler(self, event):\n        # Mouse wheel in spinboxes...\n        # http://www.daniweb.com/forums/post1158775.html#post1158775\n        dir = cross_platform_mouse_wheel(event)\n\n        while dir > 0:\n            self.invoke(\"buttonup\")\n            dir -= 1\n        while dir < 0:\n            self.invoke(\"buttondown\")\n            dir += 1\n\n\nclass FilesFrame(LabelFrame):\n    def __init__(self, master=None):\n        LabelFrame.__init__(self, master,\n            text = u\"Files\",\n            padx = 5,\n            pady = 5\n        )\n\n        self.exepath_label = Label(self, text=u\"c10t path\", anchor=W, justify=LEFT)\n        self.exepath_label.grid(column=0, row=0, columnspan=2, sticky=EW)\n        self.exepath_entry = XEntry(self, name=\"exepath\")\n        self.exepath_entry.grid(column=2, row=0, sticky=EW)\n        add_tooltip(u\"Path to the c10t executable\", (\n            self.exepath_label,\n            self.exepath_entry,\n        ))\n\n        self.world_label = Label(self, text=u\"Input world\", anchor=W, justify=LEFT)\n        self.world_label.grid(column=0, row=1, columnspan=2, sticky=EW)\n        self.world_entry = XEntry(self, name=\"world\")\n        self.world_entry.grid(column=2, row=1, sticky=EW)\n        add_tooltip(u\"Path to the World directory (the one that contains level.dat)\", (\n            self.world_label,\n            self.world_entry,\n        ))\n\n        self.output_label = Label(self, text=u\"Output image\", anchor=W, justify=LEFT)\n        self.output_label.grid(column=0, row=2, sticky=EW)\n        self.load_button = Button(self, padx=0, pady=0, text=u\"Load\")\n        self.load_button.grid(column=1, row=2)\n        self.output_entry = XEntry(self, name=\"output\")\n        self.output_entry.grid(column=2, row=2, sticky=EW)\n        add_tooltip(u\"Destination file for the generated PNG\", (\n            self.output_label,\n            self.output_entry,\n        ))\n        add_tooltip(u\"(re)Loads this image.\", (\n            self.load_button,\n        ))\n\n        # Setting columns and rows to auto-expand\n        for i in (0,2):\n            self.columnconfigure(i, weight=1)\n        for i in xrange(3):\n            self.rowconfigure(i, weight=1)\n\n\nclass FilteringFrame(LabelFrame):\n    def __init__(self, master=None):\n        LabelFrame.__init__(self, master,\n            text = u\"Filtering\",\n            padx = 5,\n            pady = 5\n        )\n\n        self.top_checkbutton = XCheckbutton(self, name=\"topcheck\", text=u\"Top\", anchor=W, justify=LEFT)\n        self.top_checkbutton.grid(column=0, row=0, sticky=EW)\n        self.top_spinbox = XSpinbox(self, name=\"top\", from_=0, to=127, width=3)\n        self.top_spinbox.set(127)\n        self.top_spinbox.grid(column=1, row=0, sticky=EW)\n        add_tooltip(u\"Splice from the top, must be <= 127\", (\n            self.top_checkbutton,\n            self.top_spinbox,\n        ))\n\n        self.bottom_checkbutton = XCheckbutton(self, name=\"bottomcheck\", text=u\"Bottom\", anchor=W, justify=LEFT)\n        self.bottom_checkbutton.grid(column=0, row=1, sticky=EW)\n        self.bottom_spinbox = XSpinbox(self, name=\"bottom\", from_=0, to=127, width=3)\n        self.bottom_spinbox.set(0)\n        self.bottom_spinbox.grid(column=1, row=1, sticky=EW)\n        add_tooltip(u\"Splice from the bottom, must be >= 0\", (\n            self.bottom_checkbutton,\n            self.bottom_spinbox,\n        ))\n\n        # Begin \"Limits\" row...\n        self.limits_checkbutton = XCheckbutton(self, name=\"limitscheck\", text=u\"Limits\", anchor=W, justify=LEFT)\n        self.limits_checkbutton.grid(column=0, row=2, sticky=EW)\n        add_tooltip(u\"Limit render to certain area (North, South, East, West)\", (\n            self.limits_checkbutton,\n        ))\n\n        self.limits_frame = Frame(self)\n        self.limits_frame.grid(column=1, row=2, sticky=EW)\n\n        # This loop sets the following vars:\n        # self.limitsnorth_spinbox\n        # self.limitssouth_spinbox\n        # self.limitseast_spinbox\n        # self.limitswest_spinbox\n        for index, dir in enumerate((\"north\", \"south\", \"east\", \"west\")):\n            name=\"limits\"+dir\n            widget = XSpinbox(self.limits_frame, name=name, from_=-999, to=999, width=4)\n            widget.set(0)\n            widget.grid(column=index, row=0, sticky=EW)\n            self.limits_frame.columnconfigure(index, weight=1)\n\n            setattr(self, name+\"_spinbox\", widget)\n\n            signal = u\"negative\" if index % 2 == 0 else u\"positive\"\n            tooltip = u\"%s limit (%s)\" % (dir.capitalize(), signal)\n            add_tooltip(tooltip, (widget,))\n        # End \"Limits\" row...\n\n        self.cavemode_checkbutton = XCheckbutton(self, name=\"cavemodecheck\", text=u\"Cave mode\", anchor=W, justify=LEFT)\n        self.cavemode_checkbutton.grid(column=0, row=3, sticky=EW)\n        add_tooltip(u\"Cave mode - top down until solid block found, then render bottom outlines only\", (\n            self.cavemode_checkbutton,\n        ))\n\n        self.exclude_checkbutton = XCheckbutton(self, name=\"excludecheck\", text=u\"Exclude\", anchor=W, justify=LEFT)\n        self.exclude_checkbutton.grid(column=0, row=4, sticky=EW)\n        self.exclude_entry = XEntry(self, name=\"exclude\")\n        self.exclude_entry.grid(column=1, row=4, sticky=EW)\n        add_tooltip(u\"Exclude block-ids from render\", (\n            self.exclude_checkbutton,\n            self.exclude_entry,\n        ))\n\n        self.include_checkbutton = XCheckbutton(self, name=\"includecheck\", text=u\"Include\", anchor=W, justify=LEFT)\n        self.include_checkbutton.grid(column=0, row=5, sticky=EW)\n        self.include_entry = XEntry(self, name=\"include\")\n        self.include_entry.grid(column=1, row=5, sticky=EW)\n        add_tooltip(u\"Include block-ids in render (and automatically exclude all non-listed blocks)\", (\n            self.include_checkbutton,\n            self.include_entry,\n        ))\n\n        # Setting columns to auto-expand\n        for i in xrange(2):\n            self.columnconfigure(i, weight=1)\n        for i in xrange(6):\n            self.rowconfigure(i, weight=1)\n\n\nclass RenderingFrame(LabelFrame):\n    def __init__(self, master=None):\n        LabelFrame.__init__(self, master,\n            text = u\"Rendering\",\n            padx = 5,\n            pady = 5\n        )\n\n        self.oblique_checkbutton = XCheckbutton(self, name=\"obliquecheck\", text=u\"Oblique\", anchor=W, justify=LEFT)\n        self.oblique_checkbutton.grid(column=0, row=0, sticky=EW)\n        add_tooltip(u\"Oblique rendering\", (\n            self.oblique_checkbutton,\n        ))\n\n        self.obliqueangle_checkbutton = XCheckbutton(self, name=\"obliqueanglecheck\", text=u\"Oblique angle\", anchor=W, justify=LEFT)\n        self.obliqueangle_checkbutton.grid(column=0, row=1, sticky=EW)\n        add_tooltip(u\"Oblique angle rendering\", (\n            self.obliqueangle_checkbutton,\n        ))\n\n        self.isometric_checkbutton = XCheckbutton(self, name=\"isometriccheck\", text=u\"Isometric\", anchor=W, justify=LEFT)\n        self.isometric_checkbutton.grid(column=0, row=2, sticky=EW)\n        add_tooltip(u\"Isometric rendering\", (\n            self.isometric_checkbutton,\n        ))\n\n        self.night_checkbutton = XCheckbutton(self, name=\"nightcheck\", text=u\"Night-time\", anchor=W, justify=LEFT)\n        self.night_checkbutton.grid(column=0, row=3, sticky=EW)\n        add_tooltip(u\"Night-time rendering\", (\n            self.night_checkbutton,\n        ))\n\n        self.heightmap_checkbutton = XCheckbutton(self, name=\"heightmapcheck\", text=u\"Heightmap\", anchor=W, justify=LEFT)\n        self.heightmap_checkbutton.grid(column=0, row=4, sticky=EW)\n        add_tooltip(u\"Heightmap rendering\", (\n            self.heightmap_checkbutton,\n        ))\n\n        self.rotate_label = Label(self, text=u\"Rotate\", anchor=W, justify=LEFT)\n        self.rotate_label.grid(column=0, row=5, sticky=EW)\n        add_tooltip(u\"Rotate the rendering clockwise\", (\n            self.rotate_label,\n        ))\n        self.rotate_frame = Frame(self)\n        self.rotate_frame.grid(column=1, row=5, sticky=EW)\n        self.rotate_var = IntVar(name=\"rotate\")\n        # This loop sets the following vars:\n        # self.rotate0_radiobutton\n        # self.rotate90_radiobutton\n        # self.rotate180_radiobutton\n        # self.rotate270_radiobutton\n        for index, angle in enumerate((\"0\", \"90\", \"180\", \"270\")):\n            name = \"rotate\"+angle\n            widget = Radiobutton(self.rotate_frame, text=angle, variable=self.rotate_var, value=int(angle))\n            widget.var = self.rotate_var\n            widget.grid(column=index, row=0, sticky=EW)\n            self.rotate_frame.columnconfigure(index, weight=1)\n            setattr(self, name+\"_radiobutton\", widget)\n        self.rotate_var.set(0)\n\n        self.threads_label = Label(self, text=u\"Threads\", anchor=W, justify=LEFT)\n        self.threads_label.grid(column=0, row=6, sticky=EW)\n        self.threads_spinbox = XSpinbox(self, name=\"threads\", from_=0, to=999, width=3)\n        self.threads_spinbox.set(0)\n        self.threads_spinbox.grid(column=1, row=6, sticky=EW)\n        add_tooltip(u\"Specify the amount of threads to use, for maximum efficency, this should match the amount of cores on your machine. Use zero to auto-detect the number of cores.\", (\n            self.threads_label,\n            self.threads_spinbox,\n        ))\n\n        # Setting columns to auto-expand\n        for i in xrange(2):\n            self.columnconfigure(i, weight=1)\n        for i in xrange(7):\n            self.rowconfigure(i, weight=1)\n\n\nclass FontFrame(LabelFrame):\n    def __init__(self, master=None):\n        LabelFrame.__init__(self, master,\n            text = u\"Text and fonts\",\n            padx = 5,\n            pady = 5\n        )\n\n        self.ttfsize_label = Label(self, text=u\"Font size\", anchor=W, justify=LEFT)\n        self.ttfsize_label.grid(column=0, row=0, columnspan=2, sticky=EW)\n        self.ttfsize_spinbox = XSpinbox(self, name=\"ttfsize\", from_=1, to=999, width=3)\n        self.ttfsize_spinbox.set(12)\n        self.ttfsize_spinbox.grid(column=2, row=0, sticky=EW)\n        add_tooltip(u\"Use the specified font size when drawing text\", (\n            self.ttfsize_label,\n            self.ttfsize_spinbox,\n        ))\n\n        self.ttfcolor_label = Label(self, text=u\"Default color\", anchor=W, justify=LEFT)\n        self.ttfcolor_label.grid(column=0, row=1, columnspan=2, sticky=EW)\n        add_tooltip(u\"Use the specified color when drawing text\", (\n            self.ttfcolor_label,\n        ))\n        self.ttfcolor_entry = XEntry(self, name=\"ttfcolor\", width=15)\n        self.ttfcolor_entry.set(u\"0,0,0,255\")\n        self.ttfcolor_entry.grid(column=2, row=1, sticky=EW)\n\n        self.showplayers_checkbutton = XCheckbutton(self, name=\"showplayerscheck\", text=u\"Show players\", anchor=W, justify=LEFT)\n        self.showplayers_checkbutton.grid(column=0, row=2, sticky=EW)\n        add_tooltip(u\"Will draw out player position and names from the players database in <world>/players\", (\n            self.showplayers_checkbutton,\n        ))\n        self.playercolor_checkbutton = XCheckbutton(self, name=\"playercolorcheck\", text=u\"Color:\", anchor=W, justify=LEFT)\n        self.playercolor_checkbutton.grid(column=1, row=2, sticky=EW)\n        add_tooltip(u\"Use a custom color for players\", (\n            self.playercolor_checkbutton,\n        ))\n        self.playercolor_entry = XEntry(self, name=\"playercolor\", width=15)\n        self.playercolor_entry.set(u\"0,0,0,255\")\n        self.playercolor_entry.grid(column=2, row=2, sticky=EW)\n\n        self.showsigns_checkbutton = XCheckbutton(self, name=\"showsignscheck\", text=u\"Show signs\", anchor=W, justify=LEFT)\n        self.showsigns_checkbutton.grid(column=0, row=3, sticky=EW)\n        add_tooltip(u\"Will draw out signs from all chunks\", (\n            self.showsigns_checkbutton,\n        ))\n        self.signcolor_checkbutton = XCheckbutton(self, name=\"signcolorcheck\", text=u\"Color:\", anchor=W, justify=LEFT)\n        self.signcolor_checkbutton.grid(column=1, row=3, sticky=EW)\n        add_tooltip(u\"Use a custom color for signs\", (\n            self.signcolor_checkbutton,\n        ))\n        self.signcolor_entry = XEntry(self, name=\"signcolor\", width=15)\n        self.signcolor_entry.set(u\"0,0,0,255\")\n        self.signcolor_entry.grid(column=2, row=3, sticky=EW)\n\n        self.showcoords_checkbutton = XCheckbutton(self, name=\"showcoordscheck\", text=u\"Show coordinates\", anchor=W, justify=LEFT)\n        self.showcoords_checkbutton.grid(column=0, row=4, sticky=EW)\n        add_tooltip(u\"Will draw out each chunks expected coordinates\", (\n            self.showcoords_checkbutton,\n        ))\n        self.coordcolor_checkbutton = XCheckbutton(self, name=\"coordcolorcheck\", text=u\"Color:\", anchor=W, justify=LEFT)\n        self.coordcolor_checkbutton.grid(column=1, row=4, sticky=EW)\n        add_tooltip(u\"Use a custom color for coordinates\", (\n            self.coordcolor_checkbutton,\n        ))\n        self.coordcolor_entry = XEntry(self, name=\"coordcolor\", width=15)\n        self.coordcolor_entry.set(u\"0,0,0,255\")\n        self.coordcolor_entry.grid(column=2, row=4, sticky=EW)\n\n        add_tooltip(u\"Red,Green,Blue,Alpha\\n0,0,0,255 means black\", (\n            self.playercolor_entry,\n            self.signcolor_entry,\n            self.coordcolor_entry,\n            self.ttfcolor_entry,\n        ))\n\n        # Setting columns to auto-expand\n        for i in xrange(3):\n            self.columnconfigure(i, weight=1)\n        for i in xrange(5):\n            self.rowconfigure(i, weight=1)\n\n\nclass ConfigurationFrame(Frame):\n    def __init__(self, master=None):\n        Frame.__init__(self, master)\n\n        self.files_frame = FilesFrame(self)\n        self.files_frame.pack(fill=BOTH, expand=1)\n\n        self.filtering_frame = FilteringFrame(self)\n        self.filtering_frame.pack(fill=BOTH, expand=1)\n\n        self.rendering_frame = RenderingFrame(self)\n        self.rendering_frame.pack(fill=BOTH, expand=1)\n\n        self.font_frame = FontFrame(self)\n        self.font_frame.pack(fill=BOTH, expand=1)\n\n\nclass RunFrame(Frame):\n    def __init__(self, master=None):\n        Frame.__init__(self, master)\n\n        self.run_button = Button(self, text=u\"Run!\")\n        self.run_button.pack(side=LEFT)\n\n        self.update_button = Button(self, text=u\"Update\")\n        self.update_button.pack(side=LEFT)\n        add_tooltip(u\"Update the command-line, without running the command. Easy for copy-and-paste into scripts.\", (\n            self.update_button,\n        ))\n\n        self.command_entry = XEntry(self, name=\"command\", state=\"readonly\")\n        self.command_entry.pack(side=LEFT, fill=X, expand=1)\n        add_tooltip(u\"The full command-line that will be invoked\", (\n            self.command_entry,\n        ))\n\n\nclass ImageFrame(Frame):\n    \"\"\"This is just a Frame containing one Canvas, two scrollbars and some\n    logic for scrolling the image.\"\"\"\n\n    # This class is inspired by:\n    # http://effbot.org/tkinterbook/photoimage.htm\n    # http://www.swharden.com/blog/2010-03-03-viewing-large-images-with-scrollbars-using-python-tk-and-pil/\n\n    def __init__(self, master=None):\n        Frame.__init__(self, master)\n\n        # Adding the widgets\n        self.vertical_scrollbar = Scrollbar(self, orient=VERTICAL)\n        self.vertical_scrollbar.pack(side=RIGHT, fill=Y)\n        self.horizontal_scrollbar = Scrollbar(self, orient=HORIZONTAL)\n        self.horizontal_scrollbar.pack(side=BOTTOM, fill=X)\n\n        self.canvas = Canvas(self)\n        self.canvas.pack(side=LEFT, expand=YES, fill=BOTH)\n\n        # Add an error message if needed\n        if PIL_NOT_AVAILABLE:\n            self.canvas.create_text(10, 10, anchor=NW, text=u\"Python Image Library (PIL) could not be loaded.\\n\\nNo image will be displayed here, but\\nthey will still be rendered to the disk.\\n\\n%s\" % (PIL_NOT_AVAILABLE_MESSAGE,))\n\n        # Connecting canvas and scrollbars\n        self.horizontal_scrollbar[\"command\"] = self.canvas.xview\n        self.vertical_scrollbar[\"command\"] = self.canvas.yview\n        self.canvas[\"xscrollcommand\"] = self.horizontal_scrollbar.set\n        self.canvas[\"yscrollcommand\"] = self.vertical_scrollbar.set\n\n        # Adding the event handlers to the canvas\n        self.canvas.bind(\"<Button-1>\", self.button_press_1_handler)\n        self.canvas.bind(\"<B1-Motion>\", self.button_motion_1_handler)\n        self.canvas.bind(\"<ButtonRelease-1>\", self.button_release_1_handler)\n\n        self.canvas.bind(\"<MouseWheel>\", self.mouse_wheel_handler)\n        self.canvas.bind(\"<Button-4>\", self.mouse_wheel_handler)\n        self.canvas.bind(\"<Button-5>\", self.mouse_wheel_handler)\n\n        # Adding mouse wheel support to scrollbars\n        self.horizontal_scrollbar.bind(\"<MouseWheel>\", self.hscroll_mouse_wheel_handler)\n        self.horizontal_scrollbar.bind(\"<Button-4>\", self.hscroll_mouse_wheel_handler)\n        self.horizontal_scrollbar.bind(\"<Button-5>\", self.hscroll_mouse_wheel_handler)\n        self.vertical_scrollbar.bind(\"<MouseWheel>\", self.vscroll_mouse_wheel_handler)\n        self.vertical_scrollbar.bind(\"<Button-4>\", self.vscroll_mouse_wheel_handler)\n        self.vertical_scrollbar.bind(\"<Button-5>\", self.vscroll_mouse_wheel_handler)\n\n        # Internal vars for handling the image\n        self.pil_image = None\n        self.tk_resized_images = {}\n        self.canvas_image = None\n        self.zoom = 0\n\n    def hscroll_mouse_wheel_handler(self, event):\n        dir = cross_platform_mouse_wheel(event)\n        self.canvas.xview_scroll(-dir, UNITS)\n\n    def vscroll_mouse_wheel_handler(self, event):\n        dir = cross_platform_mouse_wheel(event)\n        self.canvas.yview_scroll(-dir, UNITS)\n\n    def button_press_1_handler(self, event):\n        self.canvas.scan_mark(event.x, event.y)\n        self.canvas[\"cursor\"] = \"fleur\"\n\n    def button_motion_1_handler(self, event):\n        self.canvas.scan_dragto(event.x, event.y, gain=1)\n\n    def button_release_1_handler(self, event):\n        self.canvas[\"cursor\"] = \"\"\n\n    def mouse_wheel_handler(self, event):\n        dir = cross_platform_mouse_wheel(event)\n        if dir == 0:\n            return\n\n        # Code for zooming the image (like Google Maps)\n        self.resize_image_to_zoom(delta=dir, center=(event.x, event.y))\n\n    def resize_image_to_zoom(self, delta=None, zoom=None, center=None, forcereload=False):\n        \"\"\"Parameters:\n         delta      : How much to increase/decrease the current zoom?\n         zoom       : Set zoom to this absolute value.\n         center     : Uses these coordinates (x,y) as the zoom center,\n                      scrolling the canvas as needed. These are \"window\n                      coordinates\", relative to the widget's top-left\n                      corner.\n         forcereload: Clears the zoom cache, forces reloading the canvas\n                      from self.pil_image.\n        \"\"\"\n\n        # Sanity check\n        if PIL_NOT_AVAILABLE:\n            return\n        if self.pil_image is None:\n            return\n\n        # Calculating the new zoom value\n        prevzoom = self.zoom\n        if zoom is not None:\n            self.zoom = zoom\n        if delta is not None:\n            self.zoom += delta\n\n        # Clamping maximum zoom\n        if self.zoom > 2:\n            self.zoom = 2\n        # Clamping minimum zoom\n        if self.zoom < -4:\n            self.zoom = -4\n\n        if forcereload:\n            # Clearing the image cache\n            self.tk_resized_images = {}\n\n        # Zoom size is not cached...\n        if not self.tk_resized_images.has_key(self.zoom):\n            mult = 2 ** self.zoom\n            ow, oh = self.pil_image.size\n            w, h = int(mult * ow), int(mult * oh)\n\n            # Let's apply a nice filter when scaling down,\n            # but keep those lovely pixels when scaling up!\n            filter = PIL.Image.NEAREST if mult >=1 else PIL.Image.BICUBIC\n\n            # Resizing\n            pil_resized_image = self.pil_image.resize((w,h), filter)\n            # Converting to Tk\n            tk_photoimage = PIL.ImageTk.PhotoImage(pil_resized_image)\n            # Saving the Tk image to cache\n            self.tk_resized_images[self.zoom] = tk_photoimage\n\n        # Keeping the position centered\n        if center:\n            # Window coordinates, relative to widget's top-left corner\n            wx, wy = center\n\n            # Old canvas coordinates\n            ocx = self.canvas.canvasx(wx)\n            ocy = self.canvas.canvasy(wy)\n\n            tx = self.canvas.canvasx(0)\n            ty = self.canvas.canvasy(0)\n\n            # Old scroll position\n            osx = ocx - wx\n            osy = ocy - wy\n\n            # Multiplication...\n            deltazoom = self.zoom - prevzoom\n            deltamult = 2 ** deltazoom\n\n            # New canvas coordinates\n            ncx = ocx * deltamult\n            ncy = ocy * deltamult\n\n            # New scroll position\n            nsx = ncx - wx\n            nsy = ncy - wy\n\n            # Debug\n            #print (\n            #    \"w=({wx},{wy})\\n\"\n            #    \"old canvas=({ocx},{ocy})\\n\"\n            #    \"old scroll=({osx},{osy})\\n\"\n            #    \"old scroll=({tx},{ty})\\n\"\n            #    \"new canvas=({ncx},{ncy})\\n\"\n            #    \"new scroll=({nsx},{nsy})\\n\"\n            #    \"deltazoom={deltazoom}; deltamult={deltamult}\"\n            #    .format(**locals())\n            #)\n\n        # Getting the image from cache\n        tk_img = self.tk_resized_images[self.zoom]\n        # Setting it to canvas\n        self.canvas.itemconfigure(self.canvas_image, image=tk_img)\n        # Setting the size\n        new_width = tk_img.width()\n        new_height = tk_img.height()\n        self.canvas[\"scrollregion\"] = (0, 0, new_width, new_height)\n\n        # Finally, scrolling in order to keep the position centered\n        if center:\n            # It was difficult to find the right formula to make\n            # tkinter flawlessly...\n            # http://stackoverflow.com/questions/3950773/how-to-scroll-a-tkinter-canvas-to-an-absolute-position\n            offset_x = +1 if nsx >= 0 else 0\n            offset_y = +1 if nsy >= 0 else 0\n            self.canvas.xview_moveto(float(nsx + offset_x)/new_width)\n            self.canvas.yview_moveto(float(nsy + offset_y)/new_height)\n\n    def load_image_from_file(self, imagepath):\n        if PIL_NOT_AVAILABLE:\n            return\n\n        # Loading the image from disk\n        self.pil_image = PIL.Image.open(imagepath)\n\n        # Creating the image inside the canvas\n        if self.canvas_image is None:\n            self.canvas_image = self.canvas.create_image(0, 0, anchor=NW)\n\n        # Updating the canvas image\n        self.resize_image_to_zoom(forcereload=True)\n\n\nclass ApplicationFrame(Frame):\n    \"\"\"The main application frame is divided like this:\n\n    +--------------+--------------------+\n    |Configuration | Run Frame here     |\n    |Frame here,   +--------------------+\n    |which contains|                   ^|\n    |sub-frames for| Image Frame here   |\n    |each section. |                    |\n    |              |                    |\n    |              |<                 >v|\n    +--------------+--------------------+\n    \"\"\"\n\n    def __init__(self, master=None):\n        Frame.__init__(self, master,\n            padx=5,\n            pady=5\n        )\n\n        self.configuration_frame = ConfigurationFrame(self)\n        self.configuration_frame.grid(column=0, row=0, rowspan=2, sticky=NSEW)\n\n        self.run_frame = RunFrame(self)\n        self.run_frame.grid(column=1, row=0, sticky=NSEW)\n\n        self.image_frame = ImageFrame(self)\n        self.image_frame.grid(column=1, row=1, sticky=NSEW)\n\n        self.columnconfigure(1, weight=1)\n        self.rowconfigure(1, weight=1)\n\n\ndef find_named_widgets(widget):\n    \"\"\"Starting at the 'widget', scans down recursively and returns a dict\n    with {'name': widget_instance}, but only if the name has been set by\n    the user.\n    \n    There is a special treatment for Radiobutton: it returns the associated\n    variable instead of the widget, but only if the user has set a name to\n    the variable and stored it at the widget's \"var\" attribute.\"\"\"\n\n    d = {}\n    for name, w in widget.children.iteritems():\n        # If the user has set a name for this widget, and it is a valid name.\n        # Unnamed widgets get numbers in their name.\n        if name[0].isalpha() or name[0] == \"_\":\n            d[name] = w\n\n        # Special case for Radiobutton\n        if (\n            isinstance(w, Radiobutton) and\n            hasattr(w, \"var\") and\n            not w.var._name.startswith(\"PY_VAR\")\n        ):\n            d[w.var._name] = w.var\n\n        # Recursive call\n        d.update(find_named_widgets(w))\n    return d\n\n\nclass UiShortcuts(object):\n    \"\"\"This object is a quick and handy way of accessing widget values.\n    See the following small example to get an idea of how it works:\n\n    ui = UiShortcuts(root_window)\n\n    # This will call .set(\"bar\") on a widget named \"foo\"\n    ui.foo = \"bar\"\n    # This will call .get() on a widget named \"foo\"\n    print ui.foo\n    \"\"\"\n\n    def __init__(self, root):\n        object.__setattr__(self, \"widgets\", find_named_widgets(root))\n\n    def __dir__(self):\n        # Simple method to support tab-completion\n        return self.__dict__.keys() + self.widgets.keys()\n\n    def __getattr__(self, name):\n        return self.widgets[name].get()\n\n    def __setattr__(self, name, value):\n        self.widgets[name].set(value)\n\n\nclass MainWindow(Tk):\n    \"\"\"Root window. Contains one ApplicationFrame at self.app, and has\n    shortcuts to all important widgets in self.ui.\n    \n    If you want to interact with the interface, using self.ui should be\n    enough, and it hides all the messy toolkit-related code.\"\"\"\n\n    def __init__(self):\n        Tk.__init__(self)\n\n        self.title(\"c10t GUI\")\n\n        self.app = ApplicationFrame(self)\n        self.app.pack(fill=BOTH, expand=1)\n\n        self.ui = UiShortcuts(self)\n\n        # Global quit handlers\n        self.bind_all(\"<Control-q>\", self.quit_handler)\n        self.protocol(\"WM_DELETE_WINDOW\", self.quit_handler)\n\n        #self.on_change_callback = None\n        #self.app.configuration_frame.bind(\"\")\n\n        # Adding an \"update\" button, just because I don't know how to bind\n        # to \"on change\"-like events in Tkinter.\n        # http://stackoverflow.com/questions/3876229/how-to-run-a-code-whenever-a-tkinter-widget-value-changes\n        self.update_button_callback = None\n        self.app.run_frame.update_button[\"command\"] = self.update_button_handler\n\n        self.run_button_callback = None\n        self.app.run_frame.run_button[\"command\"] = self.run_button_handler\n\n        self.load_button_callback = None\n        self.app.configuration_frame.files_frame.load_button[\"command\"] = self.load_button_handler\n\n    def quit_handler(self, event=None):\n        self.destroy()\n\n    #def on_change_handler(self, event=None):\n    #    if self.on_change_callback:\n    #        self.on_change_callback()\n\n    def update_button_handler(self, event=None):\n        if self.update_button_callback:\n            self.update_button_callback()\n\n    def run_button_handler(self, event=None):\n        if self.run_button_callback:\n            self.run_button_callback()\n\n    def load_button_handler(self):\n        if self.load_button_callback:\n            self.load_button_callback()\n\n    def load_image_from_file(self, imagepath):\n        self.app.image_frame.load_image_from_file(imagepath)\n\n"
  },
  {
    "path": "gui/c10t-tk/tooltip.py",
    "content": "# -*- coding: utf-8 -*-\n# vi:ts=4 sw=4 et\n\n# Downloaded from:\n# http://tkinter.unpythonic.net/wiki/ToolTip\n\n'''Michael Lange <klappnase (at) freakmail (dot) de>\nThe ToolTip class provides a flexible tooltip widget for Tkinter; it is based on IDLE's ToolTip\nmodule which unfortunately seems to be broken (at least the version I saw).\nINITIALIZATION OPTIONS:\nanchor :        where the text should be positioned inside the widget, must be on of \"n\", \"s\", \"e\", \"w\", \"nw\" and so on;\n                default is \"center\"\nbd :            borderwidth of the widget; default is 1 (NOTE: don't use \"borderwidth\" here)\nbg :            background color to use for the widget; default is \"lightyellow\" (NOTE: don't use \"background\")\ndelay :         time in ms that it takes for the widget to appear on the screen when the mouse pointer has\n                entered the parent widget; default is 1500 (XXX: changed to 800)\nfg :            foreground (i.e. text) color to use; default is \"black\" (NOTE: don't use \"foreground\")\nfollow_mouse :  if set to 1 the tooltip will follow the mouse pointer instead of being displayed\n                outside of the parent widget; this may be useful if you want to use tooltips for\n                large widgets like listboxes or canvases; default is 0\nfont :          font to use for the widget; default is system specific\njustify :       how multiple lines of text will be aligned, must be \"left\", \"right\" or \"center\"; default is \"left\"\npadx :          extra space added to the left and right within the widget; default is 4\npady :          extra space above and below the text; default is 2\nrelief :        one of \"flat\", \"ridge\", \"groove\", \"raised\", \"sunken\" or \"solid\"; default is \"solid\"\nstate :         must be \"normal\" or \"disabled\"; if set to \"disabled\" the tooltip will not appear; default is \"normal\"\ntext :          the text that is displayed inside the widget\ntextvariable :  if set to an instance of Tkinter.StringVar() the variable's value will be used as text for the widget\nwidth :         width of the widget; the default is 0, which means that \"wraplength\" will be used to limit the widgets width\nwraplength :    limits the number of characters in each line; default is 150 (XXX: changed to 200)\n\nWIDGET METHODS:\nconfigure(**opts) : change one or more of the widget's options as described above; the changes will take effect the\n                    next time the tooltip shows up; NOTE: follow_mouse cannot be changed after widget initialization\n\nOther widget methods that might be useful if you want to subclass ToolTip:\nenter() :           callback when the mouse pointer enters the parent widget\nleave() :           called when the mouse pointer leaves the parent widget\nmotion() :          is called when the mouse pointer moves inside the parent widget if follow_mouse is set to 1 and the\n                    tooltip has shown up to continually update the coordinates of the tooltip window\ncoords() :          calculates the screen coordinates of the tooltip window\ncreate_contents() : creates the contents of the tooltip window (by default a Tkinter.Label)\n'''\n# Ideas gleaned from PySol\n\nimport Tkinter\n\nclass ToolTip:\n    # XXX Changed the default delay from 1500 to 800\n    # XXX Changed the default wraplength from 150 to 200\n    def __init__(self, master, text='Your text here', delay=800, **opts):\n        self.master = master\n        self._opts = {'anchor':'center', 'bd':1, 'bg':'lightyellow', 'delay':delay, 'fg':'black',\\\n                      'follow_mouse':0, 'font':None, 'justify':'left', 'padx':4, 'pady':2,\\\n                      'relief':'solid', 'state':'normal', 'text':text, 'textvariable':None,\\\n                      'width':0, 'wraplength':200}\n        self.configure(**opts)\n        self._tipwindow = None\n        self._id = None\n        self._id1 = self.master.bind(\"<Enter>\", self.enter, '+')\n        self._id2 = self.master.bind(\"<Leave>\", self.leave, '+')\n        self._id3 = self.master.bind(\"<ButtonPress>\", self.leave, '+')\n        self._follow_mouse = 0\n        if self._opts['follow_mouse']:\n            self._id4 = self.master.bind(\"<Motion>\", self.motion, '+')\n            self._follow_mouse = 1\n\n    def configure(self, **opts):\n        for key in opts:\n            if self._opts.has_key(key):\n                self._opts[key] = opts[key]\n            else:\n                KeyError = 'KeyError: Unknown option: \"%s\"' %key\n                raise KeyError\n\n    ##----these methods handle the callbacks on \"<Enter>\", \"<Leave>\" and \"<Motion>\"---------------##\n    ##----events on the parent widget; override them if you want to change the widget's behavior--##\n\n    def enter(self, event=None):\n        self._schedule()\n\n    def leave(self, event=None):\n        self._unschedule()\n        self._hide()\n\n    def motion(self, event=None):\n        if self._tipwindow and self._follow_mouse:\n            x, y = self.coords()\n            self._tipwindow.wm_geometry(\"+%d+%d\" % (x, y))\n\n    ##------the methods that do the work:---------------------------------------------------------##\n\n    def _schedule(self):\n        self._unschedule()\n        if self._opts['state'] == 'disabled':\n            return\n        self._id = self.master.after(self._opts['delay'], self._show)\n\n    def _unschedule(self):\n        id = self._id\n        self._id = None\n        if id:\n            self.master.after_cancel(id)\n\n    def _show(self):\n        if self._opts['state'] == 'disabled':\n            self._unschedule()\n            return\n        if not self._tipwindow:\n            self._tipwindow = tw = Tkinter.Toplevel(self.master)\n            # hide the window until we know the geometry\n            tw.withdraw()\n            tw.wm_overrideredirect(1)\n\n            if tw.tk.call(\"tk\", \"windowingsystem\") == 'aqua':\n                tw.tk.call(\"::tk::unsupported::MacWindowStyle\", \"style\", tw._w, \"help\", \"none\")\n\n            self.create_contents()\n            tw.update_idletasks()\n            x, y = self.coords()\n            tw.wm_geometry(\"+%d+%d\" % (x, y))\n            tw.deiconify()\n\n    def _hide(self):\n        tw = self._tipwindow\n        self._tipwindow = None\n        if tw:\n            tw.destroy()\n\n    ##----these methods might be overridden in derived classes:----------------------------------##\n\n    def coords(self):\n        # The tip window must be completely outside the master widget;\n        # otherwise when the mouse enters the tip window we get\n        # a leave event and it disappears, and then we get an enter\n        # event and it reappears, and so on forever :-(\n        # or we take care that the mouse pointer is always outside the tipwindow :-)\n        tw = self._tipwindow\n        twx, twy = tw.winfo_reqwidth(), tw.winfo_reqheight()\n        w, h = tw.winfo_screenwidth(), tw.winfo_screenheight()\n        # calculate the y coordinate:\n        if self._follow_mouse:\n            y = tw.winfo_pointery() + 20\n            # make sure the tipwindow is never outside the screen:\n            if y + twy > h:\n                y = y - twy - 30\n        else:\n            y = self.master.winfo_rooty() + self.master.winfo_height() + 3\n            if y + twy > h:\n                y = self.master.winfo_rooty() - twy - 3\n        # we can use the same x coord in both cases:\n        x = tw.winfo_pointerx() - twx / 2\n        if x < 0:\n            x = 0\n        elif x + twx > w:\n            x = w - twx\n        return x, y\n\n    def create_contents(self):\n        opts = self._opts.copy()\n        for opt in ('delay', 'follow_mouse', 'state'):\n            del opts[opt]\n        label = Tkinter.Label(self._tipwindow, **opts)\n        label.pack()\n\n##---------demo code-----------------------------------##\n\ndef demo():\n    root = Tkinter.Tk(className='ToolTip-demo')\n    l = Tkinter.Listbox(root)\n    l.insert('end', \"I'm a listbox\")\n    l.pack(side='top')\n    t1 = ToolTip(l, follow_mouse=1, text=\"I'm a tooltip with follow_mouse set to 1, so I won't be placed outside my parent\")\n    b = Tkinter.Button(root, text='Quit', command=root.quit)\n    b.pack(side='bottom')\n    t2 = ToolTip(b, text='Enough of this')\n    root.mainloop()\n\nif __name__ == '__main__':\n    demo()\n"
  },
  {
    "path": "palette.json",
    "content": "[\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"air\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": false,\n    \"legacy_id\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"stone\",\n    \"mode\": \"block\",\n    \"top_color\": [128, 128, 128, 255],\n    \"darken\": true,\n    \"legacy_id\": 1,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"granite\",\n    \"mode\": \"block\",\n    \"top_color\": [153, 113, 98, 255],\n    \"darken\": true,\n    \"legacy_id\": 1,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"polished_granite\",\n    \"mode\": \"block\",\n    \"top_color\": [133, 88, 75, 255],\n    \"darken\": true,\n    \"legacy_id\": 1,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"diorite\",\n    \"mode\": \"block\",\n    \"top_color\": [162, 161, 169, 255],\n    \"darken\": true,\n    \"legacy_id\": 1,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"polished_diorite\",\n    \"mode\": \"block\",\n    \"top_color\": [158, 158, 167, 255],\n    \"darken\": true,\n    \"legacy_id\": 1,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"andesite\",\n    \"mode\": \"block\",\n    \"top_color\": [114, 114, 119, 255],\n    \"darken\": true,\n    \"legacy_id\": 1,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"polished_andesite\",\n    \"mode\": \"block\",\n    \"top_color\": [119, 119, 124, 255],\n    \"darken\": true,\n    \"legacy_id\": 1,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"grass_block\",\n    \"mode\": \"block\",\n    \"top_color\": [120, 172, 70, 255],\n    \"side_color\": [134, 96, 67, 255],\n    \"darken\": true,\n    \"legacy_id\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dirt\",\n    \"mode\": \"block\",\n    \"top_color\": [134, 96, 67, 255],\n    \"darken\": true,\n    \"legacy_id\": 3,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"coarse_dirt\",\n    \"mode\": \"block\",\n    \"top_color\": [134, 96, 67, 255],\n    \"darken\": true,\n    \"legacy_id\": 3,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"podzol\",\n    \"mode\": \"block\",\n    \"top_color\": [108, 67, 29, 255],\n    \"darken\": true,\n    \"legacy_id\": 3,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cobblestone\",\n    \"mode\": \"block\",\n    \"top_color\": [100, 100, 100, 255],\n    \"darken\": true,\n    \"legacy_id\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_planks\",\n    \"mode\": \"block\",\n    \"top_color\": [157, 128, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": 5,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spruce_planks\",\n    \"mode\": \"block\",\n    \"top_color\": [102, 77, 46, 255],\n    \"darken\": true,\n    \"legacy_id\": 5,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"birch_planks\",\n    \"mode\": \"block\",\n    \"top_color\": [193, 177, 122, 255],\n    \"darken\": true,\n    \"legacy_id\": 5,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jungle_planks\",\n    \"mode\": \"block\",\n    \"top_color\": [152, 109, 76, 255],\n    \"darken\": true,\n    \"legacy_id\": 5,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"acacia_planks\",\n    \"mode\": \"block\",\n    \"top_color\": [168, 91, 50, 255],\n    \"darken\": true,\n    \"legacy_id\": 5,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_oak_planks\",\n    \"mode\": \"block\",\n    \"top_color\": [60, 39, 18, 255],\n    \"darken\": true,\n    \"legacy_id\": 5,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_sapling\",\n    \"mode\": \"block\",\n    \"top_color\": [74, 131, 66, 128],\n    \"darken\": true,\n    \"legacy_id\": 6,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spruce_sapling\",\n    \"mode\": \"block\",\n    \"top_color\": [50, 89, 45, 128],\n    \"darken\": true,\n    \"legacy_id\": 6,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"birch_sapling\",\n    \"mode\": \"block\",\n    \"top_color\": [94, 167, 84, 128],\n    \"darken\": true,\n    \"legacy_id\": 6,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jungle_sapling\",\n    \"mode\": \"block\",\n    \"top_color\": [58, 147, 19, 128],\n    \"darken\": true,\n    \"legacy_id\": 6,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"acacia_sapling\",\n    \"mode\": \"block\",\n    \"top_color\": [58, 145, 19, 128],\n    \"darken\": true,\n    \"legacy_id\": 6,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_oak_sapling\",\n    \"mode\": \"block\",\n    \"top_color\": [52, 131, 18, 128],\n    \"darken\": true,\n    \"legacy_id\": 6,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"bedrock\",\n    \"mode\": \"block\",\n    \"top_color\": [84, 84, 84, 255],\n    \"darken\": true,\n    \"legacy_id\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"flowing_water\",\n    \"mode\": \"block\",\n    \"top_color\": [56, 68, 127, 64],\n    \"darken\": false,\n    \"legacy_id\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"water\",\n    \"mode\": \"block\",\n    \"top_color\": [56, 68, 127, 64],\n    \"darken\": false,\n    \"legacy_id\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"flowing_lava\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 90, 0, 255],\n    \"darken\": false,\n    \"legacy_id\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lava\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 90, 0, 255],\n    \"darken\": false,\n    \"legacy_id\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sand\",\n    \"mode\": \"block\",\n    \"top_color\": [218, 210, 158, 255],\n    \"darken\": true,\n    \"legacy_id\": 12,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_sand\",\n    \"mode\": \"block\",\n    \"top_color\": [186, 102, 44, 255],\n    \"darken\": true,\n    \"legacy_id\": 12,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gravel\",\n    \"mode\": \"block\",\n    \"top_color\": [136, 126, 126, 255],\n    \"darken\": true,\n    \"legacy_id\": 13\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gold_ore\",\n    \"mode\": \"block\",\n    \"top_color\": [143, 140, 125, 255],\n    \"darken\": true,\n    \"legacy_id\": 14\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"iron_ore\",\n    \"mode\": \"block\",\n    \"top_color\": [136, 130, 127, 255],\n    \"darken\": true,\n    \"legacy_id\": 15\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"coal_ore\",\n    \"mode\": \"block\",\n    \"top_color\": [115, 115, 115, 255],\n    \"darken\": true,\n    \"legacy_id\": 16\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_log\",\n    \"mode\": \"log_block\",\n    \"top_color\": [184, 148, 95, 255],\n    \"side_color\": [101, 80, 49, 255],\n    \"darken\": false,\n    \"legacy_id\": 17,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spruce_log\",\n    \"mode\": \"log_block\",\n    \"top_color\": [106, 82, 48, 255],\n    \"side_color\": [45, 28, 12, 255],\n    \"darken\": false,\n    \"legacy_id\": 17,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"birch_log\",\n    \"mode\": \"log_block\",\n    \"top_color\": [183, 164, 118, 255],\n    \"side_color\": [201, 201, 196, 255],\n    \"darken\": false,\n    \"legacy_id\": 17,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jungle_log\",\n    \"mode\": \"log_block\",\n    \"top_color\": [155, 120, 75, 255],\n    \"side_color\": [86, 67, 27, 255],\n    \"darken\": false,\n    \"legacy_id\": 17,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_leaves\",\n    \"mode\": \"legacy_leaf_block\",\n    \"top_color\": [74, 131, 66, 128],\n    \"darken\": true,\n    \"legacy_id\": 18,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spruce_leaves\",\n    \"mode\": \"legacy_leaf_block\",\n    \"top_color\": [50, 89, 45, 128],\n    \"darken\": true,\n    \"legacy_id\": 18,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"birch_leaves\",\n    \"mode\": \"legacy_leaf_block\",\n    \"top_color\": [94, 167, 84, 128],\n    \"darken\": true,\n    \"legacy_id\": 18,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jungle_leaves\",\n    \"mode\": \"legacy_leaf_block\",\n    \"top_color\": [58, 147, 19, 128],\n    \"darken\": true,\n    \"legacy_id\": 18,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sponge\",\n    \"mode\": \"block\",\n    \"top_color\": [195, 195, 50, 255],\n    \"darken\": true,\n    \"legacy_id\": 19\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"glass\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 48],\n    \"darken\": true,\n    \"legacy_id\": 20\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lapis_ore\",\n    \"mode\": \"block\",\n    \"top_color\": [102, 112, 134, 255],\n    \"darken\": true,\n    \"legacy_id\": 21\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lapis_block\",\n    \"mode\": \"block\",\n    \"top_color\": [29, 71, 165, 255],\n    \"darken\": true,\n    \"legacy_id\": 22\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dispenser\",\n    \"mode\": \"block\",\n    \"top_color\": [107, 107, 107, 255],\n    \"darken\": true,\n    \"legacy_id\": 23\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sandstone\",\n    \"mode\": \"block\",\n    \"top_color\": [218, 210, 158, 255],\n    \"darken\": true,\n    \"legacy_id\": 24\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"note_block\",\n    \"mode\": \"block\",\n    \"top_color\": [100, 67, 50, 255],\n    \"darken\": true,\n    \"legacy_id\": 25\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [223, 223, 223, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [234, 128, 55, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [191, 76, 201, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [105, 139, 212, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [195, 181, 28, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [59, 189, 48, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [218, 132, 155, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [67, 67, 67, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_gray_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [159, 166, 166, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [39, 117, 150, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [130, 54, 196, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [39, 51, 154, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [86, 51, 28, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 12\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [56, 77, 24, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 13\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [164, 45, 41, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 14\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_bed\",\n    \"mode\": \"block\",\n    \"top_color\": [27, 23, 23, 255],\n    \"darken\": true,\n    \"legacy_id\": 26,\n    \"legacy_meta\": 15\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"powered_rail\",\n    \"mode\": \"block\",\n    \"top_color\": [120, 120, 120, 128],\n    \"side_color\": [255, 220, 0, 128],\n    \"darken\": false,\n    \"legacy_id\": 27\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"detector_rail\",\n    \"mode\": \"block\",\n    \"top_color\": [120, 120, 120, 128],\n    \"side_color\": [230, 0, 0, 128],\n    \"darken\": false,\n    \"legacy_id\": 28\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sticky_piston\",\n    \"mode\": \"block\",\n    \"top_color\": [157, 192, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": 29\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cobweb\",\n    \"mode\": \"block\",\n    \"top_color\": [237, 237, 237, 128],\n    \"darken\": true,\n    \"legacy_id\": 30\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"grass\",\n    \"mode\": \"block\",\n    \"top_color\": [144, 188, 39, 255],\n    \"side_color\": [144, 188, 39, 255],\n    \"darken\": false,\n    \"legacy_id\": 31\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dead_bush\",\n    \"mode\": \"block\",\n    \"top_color\": [157, 128, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": 32\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"piston\",\n    \"mode\": \"block\",\n    \"top_color\": [157, 128, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": 33\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"piston_head\",\n    \"mode\": \"block\",\n    \"top_color\": [157, 128, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": 34\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [223, 223, 223, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [234, 128, 55, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [191, 76, 201, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [105, 139, 212, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [195, 181, 28, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [59, 189, 48, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [218, 132, 155, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [67, 67, 67, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_gray_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [159, 166, 166, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [39, 117, 150, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [130, 54, 196, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [39, 51, 154, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [86, 51, 28, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 12\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [56, 77, 24, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 13\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [164, 45, 41, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 14\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_wool\",\n    \"mode\": \"block\",\n    \"top_color\": [27, 23, 23, 255],\n    \"darken\": true,\n    \"legacy_id\": 35,\n    \"legacy_meta\": 15\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"moving_piston\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 36\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dandelion\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 0, 255],\n    \"darken\": true,\n    \"legacy_id\": 37\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"poppy\",\n    \"mode\": \"block\",\n    \"top_color\": [209, 6, 9, 255],\n    \"darken\": true,\n    \"legacy_id\": 38,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_orchid\",\n    \"mode\": \"block\",\n    \"top_color\": [28, 146, 214, 255],\n    \"darken\": true,\n    \"legacy_id\": 38,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"allium\",\n    \"mode\": \"block\",\n    \"top_color\": [191, 117, 251, 255],\n    \"darken\": true,\n    \"legacy_id\": 38,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"azure_bluet\",\n    \"mode\": \"block\",\n    \"top_color\": [216, 222, 230, 255],\n    \"darken\": true,\n    \"legacy_id\": 38,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_tulip\",\n    \"mode\": \"block\",\n    \"top_color\": [208, 54, 18, 255],\n    \"darken\": true,\n    \"legacy_id\": 38,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_tulip\",\n    \"mode\": \"block\",\n    \"top_color\": [222, 115, 31, 255],\n    \"darken\": true,\n    \"legacy_id\": 38,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_tulip\",\n    \"mode\": \"block\",\n    \"top_color\": [231, 231, 231, 255],\n    \"darken\": true,\n    \"legacy_id\": 38,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_tulip\",\n    \"mode\": \"block\",\n    \"top_color\": [234, 190, 234, 255],\n    \"darken\": true,\n    \"legacy_id\": 38,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oxeye_daisy\",\n    \"mode\": \"block\",\n    \"top_color\": [210, 199, 30, 255],\n    \"darken\": true,\n    \"legacy_id\": 38,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_mushroom\",\n    \"mode\": \"block\",\n    \"top_color\": [200, 200, 0, 255],\n    \"darken\": true,\n    \"legacy_id\": 39\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_mushroom\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 0, 0, 255],\n    \"darken\": true,\n    \"legacy_id\": 40\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gold_block\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 237, 140, 255],\n    \"darken\": true,\n    \"legacy_id\": 41\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"iron_block\",\n    \"mode\": \"block\",\n    \"top_color\": [217, 217, 217, 255],\n    \"darken\": true,\n    \"legacy_id\": 42\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"stone_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [128, 128, 128, 255],\n    \"darken\": true,\n    \"legacy_id\": [43, 44],\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sandstone_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [218, 210, 158, 255],\n    \"darken\": true,\n    \"legacy_id\": [43, 44],\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"petrified_oak_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [157, 128, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": [43, 44],\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cobblestone_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [100, 100, 100, 255],\n    \"darken\": true,\n    \"legacy_id\": [43, 44],\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brick_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [86, 35, 23, 255],\n    \"darken\": true,\n    \"legacy_id\": [43, 44],\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"stone_brick_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [128, 128, 128, 255],\n    \"darken\": true,\n    \"legacy_id\": [43, 44],\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"nether_brick_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [66, 32, 38, 255],\n    \"darken\": true,\n    \"legacy_id\": [43, 44],\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"quartz_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [217, 213, 206, 255],\n    \"darken\": true,\n    \"legacy_id\": [43, 44],\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [86, 35, 23, 255],\n    \"darken\": true,\n    \"legacy_id\": 45\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"tnt\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 0, 0, 255],\n    \"darken\": true,\n    \"legacy_id\": 46\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"bookshelf\",\n    \"mode\": \"block\",\n    \"top_color\": [191, 169, 116, 255],\n    \"darken\": true,\n    \"legacy_id\": 47\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"mossy_cobblestone\",\n    \"mode\": \"block\",\n    \"top_color\": [127, 174, 125, 255],\n    \"darken\": true,\n    \"legacy_id\": 48\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"obsidian\",\n    \"mode\": \"block\",\n    \"top_color\": [17, 13, 26, 255],\n    \"darken\": true,\n    \"legacy_id\": 49\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"torch\",\n    \"mode\": \"torch_block\",\n    \"top_color\": [255, 225, 96, 208],\n    \"darken\": false,\n    \"legacy_id\": 50\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"wall_torch\",\n    \"mode\": \"torch_block\",\n    \"top_color\": [255, 225, 96, 208],\n    \"darken\": false\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"fire\",\n    \"mode\": \"block\",\n    \"top_color\": [224, 174, 21, 255],\n    \"darken\": false,\n    \"legacy_id\": 51\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spawner\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 52\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [157, 128, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": 53\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"chest\",\n    \"mode\": \"block\",\n    \"top_color\": [191, 135, 2, 255],\n    \"darken\": true,\n    \"legacy_id\": 54\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"redstone_wire\",\n    \"mode\": \"block\",\n    \"top_color\": [111, 1, 1, 255],\n    \"darken\": true,\n    \"legacy_id\": 55\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"diamond_ore\",\n    \"mode\": \"block\",\n    \"top_color\": [129, 140, 143, 255],\n    \"darken\": true,\n    \"legacy_id\": 56\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"diamond_block\",\n    \"mode\": \"block\",\n    \"top_color\": [45, 166, 152, 255],\n    \"darken\": true,\n    \"legacy_id\": 57\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"crafting_table\",\n    \"mode\": \"block\",\n    \"top_color\": [169, 107, 0, 255],\n    \"darken\": true,\n    \"legacy_id\": 58\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"wheat\",\n    \"mode\": \"block\",\n    \"top_color\": [144, 188, 39, 255],\n    \"darken\": true,\n    \"legacy_id\": 59\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"farmland\",\n    \"mode\": \"block\",\n    \"top_color\": [134, 96, 67, 255],\n    \"darken\": true,\n    \"legacy_id\": 60\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"furnace\",\n    \"mode\": \"block\",\n    \"top_color\": [188, 188, 188, 255],\n    \"darken\": true,\n    \"legacy_id\": [61, 62]\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sign\",\n    \"mode\": \"block\",\n    \"darken\": false,\n    \"legacy_id\": [63, 68]\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_door\",\n    \"mode\": \"block\",\n    \"darken\": false,\n    \"legacy_id\": 64\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"ladder\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 200, 140, 0],\n    \"darken\": false,\n    \"legacy_id\": 65\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"rail\",\n    \"mode\": \"block\",\n    \"top_color\": [120, 120, 120, 128],\n    \"darken\": true,\n    \"legacy_id\": 66\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cobblestone_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [120, 120, 120, 128],\n    \"darken\": true,\n    \"legacy_id\": 67\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lever\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": false,\n    \"legacy_id\": 69\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"stone_pressure_plate\",\n    \"mode\": \"half_block\",\n    \"top_color\": [120, 120, 120, 255],\n    \"darken\": true,\n    \"legacy_id\": 70\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"iron_door\",\n    \"mode\": \"block\",\n    \"darken\": false,\n    \"legacy_id\": 71\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_pressure_plate\",\n    \"mode\": \"half_block\",\n    \"top_color\": [157, 128, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": 72\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"redstone_ore\",\n    \"mode\": \"block\",\n    \"top_color\": [163, 145, 145, 255],\n    \"darken\": true,\n    \"legacy_id\": [73, 74]\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"redstone_torch\",\n    \"mode\": \"torch_block\",\n    \"top_color\": [181, 140, 64, 32],\n    \"darken\": false,\n    \"legacy_id\": [75, 76]\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"redstone_wall_torch\",\n    \"mode\": \"torch_block\",\n    \"top_color\": [181, 140, 64, 32],\n    \"darken\": false\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"stone_button\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": false,\n    \"legacy_id\": 77\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"snow\",\n    \"mode\": \"half_block\",\n    \"top_color\": [255, 255, 255, 255],\n    \"darken\": true,\n    \"legacy_id\": 78\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"ice\",\n    \"mode\": \"block\",\n    \"top_color\": [120, 120, 255, 120],\n    \"darken\": true,\n    \"legacy_id\": 79\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"snow_block\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 255],\n    \"darken\": true,\n    \"legacy_id\": 80\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cactus\",\n    \"mode\": \"block\",\n    \"top_color\": [85, 107, 47, 255],\n    \"darken\": true,\n    \"legacy_id\": 81\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"clay\",\n    \"mode\": \"block\",\n    \"top_color\": [144, 152, 168, 255],\n    \"darken\": true,\n    \"legacy_id\": 82\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sugar_cane\",\n    \"mode\": \"block\",\n    \"top_color\": [193, 234, 150, 200],\n    \"darken\": true,\n    \"legacy_id\": 83\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jukebox\",\n    \"mode\": \"block\",\n    \"top_color\": [125, 66, 44, 255],\n    \"darken\": true,\n    \"legacy_id\": 84\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_fence\",\n    \"mode\": \"block\",\n    \"top_color\": [157, 128, 79, 200],\n    \"darken\": true,\n    \"legacy_id\": 85\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pumpkin\",\n    \"mode\": \"block\",\n    \"top_color\": [227, 144, 29, 255],\n    \"darken\": true,\n    \"legacy_id\": 86\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"netherrack\",\n    \"mode\": \"block\",\n    \"top_color\": [194, 115, 115, 255],\n    \"darken\": true,\n    \"legacy_id\": 87\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"soul_sand\",\n    \"mode\": \"block\",\n    \"top_color\": [121, 97, 82, 255],\n    \"darken\": true,\n    \"legacy_id\": 88\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"glowstone\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 188, 94, 255],\n    \"darken\": true,\n    \"legacy_id\": 89\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"nether_portal\",\n    \"mode\": \"block\",\n    \"top_color\": [60, 13, 106, 127],\n    \"darken\": true,\n    \"legacy_id\": 90\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jack_o_lantern\",\n    \"mode\": \"block\",\n    \"top_color\": [227, 144, 29, 255],\n    \"darken\": true,\n    \"legacy_id\": 91\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cake\",\n    \"mode\": \"half_block\",\n    \"top_color\": [228, 205, 206, 255],\n    \"darken\": true,\n    \"legacy_id\": 92\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"repeater\",\n    \"mode\": \"half_block\",\n    \"top_color\": [111, 1, 1, 255],\n    \"darken\": true,\n    \"legacy_id\": [93, 94]\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [223, 223, 223, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [234, 128, 55, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [191, 76, 201, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [105, 139, 212, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [195, 181, 28, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [59, 189, 48, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [218, 132, 155, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [67, 67, 67, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [159, 166, 166, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [39, 117, 150, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [130, 54, 196, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [39, 51, 154, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [86, 51, 28, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 12\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [56, 77, 24, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 13\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [164, 45, 41, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 14\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_stained_glass\",\n    \"mode\": \"block\",\n    \"top_color\": [27, 23, 23, 127],\n    \"darken\": true,\n    \"legacy_id\": 95,\n    \"legacy_meta\": 15\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_trapdoor\",\n    \"mode\": \"half_block\",\n    \"top_color\": [157, 128, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": 96\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"infested_stone\",\n    \"mode\": \"block\",\n    \"top_color\": [128, 128, 128, 255],\n    \"darken\": true,\n    \"legacy_id\": 97,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"infested_cobblestone\",\n    \"mode\": \"block\",\n    \"top_color\": [100, 100, 100, 255],\n    \"darken\": true,\n    \"legacy_id\": 97,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"infested_stone_bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [128, 128, 128, 255],\n    \"darken\": true,\n    \"legacy_id\": 97,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"infested_mossy_stone_bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [127, 174, 125, 255],\n    \"darken\": true,\n    \"legacy_id\": 97,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"infested_cracked_stone_bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [128, 128, 128, 255],\n    \"darken\": true,\n    \"legacy_id\": 97,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"infested_chiseled_stone_bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [128, 128, 128, 255],\n    \"darken\": true,\n    \"legacy_id\": 97,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"stone_bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [128, 128, 128, 255],\n    \"darken\": true,\n    \"legacy_id\": 98\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_mushroom_block\",\n    \"mode\": \"block\",\n    \"top_color\": [206, 174, 123, 255],\n    \"darken\": true,\n    \"legacy_id\": 99\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_mushroom_block\",\n    \"mode\": \"block\",\n    \"top_color\": [183, 31, 29, 255],\n    \"darken\": true,\n    \"legacy_id\": 100\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"iron_bars\",\n    \"mode\": \"block\",\n    \"top_color\": [217, 217, 217, 200],\n    \"darken\": true,\n    \"legacy_id\": 101\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 48],\n    \"darken\": true,\n    \"legacy_id\": 102\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"melon\",\n    \"mode\": \"block\",\n    \"top_color\": [50, 200, 45, 255],\n    \"darken\": true,\n    \"legacy_id\": 103\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pumpkin_stem\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 104\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"melon_stem\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 105\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"vine\",\n    \"mode\": \"block\",\n    \"top_color\": [50, 89, 45, 128],\n    \"darken\": false,\n    \"legacy_id\": 106\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_fence_gate\",\n    \"mode\": \"block\",\n    \"top_color\": [157, 128, 79, 200],\n    \"darken\": true,\n    \"legacy_id\": 107\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brick_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [86, 35, 23, 255],\n    \"darken\": true,\n    \"legacy_id\": 108\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"stone_brick_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [128, 128, 128, 255],\n    \"darken\": true,\n    \"legacy_id\": 109\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"mycelium\",\n    \"mode\": \"block\",\n    \"top_color\": [110, 93, 133, 255],\n    \"darken\": true,\n    \"legacy_id\": 110\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lily_pad\",\n    \"mode\": \"half_block\",\n    \"top_color\": [50, 89, 45, 230],\n    \"darken\": false,\n    \"legacy_id\": 111\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"nether_bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [66, 32, 38, 255],\n    \"darken\": true,\n    \"legacy_id\": 112\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"nether_brick_fence\",\n    \"mode\": \"block\",\n    \"top_color\": [66, 32, 38, 200],\n    \"darken\": true,\n    \"legacy_id\": 113\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"nether_brick_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [66, 32, 38, 255],\n    \"darken\": true,\n    \"legacy_id\": 114\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"nether_wart\",\n    \"mode\": \"block\",\n    \"top_color\": [149, 21, 8, 230],\n    \"darken\": true,\n    \"legacy_id\": 115\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"enchanting_table\",\n    \"mode\": \"block\",\n    \"top_color\": [130, 5, 5, 255],\n    \"darken\": true,\n    \"legacy_id\": 116\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brewing_stand\",\n    \"mode\": \"block\",\n    \"top_color\": [124, 118, 51, 230],\n    \"darken\": true,\n    \"legacy_id\": 117\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cauldron\",\n    \"mode\": \"block\",\n    \"top_color\": [49, 49, 49, 255],\n    \"darken\": true,\n    \"legacy_id\": 118\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"end_portal\",\n    \"mode\": \"block\",\n    \"top_color\": [35, 60, 99, 128],\n    \"darken\": true,\n    \"legacy_id\": 119\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"end_portal_frame\",\n    \"mode\": \"block\",\n    \"top_color\": [62, 115, 105, 255],\n    \"darken\": true,\n    \"legacy_id\": 120\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"end_stone\",\n    \"mode\": \"block\",\n    \"top_color\": [203, 206, 148, 255],\n    \"darken\": true,\n    \"legacy_id\": 121\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dragon_egg\",\n    \"mode\": \"block\",\n    \"top_color\": [72, 4, 82, 255],\n    \"darken\": true,\n    \"legacy_id\": 122\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"redstone_lamp\",\n    \"mode\": \"block\",\n    \"top_color\": [145, 90, 57, 255],\n    \"darken\": true,\n    \"legacy_id\": 123\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [157, 128, 79, 255],\n    \"darken\": true,\n    \"legacy_id\": [125, 126],\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spruce_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [102, 77, 46, 255],\n    \"darken\": true,\n    \"legacy_id\": [125, 126],\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"birch_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [193, 177, 122, 255],\n    \"darken\": true,\n    \"legacy_id\": [125, 126],\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jungle_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [152, 109, 76, 255],\n    \"darken\": true,\n    \"legacy_id\": [125, 126],\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"acacia_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [168, 91, 50, 255],\n    \"darken\": true,\n    \"legacy_id\": [125, 126],\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_oak_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [60, 39, 18, 255],\n    \"darken\": true,\n    \"legacy_id\": [125, 126],\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cocoa\",\n    \"mode\": \"block\",\n    \"top_color\": [190, 116, 45, 230],\n    \"darken\": true,\n    \"legacy_id\": 127\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sandstone_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [218, 210, 158, 255],\n    \"darken\": true,\n    \"legacy_id\": 128\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"emerald_ore\",\n    \"mode\": \"block\",\n    \"top_color\": [94, 124, 105, 255],\n    \"darken\": true,\n    \"legacy_id\": 129\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"ender_chest\",\n    \"mode\": \"block\",\n    \"top_color\": [42, 58, 60, 255],\n    \"side_color\": [35, 49, 33, 255],\n    \"darken\": true,\n    \"legacy_id\": 130\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"tripwire_hook\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 131\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"tripwire\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 132\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"emerald_block\",\n    \"mode\": \"block\",\n    \"top_color\": [84, 218, 123, 255],\n    \"darken\": true,\n    \"legacy_id\": 133\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spruce_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [102, 77, 46, 255],\n    \"darken\": true,\n    \"legacy_id\": 134\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"birch_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [193, 177, 122, 255],\n    \"darken\": true,\n    \"legacy_id\": 135\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jungle_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [152, 109, 76, 255],\n    \"darken\": true,\n    \"legacy_id\": 136\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"command_block\",\n    \"mode\": \"block\",\n    \"top_color\": [186, 118, 74, 255],\n    \"darken\": true,\n    \"legacy_id\": 137\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"beacon\",\n    \"mode\": \"block\",\n    \"top_color\": [196, 255, 254, 230],\n    \"darken\": true,\n    \"legacy_id\": 138\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cobblestone_wall\",\n    \"mode\": \"block\",\n    \"top_color\": [100, 100, 100, 255],\n    \"darken\": true,\n    \"legacy_id\": 139\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"flower_pot\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 140\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"carrots\",\n    \"mode\": \"block\",\n    \"top_color\": [2, 161, 0, 255],\n    \"darken\": true,\n    \"legacy_id\": 141\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"potatoes\",\n    \"mode\": \"block\",\n    \"top_color\": [0, 174, 25, 255],\n    \"darken\": true,\n    \"legacy_id\": 142\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"oak_button\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 143\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"skeleton_skull\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"skeleton_wall_skull\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"wither_skeleton_skull\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"wither_skeleton_wall_skull\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"zombie_head\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"zombie_wall_head\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"player_head\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"player_wall_head\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"creeper_head\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"creeper_wall_head\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dragon_head\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dragon_wall_head\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255,255, 0],\n    \"darken\": true,\n    \"legacy_id\": 144,\n    \"legacy_meta\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"anvil\",\n    \"mode\": \"block\",\n    \"top_color\": [66, 62, 62, 255],\n    \"darken\": true,\n    \"legacy_id\": 145,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"chipped_anvil\",\n    \"mode\": \"block\",\n    \"top_color\": [66, 62, 62, 255],\n    \"darken\": true,\n    \"legacy_id\": 145,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"damaged_anvil\",\n    \"mode\": \"block\",\n    \"top_color\": [66, 62, 62, 255],\n    \"darken\": true,\n    \"legacy_id\": 145,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"trapped_chest\",\n    \"mode\": \"block\",\n    \"top_color\": [191, 135, 2, 255],\n    \"darken\": true,\n    \"legacy_id\": 146\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_weighted_pressure_plate\",\n    \"mode\": \"half_block\",\n    \"top_color\": [255, 237, 140, 255],\n    \"darken\": true,\n    \"legacy_id\": 147\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"heavy_weighted_pressure_plate\",\n    \"mode\": \"half_block\",\n    \"top_color\": [217, 217, 217, 255],\n    \"darken\": true,\n    \"legacy_id\": 148\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"comparator\",\n    \"mode\": \"half_block\",\n    \"top_color\": [111, 1, 1, 255],\n    \"darken\": true,\n    \"legacy_id\": 149\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"daylight_detector\",\n    \"mode\": \"half_block\",\n    \"top_color\": [194, 179, 158, 255],\n    \"side_color\": [29, 23, 14, 255],\n    \"darken\": true,\n    \"legacy_id\": 151\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"redstone_block\",\n    \"mode\": \"block\",\n    \"top_color\": [150, 24, 7, 255],\n    \"darken\": true,\n    \"legacy_id\": 152\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"nether_quartz_ore\",\n    \"mode\": \"block\",\n    \"top_color\": [190, 143, 136, 255],\n    \"darken\": true,\n    \"legacy_id\": 153\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"hopper\",\n    \"mode\": \"block\",\n    \"top_color\": [55, 55, 55, 255],\n    \"darken\": true,\n    \"legacy_id\": 154\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"quartz_block\",\n    \"mode\": \"block\",\n    \"top_color\": [217, 213, 206, 255],\n    \"darken\": true,\n    \"legacy_id\": 155\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"quartz_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [217, 213, 206, 255],\n    \"darken\": true,\n    \"legacy_id\": 156\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"activator_rail\",\n    \"mode\": \"block\",\n    \"top_color\": [120, 120, 120, 128],\n    \"side_color\": [255, 220, 0, 128],\n    \"darken\": false,\n    \"legacy_id\": 157\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dropper\",\n    \"mode\": \"block\",\n    \"top_color\": [107, 107, 107, 255],\n    \"darken\": true,\n    \"legacy_id\": 158\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [210, 177, 161, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [162, 82, 36, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [149, 89, 110, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [117, 111, 140, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [186, 134, 36, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [102, 115, 48, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [163, 80, 80, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [57, 42, 35, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_gray_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [135, 107, 98, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [91, 95, 94, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [119, 72, 87, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [76, 62, 92, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [77, 51, 36, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 12\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [76, 84, 43, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 13\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [142, 61, 47, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 14\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [39, 24, 17, 255],\n    \"darken\": true,\n    \"legacy_id\": 159,\n    \"legacy_meta\": 15\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [223, 223, 223, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [234, 128, 55, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [191, 76, 201, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [105, 139, 212, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [195, 181, 28, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [59, 189, 48, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [218, 132, 155, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [67, 67, 67, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [159, 166, 166, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [39, 117, 150, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [130, 54, 196, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [39, 51, 154, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [86, 51, 28, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 12\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [56, 77, 24, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 13\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [164, 45, 41, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 14\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_stained_glass_pane\",\n    \"mode\": \"block\",\n    \"top_color\": [27, 23, 23, 127],\n    \"darken\": true,\n    \"legacy_id\": 160,\n    \"legacy_meta\": 15\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"acacia_leaves\",\n    \"mode\": \"legacy_leaf_block\",\n    \"top_color\": [58, 145, 19, 128],\n    \"darken\": true,\n    \"legacy_id\": 161,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_oak_leaves\",\n    \"mode\": \"legacy_leaf_block\",\n    \"top_color\": [52, 131, 18, 128],\n    \"darken\": true,\n    \"legacy_id\": 161,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"acacia_log\",\n    \"mode\": \"log_block\",\n    \"top_color\": [155, 90, 62, 255],\n    \"side_color\": [104, 98, 88, 255],\n    \"darken\": false,\n    \"legacy_id\": 162,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_oak_log\",\n    \"mode\": \"log_block\",\n    \"top_color\": [79, 63, 41, 255],\n    \"side_color\": [51, 40, 23, 255],\n    \"darken\": false,\n    \"legacy_id\": 162,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"acacia_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [168, 91, 50, 255],\n    \"darken\": true,\n    \"legacy_id\": 163\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_oak_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [60, 39, 18, 255],\n    \"darken\": true,\n    \"legacy_id\": 164\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"slime_block\",\n    \"mode\": \"block\",\n    \"top_color\": [114, 188, 105, 230],\n    \"darken\": true,\n    \"legacy_id\": 165\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"barrier\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": true,\n    \"legacy_id\": 166\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"iron_trapdoor\",\n    \"mode\": \"half_block\",\n    \"top_color\": [217, 217, 217, 255],\n    \"darken\": true,\n    \"legacy_id\": 167\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"prismarine\",\n    \"mode\": \"block\",\n    \"top_color\": [69, 122, 123, 255],\n    \"darken\": true,\n    \"legacy_id\": 168,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"prismarine_bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [69, 123, 108, 255],\n    \"darken\": true,\n    \"legacy_id\": 168,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_prismarine\",\n    \"mode\": \"block\",\n    \"top_color\": [59, 87, 75, 255],\n    \"darken\": true,\n    \"legacy_id\": 168,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sea_lantern\",\n    \"mode\": \"block\",\n    \"top_color\": [68, 121, 104, 255],\n    \"darken\": true,\n    \"legacy_id\": 169\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"hay_block\",\n    \"mode\": \"block\",\n    \"top_color\": [192, 160, 14, 255],\n    \"darken\": true,\n    \"legacy_id\": 170\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [223, 223, 223, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [234, 128, 55, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [191, 76, 201, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [105, 139, 212, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [195, 181, 28, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [59, 189, 48, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [218, 132, 155, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [67, 67, 67, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_gray_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [159, 166, 166, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [39, 117, 150, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [130, 54, 196, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [39, 51, 154, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [86, 51, 28, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 12\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [56, 77, 24, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 13\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [164, 45, 41, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 14\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_carpet\",\n    \"mode\": \"half_block\",\n    \"top_color\": [27, 23, 23, 255],\n    \"darken\": true,\n    \"legacy_id\": 171,\n    \"legacy_meta\": 15\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"terracotta\",\n    \"mode\": \"block\",\n    \"top_color\": [140, 86, 63, 255],\n    \"darken\": true,\n    \"legacy_id\": 172\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"coal_block\",\n    \"mode\": \"block\",\n    \"top_color\": [20, 20, 20, 255],\n    \"darken\": true,\n    \"legacy_id\": 173\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"packed_ice\",\n    \"mode\": \"block\",\n    \"top_color\": [120, 120, 255, 180],\n    \"darken\": true,\n    \"legacy_id\": 174\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"sunflower\",\n    \"mode\": \"large_plant_block\",\n    \"top_color\": [230, 187, 33, 255],\n    \"side_color\": [66, 108, 43, 255],\n    \"darken\": false,\n    \"legacy_id\": 175,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lilac\",\n    \"mode\": \"large_plant_block\",\n    \"top_color\": [159, 120, 164, 255],\n    \"darken\": false,\n    \"legacy_id\": 175,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"tall_grass\",\n    \"mode\": \"large_plant_block\",\n    \"top_color\": [144, 188, 39, 255],\n    \"darken\": false,\n    \"legacy_id\": 175,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"large_fern\",\n    \"mode\": \"large_plant_block\",\n    \"top_color\": [144, 188, 39, 255],\n    \"darken\": false,\n    \"legacy_id\": 175,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"rose_bush\",\n    \"mode\": \"large_plant_block\",\n    \"top_color\": [190, 26, 18, 255],\n    \"darken\": false,\n    \"legacy_id\": 175,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"peony\",\n    \"mode\": \"large_plant_block\",\n    \"top_color\": [222, 165, 247, 255],\n    \"side_color\": [69, 96, 73, 255],\n    \"darken\": false,\n    \"legacy_id\": 175,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_sandstone\",\n    \"mode\": \"block\",\n    \"top_color\": [166, 85, 30, 255],\n    \"darken\": true,\n    \"legacy_id\": 179\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_sandstone_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [166, 85, 30, 255],\n    \"darken\": true,\n    \"legacy_id\": 180\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_sandstone_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [166, 85, 30, 255],\n    \"darken\": true,\n    \"legacy_id\": [\n      181,\n      182\n    ]\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spruce_fence_gate\",\n    \"mode\": \"block\",\n    \"top_color\": [102, 77, 46, 200],\n    \"darken\": true,\n    \"legacy_id\": 183\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"birch_fence_gate\",\n    \"mode\": \"block\",\n    \"top_color\": [193, 177, 122, 200],\n    \"darken\": true,\n    \"legacy_id\": 184\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jungle_fence_gate\",\n    \"mode\": \"block\",\n    \"top_color\": [152, 109, 76, 200],\n    \"darken\": true,\n    \"legacy_id\": 185\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_oak_fence_gate\",\n    \"mode\": \"block\",\n    \"top_color\": [60, 39, 18, 200],\n    \"darken\": true,\n    \"legacy_id\": 186\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"acacia_fence_gate\",\n    \"mode\": \"block\",\n    \"top_color\": [168, 91, 50, 200],\n    \"darken\": true,\n    \"legacy_id\": 187\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spruce_fence\",\n    \"mode\": \"block\",\n    \"top_color\": [102, 77, 46, 200],\n    \"darken\": true,\n    \"legacy_id\": 188\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"birch_fence\",\n    \"mode\": \"block\",\n    \"top_color\": [193, 177, 122, 200],\n    \"darken\": true,\n    \"legacy_id\": 189\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jungle_fence\",\n    \"mode\": \"block\",\n    \"top_color\": [152, 109, 76, 200],\n    \"darken\": true,\n    \"legacy_id\": 190\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_oak_fence\",\n    \"mode\": \"block\",\n    \"top_color\": [60, 39, 18, 200],\n    \"darken\": true,\n    \"legacy_id\": 191\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"acacia_fence\",\n    \"mode\": \"block\",\n    \"top_color\": [168, 91, 50, 200],\n    \"darken\": true,\n    \"legacy_id\": 192\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"spruce_door\",\n    \"mode\": \"block\",\n    \"darken\": false,\n    \"legacy_id\": 193\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"birch_door\",\n    \"mode\": \"block\",\n    \"darken\": false,\n    \"legacy_id\": 194\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"jungle_door\",\n    \"mode\": \"block\",\n    \"darken\": false,\n    \"legacy_id\": 195\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"acacia_door\",\n    \"mode\": \"block\",\n    \"darken\": false,\n    \"legacy_id\": 196\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"dark_oak_door\",\n    \"mode\": \"block\",\n    \"darken\": false,\n    \"legacy_id\": 197\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"end_rod\",\n    \"mode\": \"block\",\n    \"top_color\": [94, 73, 131, 140],\n    \"darken\": false,\n    \"legacy_id\": 198\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"chorus_plant\",\n    \"mode\": \"block\",\n    \"top_color\": [116, 70, 124, 255],\n    \"darken\": true,\n    \"legacy_id\": 199\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"chorus_flower\",\n    \"mode\": \"block\",\n    \"top_color\": [108, 84, 108, 255],\n    \"darken\": true,\n    \"legacy_id\": 200\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purpur_block\",\n    \"mode\": \"block\",\n    \"top_color\": [104, 58, 103, 255],\n    \"darken\": true,\n    \"legacy_id\": 201\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purpur_pillar\",\n    \"mode\": \"block\",\n    \"top_color\": [166, 124, 166, 255],\n    \"darken\": true,\n    \"legacy_id\": 202\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purpur_stairs\",\n    \"mode\": \"block\",\n    \"top_color\": [140, 105, 142, 255],\n    \"darken\": true,\n    \"legacy_id\": 203\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purpur_slab\",\n    \"mode\": \"legacy_slab_block\",\n    \"top_color\": [104, 58, 103, 255],\n    \"darken\": true,\n    \"legacy_id\": [204, 205]\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"end_stone_bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [223, 229, 170, 255],\n    \"darken\": true,\n    \"legacy_id\": 206\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"beetroots\",\n    \"mode\": \"block\",\n    \"top_color\": [76, 108, 49, 255],\n    \"darken\": true,\n    \"legacy_id\": 207\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"grass_path\",\n    \"mode\": \"block\",\n    \"top_color\": [149, 125, 71, 255],\n    \"darken\": true,\n    \"legacy_id\": 208\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"end_gateway\",\n    \"mode\": \"block\",\n    \"top_color\": [15, 15, 25, 255],\n    \"darken\": true,\n    \"legacy_id\": 209\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"repeating_command_block\",\n    \"mode\": \"block\",\n    \"top_color\": [135, 122, 152, 255],\n    \"darken\": true,\n    \"legacy_id\": 210\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"chain_command_block\",\n    \"mode\": \"block\",\n    \"top_color\": [114, 135, 131, 255],\n    \"darken\": true,\n    \"legacy_id\": 211\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"frosted_ice\",\n    \"mode\": \"block\",\n    \"top_color\": [120, 120, 255, 120],\n    \"darken\": true,\n    \"legacy_id\": 212\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magma_block\",\n    \"mode\": \"block\",\n    \"top_color\": [132, 64, 26, 255],\n    \"darken\": true,\n    \"legacy_id\": 213\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"nether_wart_block\",\n    \"mode\": \"block\",\n    \"top_color\": [107, 60, 60, 255],\n    \"darken\": true,\n    \"legacy_id\": 214\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_nether_bricks\",\n    \"mode\": \"block\",\n    \"top_color\": [106, 59, 62, 255],\n    \"darken\": true,\n    \"legacy_id\": 215\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"bone_block\",\n    \"mode\": \"block\",\n    \"top_color\": [218, 214, 193, 255],\n    \"darken\": true,\n    \"legacy_id\": 216\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"structure_void\",\n    \"mode\": \"block\",\n    \"top_color\": [255, 255, 255, 0],\n    \"darken\": false,\n    \"legacy_id\": 217\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"observer\",\n    \"mode\": \"block\",\n    \"top_color\": [107, 107, 107, 255],\n    \"darken\": true,\n    \"legacy_id\": 218\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [205, 210, 210, 255],\n    \"darken\": true,\n    \"legacy_id\": 219\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [228, 104, 9, 255],\n    \"darken\": true,\n    \"legacy_id\": 220\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [168, 52, 158, 255],\n    \"darken\": true,\n    \"legacy_id\": 221\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [46, 156, 206, 255],\n    \"darken\": true,\n    \"legacy_id\": 222\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [241, 182, 27, 255],\n    \"darken\": true,\n    \"legacy_id\": 223\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [94, 163, 22, 255],\n    \"darken\": true,\n    \"legacy_id\": 224\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [221, 114, 150, 255],\n    \"darken\": true,\n    \"legacy_id\": 225\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [56, 59, 63, 255],\n    \"darken\": true,\n    \"legacy_id\": 226\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_gray_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [117, 117, 108, 255],\n    \"darken\": true,\n    \"legacy_id\": 227\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [20, 116, 130, 255],\n    \"darken\": true,\n    \"legacy_id\": 228\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [148, 103, 148, 255],\n    \"darken\": true,\n    \"legacy_id\": 229\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [42, 44, 135, 255],\n    \"darken\": true,\n    \"legacy_id\": 230\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [103, 64, 35, 255],\n    \"darken\": true,\n    \"legacy_id\": 231\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [76, 96, 32, 255],\n    \"darken\": true,\n    \"legacy_id\": 232\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [138, 30, 29, 255],\n    \"darken\": true,\n    \"legacy_id\": 233\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_shulker_box\",\n    \"mode\": \"block\",\n    \"top_color\": [23, 24, 28, 255],\n    \"darken\": true,\n    \"legacy_id\": 234\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 235\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 236\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 237\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 238\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 239\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 240\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 241\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 242\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"silver_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 243\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 244\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 245\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 246\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_glazed_terracotta \",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 247\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 248\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 249\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_glazed_terracotta\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 250\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_gray_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 12\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 13\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 14\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_concrete\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 251,\n    \"legacy_meta\": 15\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"white_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 0\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"orange_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 1\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"magenta_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 2\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_blue_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 3\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"yellow_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 4\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"lime_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 5\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"pink_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 6\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"gray_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 7\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"light_gray_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 8\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"cyan_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 9\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"purple_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 10\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"blue_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 11\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"brown_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 12\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"green_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 13\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"red_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 14\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"black_concrete_powder\",\n    \"mode\": \"block\",\n    \"darken\": true,\n    \"legacy_id\": 252,\n    \"legacy_meta\": 15\n  },\n  {\n    \"namespace\": \"minecraft\",\n    \"material\": \"structure_block\",\n    \"mode\": \"block\",\n    \"top_color\": [98, 74, 98, 255],\n    \"darken\": true,\n    \"legacy_id\": 255\n  }\n]\n"
  },
  {
    "path": "res/example.html",
    "content": "<html>\n  <head>\n    <script type=\"text/javascript\" src=\"libc10t.js\"></script>\n    <script type=\"text/javascript\" src=\"c10t_json.js\"></script>\n    <script type=\"text/javascript\">\n      if (window.c10t_json == undefined) {\n        alert(\"There is no c10t_json.js available, render one with `--write-js <output>'\");\n      }\n      else {\n        var c = new c10t(c10t_json);\n        // try out a projection\n        var p = {\"X\":-123,\"Y\":5,\"Z\":19,\"text\":\"Protected\",\"type\":\"player\",\"x\":4610,\"y\":2444}\n        alert(c.project(p.X, p.Y, p.Z));\n      }\n    </script>\n  </head>\n\t<body></body>\n</html>\n"
  },
  {
    "path": "res/libc10t.js",
    "content": "function c10t(json) {\n  this.MapX = json.st.MapX;\n  this.MapY = json.st.MapY;\n  this.MapZ = json.st.MapZ;\n  \n  this.mx_x = json.world.mx_x;\n  this.mn_x = json.world.mn_x;\n  this.mx_z = json.world.mx_z;\n  this.mn_z = json.world.mn_z;\n  this.mx_y = this.MapY;\n  this.mn_y = 0;\n  this.cx = json.world.cx;\n  this.cy = json.world.cy;\n  this.dx = json.world.dx;\n  this.dz = json.world.dz;\n  this.dy = this.MapY;\n  \n  this.mode = this.modes[json.world.mode];\n  this.projection = this.projections[this.mode];\n  \n  this.project = function (x, y, z)\n  {\n    cropCompensation = this.projection(0, 0, 0);\n    coordinates = this.projection(x, y, z);\n    \n    coordinates[0] -= cropCompensation[0] - this.cx;\n    coordinates[1] -= cropCompensation[1] - this.cy;\n    \n    return coordinates;\n  }\n}\n\nc10t.prototype.modes = {\n  0x0: \"top\",\n  0x1: \"oblique\",\n  0x2: \"obliqueangle\",\n  0x3: \"isometric\"\n};\n\nc10t.prototype.projections = {\n  'top': function(x, y, z) {\n    x -= this.mn_x;\n    z -= this.mn_z;\n    return [(this.dz - z - 1), x];\n  },\n  'oblique': function(x, y, z) {\n    x -= this.mn_x;\n    z -= this.mn_z;\n    return [(this.dz - z - 1) + x, x];\n  },\n  'obliqueangle': function(x, y, z) {\n    x -= this.mn_x;\n    z -= this.mn_z;\n    return [(this.dz - z - 1) + x, (this.dy - y - 1) + z + x];\n  },\n  'isometric': function(x, y, z) {\n    x -= this.mn_x;\n    z -= this.mn_z;\n    return [2 * ((this.dz - z - 1) + x), 2 * (this.dy - y - 1) + z + x];\n  }\n};\n"
  },
  {
    "path": "scripts/area-set.sh",
    "content": "#!/bin/bash\nbasics=\" -w /home/j/.minecraft/saves/World1\"\nprefix='./images/area'\nthreads=2\nfor i in $(seq -150 -20)\ndo\nimgfile=\"$prefix$i.png\"\necho \"Rendering $i...\"\n./c10t $basics -o $imgfile -L -150,$i,-100,150 -q -s &\n# Wait for threads to finish...\nlet mod=$i%$threads\nif [ $mod = 0 ]; then\n  wait\nfi \ndone\n\necho Trimming...\n# Make all images the same size (assuming last image largest)\nmogrify -bordercolor white -border 1x1 -trim $prefix*.png\nnewsize=$(identify -format '%wx%h' $imgfile)\nmogrify -extent $newsize -background white +repage $prefix*.png\n#Animate into a gif...\necho Animating...\nconvert -delay 20 -loop -1 $prefix*.png $prefix-animated.gif\n\n"
  },
  {
    "path": "scripts/area-slice.sh",
    "content": "#!/bin/bash\nbasics=\" -w /home/j/.minecraft/saves/World1\"\nprefix='./images/areaslice'\nthreads=2\nfor i in $(seq -150 -20)\ndo\nimgfile=\"$prefix$i.png\"\nlet j=i-2\necho \"Rendering $i...\"\n./c10t $basics -o $imgfile -L $j,$i,-100,150 -q -s &\n# Wait for threads to finish...\nlet mod=$i%$threads\nif [ $mod = 0 ]; then\n  wait\nfi \ndone\necho Trimming...\n# Make all images the same size (assuming last image largest)\nmogrify -bordercolor white -border 1x1 -trim $prefix*.png\nnewsize=$(identify -format '%wx130' $imgfile)\nmogrify -gravity south -extent $newsize -background white +repage $prefix*.png\n#Animate into a gif...\necho Animating...\nsleep 1\nconvert -delay 20 -loop -1 $prefix*.png $prefix-animated.gif\n"
  },
  {
    "path": "scripts/generate-tests.sh",
    "content": "#!/bin/bash\n\nset -e\n\nworld=$1\ndir=$2\n\nC10T=./c10t\nC10T_ARGS=\"-w $world -L -70,-60,5,20\"\n\nif [[ ! -d $world ]]; then\n  echo \"Not a directory: $world\"\n  exit 1;\nfi\n\nif [[ ! -d $dir ]]; then\n  echo \"Not a directory: $dir\"\n  exit 1;\nfi\n\necho_palette() {\n  cat << END\n  Wood 0,255,0\n  Stone 0,0,0,20\n  Leaves 0,0,255,20\nEND\n}\n\necho_html() {\n  cat << END\n<html>\n  <head>\n    <title>c10t - showroom</title>\n    <style type=\"text/css\">\n.desc {\n  font-size: 120%;\n  padding: 20px;\n}\n\n.images {\n  padding: 10px;\n}\n    </style>\n  </head>\n  <body>\n    <h1>c10t Showroom</h1>\n    <p class=\"desc\">\n      Normal map\n    </p>\n    <div class=\"images\">\n      <img src=\"n.png\" />\n      <img src=\"n-n.png\" />\n      <img src=\"n-H.png\" />\n      <img src=\"n-C.png\" />\n      <img src=\"n-A.png\" />\n      <img src=\"n-P.png\" />\n    </div>\n    \n    <p class=\"desc\">\n      Oblique map\n    </p>\n    <div class=\"images\">\n      <img src=\"q.png\" />\n      <img src=\"q-n.png\" />\n      <img src=\"q-H.png\" />\n      <img src=\"q-C.png\" />\n      <img src=\"q-A.png\" />\n      <img src=\"q-P.png\" />\n    </div>\n    \n    <p class=\"desc\">\n      Oblique angled map\n    </p>\n    <div class=\"images\">\n      <img src=\"y.png\" />\n      <img src=\"y-n.png\" />\n      <img src=\"y-H.png\" />\n      <img src=\"y-C.png\" />\n      <img src=\"y-A.png\" />\n      <img src=\"y-P.png\" />\n    </div>\n    \n    <p class=\"desc\">\n      Isometric\n    </p>\n    <div class=\"images\">\n      <img src=\"z.png\" />\n      <img src=\"z-n.png\" />\n      <img src=\"z-H.png\" />\n      <img src=\"z-C.png\" />\n      <img src=\"z-A.png\" />\n      <img src=\"z-P.png\" />\n    </div>\n  </body>\n</html>\nEND\n}\n\necho_html > $dir/index.html\n\nmotion() {\n  $C10T $C10T_ARGS $1 -o $dir/$2.png\n  $C10T $C10T_ARGS $1 --night -o $dir/$2-n.png\n  $C10T $C10T_ARGS $1 --heightmap -o $dir/$2-H.png\n  $C10T $C10T_ARGS $1 --cave-mode -o $dir/$2-C.png\n  $C10T $C10T_ARGS $1 --no-alpha -o $dir/$2-A.png\n  $C10T $C10T_ARGS $1 -P <(echo_palette;) -o $dir/$2-P.png\n}\n\nmotion \"\" \"n\"\nmotion \"-q\" \"q\"\nmotion \"-y\" \"y\"\nmotion \"-z\" \"z\"\n"
  },
  {
    "path": "scripts/google-api/README.txt",
    "content": "There has been a couple of variants of this script popping out recently, I took the liberty of consolidating them into the master branch.\n-- Udoprog - Nov 17 2010\n\n=== google-api.ps1 ===\nOriginally authored by Kochu\n\n\"\"\"\n  Usage is the same as with the .sh: google-api.ps1 \"world\" \"target\"\n  You may need to change the path to the c10t executable in the script, add its location to the PATH variable, or install it into system32.\n\n  To run it, you will need to enable script execution by powershell - it is off by default.\n  To do this, you will need to run powershell as an admin and type \"set-executionpolicy unrestricted\", then \"y\" to confirm\n  You'll have to do it only once.\n\n  Hope it works.\n\"\"\" -- Kochu @ http://www.minecraftforum.net/viewtopic.php?f=25&t=33803&start=570\n\n=== google-api.php ===\nOriginally authored by Rendrik\n\n\"\"\"\n  I've ported the google-api script to PHP, mainly for use in a windows environment. I haven't tested this in Linux.\n  It uses GD to resize the images.\n  The script must be placed in the same directory as c10t.exe\n\n  Usage is:\n  php google-api.php [world path]* [image output directory]* [c10t args in quotes]\n\n  For example:\n  php google-api.php world\\ gmap_images\\ \"--isometric -r 270\"\n  or \n  php google-api.php world\\ tiles\\ \"--oblique-angle --show-signs\"\n\n  Make sure you have the trailing slash for directorys.\n  This will create the following files:\n  map.html\n  options.js\n  (image dir)\\(lots of images).png\n\n  Just open map.html to test it out.\n\n  If there is any issue, you can open the PHP file and change the VERBOSE constant to true. This will output the c10t commands and responses.\n\"\"\" -- Rendrik @ http://www.minecraftforum.net/viewtopic.php?f=25&t=33803&start=570\n"
  },
  {
    "path": "scripts/google-api/google-api.php",
    "content": "<?php\r\nini_set(\"memory_limit\", \"200M\");\r\ndefine(\"VERBOSE\", false);\r\n/**\r\n * google-api.php\r\n *\r\n * author - Ben Rice (dashiva@dashiva.com)\r\n *\r\n * The function of this script is to render several Minecraft maps using the\r\n * map generator \"c10t\". A googlemap is then created using the tiles, and output.\r\n *\r\n * Usage:\r\n * php google-api.php [world] [output] [c10t args in quotes]\r\n * e.x.: php google-api.php myworld gmap \"-isometric -r 270\"\r\n */\r\n\r\n\r\n# Required args\r\nif(empty($argv[1]) || empty($argv[2]) ) {\r\n\techo(\"google-api.php (Minecraft map parsing script)\\r\\nScriped by Ben Rice (dashiva@dashiva.com)\\r\\n\\r\\nUsage:\\r\\nphp google-api.php [world path]* [output directory]* [c10t args in quotes]\\r\\n *Required\");\r\n\texit();\r\n}\r\n\r\n$outHTML = \"map.html\";\r\n$inPath = $argv[1];\t\t# World files directory\r\n$outDir = $argv[2];\t\t# Tile directory\r\nif( isset($argv[3]) ) {\t# c10t args\r\n\t$c10tArgs = $argv[3]; //\"--isometric\";\r\n}\r\n\r\n$scale = array( 4096 => .0625, \t# 6.25%\r\n\t\t\t\t2048 => .125,\t# 12.5%\r\n\t\t\t\t1024 => .25,\t\t# 25%\r\n\t\t\t\t512  => .5,\t\t# 50%\r\n\t\t\t\t256  => 1,\t\t# 100%\r\n\t\t\t\t128  => 2 );\t# 200%\r\n\r\n$zoom = array(\t4096 => 0,\r\n\t\t\t\t2048 => 1,\r\n\t\t\t\t1024 => 2,\r\n\t\t\t\t512  => 3,\r\n\t\t\t\t256  => 4,\r\n\t\t\t\t128  => 5);\r\n\t\t\t\t\r\n$tileSizes = array(0 => 4096, 1 => 2048, 2=> 1024, 3=> 512, 4 => 256, 5 => 128);\r\n\r\n# Verify world directory is valid\r\nif( !is_dir($inPath) || !file_exists($inPath.\"level.dat\") ) {\r\n\techo(\"Invalid world directory: \".$inPath.\"\\r\\n\");\r\n\texit();\r\n}\r\nelse\r\n\techo(\"World directory...OK\\r\\n\");\r\n\r\n# Verify the executable\r\nexec(\"c10t\", $output);\r\nif( empty($output) ) {\r\n\techo(\"Cannot find c10t.exe!\\r\\n\");\r\n\texit();\r\n}\r\nelse\r\n\techo(\"c10t.exe...OK\\r\\n\");\r\n\r\nif (extension_loaded('gd') && function_exists('gd_info')) {\r\n    echo(\"PHP GD extension...OK\\r\\n\");\r\n}\r\nelse {\r\n\techo(\"GD extension is not installed or loaded!\\r\\nSee php.ini and be sure it contains extension=php_gd2.dll\\r\\n\");\r\n\texit();\r\n}\r\n\r\n# check / create output dir for images\r\nif( !is_dir($outDir) ) {\r\n\tmkdir($outDir);\r\n\techo(\"Creating folder \".$outDir.\"\\r\\n\");\r\n}\r\nelse\r\n\techo(\"Folder \".$outDir.\" already exists.\\r\\n\");\r\n\r\n\r\n\r\n/**\r\n * function resizeImage\r\n *\r\n * This will use GD to resize an image.\r\n */\r\nfunction resizeImage($file, $scale) {\r\n    list($width, $height) = getimagesize($file);\r\n\t\r\n    $newheight = $height * $scale;\r\n    $newwidth = $newheight;\r\n\t\r\n\tif(VERBOSE)\r\n\t\techo(\"Resizing \" . $file . \"\\told(\".$height.\")\". \"\\tnew(\".$newheight.\")\" . \"\\tscale(\" . $scale . \")\\r\\n\");\r\n\techo(\".\");\r\n    $src = imagecreatefrompng($file);\r\n    $dst = imagecreatetruecolor($newwidth, $newheight);\r\n    $img = imagecopyresampled($dst, $src, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);\r\n\r\n\timagealphablending( $dst, false );\r\n\timagesavealpha( $dst, true );\r\n\timagepng(  $dst, $file, 9 );\r\n}\r\n\r\n\r\n/**\r\n * function generate\r\n *\r\n * This will execute c10t with the proper parameters.\r\n */\r\nfunction generate($arg1, $name, $tile, $zoom, $scale) {\r\n\t$start = time();\r\n\tglobal $inPath;\r\n\tglobal $outDir;\r\n\tglobal $c10tArgs;\r\n\techo(\"Generating: \".$name.\"\\t Tile Size:\".$tile.\"\\t Zoom:\".$zoom.\"...\");\r\n\t\r\n\t# generate a set of split files\r\n\t$run = \"c10t \".$c10tArgs.\" \".$arg1.\" --split \".$tile.\" -w \".$inPath.\" -o \".$outDir.$name.\".%d.%d.\".$zoom.\".png --write-json \".$outDir.$name.\".json\";\r\n\t\r\n\t# Uncomment for details\r\n\tif(VERBOSE)\r\n\t\techo(\"\\r\\n\".$run.\"\\r\\n\");\r\n\t\r\n\texec($run, $output);\r\n\tif(VERBOSE)\r\n\t\tvar_dump($output);\r\n\t$end = time();\r\n\t$elapsed = $end - $start;\r\n\techo(\"Done in \".getTimeStr($elapsed).\"\\r\\n\");\r\n\t\r\n}\r\n\r\n/**\r\n * function read\r\n *\r\n * This will open a file and return it's contents.\r\n */\r\nfunction read($file) {\r\n\tif(file_exists($file)) {\r\n\t\t$in = fopen ($file, \"r\");\r\n\t\tif (!$in)\r\n\t\t\treturn false;\r\n\t\t$raw = \"\";\r\n\t\tif(filesize($file) <= 0)\r\n\t\t\treturn false;\r\n\t\telse \r\n\t\t\t$raw = fread($in, filesize($file));\r\n\t\tfclose($in);\r\n\t\t\r\n\t\treturn $raw;\r\n\t}\r\n\treturn false; \r\n}\r\n\r\n/**\r\n * function write\r\n *\r\n * This will write contents to a file.\r\n */\r\nfunction write($file, $content) {\r\n\tif( empty($file) || empty($content) )\r\n\t\treturn false;\r\n\t\r\n\t$fl = fopen($file, \"w+\"); \r\n\tfputs($fl, $content);\r\n\tfclose($fl);\r\n\treturn true;\r\n}\r\n\r\n/**\r\n * function getTimeStr\r\n *\r\n * Return text for how many seconds is passed in.\r\n */\r\nfunction getTimeStr($durationInSeconds)\r\n{\r\n  $week = floor($durationInSeconds / 86400 / 7);\r\n  $day = $durationInSeconds / 86400 % 7;\r\n  $hour = $durationInSeconds / 3600 % 24;\r\n  $min = $durationInSeconds / 60 % 60;\r\n  $sec = $durationInSeconds % 60;\r\n\r\n  if($week != 0)\r\n  {\r\n    $time  = $week . isPlural($week, \" week\");\r\n    if($day != 0)\r\n      $time .= \", \" . $day  . isPlural($day, \" day\");\r\n  }\r\n  else if($day != 0)\r\n  {\r\n    $time  = $day  . isPlural($day, \" day\");\r\n    if($hour != 0)\r\n      $time .= \", \" . $hour . isPlural($hour, \" hour\");\r\n  }\r\n  else if($hour != 0)\r\n  {\r\n    $time  = $hour . isPlural($hour, \" hour\");\r\n    if($min != 0)\r\n      $time .= \", \" . $min  . isPlural($min, \" minute\");\r\n  }\r\n  else if($min != 0)\r\n  {\r\n    $time  = $min  . isPlural($min, \" minute\");\r\n    if($sec != 0)\r\n      $time .= \", \" . $sec  . isPlural($sec, \" second\");\r\n  }\r\n  else if($sec != 0)\r\n  {\r\n    $time  = $sec  . isPlural($sec, \" second\");\r\n  }\r\n  \r\n  return $time;\r\n}\r\n\r\n/**\r\n * function isPlural\r\n *\r\n * Return pluralized text.\r\n */\r\nfunction isPlural($num, $word){\r\n  if($num > 1)\r\n    return $word.\"s\";\r\n  else\r\n    return $word;\r\n}\r\n\r\n\r\n$_start = time();\r\n\r\n$fl = fopen($outHTML, \"w+\"); \r\nfputs($fl, $output);\r\nfclose($fl);\r\n\r\n\r\n# Loop and call generate for day/night and each zoom level\r\nforeach($tileSizes as $t) {\r\n\t$z = $zoom[$t];\r\n\t$s = $scale[$t];\r\n\t\r\n\tgenerate(\"\", \"day\", $t, $z, $s);\r\n\tgenerate(\"-n\", \"ngt\", $t, $z, $s);\r\n}\r\n\r\n\r\n# convert the files to the appropriate sizes using GD module\r\n$validExtensions = array(\"png\");\r\n$files = array();\r\nif(is_dir($outDir)) {\r\n\tif($handle = opendir($outDir)) {\r\n\t\twhile(($file = readdir($handle)) !== false) {\r\n\t\t\t## List\r\n\t\t\t$extension = end(explode(\".\", $file));\r\n\t\t\t\r\n\t\t\tif( in_array($extension, $validExtensions) )\r\n\t\t\t\tarray_push($files, $file);\r\n\r\n\t\t}\r\n\t\tclosedir($handle);\r\n\t}\r\n\t\r\n\techo(\"Resizing images\");\r\n\tforeach($files as $file) {\r\n\t\t$zoomLevel = substr($file, -5, 1);\r\n\t\tresizeImage($outDir.$file, $scale[$tileSizes[$zoomLevel]]);\r\n\t}\r\n\techo(\" Done.\\r\\n\");\r\n}\r\nelse {\r\n\techo($outDir.\" is not a valid directory... Somehow. Quitting.\");\r\n\texit();\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n$output = '\r\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n  <head>\r\n    <meta name=\"viewport\" content=\"initial-scale=1.0, user-scalable=no\" />\r\n    <script type=\"text/javascript\" src=\"http://maps.google.com/maps/api/js?sensor=false\"></script>\r\n    <script type=\"text/javascript\">\r\n      function extend(t , o) {\r\n        for (k in o) { if (o[k] != null) { t[k] = o[k]; } }\r\n        return t;\r\n      }\r\n      \r\n      function keys(o) {\r\n        var a = [];\r\n        for (m in modes) { a[a.length] = m; };\r\n        return a;\r\n      }\r\n      \r\n      // The maximum width/height of the grid in regions (must be a power of two)\r\n      var GRID_WIDTH_IN_REGIONS = 4096;\r\n      // Map from a GRID_WIDTH_IN_REGIONS x GRID_WIDTH_IN_REGIONS square to Lat/Long (0, 0),(-90, 90)\r\n      var SCALE_FACTOR = 90.0 / GRID_WIDTH_IN_REGIONS;\r\n      \r\n      // Override the default Mercator projection with Euclidean projection\r\n      // (insert oblig. Flatland reference here)\r\n      function EuclideanProjection() {};\r\n      \r\n      EuclideanProjection.prototype.fromLatLngToPoint = function(latLng, opt_point) {\r\n        var point = opt_point || new google.maps.Point(0, 0);\r\n        point.x = latLng.lng() / SCALE_FACTOR;\r\n        point.y = latLng.lat() / SCALE_FACTOR;\r\n        return point;\r\n      };\r\n      \r\n      EuclideanProjection.prototype.fromPointToLatLng = function(point) {\r\n        var lng = point.x * SCALE_FACTOR;\r\n        var lat = point.y * SCALE_FACTOR;\r\n        return new google.maps.LatLng(lat, lng, true);\r\n      };\r\n      \r\n      function new_map_type(m, o, ob) {\r\n        return extend(\r\n          {\r\n            getTileUrl: function(c, z) {\r\n                return o.host + m + \".\" + c.x + \".\" + c.y + \".\" + z + \".png\";\r\n            },\r\n            isPng: true,\r\n            name : \"none\",\r\n            alt : \"none\",\r\n            minZoom: 0, maxZoom: 5,\r\n            tileSize: new google.maps.Size(256, 256)\r\n          },\r\n          ob\r\n        );\r\n      }\r\n      \r\n      function initialize(id, opt, modes) {\r\n        var element = document.getElementById(id);\r\n        \r\n        opt = extend(opt, {\r\n          mapTypeControlOptions: {\r\n            mapTypeIds: keys(modes),\r\n            style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}});\r\n        \r\n        var map = new google.maps.Map(element, opt);\r\n\r\n        var firstMode = null;\r\n        \r\n        for (m in modes) {\r\n          var imt  = new google.maps.ImageMapType(new_map_type(m, opt, modes[m]));\r\n          imt.projection = new EuclideanProjection();\r\n          \r\n          // Now attach the grid map type to the maps registry\r\n          map.mapTypes.set(m, imt);\r\n          if (firstMode == null) firstMode = m;\r\n        }\r\n        \r\n        map.setMapTypeId(firstMode);\r\n\r\n        var globaldata = modes[firstMode].data;\r\n        \r\n        {\r\n          var world = globaldata.world;\r\n          var center = new google.maps.Point(world[\"cx\"] / 16, world[\"cy\"] / 16);\r\n          var latlng = EuclideanProjection.prototype.fromPointToLatLng(center)\r\n          map.setCenter(latlng);\r\n          map.setZoom(0);\r\n        }\r\n        \r\n        for (var i = 0; i < globaldata.markers.length; i++)\r\n        {\r\n          var m = globaldata.markers[i];\r\n          var point = new google.maps.Point(m.x / 16, m.y / 16);\r\n          var latlng = EuclideanProjection.prototype.fromPointToLatLng(point)\r\n          \r\n          new google.maps.Marker({\r\n              position: latlng, \r\n              map: map, \r\n              title: m.text\r\n          });\r\n        }\r\n        \r\n        if (window.attachEvent) {\r\n          window.attachEvent(\"onresize\", function() {this.map.onResize()} );\r\n        } else {\r\n          window.addEventListener(\"resize\", function() {this.map.onResize()} , false);\r\n        }\r\n      }\r\n    </script>\r\n    \r\n    <!-- Make the document body take up the full screen -->\r\n    <style type=\"text/css\">\r\n        v\\:* {behavior:url(#default#VML);}\r\n        html, body {width: 100%; height: 100%}\r\n        body {margin-top: 0px; margin-right: 0px; margin-left: 0px; margin-bottom: 0px}\r\n    </style>\r\n    \r\n    <script type=\"text/javascript\" src=\"options.js\"></script>\r\n  </head>\r\n  <body onload=\"initialize(\\'map_canvas\\', options, modes)\">\r\n    <div id=\"map_canvas\" style=\"width: 100%; height: 100%;\"></div>\r\n  </body>\r\n</html>';\r\n\r\necho(\"Writing \".$outHTML.\"...\");\r\nif( !write($outHTML, $output) ) {\r\n\techo(\"Error writing \".$outHTML);\r\n\texit();\r\n}\r\necho(\"Done.\\r\\n\");\r\n\r\n\r\n# Googlemap options JS\r\nif( !$jsonDay = read($outDir.\"day.json\") ) {\r\n\techo(\"Error opening day.json\");\r\n\texit();\r\n}\r\n\r\nif( !$jsonNgt = read($outDir.\"ngt.json\") ) {\r\n\techo(\"Error opening ngt.json\");\r\n\texit();\r\n}\r\n\r\n# '.$outDir.'\\ This extra slash below is intended for escaping\r\n$js = 'var options = {\r\n  host: \"'.$outDir.'\\\",\r\n  scaleControl: false,\r\n  navigationControl: true,\r\n  streetViewControl: false,\r\n  noClear: false,\r\n  backgroundColor: \"#000000\",\r\n  isPng: true,\r\n}\r\n\r\nvar modes = {\r\n  \\'day\\': { name: \"Day\", alt: \"Day Mode\", data: '.$jsonDay.'},\r\n  \\'ngt\\': { name: \"Night\", alt: \"Night Mode\", data: '.$jsonNgt.'},\r\n}';\r\n\r\necho(\"Writing options.js...\");\r\nif( !write(\"options.js\", $js) ) {\r\n\techo(\"Error writing options.js\");\r\n\texit();\r\n}\r\necho(\"Done.\\r\\n\");\r\n\r\n$_end = time();\r\n\r\necho(\"Complete in \".getTimeStr($_end - $_start) );\r\n\r\n?>\r\n"
  },
  {
    "path": "scripts/google-api/google-api.ps1",
    "content": "$CONVERT=\"convert\"\n$C10T=\"c10t.exe\"\n$C10T_OPTS=\"\"\n$C10T_OUT=\"c10t.out.txt\"\n\n$TILE_SIZES=\"4096\", \"2048\", \"1024\", \"512\", \"256\", \"128\"\n$SCALE = @{\"4096\"=\"6.25%\"; \"2048\"=\"12.5%\"; \"1024\"=\"25%\"; \"512\"=\"50%\"; \"256\"=\"100%\"; \"128\"=\"200%\"}\n$ZOOM  = @{\"4096\"=\"0\"; \"2048\"=\"1\"; \"1024\"=\"2\"; \"512\"=\"3\"; \"256\"=\"4\"; \"128\"=\"5\"}\n\n\n$FACTOR=16\n\n$current= [IO.Directory]::GetCurrentDirectory()\n$world=$args[0]\n$target=$args[1]\n$tiles=\"tiles\"\n$hostn=\"\"\n\n$C10T_OPTS=\"$C10T_OPTS -w $world\"\n\nif ( !($world) -or !(test-path $world -pathtype container) )\n{\n  write-host \"Directory does not exist: $world\";\n  return 1\n}\nif ((!($C10T -match \".exe$\")) -or (!(test-path $C10T -pathtype leaf)) )\n{\n  write-host \"Not an executable: $C10T\"\n  return 1\n}\n\nif(!(test-path $target -pathtype container)){new-item -type directory -path $target}\nif(!(test-path \"$target\\$tiles\" -pathtype container)){new-item -type directory -path \"$target\\$tiles\"}\n\nset-content -Path $target/index.html -Value @\"\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n  <head>\n    <meta name=\"viewport\" content=\"initial-scale=1.0, user-scalable=no\" />\n    <script type=\"text/javascript\" src=\"http://maps.google.com/maps/api/js?sensor=false\"></script>\n    <script type=\"text/javascript\">\n      function extend(t , o) {\n        for (k in o) { if (o[k] != null) { t[k] = o[k]; } }\n        return t;\n      }\n      \n      function keys(o) {\n        var a = [];\n        for (m in modes) { a[a.length] = m; };\n        return a;\n      }\n      \n      // The maximum width/height of the grid in regions (must be a power of two)\n      var GRID_WIDTH_IN_REGIONS = 4096;\n      // Map from a GRID_WIDTH_IN_REGIONS x GRID_WIDTH_IN_REGIONS square to Lat/Long (0, 0),(-90, 90)\n      var SCALE_FACTOR = 90.0 / GRID_WIDTH_IN_REGIONS;\n      \n      // Override the default Mercator projection with Euclidean projection\n      // (insert oblig. Flatland reference here)\n      function EuclideanProjection() {};\n      \n      EuclideanProjection.prototype.fromLatLngToPoint = function(latLng, opt_point) {\n        var point = opt_point || new google.maps.Point(0, 0);\n        point.x = latLng.lng() / SCALE_FACTOR;\n        point.y = latLng.lat() / SCALE_FACTOR;\n        return point;\n      };\n      \n      EuclideanProjection.prototype.fromPointToLatLng = function(point) {\n        var lng = point.x * SCALE_FACTOR;\n        var lat = point.y * SCALE_FACTOR;\n        return new google.maps.LatLng(lat, lng, true);\n      };\n      \n      function new_map_type(m, o, ob) {\n        return extend(\n          {\n            getTileUrl: function(c, z) {\n                return o.host + m + \".\" + c.x + \".\" + c.y + \".\" + z + \".png\";\n            },\n            isPng: true,\n            name : \"none\",\n            alt : \"none\",\n            minZoom: 0, maxZoom: 5,\n            tileSize: new google.maps.Size(256, 256)\n          },\n          ob\n        );\n      }\n      \n      function initialize(id, opt, modes) {\n        var element = document.getElementById(id);\n        \n        opt = extend(opt, {\n          mapTypeControlOptions: {\n            mapTypeIds: keys(modes),\n            style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}});\n        \n        var map = new google.maps.Map(element, opt);\n\n        var firstMode = null;\n        \n        for (m in modes) {\n          var imt  = new google.maps.ImageMapType(new_map_type(m, opt, modes[m]));\n          imt.projection = new EuclideanProjection();\n          \n          // Now attach the grid map type to the map's registry\n          map.mapTypes.set(m, imt);\n          if (firstMode == null) firstMode = m;\n        }\n        \n        map.setMapTypeId(firstMode);\n\n        var globaldata = modes[firstMode].data;\n        \n        {\n          var world = globaldata.world;\n          var center = new google.maps.Point(world[\"cx\"] / $FACTOR, world[\"cy\"] / $FACTOR);\n          var latlng = EuclideanProjection.prototype.fromPointToLatLng(center)\n          map.setCenter(latlng);\n          map.setZoom(0);\n        }\n        \n        for (var i = 0; i < globaldata.markers.length; i++)\n        {\n          var m = globaldata.markers[i];\n          var point = new google.maps.Point(m.x / $FACTOR, m.y / $FACTOR);\n          var latlng = EuclideanProjection.prototype.fromPointToLatLng(point)\n          \n          new google.maps.Marker({\n              position: latlng, \n              map: map, \n              title: m.text\n          });\n        }\n        \n        if (window.attachEvent) {\n          window.attachEvent(\"onresize\", function() {this.map.onResize()} );\n        } else {\n          window.addEventListener(\"resize\", function() {this.map.onResize()} , false);\n        }\n      }\n    </script>\n    \n    <!-- Make the document body take up the full screen -->\n    <style type=\"text/css\">\n        v\\:* {behavior:url(#default#VML);}\n        html, body {width: 100%; height: 100%}\n        body {margin-top: 0px; margin-right: 0px; margin-left: 0px; margin-bottom: 0px}\n    </style>\n    \n    <script type=\"text/javascript\" src=\"options.js\"></script>\n  </head>\n  <body onload=\"initialize('map_canvas', options, modes)\">\n    <div id=\"map_canvas\" style=\"width: 100%; height: 100%;\"></div>\n  </body>\n</html>\n\"@\nwrite-host \"NOTE: if something goes wrong, check out $C10T_OUT\"\n\nwrite-host \"\" > $C10T_OUT\nfunction generate \n{\n    Param ($x_opts, $name, $pixelsplit, $zoom, $scale)\n    \n    # generate a set of split files\n    $src=\"$target\\$tiles\\$name.`%d.`%d.$zoom.png\"\n    write-host \"$C10T $C10T_OPTS $x_opts --pixelsplit=$pixelsplit -o $src --write-json=$target\\$name.json\"\n    \n    \"$C10T $C10T_OPTS $x_opts --pixelsplit=$pixelsplit -o $src --write-json=`\"$target\\$name.json`\" \"\n    invoke-expression \"$C10T $C10T_OPTS $x_opts --pixelsplit=$pixelsplit -o $src --write-json=`\"$target\\$name.json`\" \"\n    \n    # convert the files to the appropriate sizes\n     \n    foreach ($file in Get-ChildItem \"$target\\$tiles\\$name.*.*.$zoom.png\")\n    {\n        $tg=$file.FullName\n        write-host \"$CONVERT $file -scale $scale $tg\"\n        invoke-expression \"$CONVERT $file -scale $scale $file\"\n    }    \n      \n    write-host \"done!\"\n    Get-ChildItem \"$target\\$tiles\\$name.*.*.$zoom.png\"\n}\n\necho 1\nforeach ($t in $TILE_SIZES)\n{\n    $z=$ZOOM.Get_Item(\"$t\")\n    $s=$SCALE.Get_Item(\"$t\")\n      \n    generate -x_opts \" \" -name \"day\" -pixelsplit $t -zoom $z -scale $s\n    generate -x_opts \"-n\" -name \"night\" -pixelsplit $t -zoom $z -scale $s\n}    \n\nset-content $target\\options.js @\"\nvar options = {\n  host: \"$hostn$tiles/\",\n  scaleControl: false,\n  navigationControl: true,\n  streetViewControl: false,\n  noClear: false,\n  backgroundColor: \"#000000\",\n  isPng: true,\n}\n\nvar modes = {\n  'day': { name: \"Day\", alt: \"Day Mode\", data: $(cat $target/day.json)},\n  'night': { name: \"Night\", alt: \"Night Mode\", data: $(cat $target/night.json)},\n}\n\"@"
  },
  {
    "path": "scripts/google-api/google-api.sh",
    "content": "#!/bin/bash\n\nC10T=c10t\n[[ -x ./$C10T ]] && C10T=./$C10T\n\nscriptdir=$(dirname $(readlink -f $0))\n\nworld=\"\"\noutput=\"\"\nhost=\"\"\nzoom=5\nfactor=4\nbase=256\nres=$scriptdir\nopts=\"\"\n\nexit_usage() {\n  echo \"Usage: google-api -w <world> -o <output> [options]\"\n  echo \"-H <host>     - Host prefix to use for all scripts\"\n  echo \"-z <levels>   - Number of zoom levels to generate (default: 5)\"\n  echo \"-b <res>      - Resolution for the base tile (default: 256px)\"\n  echo \"-r <dir>      - Directory to look for reasources (defaults to script directory)\"\n  echo \"-O <opts>     - Extra options to pass directly to c10t\"\n  exit 1\n}\n\nwhile getopts \"w:o:H:z:b:O:h\" opt; do\n  case $opt in\n    w) world=$OPTARG ;;\n    o) output=$OPTARG ;;\n    H) host=$OPTARG ;;\n    O) opts=$OPTARG ;;\n    h) exit_usage ;;\n    z)\n      zoom=$OPTARG\n      factor=$[$zoom - 1]\n      ;;\n    b) base=$OPTARG ;;\n    \\?) exit 1 ;;\n  esac\ndone\n\nshift $OPTIND\n\n[ -z $world ] && exit_usage\n[ -z $output ] && exit_usage\n\n[ ! -d $world ] && {\n  echo \"$0: -w: directory does not exist: $world\";\n  exit_usage\n}\n\n[ ! -d $output ] && {\n  echo \"$0: -o: directory does not exist: $output\";\n  exit_usage\n}\n\n[ $zoom -lt 2 ] && {\n  echo \"$0: -z: must be a numberic value greater than 2, but was '$zoom'\";\n  exit_usage\n}\n\n[ $base -lt 32 ] && {\n  echo \"$0: -b: must be a numberic value greater than 32, but was '$base'\";\n  exit_usage\n}\n\nif ! $C10T -h &> /dev/null; then\n  echo \"Could not find executable: $C10T\"\n  exit_usage\nfi\n\ngoogle_js=$res/libc10t.google.js\nindex_html=$res/index.html\n\n[ ! -f $google_js ] && {\n  echo \"could not find: $google_js\"\n  exit 1;\n}\n\n[ ! -f $index_html ] && {\n  echo \"could not find: $index_html\"\n  exit 1;\n}\n\nhost_google_js=\"${host}$(basename $google_js)\"\nhost_options_js=\"${host}options.js\"\n\ncreate_tile_sizes() {\n  b=$base\n  i=$[$zoom - 1]\n\n  echo -n $[$b / 2]\n\n  while [[ $i -gt 0 ]]; do\n    echo -n \" $b\"\n    b=$[$b*2]\n    i=$[$i - 1]\n  done\n}\n\nsplits=$(create_tile_sizes)\n# this is what each tile will be resized to\n\ntiles=$output/tiles\nc10t_opts=\"$opts -w $world\"\n\nif [[ -z $world ]] || [[ ! -d $world ]]; then\n  echo \"Directory does not exist: $world\";\n  exit 1;\nfi\n\n[ ! -d $target ] && mkdir -p $target\n[ ! -d $tiles ] && mkdir -p $tiles\n\ngenerate() {\n  x_opts=$1\n  name=$2\n  pixelsplit=\"$3\"\n\n  # generate a set of split files\n  tile=$tiles/$name.%d.%d.%d.png\n\n  echo \"$C10T $c10t_opts $x_opts --split=\\\"$pixelsplit\\\" --split-base=$base -o $tile --write-json=$output/$name.json\"\n  if ! $C10T $c10t_opts $x_opts --split=\"$pixelsplit\" --split-base=$base -o $tile --write-json=\"$output/$name.json\"; then\n    exit 1\n  fi\n\n  echo \"done!\"\n}\n\necho \"Copying $index_html\"\ncat $index_html | \\\n  sed -r \"s/\\bC10T_GOOGLE_JS\\b/$host_google_js/\" | \\\n  sed \"s/\\bC10T_OPTIONS_JS\\b/$host_options_js/\" > $output/index.html\n\necho \"Copying $google_js\"\ncp $google_js $output\n\ngenerate \"\" \"day\" \"$splits\"\ngenerate \"-n\" \"night\" \"$splits\"\n\ncat > $output/options.js << ENDL\nvar options = {\n  factor: $factor,\n  host: \"${host}tiles/\",\n  scaleControl: false,\n  navigationControl: true,\n  streetViewControl: false,\n  noClear: false,\n  backgroundColor: \"#000000\",\n  isPng: true,\n}\n\nvar modes = {\n  'day': { name: \"Day\", alt: \"Day Mode\", data: $(cat $output/day.json)},\n  'night': { name: \"Night\", alt: \"Night Mode\", data: $(cat $output/night.json)},\n}\nENDL\n"
  },
  {
    "path": "scripts/google-api/index.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n  <head>\n    <meta name=\"viewport\" content=\"initial-scale=1.0, user-scalable=no\" />\n    <script type=\"text/javascript\" src=\"http://maps.google.com/maps/api/js?sensor=false\"></script>\n    <script type=\"text/javascript\" src=\"C10T_GOOGLE_JS\"></script>\n    <script type=\"text/javascript\" src=\"C10T_OPTIONS_JS\"></script>\n    \n    <!-- Make the document body take up the full screen -->\n    <style type=\"text/css\">\n        v\\:* {behavior:url(#default#VML);}\n        html, body {width: 100%; height: 100%}\n        body {margin-top: 0px; margin-right: 0px; margin-left: 0px; margin-bottom: 0px}\n    </style>\n  </head>\n  <body onload=\"initialize('map_canvas', options, modes)\">\n    <div id=\"map_canvas\" style=\"width: 100%; height: 100%;\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "scripts/google-api/libc10t.google.js",
    "content": "function extend(t , o) {\n  for (k in o) { if (o[k] != null) { t[k] = o[k]; } }\n  return t;\n}\n\nfunction keys(o) {\n  var a = [];\n  for (m in modes) { a[a.length] = m; };\n  return a;\n}\n\n// Direct Link Feature\nvar _globalDefaults = {\n  lat : 0,\n  lng : 0,\n  zoom : 1,\n  type : \"day\",\n}\n\nfunction get_parameters() {\n  var lat = _globalDefaults.lat;\n  var lng = _globalDefaults.lng;\n  var zoom = _globalDefaults.zoom;\n  var type = _globalDefaults.type;\n\n  var query = location.search.substring(1);\n\n  var pairs = query.split(\"&\");\n  for (var i=0; i<pairs.length; i++) {\n    var pos = pairs[i].indexOf(\"=\");\n    var argname = pairs[i].substring(0,pos).toLowerCase();\n    var value = pairs[i].substring(pos+1).toLowerCase();\n\n    if (argname == \"lat\") {lat = parseFloat(value);}\n    if (argname == \"lng\") {lng = parseFloat(value);}\n    if (argname == \"zoom\") {zoom = parseInt(value);}\n    if (argname == \"type\") {type = value;}\n  }\n\n  return {\n    lat: lat,\n    lng: lng,\n    zoom: zoom,\n    type: type,\n  };\n}\n\nfunction retrieveLink(map) {\n\n  var latlng = EuclideanProjection.prototype.fromPointToLatLng(_globalCenter);\n  \n  var lat = map.getCenter().lat() - latlng.lat();\n  var lng = map.getCenter().lng() - latlng.lng();\n\n  var pos = window.location.href.indexOf(\"?\");\n  var base = pos > -1 ? window.location.href.substring(0,pos) : window.location.href;\n  var ret = base\n    + \"?lat=\" + lat.toFixed(6)\n    + \"&lng=\" + lng.toFixed(6);\n  if (map.getZoom() != _globalDefaults.zoom)\n    ret += \"&zoom=\" + map.getZoom();\n  if (map.getMapTypeId() != _globalDefaults.type)\n    ret += \"&type=\" + map.getMapTypeId();\n    \n  return ret;\n}\n\nfunction refreshLink(map, control) {\n  var link = retrieveLink(map);\n  \n  if (!(control.innerHTML.replace(/&amp;/gi,\"&\") == link)) {\n    control.innerHTML = link;\n  }\n}\n\nfunction createLinkControl(map) {\n  \n  var controlDiv = document.createElement('DIV');\n  controlDiv.style.padding = '5px';\n\n  var controlUI = document.createElement('DIV');\n  controlUI.style.backgroundColor = 'white';\n  controlUI.style.borderStyle = 'solid';\n  controlUI.style.borderWidth = '1px';\n  controlUI.style.textAlign = 'center';\n  controlUI.title = 'The link to the current position';\n  controlDiv.appendChild(controlUI);\n\n  var controlText = document.createElement('DIV');\n  controlText.name = \"linkControl\";\n  controlText.style.fontFamily = 'Arial,sans-serif';\n  controlText.style.fontSize = '12px';\n  controlText.style.paddingLeft = '4px';\n  controlText.style.paddingRight = '4px';\n  controlUI.appendChild(controlText);\n  \n  if (controlDiv.attachEvent) {\n    controlDiv.attachEvent(\"onclick\", function() {window.location.href = retrieveLink(map)});\n  } else {\n    controlDiv.addEventListener(\"click\", function() {window.location.href = retrieveLink(map)} , false);\n  }\n  \n  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(controlDiv);\n  \n  refreshLink(map, controlText);\n  \n  return controlText;\n}\n\n// The maximum width/height of the grid in regions (must be a power of two)\nvar GRID_WIDTH_IN_REGIONS = 4096;\n// Map from a GRID_WIDTH_IN_REGIONS x GRID_WIDTH_IN_REGIONS square to Lat/Long (0, 0),(-90, 90)\nvar SCALE_FACTOR = 90.0 / GRID_WIDTH_IN_REGIONS;\n\n// Override the default Mercator projection with Euclidean projection\n// (insert oblig. Flatland reference here)\nfunction EuclideanProjection() {};\n\nEuclideanProjection.prototype.fromLatLngToPoint = function(latLng, opt_point) {\n  var point = opt_point || new google.maps.Point(0, 0);\n  point.x = latLng.lng() / SCALE_FACTOR;\n  point.y = latLng.lat() / SCALE_FACTOR;\n  return point;\n};\n\nEuclideanProjection.prototype.fromPointToLatLng = function(point) {\n  var lng = point.x * SCALE_FACTOR;\n  var lat = point.y * SCALE_FACTOR;\n  return new google.maps.LatLng(lat, lng, true);\n};\n\nfunction new_map_type(m, o, ob) {\n  var world = ob.data.world;\n\n  return extend(\n    {\n      getTileUrl: function(c, z) {\n        var img = o.host + m + \".\" + (world.split - z) + \".\" + c.x + \".\" + c.y + \".png\";\n        return img\n      },\n      isPng: true,\n      name : \"none\",\n      alt : \"none\",\n      minZoom: 1, maxZoom: world.split,\n      tileSize: new google.maps.Size(world.split_base, world.split_base)\n    },\n    ob\n  );\n}\n\nfunction initialize(id, opt, modes) {\n  var element = document.getElementById(id);\n  \n  opt = extend(opt, {\n    mapTypeControlOptions: {\n      mapTypeIds: keys(modes),\n      style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}});\n  \n  var map = new google.maps.Map(element, opt);\n\n  var firstMode = null;\n  \n  for (m in modes) {\n    var imt  = new google.maps.ImageMapType(new_map_type(m, opt, modes[m]));\n    imt.projection = new EuclideanProjection();\n    \n    // Now attach the grid map type to the map's registry\n    map.mapTypes.set(m, imt);\n    if (firstMode == null) firstMode = m;\n  }\n  \n  map.setMapTypeId(firstMode);\n\n  var globaldata = modes[firstMode].data;\n\n  var world = globaldata.world;\n  var factor = Math.pow(2, opt.factor);\n  \n  {\n    var parameters = get_parameters();\n    var latlng;\n    _globalCenter = new google.maps.Point(world.cx / factor, world.cy / factor);\n    latlng = EuclideanProjection.prototype.fromPointToLatLng(_globalCenter)\n    parameters.lat += latlng.lat();\n    parameters.lng += latlng.lng();\n\t  latlng = new google.maps.LatLng(parameters.lat, parameters.lng, true);\n    map.setZoom(parameters.zoom);\n    map.setMapTypeId(parameters.type);\n\n    map.setCenter(latlng);\n  }\n  \n  for (var i = 0; i < globaldata.markers.length; i++)\n  {\n    var m = globaldata.markers[i];\n    var point = new google.maps.Point(m.x / factor, m.y / factor);\n    var latlng = EuclideanProjection.prototype.fromPointToLatLng(point)\n    \n    new google.maps.Marker({\n        position: latlng, \n        map: map, \n        title: m.text\n    });\n  }\n  \n  var linkControl = createLinkControl(map);\n  \n  if (window.attachEvent) {\n    window.attachEvent(\"onresize\", function() {this.map.onResize()} );\n    window.attachEvent(\"onmousemove\", function() {refreshLink(map, linkControl)} );\n  } else {\n    window.addEventListener(\"resize\", function() {this.map.onResize()} , false);\n    window.addEventListener(\"mousemove\", function() {refreshLink(map, linkControl)} , false);\n  }\n}\n"
  },
  {
    "path": "src/2d/cube.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef _CUBE_H_\n#define _CUBE_H_\n\n#include <stdlib.h>\n#include <stdint.h>\n\nstruct point {\n  typedef uint64_t pos_t;\n  \n  pos_t x;\n  pos_t y;\n  pos_t z;\n\n  inline point(pos_t x, pos_t y, pos_t z) : x(x), y(y), z(z) {}\n};\n\nclass point2 {\npublic:\n  typedef uint64_t pos_t;\n  \n  const pos_t x;\n  const pos_t y;\n\n  point2(const pos_t x, const pos_t y) : x(x), y(y) {}\n  \n  bool operator<(const point2& oth) const {\n    if (y < oth.y) {\n      return true;\n    }\n    \n    if (y == oth.y && x < oth.x) {\n      return true;\n    }\n    \n    return false;\n  }\n};\n\nclass top_cube {\npublic:\n  typedef uint64_t pos_t;\n  \n  top_cube(const pos_t x, const pos_t y, const pos_t z) : x(x), y(y), z(z) {}\n  \n  inline void project(point &p, pos_t &rx, pos_t &ry) const\n  {\n    rx = z - p.z - 1;\n    ry = p.x;\n  }\n\n  inline void limits(pos_t &rx, pos_t &ry) const\n  {\n    rx = z;\n    ry = x;\n  }\nprivate:\n  const pos_t x;\n  const pos_t y;\n  const pos_t z;\n};\n\nclass oblique_cube {\npublic:\n  typedef uint64_t pos_t;\n\n  oblique_cube(const pos_t x, const pos_t y, const pos_t z) : x(x), y(y), z(z) {}\n\n  inline void project(point &p, pos_t &rx, pos_t &ry) const\n  {\n    rx = z - p.z - 1;\n    ry = p.x + (y - p.y - 1);\n  }\n\n  inline void limits(pos_t &rx, pos_t &ry) const\n  {\n    rx = z;\n    ry = x + y;\n  }\nprivate:\n  const pos_t x;\n  const pos_t y;\n  const pos_t z;\n};\n\ntemplate<int F1 = 1, int F2 = 1, int F3 = 1>\nclass angle_cube {\npublic:\n  typedef uint64_t pos_t;\n\n  angle_cube(const pos_t x, const pos_t y, const pos_t z) : x(x), y(y), z(z) {}\n  \n  inline void project(point &p, pos_t &rx, pos_t &ry) const\n  {\n    rx = F1 * ((z - p.z - 1) + p.x);\n    ry = F2 * (y - p.y - 1) + F3 * p.z + F3 * p.x;\n  }\n\n  inline void limits(pos_t &rx, pos_t &ry) const\n  {\n    rx = F1 * (z + x);\n    ry = F2 * y + F3 * z + F3 * x;\n  }\nprivate:\n  const pos_t x;\n  const pos_t y;\n  const pos_t z;\n};\n\n#endif /* _CUBE_H_ */\n"
  },
  {
    "path": "src/algorithm.cpp",
    "content": "#include <string>\n#include <vector>\n#include <sstream>\n\nnamespace nonstd {\n  // hackish split\n}\n"
  },
  {
    "path": "src/algorithm.hpp",
    "content": "#ifndef NONSTD_ALGORITHM\n#define NONSTD_ALGORITHM\n\n#include <stdlib.h>\n#include <ostream>\n\nnamespace nonstd\n{\n  template<typename T>\n  class reporting\n  {\n    public:\n      virtual void add(T) = 0;\n      virtual void done(T) = 0;\n  };\n\n  template<typename T, typename O = std::ostream>\n  class continious : public reporting<T>\n  {\n    public:\n      const static uintmax_t LINE_WIDTH = 30;\n\n      typedef void (*progress_func)(O&, T);\n      typedef void (*endline_func)(O&, T);\n\n      continious(O& out,\n                 T progress_threshold,\n                 progress_func progress_f,\n                 endline_func endline_f)\n      : out(out),\n        chunks(0),\n        total(0),\n        progress_threshold(progress_threshold),\n        line(0), \n        progress_f(progress_f),\n        endline_f(endline_f)\n      {\n      }\n      \n      virtual void add(T parts)\n      {\n        chunks += parts;\n        \n        while (chunks > progress_threshold)\n        {\n          chunks -= progress_threshold;\n          total += progress_threshold;\n          \n          progress_f(out, total);\n          \n          if (!(line++ < LINE_WIDTH)) {\n            endline_f(out, total);\n            line = 0;\n          }\n        }\n      }\n      \n      void done(T last_part)\n      {\n        total += chunks + last_part;\n        endline_f(out, total);\n      }\n    private:\n      O& out;\n      T chunks;\n      T total;\n      T progress_threshold;\n      \n      unsigned int line;\n      \n      progress_func progress_f;\n      endline_func endline_f;\n  };\n  \n  template<typename T, typename O = std::ostream>\n  class limited : public reporting<T>\n  {\n    public:\n      const static uintmax_t LINE_WIDTH = 30;\n\n      typedef void (*progress_func)(O&, T);\n      typedef void (*endline_func)(O&, T, T);\n\n      limited(O& out,\n              T progress_threshold,\n              T total_limit,\n              progress_func progress_f,\n              endline_func endline_f)\n      : out(out),\n        chunks(0),\n        total(0),\n        progress_threshold(progress_threshold),\n        line(0), \n        progress_f(progress_f),\n        endline_f(endline_f),\n        total_limit(total_limit)\n      {\n      }\n      \n      virtual void add(T parts)\n      {\n        chunks += parts;\n        \n        while (chunks > progress_threshold)\n        {\n          chunks -= progress_threshold;\n          total += progress_threshold;\n          \n          progress_f(out, total);\n          \n          if (line++ >= LINE_WIDTH)\n          {\n            endline_f(out, total, total_limit);\n            line = 0;\n          }\n        }\n      }\n      \n      void done(T last)\n      {\n        total += last;\n        endline_f(out, total_limit, total_limit);\n      }\n    private:\n      O& out;\n\n      T chunks;\n      T total;\n      T progress_threshold;\n      \n      unsigned int line;\n      \n      progress_func progress_f;\n      endline_func endline_f;\n\n      T total_limit;\n  };\n}\n\n#endif /* NONSTD_ALGORITHM */\n"
  },
  {
    "path": "src/altitude_graph.cpp",
    "content": "#include \"altitude_graph.hpp\"\n#include \"text.hpp\"\n\nusing namespace std;\nnamespace fs = boost::filesystem;\n\n#define BORDER_X 50\n#define BORDER_Y 50\n\nAltitudeGraph::AltitudeGraph(settings_t& _s)\n    :  s(_s), width(800), height(600)\n{\n    altitudeRegistry.reset(new long[mc::MapY]);\n    for(int i = 0; i < mc::MapY; i++)\n    {\n         altitudeRegistry[i] = 0;\n    }\n}\n\nvoid AltitudeGraph::createGraph()\n{\n    image_ptr graphImg;\n\n    memory_image* image = new memory_image(width, height);\n\n    graphImg.reset(image);\n\n    color bgcolor(255, 255, 255, 255);\n    color fgcolor(150,0,0,255);\n    color axiscolor(0,0,0,255);\n    color seacolor(0,0,255,255);\n\n    text::font_face ffsea(s.ttf_path, 8, seacolor);\n    ffsea.init();\n    text::font_face ff12(s.ttf_path, 12, axiscolor);\n    ff12.init();\n\n    // fill background\n    graphImg->fill(bgcolor);\n\n    int _w = width - BORDER_X;\n    int _h = height - BORDER_Y;\n\n    long maxVal = this->getMax();\n\n    int x_step = _w / mc::MapY;\n\n    std::stringstream maxss;\n    maxss << \"MAX = \" << maxVal;\n    ff12.draw(graphImg, \"NB of blocks\", BORDER_X - 30 , BORDER_Y - 25);\n    ff12.draw(graphImg, maxss.str(), BORDER_X - 20 , BORDER_Y - 10);\n\n    ff12.draw(graphImg, \"Altitude\", _w - 2*BORDER_X , _h + 17);\n\n    int x=0, y=0, x0=BORDER_X, y0=_h;\n\n    for(int i = 0; i < mc::MapY; i++)\n    {\n       x =  BORDER_X + x_step*i;\n       if (maxVal == 0) {\n           y = _h;\n       } else {\n           y = _h - (int)( ( (float)altitudeRegistry[i] / (float)maxVal ) * (_h-BORDER_Y) );\n       }\n       graphImg->draw_line(x, y, x0, y0, fgcolor);\n       x0 = x;\n       y0 = y;\n    }\n\n    // draw axis\n    graphImg->draw_line(BORDER_X, BORDER_Y, BORDER_X, _h, axiscolor);\n    graphImg->draw_line(BORDER_X, _h, _w, _h, axiscolor);\n\n    // draw axis labels\n    for(int i=0; i < mc::MapY; i++)\n    {\n        color _axiscolor = axiscolor;\n        x =  BORDER_X + x_step*i;\n        int size = 2;\n        if(i == 63)\n        {\n            _axiscolor = seacolor;\n            ffsea.draw(graphImg, \"Sea\", x+4, _h+25);\n            size = 25;\n        }\n        if(i%10 == 0)\n        {\n            size = 5;\n        }\n        graphImg->draw_line(x, _h, x, _h+size, _axiscolor);\n    }\n\n    png_format::opt_type opts;\n    graphImg->save<png_format>(s.statistics_path.string() + \"_graph.png\", opts);\n}\n\nvoid AltitudeGraph::registerBloc(mc::MaterialT *material, int altitude)\n{\n    altitudeRegistry[altitude] += 1;\n}\n\nlong AltitudeGraph::getMax()\n{\n    long max = 0;\n    for(int i = 0; i < mc::MapY; i++)\n    {\n        if(max < altitudeRegistry[i])\n            max = altitudeRegistry[i];\n    }\n    return max;\n}\n"
  },
  {
    "path": "src/altitude_graph.hpp",
    "content": "#ifndef STATISTICS_HPP\n#define STATISTICS_HPP\n\n// Include this first, to evade setjmp header bug\n#include \"image/format/png.hpp\"\n\n#include <string>\n#include <vector>\n#include <set>\n#include <exception>\n\n#include <boost/scoped_array.hpp>\n\n#include \"settings_t.hpp\"\n\n#include \"players.hpp\"\n\n#include \"image/image_base.hpp\"\n#include \"image/memory_image.hpp\"\n#include \"image/cached_image.hpp\"\n#include \"image/algorithms.hpp\"\n#include \"image/format/png.hpp\"\n\n#include \"mc/world.hpp\"\n#include \"mc/blocks.hpp\"\n#include \"mc/utils.hpp\"\n\n#include \"nbt/nbt.hpp\"\n\nclass AltitudeGraph\n{\npublic:\n    AltitudeGraph(settings_t& _s);\n    void createGraph();\n\n    /* call this to register block information */\n    void registerBloc(mc::MaterialT *material, int altitude);\n\n    long getMax();\nprivate:\n    settings_t s;\n    int width;\n    int height;\n    boost::scoped_array<long> altitudeRegistry;\n\n};\n\n#endif // STATISTICS_HPP\n"
  },
  {
    "path": "src/cache.hpp",
    "content": "#ifndef _CACHE_H_\n#define _CACHE_H_\n\n#include <fstream>\n#include <ctime>\n#include <boost/filesystem.hpp>\n#include <zlib.h>\n\n#include \"image/image_operations.hpp\"\n\nnamespace fs = boost::filesystem;\n\n#define CACHE_MAGIC \"CMap\"\n\nstruct cache_hdr {\n  bool compressed;\n  std::time_t mod;\n  size_t max_x, max_y;\n  size_t size;\n};\n\nclass cache_file {\nprivate:\n  const fs::path cache_dir;\n  const uint32_t source_write_time;\n  const bool cache_compress;\n  \n  const fs::path cache_path;\n  \n  typedef std::vector<image_operation>::size_type v_size_type;\n  \npublic:\n  cache_file(const fs::path cache_dir, std::string basename, const uint32_t source_write_time, bool cache_compress)\n    : cache_dir(cache_dir), source_write_time(source_write_time), \n      cache_compress(cache_compress),\n      cache_path(cache_dir / basename)\n  {\n  }\n  \n  bool create_directories() {\n    return fs::create_directories(cache_dir);\n  }\n  \n  bool exists() {\n    return fs::is_regular_file(cache_path)\n      && fs::last_write_time(cache_path) >= source_write_time;\n  }\n\n  void clear() {\n    fs::remove(cache_path);\n  }\n  \n  bool gzreadall(gzFile gzf, char* buf, unsigned int len) {\n    unsigned int read = 0;\n    while (read < len) {\n      int have = gzread(gzf, buf + read, len - read);\n\n      if (have == 0) {\n        int errnum;\n        const char* errorstr = gzerror(gzf, &errnum);\n        \n        if (errnum != 0) {\n          std::cerr << errorstr << std::endl;\n          gzclose(gzf);\n          return false;\n        }\n        \n        if (gzeof(gzf)) {\n          gzclose(gzf);\n          return false;\n        }\n      }\n      \n      if (have < 0) {\n        gzclose(gzf);\n        return false;\n      }\n      \n      read += have;\n    }\n    return true;\n  }\n  \n  bool gzwriteall(gzFile gzf, const char* buf, unsigned int len) {\n    unsigned int written = 0;\n    while (written < len) {\n      int have = gzwrite(gzf, buf + written, len - written);\n      \n      if (have <= 0) {\n        int errnum;\n        const char* errorstr = gzerror(gzf, &errnum);\n        \n        if (errnum != 0) {\n          std::cerr << errorstr << std::endl;\n          gzclose(gzf);\n          return false;\n        }\n        \n        gzclose(gzf);\n        return false;\n      }\n      \n      written += have;\n    }\n    return true;\n  }\n  \n  bool read(boost::shared_ptr<image_operations> oper) {\n    gzFile gzf = gzopen(cache_path.string().c_str(), \"r\");\n\n    if (gzf == Z_NULL) {\n      return false;\n    }\n\n    //std::ifstream fs(cache_path.string().c_str());\n    \n    cache_hdr hdr;\n    \n    {\n      char m[4];\n      //fs.read(m, 4);\n      //if (fs.fail()) return false;\n      \n      if (!gzreadall(gzf, m, 4)) {\n        return false;\n      }\n      \n      if (\n            m[0] != CACHE_MAGIC[0]\n        ||  m[1] != CACHE_MAGIC[1]\n        ||  m[2] != CACHE_MAGIC[2]\n        ||  m[3] != CACHE_MAGIC[3]\n        ) return false;\n      \n      //fs.read(reinterpret_cast<char*>(&hdr), sizeof(cache_hdr));\n      //if (fs.fail()) return false;\n      \n      if (!gzreadall(gzf, reinterpret_cast<char*>(&hdr), sizeof(cache_hdr))) {\n        return false;\n      }\n    }\n      \n    if (hdr.compressed != cache_compress) return false;\n    if (hdr.mod != source_write_time) return false;\n    \n    oper->max_x = hdr.max_x;\n    oper->max_y = hdr.max_y;\n    oper->operations.resize(hdr.size);\n    \n    //fs.read(reinterpret_cast<char*>(&(oper->operations.front())), sizeof(image_operation) * hdr.size);\n    //if (fs.fail()) return false;\n    \n    if (!gzreadall(gzf, reinterpret_cast<char*>(&(oper->operations.front())), sizeof(image_operation) * hdr.size)) {\n      return false;\n    }\n    \n    gzclose(gzf);\n    return true;\n  }\n  \n  bool write(boost::shared_ptr<image_operations> oper) {\n    //std::ofstream fs(cache_path.string().c_str());\n    gzFile gzf = gzopen(cache_path.string().c_str(), \"w\");\n    \n    if (gzf == Z_NULL) {\n      return false;\n    }\n    \n    cache_hdr hdr;\n    \n    {\n      //fs.write(CACHE_MAGIC, 4);\n      //if (fs.fail()) return false;\n      if (!gzwriteall(gzf, CACHE_MAGIC, 4)) {\n        return false;\n      }\n      \n      hdr.compressed = cache_compress;\n      hdr.max_x = oper->max_x;\n      hdr.max_y = oper->max_y;\n      hdr.mod = source_write_time;\n      hdr.size = oper->operations.size();\n      \n      //fs.write(reinterpret_cast<char*>(&hdr), sizeof(cache_hdr));\n      //if (fs.fail()) return false;\n      if (!gzwriteall(gzf, reinterpret_cast<char*>(&hdr), sizeof(cache_hdr))) {\n        return false;\n      }\n    }\n    \n    //fs.write(reinterpret_cast<char*>(&(oper->operations.front())), sizeof(image_operation) * hdr.size);\n    //if (fs.fail()) return false;\n    \n    if (!gzwriteall(gzf, reinterpret_cast<char*>(&(oper->operations.front())), sizeof(image_operation) * hdr.size)) {\n      return false;\n    }\n    \n    gzclose(gzf);\n    return true;\n  }\n};\n\n#endif /* _CACHE_H_ */\n"
  },
  {
    "path": "src/dirlist.cpp",
    "content": "#include \"dirlist.hpp\"\n#include \"fileutils.hpp\"\n\ndirlist::dirlist(const fs::path path) {\n  if (fs::is_directory(path))\n    directories.push(path);\n}\n\nbool dirlist::has_next(dir_filter_func dir_filter, file_filter_func file_filter)\n{\n  if (!files.empty()) {\n    return true;\n  }\n\n  if (directories.empty()) {\n    return false;\n  }\n  \n  // work until you find any files\n  while (!directories.empty()) {\n    fs::path dir_path = directories.front();\n    directories.pop();\n    \n    if (!fs::is_directory(dir_path)) {\n      continue;\n    }\n    \n    fs::directory_iterator end_itr;\n\n    for ( fs::directory_iterator itr(dir_path);\n          itr != end_itr;\n          ++itr )\n    {\n      if (fs::is_directory(itr->status())) {\n        if (!dir_filter(itr->path().stem().string())) {\n          continue;\n        }\n        \n        directories.push(itr->path());\n      }\n      else if (fs::is_regular_file(itr->status())) {\n        if (!file_filter(path_string(itr->path().filename()))) {\n          continue;\n        }\n        \n        files.push(itr->path());\n      }\n    }\n  }\n  \n  return !files.empty();\n}\n\nfs::path dirlist::next()\n{\n  fs::path next = files.front();\n  files.pop();\n  return next;\n}\n"
  },
  {
    "path": "src/dirlist.hpp",
    "content": "#ifndef _DIRLIST_HPP\n#define _DIRLIST_HPP\n\n#include <queue>\n#include <string>\n\n#include <boost/filesystem.hpp>\n\nnamespace fs = boost::filesystem;\n\nclass dirlist {\npublic:\n  typedef bool (dir_filter_func)(const std::string&);\n  typedef bool (file_filter_func)(const std::string&);\n\n  dirlist(const fs::path path);\n  \n  bool has_next(dir_filter_func, file_filter_func);\n\n  fs::path next();\nprivate:\n  std::queue<fs::path> directories;\n  std::queue<fs::path> files;\n};\n\n#endif /* _DIRLIST_HPP */\n"
  },
  {
    "path": "src/dlopen.cpp",
    "content": "#include \"dlopen.hpp\"\n\n/**\n * Concept shamelessly stolen from;\n * http://www.codeproject.com/KB/architecture/plat_ind_coding.aspx\n */\n\n#include <string>\n\n#if defined(_MSC_VER)\n#   include <windows.h>\n#elif defined(__GNUC__)\n#   include <dlfcn.h>\n#else\n#error Unknown compiler\n#endif\n\nstruct dl_t {\n#if defined(_MSC_VER)\n  HINSTANCE impl;\n#elif defined(__GNUC__)\n  void* impl;\n#endif\n};\n\n# if defined(_MSC_VER)\n#define EXT \".dll\"\n#define EXTL 4\n# elif defined(__GNUC__)\n#define EXT \".so\"\n#define EXTL 3\n# endif\n\ndl_t* dl_open(const char *name)\n{\n  std::string fullname = std::string(name);\n  void* impl;\n\n  if (fullname.substr(fullname.size() - EXTL).compare(EXT) != 0) {\n    fullname += EXT;\n  }\n\n# if defined(_MSC_VER)\n  impl = LoadLibrary(fullname);\n# elif defined(__GNUC__)\n  impl = dlopen(fullname.c_str(), RTLD_LAZY);\n# endif\n\n  if (impl == NULL) {\n    return NULL;\n  }\n\n  dl_t* dl = new dl_t;\n  dl->impl = impl;\n  return dl;\n}\n\nvoid* dl_sym(dl_t* dl, const char *sym)\n{\n#if defined(_MSC_VER)\n  return (void*)GetProcAddress(dl->impl, sym);\n#elif defined(__GNUC__)\n  return dlsym(dl->impl, sym);\n#endif\n}\n\nbool dl_close(dl_t* dl)\n{\n  bool ok;\n#if defined(_MSC_VER)\n  ok = FreeLibrary(dl->impl);\n#elif defined(__GNUC__)\n  ok = dlclose(dl->impl);\n#endif\n  delete dl;\n  return ok;\n}\n"
  },
  {
    "path": "src/dlopen.hpp",
    "content": "#ifndef _DLOPEN_HPP\n#define _DLOPEN_HPP\n\nstruct dl_t;\n\ndl_t* dl_open(const char*);\nvoid* dl_sym(dl_t*, const char*);\nbool dl_close(dl_t*);\n\n#endif /* _DLOPEN_HPP */\n"
  },
  {
    "path": "src/engine/CMakeLists.txt",
    "content": "add_library(\n  c10t-engine\n  isometric_base.cpp\n  flat_base.cpp\n  topdown_engine.cpp\n  oblique_engine.cpp\n  obliqueangle_engine.cpp\n  isometric_engine.cpp\n  fatiso_engine.cpp\n  functions.cpp\n  block_rotation.cpp\n)\n\nset_target_properties(c10t-engine PROPERTIES COMPILE_FLAGS \"-O3 -Wall -pedantic -g\")\n"
  },
  {
    "path": "src/engine/block_rotation.cpp",
    "content": "#include \"engine/block_rotation.hpp\"\n\nblock_rotation::block_rotation(\n    int rotation,\n    boost::shared_ptr<nbt::ByteArray> array)\n    : x(0), z(0), rotation(rotation), array(array)\n{\n}\n\nvoid block_rotation::set_xz(int x, int z) {\n  transform_xz(x, z);\n  this->x = x;\n  this->z = z;\n}\n\nvoid block_rotation::transform_xz(int& x, int& z) {\n  int t = x;\n\n  switch (rotation) {\n    case 270:\n      x = 15 - z;\n      z = t;\n      break;\n    case 180:\n      z = 15 - z;\n      x = 15 - x;\n      break;\n    case 90:\n      x = z;\n      z = 15 - t;\n      break;\n  };\n}\n\n/**\n */\nint block_rotation::get8(int y, int d) {\n  int p = ((y * 16 + z) * 16 + x);\n  if (!(p >= 0 && p < array->length)) return d;\n  return array->values[p] & 0xff;\n}\n\n/**\n * Data values are packed two by two and the position LSB decides which\n * half-byte contains the requested block data value.\n */\nint block_rotation::get4(int y, int d) {\n  int tmp = (y * 16 + z) * 16 + x;\n  int p = tmp >> 1;\n  int b = tmp & 0x1;\n  if (!(p >= 0 && p < array->length)) return d;\n  return (array->values[p] >> (b * 4)) & 0xf;\n}\n"
  },
  {
    "path": "src/engine/block_rotation.hpp",
    "content": "#ifndef _ENGINE_BLOCK_ROTATION_HPP\n#define _ENGINE_BLOCK_ROTATION_HPP\n\n#include <stdint.h>\n\n#include <boost/shared_ptr.hpp>\n\n#include \"nbt/types.hpp\"\n#include \"mc/blocks.hpp\"\n\nclass block_rotation {\npublic:\n  block_rotation(int rotation, boost::shared_ptr<nbt::ByteArray> array);\n\n  void set_xz(int x, int z);\n  void transform_xz(int& x, int& z);\n\n  int get8(int y, int d=-1);\n  int get4(int y, int d=-1);\nprivate:\n  int x, z;\n  int rotation;\n  boost::shared_ptr<nbt::ByteArray> array;\n};\n\n#endif /* _ENGINE_BLOCK_ROTATION_HPP */\n"
  },
  {
    "path": "src/engine/engine_base.hpp",
    "content": "#ifndef _ENGINE_ENGINE_BASE_HPP\n#define _ENGINE_ENGINE_BASE_HPP\n\n#include \"engine/engine_settings.hpp\"\n#include \"engine/engine_core.hpp\"\n\n#include \"2d/cube.hpp\"\n#include \"mc/level.hpp\"\n#include \"mc/world.hpp\"\n#include \"mc/blocks.hpp\"\n#include \"image/image_operations.hpp\"\n\ntemplate<typename C>\nclass engine_base : public engine_core {\n  public:\n    engine_base(engine_settings engine_s, mc::world& world) :\n      part_c(mc::MapX + 1, mc::MapY + 1, mc::MapZ + 1),\n      pos_c(world.diff_x * mc::MapX, mc::MapY, world.diff_z * mc::MapZ),\n      mpos_c((world.diff_x + 1) * mc::MapX, mc::MapY, (world.diff_z + 1) * mc::MapZ),\n      engine_s(engine_s),\n      world(world)\n    {\n    }\n\n    void project_limits(pos_t& image_width, pos_t& image_height) {\n      part_c.limits(image_width, image_height);\n    }\n\n    void project_position(point& p, pos_t& image_x, pos_t& image_y) {\n      part_c.project(p, image_x, image_y);\n    }\n\n    void get_boundaries(pos_t& width, pos_t& height) {\n      mpos_c.limits(width, height);\n    }\n\n    void get_level_boundaries(pos_t& width, pos_t& height) {\n      part_c.limits(width, height);\n    }\n\n    void w2pt(int xPos, int zPos, pos_t& x, pos_t& y) {\n      pos_t posx = xPos - get_world().min_x;\n      pos_t posz = zPos - get_world().min_z;\n\n      point pos(posx * mc::MapX, mc::MapY, posz * mc::MapZ);\n\n      pos_c.project(pos, x, y);\n    }\n    \n    void wp2pt(int xPos, int yPos, int zPos, pos_t& x, pos_t& y) {\n      point pos(xPos - get_world().min_xp, yPos, zPos - get_world().min_zp);\n      mpos_c.project(pos, x, y);\n      x -= im_min_x;\n      y -= im_min_y;\n    }\n\n    void reset_image_limits() {\n      im_min_x = std::numeric_limits<pos_t>::max();\n      im_min_y = std::numeric_limits<pos_t>::max();\n      im_max_x = std::numeric_limits<pos_t>::min();\n      im_max_y = std::numeric_limits<pos_t>::min();\n    }\n\n    void update_image_limits(pos_t x, pos_t y, pos_t max_x, pos_t max_y) {\n      im_min_x = std::min(im_min_x, x);\n      im_min_y = std::min(im_min_y, y);\n      im_max_x = std::max(im_max_x, max_x);\n      im_max_y = std::max(im_max_y, max_y); \n    };\n\n    const engine_settings& get_settings() {\n      return engine_s;\n    }\n\n    const mc::world& get_world() {\n      return world;\n    }\n\n    pos_t get_min_x() {\n      return im_min_x;\n    }\n\n    pos_t get_max_x() {\n      return im_max_x;\n    }\n\n    pos_t get_min_y() {\n      return im_min_y;\n    }\n\n    pos_t get_max_y() {\n      return im_max_y;\n    }\n  private:\n    const C part_c;\n    const C pos_c;\n    const C mpos_c;\n\n    const engine_settings engine_s;\n    const mc::world& world;\n\n    pos_t im_min_x;\n    pos_t im_min_y;\n    pos_t im_max_x;\n    pos_t im_max_y;\n};\n\n#endif /* _ENGINE_ENGINE_BASE_HPP */\n"
  },
  {
    "path": "src/engine/engine_core.hpp",
    "content": "#ifndef _ENGINE_ENGINE_CORE_HPP\n#define _ENGINE_ENGINE_CORE_HPP\n\n#include <stdint.h>\n#include <boost/shared_ptr.hpp>\n\n#include \"mc/level.hpp\"\n#include \"image/image_operations.hpp\"\n\nclass engine_core;\n\ntypedef boost::shared_ptr<engine_core> engine_core_ptr;\n\nclass engine_core {\npublic:\n  typedef uint64_t pos_t;\n  typedef boost::shared_ptr<mc::level> level_ptr;\n  typedef boost::shared_ptr<image_operations> image_operations_ptr;\n\n  virtual void get_boundaries(pos_t& width, pos_t& height) = 0;\n  virtual void get_level_boundaries(pos_t& width, pos_t& height) = 0;\n  virtual void w2pt(int xPos, int zPos, pos_t& x, pos_t& y) = 0;\n  virtual void wp2pt(int xPos, int yPos, int zPos, pos_t& x, pos_t& y) = 0;\n  virtual void reset_image_limits() = 0;\n  virtual void update_image_limits(pos_t x, pos_t y, pos_t max_x, pos_t max_y) = 0;\n  virtual void render(level_ptr, image_operations_ptr) = 0;\n\n  virtual pos_t get_min_x() = 0;\n  virtual pos_t get_max_x() = 0;\n  virtual pos_t get_min_y() = 0;\n  virtual pos_t get_max_y() = 0;\n};\n\n#endif /* _ENGINE_ENGINE_CORE_HPP */\n"
  },
  {
    "path": "src/engine/engine_settings.hpp",
    "content": "#ifndef _ENGINE_ENGINE_SETTINGS_HPP\n#define _ENGINE_ENGINE_SETTINGS_HPP\n\n#include <boost/shared_array.hpp>\n\nstruct engine_settings {\n  int rotation;\n  bool night;\n  bool heightmap;\n  bool striped_terrain;\n  bool hellmode;\n  bool cavemode;\n  int top;\n  int bottom;\n};\n\n#endif /* _ENGINE_ENGINE_SETTINGS_HPP */\n"
  },
  {
    "path": "src/engine/fatiso_engine.cpp",
    "content": "#include \"engine/fatiso_engine.hpp\"\n\nfatiso_engine::fatiso_engine(\n    engine_settings& s,\n    mc::world& world\n    )\n  : isometric_base<fatiso_cube>(s, world)\n{\n}\n\nvoid fatiso_engine::render_block(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  color topdark(top);\n  color toplight(top);\n  color sidelight(side);\n\n  if (bt == mc::LegacyBlocks::Grass) {\n    topdark.darken(0x20);\n    toplight.darken(0x10);\n    sidelight.lighten(0x20);\n  }\n  else {\n    toplight = color(side);\n    topdark = color(side);\n  }\n\n  o->add_pixel(px + 0, py + 0, side);\n  o->add_pixel(px + 0, py + 1, side);\n  o->add_pixel(px + 0, py + 2, side);\n  o->add_pixel(px + 1, py - 1, side);\n  o->add_pixel(px + 1, py + 0, side);\n  o->add_pixel(px + 1, py + 1, side);\n  o->add_pixel(px + 2, py - 1, side);\n  o->add_pixel(px + 2, py + 0, side);\n  o->add_pixel(px + 2, py + 1, side);\n  o->add_pixel(px + 3, py - 2, side);\n  o->add_pixel(px + 3, py - 1, side);\n  o->add_pixel(px + 3, py + 0, side);\n\n  o->add_pixel(px - 1, py + 0, sidelight);\n  o->add_pixel(px - 1, py + 1, sidelight);\n  o->add_pixel(px - 1, py + 2, sidelight);\n  o->add_pixel(px - 2, py - 1, sidelight);\n  o->add_pixel(px - 2, py + 0, sidelight);\n  o->add_pixel(px - 2, py + 1, sidelight);\n  o->add_pixel(px - 3, py - 1, sidelight);\n  o->add_pixel(px - 3, py + 0, sidelight);\n  o->add_pixel(px - 3, py + 1, sidelight);\n  o->add_pixel(px - 4, py - 2, sidelight);\n  o->add_pixel(px - 4, py - 1, sidelight);\n  o->add_pixel(px - 4, py + 0, sidelight);\n\n  o->add_pixel(px + 0, py - 2, topdark);\n  o->add_pixel(px + 0, py - 1, topdark);\n  o->add_pixel(px + 1, py - 3, topdark);\n  o->add_pixel(px + 1, py - 2, topdark);\n  o->add_pixel(px + 2, py - 3, topdark);\n  o->add_pixel(px + 2, py - 2, topdark);\n  o->add_pixel(px + 3, py - 4, topdark);\n  o->add_pixel(px + 3, py - 3, topdark);\n\n  o->add_pixel(px - 1, py - 2, toplight);\n  o->add_pixel(px - 1, py - 1, toplight);\n  o->add_pixel(px - 2, py - 3, toplight);\n  o->add_pixel(px - 2, py - 2, toplight);\n  o->add_pixel(px - 3, py - 3, toplight);\n  o->add_pixel(px - 3, py - 2, toplight);\n  o->add_pixel(px - 4, py - 4, toplight);\n  o->add_pixel(px - 4, py - 3, toplight);\n\n  o->add_pixel(px - 3, py - 5, top);\n  o->add_pixel(px - 3, py - 4, top);\n  o->add_pixel(px - 2, py - 5, top);\n  o->add_pixel(px - 2, py - 4, top);\n  o->add_pixel(px - 1, py - 6, top);\n  o->add_pixel(px - 1, py - 5, top);\n  o->add_pixel(px - 1, py - 4, top);\n  o->add_pixel(px - 1, py - 3, top);\n  o->add_pixel(px + 0, py - 6, top);\n  o->add_pixel(px + 0, py - 5, top);\n  o->add_pixel(px + 0, py - 4, top);\n  o->add_pixel(px + 0, py - 3, top);\n  o->add_pixel(px + 1, py - 5, top);\n  o->add_pixel(px + 1, py - 4, top);\n  o->add_pixel(px + 2, py - 5, top);\n  o->add_pixel(px + 2, py - 4, top);\n}\n\nvoid fatiso_engine::render_halfblock(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  render_block(o, bt, px, py, top, side);\n}\n\nvoid fatiso_engine::render_torchblock(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  render_block(o, bt, px, py, top, side);\n}\n"
  },
  {
    "path": "src/engine/fatiso_engine.hpp",
    "content": "#ifndef FATISO_ENGINE\n#define FATISO_ENGINE\n\n#include \"engine/isometric_base.hpp\"\n\ntypedef angle_cube<4,5,2> fatiso_cube;\n\nclass fatiso_engine : public isometric_base<fatiso_cube> {\npublic:\n  fatiso_engine(engine_settings& s, mc::world& world);\n\n  void project_limits(\n      pos_t& image_width,\n      pos_t& image_height\n      );\n\n  void project_position(\n      point& p,\n      pos_t& image_x,\n      pos_t& image_y\n      );\n\n  void project_world_limits(\n      pos_t& image_width,\n      pos_t& image_height\n      );\n\n  void project_world_position(\n      point& p,\n      pos_t& image_x,\n      pos_t& image_y\n      );\n\n  void render_block(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n\n  void render_halfblock(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n\n  void render_torchblock(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n};\n\n#endif /* FATISO_ENGINE */\n"
  },
  {
    "path": "src/engine/flat_base.cpp",
    "content": "#include \"engine/flat_base.hpp\"\n\n"
  },
  {
    "path": "src/engine/flat_base.hpp",
    "content": "#ifndef _ENGINE_FLAT_BASE_HPP\n#define _ENGINE_FLAT_BASE_HPP\n\n#include \"engine/engine_base.hpp\"\n#include \"engine/block_rotation.hpp\"\n#include \"engine/functions.hpp\"\n\n#include <boost/foreach.hpp>\n\ntemplate<typename C>\nclass flat_base : public engine_base<C> {\npublic:\n  typedef uint64_t pos_t;\n  typedef boost::shared_ptr<mc::level> level_ptr;\n  typedef boost::shared_ptr<image_operations> image_operations_ptr;\n\n  flat_base(engine_settings& s, mc::world& world)\n    : engine_base<C>(s, world)\n  {\n  }\n\n  void render(level_ptr level, image_operations_ptr oper)\n  {\n    const engine_settings& s = flat_base<C>::get_settings();\n\n    pos_t iw, ih;\n    flat_base<C>::get_level_boundaries(iw, ih);\n\n    oper->set_limits(iw, ih);\n\n    boost::shared_ptr<mc::Level_Compound> L = level->get_level();\n\n    bool* blocked = new bool[iw*ih];\n\n    for (unsigned int i = 0; i < iw*ih; i++) {\n      blocked[i] = false;\n    }\n\n    // block type\n\n    BOOST_REVERSE_FOREACH(mc::Section_Compound Section, L->Sections) {\n      block_rotation br_blocks(s.rotation, Section.Blocks);\n      block_rotation br_data(s.rotation, Section.Data);\n      //block_rotation br_block_light(s.rotation, Section.BlockLight);\n      //block_rotation br_sky_light(s.rotation, Section.SkyLight);\n\n      for (int y = 15; y >= 0; y--) {\n        int abs_y = (Section.Y * 16) + y;\n\n        for (int z = 0; z < mc::MapZ; z++) {\n          for (int x = 0; x < mc::MapX; x++) {\n            unsigned int blocked_position = x * iw + z;\n\n            if (blocked[blocked_position]) {\n              continue;\n            }\n\n            br_blocks.set_xz(x, z);\n            br_data.set_xz(x, z);\n            //br_block_light.set_xz(x, z);\n            //br_sky_light.set_xz(x, z);\n\n            // do incremental color fill until color is opaque\n            int block_type = br_blocks.get8(y);\n            int block_data = br_data.get4(y);\n\n            mc::MaterialMode mode;\n            color top;\n            color side;\n\n            boost::optional<mc::MaterialT*> material = mc::get_material_legacy(block_type, block_data);\n            if (material) {\n              mc::MaterialT *m = material.get();\n              if (!m->enabled) {\n                continue;\n              }\n              mode = m->mode;\n              top = m->top;\n              side = m->side;\n            } else {\n              mode = mc::MaterialMode::Block;\n              top = mc::SharedDefaultColor;\n              side = mc::SharedDefaultColor;\n            }\n\n            blocked[blocked_position] = top.is_opaque();\n\n            /*int block_light = br_block_light.get4(y + 1);\n            int sky_light = br_sky_light.get4(y + 1, 15);*/\n\n            //apply_shading(s, block_light, sky_light, 0, abs_y, top);\n\n            point p(x, abs_y, z);\n\n            pos_t px;\n            pos_t py;\n\n            flat_base<C>::project_position(p, px, py);\n\n            int log_rotation;\n\n            switch(mode) {\n            case mc::MaterialMode::Block:\n              render_block(oper, block_type, px, py, top, side);\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::HalfBlock:\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::TorchBlock:\n              render_torchblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::LargeFlowerBlock:\n              // Check if the requested block is the top block\n              if(block_data & 0x08) {\n                // Small sanity check\n                if(y > 0 && br_blocks.get8(y-1) == block_type) {\n                  // Minecraft currently doesn't set the lower bits to the\n                  // corresponding type so we have to do this here.\n                  block_data = br_data.get4(y-1) & 0x07;\n                  top =  mc::get_color_legacy(block_type, block_data);\n                  side = mc::get_side_color_legacy(block_type, block_data);\n                } else {\n                  // Top block not placed on a correct bottom block.\n                  // The expected LargeFlower multi block structure is invalid, skip it.\n                  continue;\n                }\n              } else {\n                // Force the top of the lower block to also be the side color.\n                top = side;\n              }\n              render_block(oper, block_type, px, py, top, side);\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::LogBlock:\n              // Log blocks are just a regular block that may differ in orientation. Top\n              // color is considered the inner material. Because some bits of metadata are\n              // used both for variant and rotation state, block type needs to be fetched again.\n              log_rotation = (block_data & 0x0C) >> 2;\n              switch(log_rotation) {\n              case 0:\n                // Up/down\n                top =  mc::get_color_legacy(block_type, block_data & 0x3);\n                side = mc::get_side_color_legacy(block_type, block_data & 0x3);\n                break;\n              case 1:\n                // East/west\n              case 2:\n                // North/south\n                // TODO: Actually implement render rotation, for now simply swap top and side.\n                side =  mc::get_color_legacy(block_type, block_data & 0x3);\n                top = mc::get_side_color_legacy(block_type, block_data & 0x3);\n                break;\n              case 3:\n                // Only sides, thus no top color.\n                side = mc::get_side_color_legacy(block_type, block_data & 0x3);\n                top = side;\n                break;\n              }\n              render_block(oper, block_type, px, py, top, side);\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::LegacySlab:\n              // Legacy slab is just a half block; but is sometimes a full block.\n              // The first legacy id is the full block version.\n              if (block_type == material.get()->legacy_ids[0]) {\n                render_block(oper, block_type, px, py, top, side);\n              }\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::LegacyLeaves:\n              // Legacy leaves is just a regular block; however some bits of the metadata\n              // are used for other block states, only the two first bits are used for block\n              // type therefore we need to re-fetch the block type now.\n              top =  mc::get_color_legacy(block_type, block_data & 0x3);\n              side = mc::get_side_color_legacy(block_type, block_data & 0x3);\n              render_block(oper, block_type, px, py, top, side);\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            }\n          }\n        }\n      }\n    }\n\n    delete [] blocked;\n    oper->reverse();\n  }\n\n  virtual void render_block(image_operations_ptr, int, pos_t, pos_t, color, color) = 0;\n  virtual void render_halfblock(image_operations_ptr, int, pos_t, pos_t, color, color) = 0;\n  virtual void render_torchblock(image_operations_ptr, int, pos_t, pos_t, color, color) = 0;\n};\n\n#endif /* _ENGINE_FLAT_BASE_HPP */\n"
  },
  {
    "path": "src/engine/functions.cpp",
    "content": "#include \"engine/functions.hpp\"\n\nvoid apply_shading(\n        const engine_settings& s,\n        int block_light,\n        int sky_light,\n        int height_map,\n        int y,\n        color &c)\n{\n  if(s.night) {\n    c.darken(0x6 * (16 - block_light));\n  }\n  else if (sky_light != -1 && y != s.top) {\n    c.darken(0x6 * (16 - std::max(sky_light, block_light)));\n  }\n  \n  //c.darken((mc::MapY - y));\n  \n  // in heightmap mode, brightness = height\n  if (s.heightmap) {\n    c.b = y*2;\n    c.g = y*2;\n    c.r = y*2;\n    c.a = 0xff;\n  }\n  else if (s.striped_terrain && y % 2 == 0) {\n    c.darken(0xf);\n  }\n}\n"
  },
  {
    "path": "src/engine/functions.hpp",
    "content": "#ifndef _ENGINE_FUNCTIONS_HPP\n#define _ENGINE_FUNCTIONS_HPP\n\n#include \"engine/block_rotation.hpp\"\n#include \"engine/engine_settings.hpp\"\n#include \"image/color.hpp\"\n#include \"mc/blocks.hpp\"\n\n/**\n * Shared functions between engines.\n */\n\n/**\n * Apply shading to specified block and color.\n **/\nvoid apply_shading(\n    const engine_settings& engine_s,\n    int bl, int sl, int hm, int y, color &c);\n\ninline bool is_open(mc::MaterialT*& m) {\n  if (!m) {\n    return false;\n  }\n\n  return m->top.is_transparent();\n}\n\ninline bool is_open(int bt) {\n  if (bt == -1) {\n    return false;\n  }\n\n  switch(bt) {\n    case mc::LegacyBlocks::Air: return true;\n    case mc::LegacyBlocks::Leaves: return true;\n    default: return false;\n  }\n}\n\n// this functions is currently unused\ninline bool cave_ignore_block(int y, int bt, block_rotation& b_r, bool &cave_initial) {\n  if (cave_initial) {\n    if (!is_open(bt)) {\n      cave_initial = false;\n      return true;\n    }\n\n    return true;\n  }\n\n  if (!is_open(bt) && is_open(b_r.get8(y + 1))) {\n    return false;\n  }\n\n  return true;\n}\n\n// this functions is currently unused\ninline bool hell_ignore_block(int y, int bt, block_rotation& b_r, bool &hell_initial) {\n  if (hell_initial) {\n    if (is_open(bt)) {\n      hell_initial = false;\n      return false;\n    }\n\n    return true;\n  }\n\n  return false;\n}\n\n#endif /* _ENGINE_FUNCTIONS_HPP */\n"
  },
  {
    "path": "src/engine/isometric_base.cpp",
    "content": "#include \"engine/isometric_base.hpp\"\n\n"
  },
  {
    "path": "src/engine/isometric_base.hpp",
    "content": "#ifndef _ENGINE_ISOMETRIC_BASE_HPP\n#define _ENGINE_ISOMETRIC_BASE_HPP\n\n#include \"engine/engine_base.hpp\"\n#include \"engine/block_rotation.hpp\"\n#include \"engine/functions.hpp\"\n\n#include <boost/foreach.hpp>\n\ntemplate<typename C>\nclass isometric_base : public engine_base<C> {\npublic:\n  typedef uint64_t pos_t;\n  typedef boost::shared_ptr<mc::level> level_ptr;\n  typedef boost::shared_ptr<image_operations> image_operations_ptr;\n\n  isometric_base(engine_settings& s, mc::world& world)\n    : engine_base<C>(s, world)\n  {\n  }\n\n  void render(level_ptr level, image_operations_ptr oper)\n  {\n    const engine_settings& s = engine_base<C>::get_settings();\n\n    boost::shared_ptr<mc::Level_Compound> L = level->get_level();\n\n    pos_t image_width = 0;\n    pos_t image_height = 0;\n\n    engine_base<C>::project_limits(image_width, image_height);\n\n    oper->set_limits(image_width + 1, image_height);\n\n    BOOST_FOREACH(mc::Section_Compound Section, L->Sections) {\n      block_rotation br_blocks(s.rotation, Section.Blocks);\n      block_rotation br_data(s.rotation, Section.Data);\n      //block_rotation br_block_light(s.rotation, Section.BlockLight);\n      //block_rotation br_sky_light(s.rotation, Section.SkyLight);\n\n      for (int y = 0; y < 16; y++) {\n        int abs_y = (16 * Section.Y) + y;\n\n        for (int z = 0; z < mc::MapZ; z++) {\n          for (int x = mc::MapX - 1; x >= 0; x--) {\n            br_blocks.set_xz(x, z);\n            br_data.set_xz(x, z);\n            //br_block_light.set_xz(x, z);\n            //br_sky_light.set_xz(x, z);\n\n            int block_type = br_blocks.get8(y);\n\n            point p(x, abs_y, z);\n\n            pos_t px = 0;\n            pos_t py = 0;\n\n            engine_base<C>::project_position(p, px, py);\n\n            int block_data = br_data.get4(y);\n\n            mc::MaterialMode mode;\n            color top;\n            color side;\n\n            boost::optional<mc::MaterialT*> material = mc::get_material_legacy(block_type, block_data);\n            if (material) {\n              mc::MaterialT *m = material.get();\n              if (!m->enabled) {\n                continue;\n              }\n              mode = m->mode;\n              top = m->top;\n              side = m->side;\n            } else {\n              mode = mc::MaterialMode::Block;\n              top = mc::SharedDefaultColor;\n              side = mc::SharedDefaultColor;\n            }\n\n            int log_rotation;\n\n            //int block_light = br_block_light.get4(y + 1);\n            //int sky_light = br_sky_light.get4(y + 1);\n\n            //apply_shading(s, block_light, sky_light, 0, y, top);\n            //apply_shading(s, 0, 0, 0, y, side);\n\n            switch(mode) {\n            case mc::MaterialMode::Block:\n              render_block(oper, block_type, px, py, top, side);\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::HalfBlock:\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::TorchBlock:\n              render_torchblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::LargeFlowerBlock:\n              // Check if the requested block is the top block\n              if(block_data & 0x08) {\n                // Small sanity check\n                if(y > 0 && br_blocks.get8(y-1) == block_type) {\n                  // Minecraft currently doesn't set the lower bits to the\n                  // corresponding type so we have to do this here.\n                  block_data = br_data.get4(y-1) & 0x07;\n                  top =  mc::get_color_legacy(block_type, block_data);\n                  side = mc::get_side_color_legacy(block_type, block_data);\n                } else {\n                  // Top block not placed on a correct bottom block.\n                  // The expected LargeFlower multi block structure is invalid, skip it.\n                  continue;\n                }\n              } else {\n                // Force the top of the lower block to also be the side color.\n                top = side;\n              }\n              render_block(oper, block_type, px, py, top, side);\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::LogBlock:\n              // Log blocks are just a regular block that may differ in orientation. Top\n              // color is considered the inner material. Because some bits of metadata are\n              // used both for variant and rotation state, block type needs to be fetched again.\n              log_rotation = (block_data & 0x0C) >> 2;\n              switch(log_rotation) {\n              case 0:\n                // Up/down\n                top =  mc::get_color_legacy(block_type, block_data & 0x3);\n                side = mc::get_side_color_legacy(block_type, block_data & 0x3);\n                break;\n              case 1:\n                // East/west\n              case 2:\n                // North/south\n                // TODO: Actually implement render rotation, for now simply swap top and side.\n                side =  mc::get_color_legacy(block_type, block_data & 0x3);\n                top = mc::get_side_color_legacy(block_type, block_data & 0x3);\n                break;\n              case 3:\n                // Only sides, thus no top color.\n                side = mc::get_side_color_legacy(block_type, block_data & 0x3);\n                top = side;\n                break;\n              }\n              render_block(oper, block_type, px, py, top, side);\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::LegacySlab:\n              // Legacy slab is just a half block; but is sometimes a full block.\n              // The first legacy id is the full block version.\n              if (block_type == material.get()->legacy_ids[0]) {\n                render_block(oper, block_type, px, py, top, side);\n              }\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            case mc::MaterialMode::LegacyLeaves:\n              // Legacy leaves is just a regular block; however some bits of the metadata\n              // are used for other block states, only the two first bits are used for block\n              // type therefore we need to re-fetch the block type now.\n              top =  mc::get_color_legacy(block_type, block_data & 0x3);\n              side = mc::get_side_color_legacy(block_type, block_data & 0x3);\n              render_block(oper, block_type, px, py, top, side);\n              render_halfblock(oper, block_type, px, py, top, side);\n              break;\n            }\n          }\n        }\n      }\n    }\n  }\n\n  virtual void render_block(image_operations_ptr, int, pos_t, pos_t, color, color) = 0;\n  virtual void render_halfblock(image_operations_ptr, int, pos_t, pos_t, color, color) = 0;\n  virtual void render_torchblock(image_operations_ptr, int, pos_t, pos_t, color, color) = 0;\n};\n\n#endif /* _ENGINE_ISOMETRIC_BASE_HPP */\n"
  },
  {
    "path": "src/engine/isometric_engine.cpp",
    "content": "#include \"engine/isometric_engine.hpp\"\n\nisometric_engine::isometric_engine(\n    engine_settings& s,\n    mc::world& world\n    )\n  : isometric_base<isometric_cube>(s, world)\n{\n}\n\nvoid isometric_engine::render_block(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  o->add_pixel(px, py, top);\n  o->add_pixel(px + 1, py, top);\n  o->add_pixel(px - 2, py, top);\n  o->add_pixel(px - 1, py, top);\n  \n  o->add_pixel(px - 2, py + 1, side);\n  \n  o->add_pixel(px - 1, py + 1, side);\n  o->add_pixel(px - 1, py + 2, side);\n  \n  o->add_pixel(px - 2, py + 2, side);\n  \n  side.lighten(0x20);\n  \n  o->add_pixel(px, py + 1, side);\n  o->add_pixel(px, py + 2, side);\n  \n  o->add_pixel(px + 1, py + 1, side);\n  o->add_pixel(px + 1, py + 2, side);\n}\n\nvoid isometric_engine::render_halfblock(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  o->add_pixel(px, py + 1, top);\n  o->add_pixel(px + 1, py + 1, top);\n  o->add_pixel(px - 2, py + 1, top);\n  o->add_pixel(px - 1, py + 1, top);\n  \n  o->add_pixel(px - 2, py + 2, side);\n  o->add_pixel(px - 1, py + 2, side);\n  \n  side.lighten(0x20);\n  \n  o->add_pixel(px, py + 2, side);\n  o->add_pixel(px + 1, py + 2, side);\n}\n\nvoid isometric_engine::render_torchblock(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  o->add_pixel(px, py, top);\n  o->add_pixel(px - 1, py, top);\n  \n  top.lighten(0x20);\n  top.a -= 0xb0;\n  \n  o->add_pixel(px, py + 1, top);\n  o->add_pixel(px - 1, py + 1, top);\n  \n  o->add_pixel(px - 1, py + 1, side);\n  o->add_pixel(px - 1, py + 2, side);\n  \n  side.lighten(0x20);\n  \n  o->add_pixel(px, py + 1, side);\n  o->add_pixel(px, py + 2, side);\n  \n  o->add_pixel(px - 2, py, top);\n  o->add_pixel(px + 1, py, top);\n  o->add_pixel(px, py - 1, top);\n  o->add_pixel(px - 1, py - 1, top);\n}\n"
  },
  {
    "path": "src/engine/isometric_engine.hpp",
    "content": "#ifndef ISOMETRIC_ENGINE\n#define ISOMETRIC_ENGINE\n\n#include \"engine/isometric_base.hpp\"\n\ntypedef angle_cube<2,2,1> isometric_cube;\n\nclass isometric_engine : public isometric_base<isometric_cube> {\npublic:\n  isometric_engine(engine_settings& s, mc::world& world);\n\n  void render_block(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n\n  void render_halfblock(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n\n  void render_torchblock(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n};\n\n#endif /* ISOMETRIC_ENGINE */\n"
  },
  {
    "path": "src/engine/oblique_engine.cpp",
    "content": "#include \"engine/oblique_engine.hpp\"\n#include \"engine/block_rotation.hpp\"\n#include \"engine/functions.hpp\"\n\n#include <boost/scoped_array.hpp>\n\nvoid oblique_engine::render(level_ptr level, boost::shared_ptr<image_operations> oper)\n{\n  pos_t iw, ih;\n\n  project_limits(iw, ih);\n  \n  //const engine_settings& s = get_settings();\n}\n"
  },
  {
    "path": "src/engine/oblique_engine.hpp",
    "content": "#ifndef OBLIQUE_ENGINE\n#define OBLIQUE_ENGINE\n\n#include \"engine/engine_base.hpp\"\n\nclass oblique_engine : public engine_base<oblique_cube> {\n  public:\n    oblique_engine(engine_settings& s, mc::world& world) : engine_base<oblique_cube>(s, world) {}\n    void render(level_ptr level, boost::shared_ptr<image_operations> operations);\n};\n\n#endif /* OBLIQUE_ENGINE */\n"
  },
  {
    "path": "src/engine/obliqueangle_engine.cpp",
    "content": "#include \"engine/obliqueangle_engine.hpp\"\n\nobliqueangle_engine::obliqueangle_engine(\n    engine_settings& s,\n    mc::world& world\n    )\n  : isometric_base<obliqueangle_cube>(s, world)\n{\n}\n\nvoid obliqueangle_engine::render_block(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  o->add_pixel(px, py, top);\n  o->add_pixel(px + 1, py, top);\n  o->add_pixel(px, py + 1, side);\n  \n  side.lighten(0x20);\n  o->add_pixel(px + 1, py + 1, side);\n}\n\nvoid obliqueangle_engine::render_halfblock(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  o->add_pixel(px, py + 1, top);\n  o->add_pixel(px + 1, py + 1, top);\n}\n\nvoid obliqueangle_engine::render_torchblock(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  o->add_pixel(px, py, top);\n\n  top.lighten(0x20);\n  top.a -= 0xb0;\n  o->add_pixel(px - 1, py, top);\n  o->add_pixel(px + 2, py, top);\n  o->add_pixel(px, py - 1, top);\n  o->add_pixel(px, py + 1, top);\n  \n  o->add_pixel(px, py + 1, side);\n}\n"
  },
  {
    "path": "src/engine/obliqueangle_engine.hpp",
    "content": "#ifndef OBLIQUEANGLE_ENGINE\n#define OBLIQUEANGLE_ENGINE\n\n#include \"engine/isometric_base.hpp\"\n\ntypedef angle_cube<1,1,1> obliqueangle_cube;\n\nclass obliqueangle_engine : public isometric_base<obliqueangle_cube> {\npublic:\n  obliqueangle_engine(engine_settings& s, mc::world& world);\n\n  void render_block(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n\n  void render_halfblock(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n\n  void render_torchblock(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n};\n\n#endif /* OBLIQUE_ENGINE */\n"
  },
  {
    "path": "src/engine/topdown_engine.cpp",
    "content": "#include \"engine/topdown_engine.hpp\"\n\ntopdown_engine::topdown_engine(\n    engine_settings& s,\n    mc::world& world\n    )\n  : flat_base<top_cube>(s, world)\n{\n}\n\nvoid topdown_engine::render_block(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  o->add_pixel(px, py, top);\n}\n\nvoid topdown_engine::render_halfblock(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  render_block(o, bt, px, py, top, side);\n}\n\nvoid topdown_engine::render_torchblock(\n    image_operations_ptr o,\n    int bt,\n    pos_t px,\n    pos_t py,\n    color top,\n    color side\n    )\n{\n  render_block(o, bt, px, py, top, side);\n}\n"
  },
  {
    "path": "src/engine/topdown_engine.hpp",
    "content": "#ifndef TOPDOWN_ENGINE\n#define TOPDOWN_ENGINE\n\n#include \"engine/flat_base.hpp\"\n\nclass topdown_engine : public flat_base<top_cube> {\npublic:\n  topdown_engine(engine_settings& s, mc::world& world);\n\n  void render_block(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n\n  void render_halfblock(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n\n  void render_torchblock(\n      image_operations_ptr o,\n      int bt,\n      pos_t px,\n      pos_t py,\n      color top,\n      color side\n      );\n};\n\n#endif /* TOPDOWN_ENGINE */\n"
  },
  {
    "path": "src/fileutils.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"fileutils.hpp\"\n\n"
  },
  {
    "path": "src/fileutils.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef _FILEUTILS_HPP\n#define _FILEUTILS_HPP\n\n#include <string>\n\n#include <boost/filesystem.hpp>\n#include <boost/version.hpp>\n\n#define BOOST_FSv2 ((BOOST_VERSION / 100) <= 1045)\n\nnamespace fs = boost::filesystem;\n\ninline std::string path_string(fs::path path) {\n#if BOOST_FSv2\n  return path;\n#else\n  return path.string();\n#endif\n}\n\n#endif /* _FILEUTILS_HPP */\n"
  },
  {
    "path": "src/generate_map.cpp",
    "content": "#include \"config.hpp\"\n#include \"image/format/png.hpp\"\n\n#include \"generate_map.hpp\"\n\n#include \"text.hpp\"\n#include \"players.hpp\"\n#include \"warps.hpp\"\n#include \"marker.hpp\"\n\n#include \"algorithm.hpp\"\n\n#include \"engine/engine_core.hpp\"\n#include \"engine/topdown_engine.hpp\"\n#include \"engine/oblique_engine.hpp\"\n#include \"engine/obliqueangle_engine.hpp\"\n#include \"engine/isometric_engine.hpp\"\n#include \"engine/fatiso_engine.hpp\"\n\n#include \"mc/blocks.hpp\"\n#include \"mc/region_iterator.hpp\"\n#include \"dlopen.hpp\"\n\n#include \"image/algorithms.hpp\"\n#include \"image/image_base.hpp\"\n#include \"image/cached_image.hpp\"\n#include \"image/memory_image.hpp\"\n\n#include \"cache.hpp\"\n\n#include \"json.hpp\"\n\n#include <boost/foreach.hpp>\n#include <boost/format.hpp>\n#include <boost/shared_ptr.hpp>\n#include <boost/ptr_container/ptr_vector.hpp>\n\n#include <ostream>\n#include <iomanip>\n\nusing namespace std;\nnamespace fs = boost::filesystem;\n\ntypedef std::map<mc::utils::level_coord, mc::rotated_level_info> levels_map;\n\ntemplate<typename T>\nvoid dot(std::ostream& out, T total)\n{\n  if (total == (T) 0x00)\n  {\n    out << \" done!\";\n  }\n  else\n  {\n    out << \".\" << std::flush;\n  }\n}\n\nvoid parts_endl(std::ostream& out, unsigned int total)\n{\n  out << \" \" << setw(8) << total << \" parts\" << endl;\n}\n\nvoid parts_perc_endl(std::ostream& out, unsigned int progress, unsigned int total)\n{\n  out << \" \" << setw(8)\n      << progress << \" parts \"\n      << (progress * 100) / total << \"%\" << endl;\n}\n\nvoid mb_endl(std::ostream& out, streampos progress, streampos total)\n{\n  out << \" \" << setw(8)\n      << fixed << float(progress) / 1000000 << \" MB \"\n      << (progress * 100) / total << \"%\" << endl;\n}\n\n/**\n * Load all warps from a database and push them to a container.\n */\ntemplate<typename T>\ninline void load_warps(ostream& out, fs::path warps_path, T& warps)\n{\n  out << \"warps: \" << warps_path << \": \" << flush;\n\n  warps_db wdb(warps_path);\n\n  try {\n    wdb.read(warps);\n    out << warps.size() << \" warp(s) OK\" << endl;\n  } catch(warps_db_exception& e) {\n    out << e.what() << endl;\n  }\n}\n\n/**\n * Load all players from a database and push them to a container.\n */\ntemplate<typename T, typename S>\ninline void load_players(ostream& out, fs::path show_players_path, T& players, S& player_set)\n{\n  out << \"players: \" << show_players_path << \": \" << flush;\n\n  players_db pdb(show_players_path, player_set);\n\n  std::vector<player> all_players;\n\n  try {\n    pdb.read(all_players);\n  } catch(players_db_exception& e) {\n    out << \" \" << e.what() << endl;\n    return;\n  }\n\n  out << all_players.size() << \" player(s) found\" << endl;\n\n  BOOST_FOREACH(player p, all_players) {\n    if (p.error) {\n      out << \"  \" << p.path << \":\" << p.error_where << \": \" << p.error_why << endl;\n      continue;\n    }\n\n    players.push_back(p);\n  }\n\n  out << \"  \" << players.size() << \" player(s) OK\" << endl;\n}\n\n/**\n * Push all players to a standard type of marker.\n */\ntemplate<typename P, typename T>\nvoid push_player_markers(settings_t& s, text::font_face base_font, P& players, T& markers)\n{\n  text::font_face player_font = base_font;\n\n  if (s.has_player_color) {\n    player_font.set_color(s.player_color);\n  }\n\n  BOOST_FOREACH(player p, players) {\n    if (p.zPos / mc::MapZ < s.min_z) continue;\n    if (p.zPos / mc::MapZ > s.max_z) continue;\n    if (p.xPos / mc::MapX < s.min_x) continue;\n    if (p.xPos / mc::MapX > s.max_x) continue;\n\n    markers.push_back(new marker(p.name, \"player\", player_font, p.xPos, p.yPos, p.zPos));\n  }\n}\n\n/**\n * Push all signs to a standard type of marker.\n */\ntemplate<typename S, typename T>\nvoid push_sign_markers(settings_t& s, text::font_face base_font, S& signs, T& markers)\n{\n  text::font_face sign_font = base_font;\n\n  if (s.has_sign_color) {\n    sign_font.set_color(s.sign_color);\n  }\n\n  BOOST_FOREACH(mc::marker lm, signs) {\n    if (!s.show_signs_filter.empty() && lm.get_text().find(s.show_signs_filter) == std::string::npos) {\n      continue;\n    }\n\n    if (!s.strip_sign_prefix) {\n      markers.push_back(new marker(lm.get_text(), \"sign\", sign_font,\n            lm.get_x(), lm.get_y(), lm.get_z()));\n    } else {\n      std::string text = lm.get_text().substr(s.show_signs_filter.size());\n      markers.push_back(new marker(text, \"sign\", sign_font,\n            lm.get_x(), lm.get_y(), lm.get_z()));\n    }\n  }\n}\n\ntypedef std::map<mc::utils::level_coord, mc::rotated_level_info> levels_map;\n\n/**\n * Push all coordinates to a standard type of marker.\n */\ntemplate<typename L, typename T>\nvoid push_coordinate_markers(\n    std::ostream& out,\n    settings_t& s,\n    text::font_face base_font,\n    mc::world& world,\n    L& levels,\n    T& markers)\n{\n  text::font_face coordinate_font = base_font;\n\n  if (s.has_coordinate_color) {\n    coordinate_font.set_color(s.coordinate_color);\n  }\n\n  BOOST_FOREACH(levels_map::value_type value, levels)\n  {\n    mc::utils::level_coord c = value.second.get_coord();\n    mc::level_info::level_info_ptr level_info = value.second.get_level();\n\n    if (c.get_z() - 4 < world.min_z) continue;\n    if (c.get_z() + 4 > world.max_z) continue;\n    if (c.get_x() - 4 < world.min_x) continue;\n    if (c.get_x() + 4 > world.max_x) continue;\n    if (c.get_z() % 10 != 0) continue;\n    if (c.get_x() % 10 != 0) continue;\n\n    std::stringstream result;\n\n    result << \"(\" << level_info->get_x() * mc::MapX\n        << \", \" << level_info->get_z() * mc::MapZ << \")\";\n\n    if (s.debug) {\n      out << \"Pushing coordinate info \" << result.str() << std::endl;\n    }\n\n    markers.push_back(new marker(result.str(), \"coord\", coordinate_font, c.get_x() * mc::MapX, 0, c.get_z() * mc::MapZ));\n  }\n}\n\n/**\n * Push all warps to a standard type of marker.\n */\ntemplate<typename W, typename T>\ninline void push_warp_markers(\n        settings_t& s,\n        text::font_face base_font,\n        W& warps,\n        T& markers)\n{\n  text::font_face warp_font = base_font;\n\n  if (s.has_warp_color) {\n    warp_font.set_color(s.warp_color);\n  }\n\n  /* initial code for projecting warps */\n  BOOST_FOREACH(warp w, warps) {\n    if (w.zPos / mc::MapZ < s.min_z) continue;\n    if (w.zPos / mc::MapZ > s.max_z) continue;\n    if (w.xPos / mc::MapX < s.min_x) continue;\n    if (w.xPos / mc::MapX > s.max_x) continue;\n\n    marker *m = new marker(w.name, \"warp\", warp_font, w.xPos, w.yPos, w.zPos);\n    markers.push_back(m);\n  }\n}\n\n/*\n * Store part of a level rendered as a small image.\n *\n * This will allow us to composite the entire image later and calculate sizes then.\n */\n\nvoid populate_markers(\n        settings_t& s,\n        json::array* array,\n        boost::shared_ptr<engine_core> engine,\n        boost::ptr_vector<marker>& markers)\n{\n  boost::ptr_vector<marker>::iterator it;\n\n  for (it = markers.begin(); it != markers.end(); it++) {\n    marker m = *it;\n\n    mc::utils::level_coord original_coord(m.get_x(), m.get_z());\n    mc::utils::level_coord coord = original_coord.rotate(s.rotation);\n\n    pos_t x, y;\n\n    engine->wp2pt(coord.get_x(), m.get_y(), coord.get_z(), x, y);\n\n    json::object* o = new json::object;\n\n    o->put(\"text\", new json::string(m.get_text()));\n    o->put(\"type\", new json::string(m.get_type()));\n\n    // the projected coordinates\n    o->put(\"x\", new json::number(x));\n    o->put(\"y\", new json::number(y));\n\n    // the real coordinates\n    o->put(\"X\", new json::number(m.get_x()));\n    o->put(\"Y\", new json::number(m.get_y()));\n    o->put(\"Z\", new json::number(m.get_z()));\n\n    array->push(o);\n  }\n  // don't bother to check for errors right now, but could be done using the \"fail\" accessor.\n}\n\ninline void overlay_markers(\n    settings_t& s,\n    image_ptr work_in_progress,\n    boost::shared_ptr<engine_core> engine,\n    boost::ptr_vector<marker>& markers\n    )\n{\n  memory_image positionmark(5, 5);\n  positionmark.fill(s.ttf_color);\n\n  boost::ptr_vector<marker>::iterator it;\n\n  for (it = markers.begin(); it != markers.end(); it++) {\n    marker m = *it;\n\n    text::font_face font = m.get_font();\n\n    if (!font.is_initialized()) {\n      continue;\n    }\n\n    mc::utils::level_coord original_coord(m.get_x(), m.get_z());\n    mc::utils::level_coord coord = original_coord.rotate(s.rotation);\n\n    pos_t x;\n    pos_t y;\n\n    engine->wp2pt(coord.get_x(), m.get_y(), coord.get_z(), x, y);\n\n    font.draw(work_in_progress, m.get_text(), x + 5, y);\n    //all->safe_composite(x - 3, y - 3, positionmark);\n  }\n}\n\n/**\n * Helper blocks\n */\n\ntypedef std::map<mc::utils::level_coord, mc::rotated_level_info> levels_map;\n\nvoid write_json_file(\n    ostream& out,\n    settings_t& s,\n    boost::shared_ptr<engine_core> engine,\n    mc::world& world,\n    boost::ptr_vector<marker> markers)\n{\n  // calculate world center\n  engine_core::pos_t center_x, center_y;\n  mc::utils::level_coord coord =\n    mc::utils::level_coord(s.center_x*16, s.center_z*16).rotate(s.rotation);\n\n  engine->wp2pt(coord.get_x(), 0, coord.get_z(), center_x, center_y);\n\n  json::object file;\n  json::object* json_static = new json::object;\n\n  json_static->put(\"MapX\", new json::number(mc::MapX));\n  json_static->put(\"MapY\", new json::number(mc::MapY));\n  json_static->put(\"MapZ\", new json::number(mc::MapZ));\n\n  file.put(\"st\", json_static);\n\n  json::object* json_world = new json::object;\n\n  json_world->put(\"cx\", new json::number(center_x));\n  json_world->put(\"cy\", new json::number(center_y));\n  json_world->put(\"dx\", new json::number((world.diff_x + 1) * mc::MapX));\n  json_world->put(\"dz\", new json::number((world.diff_z + 1) * mc::MapZ));\n  json_world->put(\"dy\", new json::number(mc::MapY));\n  json_world->put(\"mn_x\", new json::number(world.min_x * 16));\n  json_world->put(\"mn_z\", new json::number(world.min_z * 16));\n  json_world->put(\"mx_x\", new json::number(world.max_x * 16));\n  json_world->put(\"mx_z\", new json::number(world.max_z * 16));\n  json_world->put(\"rot\", new json::number(s.rotation));\n  json_world->put(\"mode\", new json::number(s.mode));\n  json_world->put(\"split_base\", new json::number(s.split_base));\n  json_world->put(\"split\", new json::number(s.split.size()));\n\n  file.put(\"world\", json_world);\n\n  json::array* markers_array = new json::array;\n  populate_markers(s, markers_array, engine, markers);\n  file.put(\"markers\", markers_array);\n\n  if (s.write_json) {\n    out << \"Writing json information: \" << path_string(s.write_json_path) << endl;\n    std::ofstream of(path_string(s.write_json_path).c_str());\n    of << file;\n    of.close();\n  }\n\n  if (s.write_js) {\n    out << \"Writing js (javascript `var c10t_json') information: \" << path_string(s.write_js_path) << endl;\n    std::ofstream of(path_string(s.write_js_path).c_str());\n    of << \"var c10t_json = \" << file << \";\";\n    of.close();\n  }\n}\n\n/**\n * Generate a map\n *\n * This is one of the main methods, it does the following steps.\n *\n * - Look for specificed databases.\n * - Scan the world for regions containing levels.\n * - Depending on settings, choose which rendering engine to use.\n * - Setup work-in-progress image to required type depending on predicted  memory\n *   use.\n * - Perform rendering phase where engine takes level information, and produces\n *   image_operations, composite all operations to the work-in-progress image.\n *   Try to distribute work evenly among threads.\n *\n */\nbool generate_map(\n    ostream& out,\n    ostream& out_log,\n    ostream& error,\n    settings_t &s,\n    std::vector<std::string>& hints,\n    fs::path& world_path,\n    fs::path& output_path)\n{\n  out << endl << \"Generating PNG Map\" << endl << endl;\n\n  // all marker source information.\n  std::vector<player> players;\n  std::vector<warp> warps;\n  std::vector<mc::marker> signs;\n\n  // this is where the actual markers will be populated later.\n  boost::ptr_vector<marker> markers;\n\n  // symbolic definition of a world.\n  mc::world world(world_path);\n\n  // where to store level info\n  levels_map levels;\n\n  // this is the rendering engine that will be used.\n  boost::shared_ptr<engine_core> engine;\n\n  // image to work against, could be backed by hard drive, or purely in memory.\n  image_ptr work_in_progress;\n\n  /**\n   * Any of these options will trigger the database blocks to run.\n   */\n  bool use_any_database =\n          s.show_players\n       || s.show_signs\n       || s.show_coordinates\n       || s.show_warps;\n\n  bool output_json =\n    s.write_json || s.write_js;\n\n  /*\n   * Look for specificed databases.\n   */\n  if (use_any_database)\n  {\n    out << \" --- LOOKING FOR DATABASES --- \" << endl;\n\n    if (s.show_warps) {\n      load_warps(out, s.show_warps_path, warps);\n    }\n\n    if (s.show_players) {\n      load_players(out, world_path / \"players\", players, s.show_players_set);\n    }\n\n    if (s.show_signs) {\n      out << \"will look for signs in levels\" << endl;\n    }\n\n    if (s.show_coordinates) {\n      out << \"will store chunk coordinates\" << endl;\n    }\n  }\n\n  {\n    out << \" --- SCANNING WORLD DIRECTORY --- \" << endl;\n    out << \"world: \" << path_string(world_path) << endl;\n  }\n\n  /*\n   * Scan the world for regions containing levels.\n   */\n  {\n    nonstd::continious<unsigned int> reporter(out, 100, dot, parts_endl);\n    mc::region_iterator iterator = world.get_iterator();\n\n    int failed_regions = 0;\n    int filtered_levels = 0;\n\n    while (iterator.has_next()) {\n      mc::region_ptr region = iterator.next();\n\n      try {\n        region->read_header();\n      } catch(mc::bad_region& e) {\n        ++failed_regions;\n        out_log << path_string(region->get_path()) << \": could not read header\" << std::endl;\n        continue;\n      }\n\n      std::list<mc::utils::level_coord> coords;\n\n      region->read_coords(coords);\n\n      BOOST_FOREACH(mc::utils::level_coord c, coords) {\n        mc::level_info::level_info_ptr level(new mc::level_info(region, c));\n\n        mc::utils::level_coord coord = level->get_coord();\n\n        if (s.coord_out_of_range(coord)) {\n          ++filtered_levels;\n          out_log << level->get_path() << \": (z,x) position\"\n                  << \" (\" << coord.get_z() << \",\" << coord.get_x() << \")\"\n                  << \" out of limit\" << std::endl;\n          continue;\n        }\n\n        mc::rotated_level_info rlevel =\n          mc::rotated_level_info(level, coord.rotate(s.rotation));\n\n        levels.insert(levels_map::value_type(rlevel.get_coord(), rlevel));\n\n        world.update(rlevel.get_coord());\n        reporter.add(1);\n      }\n    }\n\n    reporter.done(0);\n\n    if (failed_regions > 0) {\n      out << \"SEE LOG: \" << failed_regions << \" region(s) failed!\" << endl;\n    }\n\n    if (filtered_levels > 0) {\n      out << \"SEE LOG: \" << filtered_levels << \" level(s) filtered!\" << endl;\n    }\n  }\n\n  if (levels.size() <= 0) {\n    out << \"No chunks to render\" << endl;\n    return 0;\n  }\n\n  if (s.debug) {\n    out << \" --- DEBUG WORLD INFO --- \" << endl;\n    out << \"mc::world\" << endl;\n    out << \"  min_x: \" << world.min_x << endl;\n    out << \"  max_x: \" << world.max_x << endl;\n    out << \"  min_z: \" << world.min_z << endl;\n    out << \"  max_z: \" << world.max_z << endl;\n    out << \"  levels: \" << levels.size() << endl;\n    out << \"  radius: \" << s.max_radius << endl;\n    out << \"  chunk pos: \" << world.chunk_x << \"x\" << world.chunk_y << endl;\n  }\n\n  engine_settings engine_s;\n\n  engine_s.rotation = s.rotation;\n  engine_s.night = s.night;\n  engine_s.heightmap = s.heightmap;\n  engine_s.striped_terrain = s.striped_terrain;\n  engine_s.hellmode = s.hellmode;\n  engine_s.cavemode = s.cavemode;\n  engine_s.top = s.top;\n  engine_s.bottom = s.bottom;\n\n  if (s.engine_use) {\n    dl_t* dl = dl_open(path_string(s.engine_path).c_str());\n\n    if (dl == NULL) {\n      error << \"Failed to open library: \" << path_string(s.engine_path) << endl;\n      return false;\n    }\n\n    return true;\n  }\n  else {\n    /**\n     * Depending on settings, choose which rendering engine to use.\n     */\n    switch (s.mode) {\n      case Top:\n        engine.reset(new topdown_engine(engine_s, world));\n        break;\n\n      case Oblique:\n        engine.reset(new oblique_engine(engine_s, world));\n        break;\n\n      case ObliqueAngle:\n        engine.reset(new obliqueangle_engine(engine_s, world));\n        break;\n\n      case Isometric:\n        engine.reset(new isometric_engine(engine_s, world));\n        break;\n\n      case FatIso:\n        engine.reset(new fatiso_engine(engine_s, world));\n        break;\n    }\n  }\n\n  /**\n   * Setup work-in-progress image to required type depending on predicted memory\n   * use.\n   */\n  {\n    pos_t image_width, image_height;\n    pos_t level_width, level_height;\n\n    engine->get_boundaries(image_width, image_height);\n    engine->get_level_boundaries(level_width, level_height);\n\n    pos_t memory_usage = (image_width * image_height * sizeof(color)) / 0x100000;\n\n    if (memory_usage >= s.memory_limit) {\n      {\n        out << \" --- BUILDING SWAP --- \" << endl;\n        out << \"NOTE: A swap file is being built to accommodate high memory usage\" << endl;\n        out << \"swap file: \" << s.swap_file << endl;\n\n        out << \"swap size: \" << memory_usage << \" MB\" << endl;\n        out << \"memory limit: \" << s.memory_limit << \" MB\" << endl;\n      }\n\n      cached_image* image;\n\n      try {\n        image = new cached_image(s.swap_file, image_width, image_height, level_width, level_height);\n      } catch(std::ios::failure& e) {\n        if (errno != 0) {\n          error << s.swap_file << \": \" << strerror(errno);\n        } else {\n          error << s.swap_file << \": \" << e.what() << \": could not open file\";\n        }\n\n        return false;\n      }\n\n      work_in_progress.reset(image);\n\n      nonstd::limited<streampos> c(out, 1024 * 1024, image->get_size(), dot, mb_endl);\n\n      try {\n        image->build(c);\n      } catch(std::ios::failure& e) {\n        if (errno != 0) {\n          error << s.swap_file << \": could not build cache: \" << strerror(errno);\n        } else {\n          error << s.swap_file << \": could not build cache: \" << e.what();\n        }\n\n        return false;\n      }\n    } else {\n      {\n        out << \" --- ALLOCATING MEMORY --- \" << endl;\n        out << \"memory usage: \" << memory_usage << \" MB\" << endl;\n        out << \"memory limit: \" << s.memory_limit << \" MB\" << endl;\n      }\n\n      work_in_progress.reset(new memory_image(image_width, image_height));\n    }\n  }\n\n  /* reset image limits for cropping */\n  engine->reset_image_limits();\n\n  /**\n   * Perform rendering phase where engine takes level information, and produces\n   * image_operations, composite all operations to the work-in-progress image.\n   * Try to distribute work evenly among threads.\n   */\n  {\n    out << \" --- RENDERING --- \" << endl;\n\n    unsigned int world_size = levels.size();\n\n    int effective_threads = s.threads - 1;\n\n    if (effective_threads <= 1) {\n      effective_threads = 1;\n    }\n\n    int cache_hits = 0;\n    int failed_levels = 0;\n\n    /**\n     * Define a dynamically growing buffer to read regions in.\n     * Is grown on demand, but never shrunk.\n     */\n    mc::dynamic_buffer region_buffer(mc::region::CHUNK_MAX);\n\n    nonstd::limited<unsigned int> reporter(out, 50, world_size, dot, parts_perc_endl);\n\n    uint32_t id = 1;\n\n    BOOST_FOREACH(levels_map::value_type value, levels) {\n      reporter.add(1);\n\n      mc::rotated_level_info rotated_level_info = value.second;\n      mc::level_info_ptr level_info = rotated_level_info.get_level();\n\n      mc::level_ptr level(new mc::level(level_info));\n      fs::path path = level_info->get_path();\n\n      try {\n        level->read(region_buffer);\n      } catch(mc::invalid_file& e) {\n        out_log << path << \": \" << e.what() << endl;\n        continue;\n      }\n\n      mc::utils::level_coord coord = rotated_level_info.get_coord();\n\n      image_operations_ptr operations(new image_operations(id++));\n\n      bool cache_hit = false;\n      time_t mod = level->modification_time();\n\n      std::stringstream ss;\n      ss << boost::format(\"%d.%d.cmap\") % coord.get_x() % coord.get_z();\n      std::string basename = ss.str();\n\n      fs::path level_dir = mc::utils::level_dir(s.cache_dir, coord.get_x(), coord.get_z());\n      cache_file cache(level_dir, basename, mod, s.cache_compress);\n\n      if (s.cache_use) {\n        if (cache.exists()) {\n          if (cache.read(operations)) {\n            cache_hit = true;\n          }\n\n          cache.clear();\n        }\n      }\n\n      if (!cache_hit) {\n        engine->render(level, operations);\n      }\n\n      //operations->optimize();\n\n      if (s.cache_use) {\n        // create the necessary directories required when caching\n        cache.create_directories();\n\n        // ignore failure while writing the operations to cache\n        if (!cache.write(operations)) {\n          // on failure, remove the cache file - this will prompt c10t to regenerate it next time\n          cache.clear();\n        }\n      }\n\n      if (s.debug) { out << path_string(path) << \": dequeued OK\" << endl; }\n\n      if (cache_hit) {\n        ++cache_hits;\n      }\n\n      //if (p.signs.size() > 0) {\n        //if (s.debug) { out << \"Found \" << p.signs.size() << \" signs\"; };\n        //signs.insert(signs.end(), p.signs.begin(), p.signs.end());\n      //}\n\n      try {\n        pos_t x, y;\n        engine->w2pt(coord.get_x(), coord.get_z(), x, y);\n\n        // update image limits\n        engine->update_image_limits(\n            x + 1, y,\n            x + operations->max_x,\n            y + operations->max_y - 1);\n\n        work_in_progress->composite(x, y, operations);\n      } catch(std::ios::failure& e) {\n        out << path_string(s.swap_file) << \": \" << strerror(errno);\n        return false;\n      }\n    }\n\n    reporter.done(0);\n\n    if (failed_levels > 0) {\n      out << \"SEE LOG: \" << failed_levels << \" level(s) failed!\" << endl;\n    }\n\n    if (s.cache_use) {\n      out << \"cache_hits: \" << cache_hits << \"/\" << world_size << endl;\n    }\n\n    out << \"image limits: \"\n        << engine->get_min_x() << \"x\" << engine->get_min_y() << \" to \"\n        << engine->get_max_x() << \"x\" << engine->get_max_y()\n        << \" will be the cropped image (\"\n        << (engine->get_max_x() - engine->get_min_x()) << \"x\"\n        << (engine->get_max_y() - engine->get_min_y())\n        << \")\" << endl;\n\n    image_ptr cropped = image::crop(work_in_progress, engine->get_min_x(), engine->get_max_x(), engine->get_min_y(), engine->get_max_y());\n    work_in_progress = cropped;\n  }\n\n  if (use_any_database) {\n    text::font_face font(s.ttf_path, s.ttf_size, s.ttf_color);\n\n    /*\n     * If we are only going to output json information, do not initialize font.\n     * This will prevent any fonts from actually rendering anything later on.\n     */\n    if (!output_json) {\n      try {\n        font.init();\n      } catch(text::text_error& e) {\n        error << \"failed to initialize font: \" << e.what() << std::endl;\n      }\n    }\n\n    if (s.show_players) {\n      push_player_markers(s, font, players, markers);\n    }\n\n    if (s.show_signs && signs.size() > 0) {\n      push_sign_markers(s, font, signs, markers);\n    }\n\n    if (s.show_coordinates) {\n      push_coordinate_markers(out, s, font, world, levels, markers);\n    }\n\n    if (s.show_warps) {\n      push_warp_markers(s, font, warps, markers);\n    }\n\n  }\n\n  if (output_json) {\n    if (!use_any_database) {\n      hints.push_back(\"Use `--write-json' in combination with `--show-*'\"\n          \" in order to write different types of markers to file\");\n    }\n\n    write_json_file(out, s, engine, world, markers);\n  }\n  else {\n    overlay_markers(s, work_in_progress, engine, markers);\n  }\n\n  engine_core::pos_t center_x, center_y;\n  engine->wp2pt(0, 0, 0, center_x, center_y);\n\n  if (s.use_split) {\n    out << \" --- SAVING MULTIPLE IMAGES --- \" << endl;\n\n    int i = 0;\n\n    image_ptr target;\n\n    BOOST_FOREACH(unsigned int split_i, s.split) {\n      if (!target && s.split_base > 0) {\n        target.reset(new memory_image(s.split_base, s.split_base));\n      }\n\n      std::map<point2, image_base*> parts;\n\n      image::split(work_in_progress, split_i, parts);\n\n      out << \"Level \" << i << \": splitting into \" << parts.size()\n          << \" image on \" << split_i << \"px\" << endl;\n\n      for (std::map<point2, image_base*>::iterator it = parts.begin(); it != parts.end(); it++) {\n        const point2 p = it->first;\n        image_ptr img(it->second);\n\n        stringstream ss;\n        ss << boost::format(path_string(output_path)) % i % p.x % p.y;\n        fs::path path(ss.str());\n\n        if (!fs::is_directory(path.parent_path())) {\n          fs::create_directories(path.parent_path());\n        }\n\n        png_format::opt_type opts;\n\n        opts.center_x = center_x;\n        opts.center_y = center_y;\n        opts.comment = C10T_COMMENT;\n\n        std::string path_str(path_string(path));\n\n        if (s.split_base > 0) {\n          target->clear();\n          img->resize(target);\n        }\n        else {\n          target = img;\n        }\n\n        try {\n          target->save<png_format>(path_str, opts);\n        } catch (format_exception& e) {\n          out << path_string(path) << \": \" << e.what() << endl;\n          continue;\n        }\n\n        out << path_string(path) << \": OK\" << endl;\n      }\n\n      ++i;\n    }\n  }\n  else {\n    {\n      out << \" --- SAVING IMAGE --- \" << endl;\n      out << \"path: \" << path_string(output_path) << endl;\n    }\n\n    png_format::opt_type opts;\n\n    opts.center_x = center_x;\n    opts.center_y = center_y;\n    opts.comment = C10T_COMMENT;\n\n    try {\n      work_in_progress->save<png_format>(path_string(output_path), opts);\n    } catch (format_exception& e) {\n      out << path_string(output_path) << \": \" << e.what() << endl;\n      return false;\n    }\n\n    out << path_string(output_path) << \": OK\" << endl;\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "src/generate_map.hpp",
    "content": "#ifndef __GENERATE_MAP_HPP__\n#define __GENERATE_MAP_HPP__\n\n#include <ostream>\n#include <vector>\n#include <string>\n#include <boost/filesystem.hpp>\n\n#include \"settings_t.hpp\"\n\nbool generate_map(\n    std::ostream& out,\n    std::ostream& out_log,\n    std::ostream& error,\n    settings_t &s,\n    std::vector<std::string>& hints,\n    boost::filesystem::path& world_path,\n    boost::filesystem::path& output_path);\n\n#endif /*__GENERATE_MAP_HPP__*/\n"
  },
  {
    "path": "src/generate_statistics.cpp",
    "content": "#include \"altitude_graph.hpp\"\n\n#include \"generate_statistics.hpp\"\n\n#include \"mc/blocks.hpp\"\n#include \"mc/region_iterator.hpp\"\n#include \"mc/level_info.hpp\"\n#include \"mc/level.hpp\"\n\n#include \"players.hpp\"\n#include \"main_utils.hpp\"\n#include \"engine/block_rotation.hpp\"\n\n#include <iomanip>\n\n#include <boost/foreach.hpp>\n#include <boost/optional.hpp>\n\nusing namespace std;\n\ntemplate<typename T>\nvoid dot(std::ostream& out, T total)\n{\n  if (total == 0x00) {\n    out << \" done!\";\n  }\n  else {\n    out << \".\" << std::flush;\n  }\n}\n\nvoid uint_endl(std::ostream& out, unsigned int total)\n{\n  out << \" \" << setw(8) << total << \" parts\" << endl;\n}\n\nbool generate_statistics(\n    std::ostream& out,\n    std::ostream& out_log,\n    std::ostream& error,\n    settings_t &s,\n    std::vector<std::string>& hints,\n    fs::path& world_path,\n    fs::path& output_path)\n{\n    out << endl << \"Generating Statistics File\" << endl << endl;\n    std::vector<player> players;\n    mc::world world(world_path);\n\n    AltitudeGraph *_stat = new AltitudeGraph(s);\n\n    mc::MaterialT *materials = mc::MaterialTable.data();\n    long statistics[mc::MaterialTable.size()];\n\n    for (int i = 0; i < mc::MaterialTable.size(); i++) {\n      statistics[i] = 0;\n    }\n\n    boost::optional<mc::MaterialT*> graph_block;\n    {\n        mc::MaterialT *material;\n        if(get_blocktype(s.graph_block, material)) {\n            graph_block = boost::optional<mc::MaterialT*>(material);\n        } else {\n            graph_block = boost::optional<mc::MaterialT*>();\n        }\n    }\n\n    bool any_db =\n      s.show_players\n      || s.show_signs\n      || s.show_coordinates\n      || s.show_warps;\n\n    if (any_db) {\n      out << \" --- LOOKING FOR DATABASES --- \" << endl;\n\n      if (s.show_players) {\n        error << \"loading of players in altitiude graph has been disabled\" << endl;\n      }\n      //if (s.show_players) {\n        //load_players(out, world_path / \"players\", players, s.show_players_set);\n      //}\n    }\n\n    int failed_regions = 0;\n    int filtered_levels = 0;\n    int failed_levels = 0;\n    int levels = 0;\n\n    {\n      nonstd::continious<unsigned int> reporter(out, 100, dot, uint_endl);\n      mc::region_iterator iterator = world.get_iterator();\n\n      mc::dynamic_buffer region_buffer(mc::region::CHUNK_MAX);\n\n      while (iterator.has_next()) {\n        mc::region_ptr region = iterator.next();\n\n        try {\n          region->read_header();\n        } catch(mc::bad_region& e) {\n          ++failed_regions;\n          out_log << region->get_path() << \": could not read header\" << std::endl;\n          continue;\n        }\n\n        std::list<mc::utils::level_coord> coords;\n\n        region->read_coords(coords);\n\n        BOOST_FOREACH(mc::utils::level_coord c, coords) {\n          mc::level_info::level_info_ptr level(new mc::level_info(region, c));\n\n          mc::utils::level_coord coord = level->get_coord();\n          ++levels;\n\n          if (s.coord_out_of_range(coord)) {\n            ++filtered_levels;\n            out_log << level->get_path() << \": (z,x) position\"\n                    << \" (\" << coord.get_z() << \",\" << coord.get_x() << \")\"\n                    << \" out of limit\" << std::endl;\n            continue;\n          }\n\n          mc::level level_data(level);\n\n          world.update(level->get_coord());\n\n          try {\n            level_data.read(region_buffer);\n          } catch(mc::invalid_file& e) {\n            ++failed_levels;\n            out_log << level->get_path() << \": \" << e.what();\n            continue;\n          }\n\n          boost::shared_ptr<mc::Level_Compound> L = level_data.get_level();\n          BOOST_FOREACH(mc::Section_Compound Section, L->Sections) {\n            block_rotation br_blocks(0, Section.Blocks);\n            block_rotation br_data(0, Section.Data);\n\n            for (int y = 15; y >= 0; y--) {\n                int abs_y = (Section.Y * 16) + y;\n\n                for (int z = 0; z < mc::MapZ; z++) {\n                    for (int x = 0; x < mc::MapX; x++) {\n                        br_blocks.set_xz(x, z);\n                        br_data.set_xz(x, z);\n\n                        int block_type = br_blocks.get8(y);\n                        int block_data = br_data.get4(y);\n                        boost::optional<mc::MaterialT*> material = mc::get_material_legacy(block_type, block_data);\n\n                        if (material) {\n                            if (material.get()->enabled) {\n                                size_t index = material.get() - materials;\n                                statistics[index] += 1;\n                            }\n                            if(graph_block && material.get() == graph_block.get()) {\n                                _stat->registerBloc(material.get(), abs_y);\n                            }\n                        }\n                    }\n                }\n            }\n          }\n\n          reporter.add(1);\n        }\n      }\n\n      reporter.done(0);\n\n      if (failed_regions > 0)\n      {\n        out << \"SEE LOG: \" << failed_regions << \" region(s) failed!\" << endl;\n      }\n\n      if (filtered_levels > 0)\n      {\n        out << \"SEE LOG: \" << filtered_levels << \" level(s) filtered!\" << endl;\n      }\n\n      if (failed_levels > 0)\n      {\n        out << \"SEE LOG: \" << failed_levels << \" level(s) failed!\" << endl;\n      }\n    }\n\n    ofstream stats(path_string(output_path).c_str());\n\n    stats << \"[WORLD]\" << endl;\n\n    stats << \"min_x \" << world.min_x << endl;\n    stats << \"max_x \" << world.max_x << endl;\n    stats << \"min_z \" << world.min_z << endl;\n    stats << \"max_z \" << world.max_z << endl;\n    stats << \"chunks \" << (levels-filtered_levels-failed_levels)\n                       << \" of \" << levels << endl;\n\n    if (s.show_players) {\n      stats << \"[PLAYERS]\" << endl;\n\n      std::vector<player>::iterator plit = players.begin();\n\n      for (; plit != players.end(); plit++) {\n        player p = *plit;\n        stats << p.name << \" \" << p.xPos << \" \" << p.yPos << \" \" << p.zPos << endl;\n      }\n    }\n\n    stats << \"[BLOCKS]\" << endl;\n    for (int i = 0; i < mc::MaterialTable.size(); i++) {\n      if (statistics[i] > 0) {\n        std::string full_name = mc::MaterialTable[i].mc_namespace + \":\" + mc::MaterialTable[i].name;\n        stats << std::left << setw(32) << full_name << \" \" << statistics[i] << endl;\n      }\n    }\n\n    stats.close();\n\n    if (stats.fail()) {\n      error << \"failed to write statistics to \" << output_path;\n      return false;\n    }\n\n    out << \"statistics written to \" << output_path;\n\n    if(graph_block)\n        _stat->createGraph();\n\n    return true;\n}\n"
  },
  {
    "path": "src/generate_statistics.hpp",
    "content": "#ifndef __GENERATE_STATISTICS_HPP__\n#define __GENERATE_STATISTICS_HPP__\n\n#include <ostream>\n#include <vector>\n#include <string>\n\n#include <boost/filesystem.hpp>\n\n#include \"settings_t.hpp\"\n\nbool generate_statistics(\n    std::ostream& out,\n    std::ostream& out_log,\n    std::ostream& error,\n    settings_t &s,\n    std::vector<std::string>& hints,\n    boost::filesystem::path& world_path,\n    boost::filesystem::path& output_path);\n\n#endif /*__GENERATE_STATISTICS_HPP__*/\n"
  },
  {
    "path": "src/image/CMakeLists.txt",
    "content": "add_library(c10t-image \n  image_operations.cpp\n  image_base.cpp\n  memory_image.cpp\n  cached_image.cpp\n  color.cpp\n  algorithms.cpp\n  ${ZLIB_LIBRARIES} ${PNG_LIBRARIES})\n\nset_target_properties(c10t-image PROPERTIES COMPILE_FLAGS \"-O3 -Wall -pedantic -g\")\n"
  },
  {
    "path": "src/image/algorithms.cpp",
    "content": "#include \"image/algorithms.hpp\"\n\nnamespace image {\n  image_ptr crop(image_ptr base, pos_t min_x, pos_t max_x, pos_t min_y, pos_t max_y)\n  {\n    image_ptr ptr(new virtual_image(max_x - min_x, max_y - min_y, base, min_x, min_y));\n    return ptr;\n  }\n}\n"
  },
  {
    "path": "src/image/algorithms.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef __IMAGE_ALGORITHMS__\n#define __IMAGE_ALGORITHMS__\n\n#include \"image/image_base.hpp\"\n#include \"image/virtual_image.hpp\"\n\n#include \"2d/cube.hpp\"\n\n#include <map>\n\nnamespace image {\n  /**\n   * Split an image into multiple smaller images based on a specific pixel size.\n   */\n  template<typename M>\n  void split(image_ptr base, int pixels, M& map)\n  {\n    for (pos_t w = 0, px = 0; w < base->get_width(); w += pixels, px++) {\n      for (pos_t h = 0, py = 0; h < base->get_height(); h += pixels, py++) {\n        map[point2(px, py)] = new virtual_image(pixels, pixels, base, w, h);\n      }\n    }\n  }\n\n  image_ptr crop(image_ptr base, pos_t min_x, pos_t max_x, pos_t min_y, pos_t max_y);\n}\n\n#endif /*__IMAGE_ALGORITHMS__*/\n"
  },
  {
    "path": "src/image/cached_image.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n\n#include \"image/cached_image.hpp\"\n\n#include \"algorithm.hpp\"\n\ncached_image::cached_image(const fs::path path, pos_t w, pos_t h, pos_t l_w, pos_t l_h) :\n  image_base(w, h),\n  path(path),\n  buffer_size((l_w + 1) * l_h),\n  buffer_set(false),\n  buffer(new color[buffer_size]),\n  buffer_w(0),\n  buffer_h(0),\n  buffer_x(0),\n  buffer_y(0)\n{\n  using namespace ::std;\n  fs.exceptions(ios::failbit | ios::badbit);\n  fs.open(path.string().c_str(), ios::in | ios::out | ios::trunc);\n\n  this->size =\n    boost::numeric_cast<streampos>(get_width()) *\n    boost::numeric_cast<streampos>(get_height()) *\n    sizeof(color);\n}\n\ncached_image::~cached_image() {\n  flush_buffer();\n  fs.close();\n}\n\nstd::streampos cached_image::get_size()\n{\n  return size;\n}\n\n// cached_image\nvoid cached_image::set_pixel(pos_t x, pos_t y, color& c)\n{\n  if (!(x < get_width())) { return; }\n  if (!(y < get_height())) { return; }\n  \n  fs.seekp(sizeof(color) * get_offset(x, y));\n  fs.write(reinterpret_cast<char*>(&c), sizeof(color));\n}\n\nvoid cached_image::get_pixel(pos_t x, pos_t y, color& c)\n{\n  if (!(x < get_width())) { return; }\n  if (!(y < get_height())) { return; }\n  \n  fs.seekg(sizeof(color) * get_offset(x, y));\n  fs.read(reinterpret_cast<char*>(&c), sizeof(color));\n}\n\nvoid cached_image::get_line(pos_t y, pos_t x, pos_t width, color* c)\n{\n  if (!(y < get_height())) { return; }\n  if (!(x < get_width())) { return; }\n  if (!(width + x < get_width())) { width = get_width() - x; }\n  \n  fs.seekg(sizeof(color) * get_offset(x, y));\n  fs.read(reinterpret_cast<char*>(c), sizeof(color) * width);\n}\n\nvoid cached_image::set_line(pos_t y, pos_t x, pos_t width, color* c)\n{\n  if (!(y < get_height())) { return; }\n  if (!(x < get_width())) { return; }\n  if (!(width + x < get_width())) { width = get_width() - x; }\n  \n  fs.seekp(sizeof(color) * get_offset(x, y));\n  fs.write(reinterpret_cast<char*>(c), sizeof(color) * width);\n}\n\nvoid cached_image::flush_buffer()\n{\n  if (buffer_set)\n  {\n    for (pos_t y = 0; y < buffer_h; y++) {\n      set_line(buffer_y + y, buffer_x, buffer_w, &buffer[y * buffer_w]);\n    }\n  }\n}\n\nvoid cached_image::read_buffer()\n{\n  for (pos_t y = 0; y < buffer_h; y++) {\n    get_line(buffer_y + y, buffer_x, buffer_w, &buffer[y * buffer_w]);\n  }\n}\n\nvoid cached_image::blend_pixel(pos_t x, pos_t y, color &c)\n{\n  // do nothing if color is invisible\n  if (c.is_invisible()) { return; }\n  \n  pos_t bx = x - buffer_x;\n  pos_t by = y - buffer_y;\n  pos_t bp = bx + by * buffer_w;\n\n  if (x >= buffer_x && y >= buffer_y && bp < buffer_size) {\n    buffer[bp].blend(c);\n  } else {\n    // Blend pixels that are \"out of (the buffer's) scope\"\n    color o;\n    get_pixel(x, y, o);\n    o.blend(c);\n    set_pixel(x, y, o);\n  }\n}\n\n\nvoid cached_image::align(pos_t x, pos_t y, pos_t w, pos_t h)\n{\n  flush_buffer();\n  \n  // reallocate buffer when the current buffer is too small\n  if (buffer_size < w * h) {\n    buffer.reset(new color[w * h]);\n    buffer_size = w * h;\n  }\n  \n  buffer_x = x, buffer_y = y;\n  buffer_w = w, buffer_h = h;\n  \n  read_buffer();\n  \n  buffer_set = true;\n}\n"
  },
  {
    "path": "src/image/cached_image.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef CACHED_IMAGE\n#define CACHED_IMAGE\n\n#include <fstream>\n#include <cstring>\n\n#include <boost/numeric/conversion/cast.hpp>\n#include <boost/scoped_array.hpp>\n#include <boost/filesystem.hpp>\n\n#include \"image/image_base.hpp\"\n#include \"image/color.hpp\"\n\n#include \"algorithm.hpp\"\n\nnamespace fs = boost::filesystem;\n\nclass cached_image : public image_base {\npublic:\n  static const pos_t WRITE_SIZE = 4096 * 8;\n  \n  cached_image(const fs::path path, pos_t w, pos_t h, pos_t l_w, pos_t l_h);\n  ~cached_image();\n  \n  /**\n   * Will build the cache from scratch, filling it with null, which coneniently fits\n   * with black transparent colors.\n   *\n   * @reporter Any type which supports 'set_limit', 'add' and 'done' functions.\n   */\n  template<typename R>\n  void build(R& reporter)\n  {\n    using namespace ::std;\n    \n    streampos written = 0;\n    \n    streampos write_size = WRITE_SIZE;\n    \n    boost::scoped_array<char> nil(new char[write_size]);\n    ::memset(nil.get(), 0x0, write_size);\n    \n    while (written < size) {\n      streampos write = min(size, write_size);\n      fs.write(nil.get(), write);\n      written += write;\n      \n      reporter.add(write);\n    }\n    \n    reporter.done(0);\n  }\n\n  std::streampos get_size();\n  \n  void set_pixel(pos_t x, pos_t y, color&);\n  void get_pixel(pos_t x, pos_t y, color&);\n  \n  /*\n   * This is where you may use caching or whatever mechanism.\n   *\n   * It is guaranteed that no other points will be used\n   * except for those that has previously been declared\n   * with 'align'.\n   *\n   * @see #align\n   **/\n  void blend_pixel(pos_t x, pos_t y, color &c);\n\n  /*\n   * Read a list of colors.\n   * The pointer color must contain all necessary colors.\n   * \n   * The rationale for this method is that it usually is much more efficient\n   * to have a continious set of colors read/written since it usually is more\n   * efficient. While letting the single operations be made against memory.\n   *\n   * This method must assert that the result reflects the same as the backend\n   * store, usually means that you actually have to read from it.\n   **/\n  void get_line(pos_t y, pos_t x, pos_t width, color*);\n  \n  /*\n   * Set a list of colors.\n   * @see #get_line\n   **/\n  void set_line(pos_t y, pos_t x, pos_t width, color*);\n  \n  /*\n   * Align whatever caching mechanism might be used to only expect blend requests for these areas.\n   **/\n  void align(pos_t x, pos_t y, pos_t w, pos_t h);\nprivate:\n  const fs::path path;\n  std::fstream fs;\n  \n  pos_t buffer_size;\n  bool buffer_set;\n  boost::scoped_array<color> buffer;\n\n  std::streampos size;\n\n  pos_t buffer_w;\n  pos_t buffer_h;\n  pos_t buffer_x;\n  pos_t buffer_y;\n\n  void read_buffer();\n  void flush_buffer();\n};\n\n#endif /* CACHED_IMAGE */\n"
  },
  {
    "path": "src/image/color.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"image/color.hpp\"\n\n#include <sstream>\n#include <string>\n\nfloat color_i_to_f[] = {\n    0.0000f, 0.0039f, 0.0078f, 0.0118f, 0.0157f, 0.0196f, 0.0235f, 0.0275f,\n    0.0314f, 0.0353f, 0.0392f, 0.0431f, 0.0471f, 0.0510f, 0.0549f, 0.0588f,\n    0.0627f, 0.0667f, 0.0706f, 0.0745f, 0.0784f, 0.0824f, 0.0863f, 0.0902f,\n    0.0941f, 0.0980f, 0.1020f, 0.1059f, 0.1098f, 0.1137f, 0.1176f, 0.1216f,\n    0.1255f, 0.1294f, 0.1333f, 0.1373f, 0.1412f, 0.1451f, 0.1490f, 0.1529f,\n    0.1569f, 0.1608f, 0.1647f, 0.1686f, 0.1725f, 0.1765f, 0.1804f, 0.1843f,\n    0.1882f, 0.1922f, 0.1961f, 0.2000f, 0.2039f, 0.2078f, 0.2118f, 0.2157f,\n    0.2196f, 0.2235f, 0.2275f, 0.2314f, 0.2353f, 0.2392f, 0.2431f, 0.2471f,\n    0.2510f, 0.2549f, 0.2588f, 0.2627f, 0.2667f, 0.2706f, 0.2745f, 0.2784f,\n    0.2824f, 0.2863f, 0.2902f, 0.2941f, 0.2980f, 0.3020f, 0.3059f, 0.3098f,\n    0.3137f, 0.3176f, 0.3216f, 0.3255f, 0.3294f, 0.3333f, 0.3373f, 0.3412f,\n    0.3451f, 0.3490f, 0.3529f, 0.3569f, 0.3608f, 0.3647f, 0.3686f, 0.3725f,\n    0.3765f, 0.3804f, 0.3843f, 0.3882f, 0.3922f, 0.3961f, 0.4000f, 0.4039f,\n    0.4078f, 0.4118f, 0.4157f, 0.4196f, 0.4235f, 0.4275f, 0.4314f, 0.4353f,\n    0.4392f, 0.4431f, 0.4471f, 0.4510f, 0.4549f, 0.4588f, 0.4627f, 0.4667f,\n    0.4706f, 0.4745f, 0.4784f, 0.4824f, 0.4863f, 0.4902f, 0.4941f, 0.4980f,\n    0.5020f, 0.5059f, 0.5098f, 0.5137f, 0.5176f, 0.5216f, 0.5255f, 0.5294f,\n    0.5333f, 0.5373f, 0.5412f, 0.5451f, 0.5490f, 0.5529f, 0.5569f, 0.5608f,\n    0.5647f, 0.5686f, 0.5725f, 0.5765f, 0.5804f, 0.5843f, 0.5882f, 0.5922f,\n    0.5961f, 0.6000f, 0.6039f, 0.6078f, 0.6118f, 0.6157f, 0.6196f, 0.6235f,\n    0.6275f, 0.6314f, 0.6353f, 0.6392f, 0.6431f, 0.6471f, 0.6510f, 0.6549f,\n    0.6588f, 0.6627f, 0.6667f, 0.6706f, 0.6745f, 0.6784f, 0.6824f, 0.6863f,\n    0.6902f, 0.6941f, 0.6980f, 0.7020f, 0.7059f, 0.7098f, 0.7137f, 0.7176f,\n    0.7216f, 0.7255f, 0.7294f, 0.7333f, 0.7373f, 0.7412f, 0.7451f, 0.7490f,\n    0.7529f, 0.7569f, 0.7608f, 0.7647f, 0.7686f, 0.7725f, 0.7765f, 0.7804f,\n    0.7843f, 0.7882f, 0.7922f, 0.7961f, 0.8000f, 0.8039f, 0.8078f, 0.8118f,\n    0.8157f, 0.8196f, 0.8235f, 0.8275f, 0.8314f, 0.8353f, 0.8392f, 0.8431f,\n    0.8471f, 0.8510f, 0.8549f, 0.8588f, 0.8627f, 0.8667f, 0.8706f, 0.8745f,\n    0.8784f, 0.8824f, 0.8863f, 0.8902f, 0.8941f, 0.8980f, 0.9020f, 0.9059f,\n    0.9098f, 0.9137f, 0.9176f, 0.9216f, 0.9255f, 0.9294f, 0.9333f, 0.9373f,\n    0.9412f, 0.9451f, 0.9490f, 0.9529f, 0.9569f, 0.9608f, 0.9647f, 0.9686f,\n    0.9725f, 0.9765f, 0.9804f, 0.9843f, 0.9882f, 0.9922f, 0.9961f, 1.0000f\n};\n\nfloat alpha_over_c(float u, float o, float ua, float oa);\n\n/**\n * Takes two color values and does an alpha over blending without using floats.\n */\ninline float alpha_over_c(float ac, float aa, float bc, float ba) {\n  return (ac * aa) + (bc * ba - aa * bc * ba);\n}\n\nvoid color::blend(const color &other) {\n  if (other.is_invisible()) return;\n\n  if (other.is_opaque() || is_invisible()) {\n    r = other.r;\n    g = other.g;\n    b = other.b;\n    a = other.a;\n    return;\n  }\n  \n  r = alpha_over_c(other.r, other.a, r, a);\n  g = alpha_over_c(other.g, other.a, g, a);\n  b = alpha_over_c(other.b, other.a, b, a);\n  a = a + other.a * (1.0f - a);\n  r = ((r * 1.0f) / a);\n  g = ((g * 1.0f) / a);\n  b = ((b * 1.0f) / a);\n}\n\n// pull color down towards black\nvoid color::darken(float f) {\n  r = std::max(r - (r * f), 0.0f);\n  g = std::max(g - (g * f), 0.0f);\n  b = std::max(b - (b * f), 0.0f);\n}\n\nvoid color::darken(int f) {\n  darken(color_i_to_f[uint8_t(f)]);\n}\n\nvoid color::lighten(float f) {\n  r = std::min(r + (r * f), 1.0f);\n  g = std::min(g + (g * f), 1.0f);\n  b = std::min(b + (b * f), 1.0f);\n}\n\nvoid color::lighten(int f) {\n  lighten(color_i_to_f[uint8_t(f)]);\n}\n"
  },
  {
    "path": "src/image/color.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef COLOR_HPP\n#define COLOR_HPP\n\n#include <stdint.h>\n#include <assert.h>\n#include <math.h>\n\n#include <string>\n#include <sstream>\n#include <ostream>\n\n#include <boost/lexical_cast.hpp>\n\nextern float color_i_to_f[0x100];\n\nstruct color{\n  float r;\n  float g;\n  float b;\n  float a;\n  int32_t z;\n\n  color(color *c)\n    : r(c->r),\n      g(c->g),\n      b(c->b),\n      a(c->a),\n      z(0)\n  {\n  }\n\n  color()\n    : r(1.0f),\n      g(1.0f),\n      b(1.0f),\n      a(0.0f),\n      z(0)\n  {\n  }\n\n  color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)\n    : r(color_i_to_f[r]),\n      g(color_i_to_f[g]),\n      b(color_i_to_f[b]),\n      a(color_i_to_f[a]),\n      z(0)\n  {\n  }\n\n  color(int r, int g, int b, int a)\n    : r(color_i_to_f[uint8_t(r)]),\n      g(color_i_to_f[uint8_t(g)]),\n      b(color_i_to_f[uint8_t(b)]),\n      a(color_i_to_f[uint8_t(a)]),\n      z(0)\n  {\n  }\n\n  color(float r, float g, float b, float a)\n    : r(r),\n      g(g),\n      b(b),\n      a(a),\n      z(0)\n  {\n  }\n\n  bool is_opaque() const {\n    return a == 1.0f;\n  }\n\n  bool is_transparent() const {\n    return a != 1.0f;\n  }\n\n  bool is_invisible() const {\n    return a == 0.0f;\n  }\n\n  ~color(){\n  }\n\n  void darken(float c);\n  void darken(int c);\n  void lighten(float c);\n  void lighten(int c);\n  void blend(const color &other);\n\n  inline void read(color *buf) {\n    r = buf->r;\n    g = buf->g;\n    b = buf->b;\n    a = buf->a;\n  }\n\n  inline void write(color *buf) {\n    buf->r = r;\n    buf->g = g;\n    buf->b = b;\n    buf->a = a;\n  }\n\n  friend std::ostream& operator<<(std::ostream& out, const color& c) // output\n  {\n    std::stringstream ss;\n    ss << (int)roundf(c.r*255.0f) << \",\" << (int)roundf(c.g*255.0f) << \",\" << (int)roundf(c.b*255.0f) << \",\" << (int)roundf(c.a*255.0f);\n    out << ss.str();\n    return out;\n  }\n\n  bool operator!=(const color &c) const\n  {\n    return !(r == c.r && g == c.g && b == c.b && a == c.a);\n  }\n\n  bool operator==(const color &c) const\n  {\n    return r == c.r && g == c.g && b == c.b && a == c.a;\n  }\n};\n\n#endif /* COLOR_HPP */\n"
  },
  {
    "path": "src/image/format/base.hpp",
    "content": "#ifndef _IMAGE_FORMAT_BASE_HPP_\n#define _IMAGE_FORMAT_BASE_HPP_\n\n#include <exception>\n\nclass format_exception : public std::exception\n{\nprivate:\n  const char* why;\npublic:\n  format_exception(const char* why) : why(why) { }\n  \n  const char* what() throw() {\n    return this->why;\n  }\n};\n\n#endif /* _IMAGE_FORMAT_BASE_HPP_ */\n"
  },
  {
    "path": "src/image/format/png.hpp",
    "content": "#ifndef FILEFORMAT_PNG\n#define FILEFORMAT_PNG\n\n#include <png.h>\n#include <zlib.h>\n\n#include \"image/format/base.hpp\"\n#include \"image/image_base.hpp\"\n\n#include <boost/lexical_cast.hpp>\n\nstruct png_config {\n  std::string comment;\n  size_t center_x, center_y;\n};\n\nclass png_format {\n  public:\n    typedef png_config opt_type;\n\n    static void save(image_base* image, const std::string& path, opt_type& opts)\n    {\n      FILE *fp;\n      png_structp write_struct = NULL;\n      png_infop info_struct = NULL;\n      png_bytep bytes_row = NULL;\n      color* color_row = NULL;\n\n      fp = fopen(path.c_str(), \"wb\");\n\n      if (fp == NULL)\n      {\n        throw format_exception(strerror(errno));\n      }\n\n      write_struct = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);\n\n      if (write_struct == NULL)\n      {\n        fclose(fp);\n        throw format_exception(\"failed to acquire write_struct\");\n      }\n\n      /* optipng tends to select these options for c10t generated images */\n      png_set_compression_level(write_struct, 9);\n      png_set_compression_mem_level(write_struct, 8);\n      png_set_compression_strategy(write_struct, Z_DEFAULT_STRATEGY);\n      png_set_filter(write_struct, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);\n\n      info_struct = png_create_info_struct(write_struct);\n\n      if (info_struct == NULL)\n      {\n        fclose(fp);\n        png_destroy_write_struct(&write_struct, NULL);\n        throw format_exception(\"failed to acquire info_struct\");\n      }\n\n      /* this is where we end up on errors */\n      if (setjmp(png_jmpbuf(write_struct)))\n      {\n        fclose(fp);\n        png_destroy_write_struct(&write_struct, &info_struct);\n        delete [] bytes_row;\n        delete [] color_row;\n        throw format_exception(\"unknown libpng error\");\n      }\n\n      png_init_io(write_struct, fp);\n\n      png_set_IHDR(write_struct, info_struct, image->get_width(), image->get_height(),\n            8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,\n            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);\n\n      if (!opts.comment.empty())\n      {\n         png_text title_text;\n         title_text.compression = PNG_TEXT_COMPRESSION_NONE;\n         title_text.key = (char *)\"Title\";\n         title_text.text = (char *)opts.comment.c_str();\n         png_set_text(write_struct, info_struct, &title_text, 1);\n      }\n\n      {\n         png_text title_text;\n         title_text.compression = PNG_TEXT_COMPRESSION_NONE;\n         title_text.key = (char *)\"center-x\";\n         std::string text = boost::lexical_cast<std::string, int>(opts.center_x);\n         title_text.text = const_cast<char*>(text.c_str());\n         png_set_text(write_struct, info_struct, &title_text, 1);\n      }\n      \n      {\n         png_text title_text;\n         title_text.compression = PNG_TEXT_COMPRESSION_NONE;\n         title_text.key = (char *)\"center-y\";\n         std::string text = boost::lexical_cast<std::string, int>(opts.center_y);\n         title_text.text = const_cast<char*>(text.c_str());\n         png_set_text(write_struct, info_struct, &title_text, 1);\n      }\n\n      png_write_info(write_struct, info_struct);\n\n      bytes_row = new png_byte[4 * image->get_width()];\n      color_row = new color[image->get_width()];\n\n      for (size_t y = 0; y < image->get_height(); y++)\n      {\n        image->get_line(y, color_row);\n\n        for (unsigned int i = 0; i < image->get_width(); i++)\n        {\n          bytes_row[i*4 + 0] = png_byte(color_row[i].r * 255.0f);\n          bytes_row[i*4 + 1] = png_byte(color_row[i].g * 255.0f);\n          bytes_row[i*4 + 2] = png_byte(color_row[i].b * 255.0f);\n          bytes_row[i*4 + 3] = png_byte(color_row[i].a * 255.0f);\n        }\n\n        png_write_row(write_struct, bytes_row);\n      }\n\n      png_write_end(write_struct, NULL);\n\n      fclose(fp);\n      png_free_data(write_struct, info_struct, PNG_FREE_ALL, -1);\n      png_destroy_write_struct(&write_struct, &info_struct);\n      delete [] bytes_row;\n      delete [] color_row;\n    }\n};\n\n#endif /* FILEFORMAT_PNG */\n"
  },
  {
    "path": "src/image/image_base.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"image_base.hpp\"\n\n#include <cstring>\n\n#include <boost/numeric/conversion/cast.hpp>\n\n// image_base\nvoid image_base::fill(color &q)\n{\n  for (pos_t x = 0; x < get_width(); x++) {\n    for (pos_t y = 0; y < get_height(); y++) {\n      set_pixel(x, y, q);\n    }\n  }\n}\n\nvoid image_base::clear() {\n  boost::shared_array<color> line(new color[get_width()]);\n  ::memset(line.get(), 0x0, get_width() * sizeof(color));\n\n  for (pos_t y = 0; y < get_height(); y++)\n    set_line(y, 0, get_width(), line.get());\n}\n\nvoid image_base::composite(int x, int y, image_operations_ptr opers)\n{\n  std::vector<image_operation>::size_type i = 0;\n  \n  align(x, y, opers->max_x, opers->max_y);\n  \n  while (i++ < opers->operations.size())\n  {\n    image_operation op = opers->operations[i];\n    blend_pixel(x + op.x, y + op.y, op.c);\n  }\n}\n\nvoid image_base::draw_line(pos_t x1, pos_t y1, pos_t x2, pos_t y2, color &c)\n{\n    int sx, sy;\n    int dx = (x1<x2) ? x2-x1 : x1-x2;\n    int dy = (y1<y2) ? y2-y1 : y1-y2;\n    sx = (x1<x2) ? 1 : -1 ;\n    sy = (y1<y2) ? 1 : -1 ;\n    int err = dx-dy;\n\n    do\n    {\n        this->set_pixel(x1, y1, c);\n        int e2 = 2*err;\n        if(e2 > -dy)\n        {\n            err -= dy;\n            x1 += sx;\n        }\n        if(e2 < dx)\n        {\n            err += dx;\n            y1 += sy;\n        }\n    } while(x1 != x2 || y1 != y2);\n}\n\nvoid image_base::safe_blend_pixel(pos_t x, pos_t y, color &c)\n{\n  if (x >= width) return;\n  if (y >= height) return;\n  blend_pixel(x, y, c);\n}\n\nvoid image_base::resize(image_ptr target) {\n  if (target->get_width() > get_width()) {\n    // scale up\n    unsigned int factor = target->get_width() / get_width();\n    boost::shared_array<color> line(new color[get_width()]);\n\n    unsigned int scanline = 0;\n    bool first = false;\n\n    for (pos_t y = 0; y < target->get_height(); y++) {\n      pos_t y_p = (y / factor);\n\n      if (y_p != scanline || !first) {\n        get_line(y_p, pos_t(0), get_width(), line.get());\n        first = true;\n        scanline = y_p;\n      }\n\n      for (pos_t x = 0; x < target->get_width(); x++) {\n        pos_t x_p = (x / factor);\n        target->set_pixel(x, y, line[x_p]);\n      }\n    }\n  }\n  else {\n    // scale down\n    unsigned int factor = get_width() / target->get_width();\n\n    boost::shared_array<color> line(new color[get_width()]);\n\n    for (pos_t y = 0; y < target->get_height(); y++) {\n      pos_t y_p = ((y * factor) + factor / 2);\n      get_line(y_p, pos_t(0), get_width(), line.get());\n      \n      for (pos_t x = 0; x < target->get_width(); x++) {\n        pos_t x_p = ((x * factor) + factor / 2);\n        target->set_pixel(x, y, line[x_p]);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/image/image_base.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef IMAGE_BASE\n#define IMAGE_BASE\n\n#include <cstdlib>\n#include <map>\n\n#include <boost/filesystem.hpp>\n#include <boost/shared_ptr.hpp>\n\n#include \"image/image_operations.hpp\"\n#include \"image/color.hpp\"\n\nclass image_base;\n\ntypedef boost::shared_ptr<image_base> image_ptr;\ntypedef uint64_t pos_t;\n\nclass image_base\n{\nprotected:\n  pos_t width, height;\npublic:\n  typedef void (*progress_c)(int , int);\n  \n  image_base(pos_t width, pos_t height)\n      : width(width), height(height) {\n  }\n  \n  virtual ~image_base() {\n  }\n  \n  void fill(color& c);\n\n  void clear();\n  \n  inline pos_t get_width() { return width; };\n  inline pos_t get_height() { return height; };\n  \n  void composite(int xoffset, int yoffset, image_operations_ptr oper);\n  \n  inline std::streampos get_offset(std::streampos x, std::streampos y) {\n    std::streampos width = get_width();\n    return x + y * width;\n  }\n  \n  void safe_blend_pixel(pos_t x, pos_t y, color &c);\n\n  void get_line(pos_t y, color *c) {\n    get_line(y, 0, get_width(), c);\n  }\n\n  template<typename T>\n  void save(const std::string str, typename T::opt_type opts) {\n    T::save(this, str, opts);\n  }\n\n  void draw_line(pos_t x1, pos_t y1, pos_t x2, pos_t y2, color &c);\n\n  void resize(image_ptr target);\n  \n  virtual void blend_pixel(pos_t x, pos_t y, color &c) = 0;\n  virtual void set_pixel(pos_t x, pos_t y, color& c) = 0;\n  virtual void get_pixel(pos_t x, pos_t y, color& c) = 0;\n  virtual void get_line(pos_t y, pos_t offset, pos_t width, color*) = 0;\n  virtual void set_line(pos_t y, pos_t offset, pos_t width, color*) {};\n  virtual void align(pos_t x, pos_t y, pos_t width, pos_t height) {};\n};\n\n#endif /* IMAGE_BASE */\n"
  },
  {
    "path": "src/image/image_operations.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"image/image_operations.hpp\"\n#include <string.h>\n\n#include <boost/foreach.hpp>\n\n#include <algorithm>\n  \nimage_operations::image_operations(uint32_t z)\n    : z(z), min_x(0), min_y(0), max_x(0), max_y(0)\n{\n}\n\nimage_operations::~image_operations()\n{\n}\n\nvoid image_operations::add_pixel(pos_t x, pos_t y, color &c)\n{\n  if (c.is_invisible()) {\n    return;\n  }\n  \n  if (!(x >= min_x)) { return; }\n  if (!(y >= min_y)) { return; }\n  if (!(x < max_x)) { return; }\n  if (!(y < max_y)) { return; }\n\n  color n = color(c);\n\n  // tag with depth.\n  n.z = z;\n  \n  image_operation oper;\n  \n  oper.x = (uint16_t)x;\n  oper.y = (uint16_t)y;\n  oper.c = n;\n  \n  operations.push_back(oper);\n}\n\nvoid image_operations::optimize()\n{\n  bool* blocked = new bool[max_x*max_y];\n\n  for (unsigned int i = 0; i < max_x*max_y; i++) {\n    blocked[i] = false;\n  }\n\n  operations_vector new_operations;\n\n  BOOST_REVERSE_FOREACH(image_operation operation, operations) {\n    int offset = operation.x * max_x + operation.y;\n    \n    if (blocked[offset]) {\n      continue;\n    }\n\n    blocked[offset] = operation.c.is_opaque();\n    new_operations.push_back(operation);\n  }\n\n  std::reverse(new_operations.begin(), new_operations.end());\n\n  operations = new_operations;\n\n  delete [] blocked;\n}\n\nvoid image_operations::reverse()\n{\n  std::reverse(operations.begin(), operations.end());\n}\n\nvoid image_operations::set_limits(pos_t x, pos_t y) \n{\n  min_x = 0;\n  min_y = 0;\n  max_x = x;\n  max_y = y;\n  \n  operations.reserve(max_x * max_y * 2);\n}\n\n"
  },
  {
    "path": "src/image/image_operations.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef IMAGE_OPERATIONS\n#define IMAGE_OPERATIONS\n\n#include <cstdlib>\n#include <vector>\n\n#include <boost/shared_ptr.hpp>\n#include <boost/shared_array.hpp>\n\n#include \"image/color.hpp\"\n\ntypedef uint64_t pos_t;\n\nclass image_operations;\n\ntypedef boost::shared_ptr<image_operations> image_operations_ptr;\n\nstruct image_operation {\n  color c;\n  uint16_t x, y;\n};\n\nclass image_operations\n{\npublic:\n  /*\n   * The depth of the image operations.\n   */\n  uint32_t z;\n\n  pos_t min_x, min_y;\n  pos_t max_x, max_y;\n\n  typedef std::vector<image_operation> operations_vector;\n  \n  image_operations(uint32_t z);\n  ~image_operations();\n\n  operations_vector operations;\n  \n  void add_pixel(pos_t x, pos_t y, color &c);\n  void set_limits(pos_t x, pos_t y);\n  void optimize();\n  void reverse();\n};\n\n\n#endif /* IMAGE_OPERATIONS */\n"
  },
  {
    "path": "src/image/memory_image.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"image/memory_image.hpp\"\n\n#include <string.h>\n\n// memory_image\nmemory_image::memory_image(int w, int h) : image_base(w, h)\n{\n  colors = new color[w * h];\n  memset(colors, 0x255, w * h);\n}\n\nmemory_image::~memory_image()\n{\n  delete [] colors;\n}\n\nvoid memory_image::set_pixel(pos_t x, pos_t y, color &c)\n{\n  if (!(x < get_width())) { return; }\n  if (!(y < get_height())) { return; }\n  c.write(this->colors + get_offset(x, y));\n}\n\nvoid memory_image::get_pixel(pos_t x, pos_t y, color &c)\n{\n  if (!(x < get_width())) { return; }\n  if (!(y < get_height())) { return; }\n  c.read(this->colors + get_offset(x, y));\n}\n\nvoid memory_image::get_line(pos_t y, pos_t offset, pos_t width, color* c)\n{\n  if (!(y < get_height())) { return; }\n  if (!(offset < get_width())) { return; }\n  if (!(width + offset < get_width())) { width = get_width() - offset; }\n  \n  memcpy(c, this->colors + get_offset(offset, y), width * sizeof(color));\n}\n\nvoid memory_image::blend_pixel(pos_t x, pos_t y, color &c)\n{\n  color o;\n  get_pixel(x, y, o);\n\n  if (c.z < o.z) {\n    c.blend(o);\n    set_pixel(x, y, c);\n  }\n  else {\n    o.blend(c);\n    set_pixel(x, y, o);\n  }\n}\n"
  },
  {
    "path": "src/image/memory_image.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef MEMORY_IMAGE\n#define MEMORY_IMAGE\n\n#include \"image/image_base.hpp\"\n#include \"image/color.hpp\"\n\nclass memory_image : public image_base {\nprivate:\n  color *colors;\npublic:\n  memory_image(int w, int h);\n  \n  ~memory_image();\n  \n  void blend_pixel(pos_t x, pos_t y, color &c);\n  void set_pixel(pos_t x, pos_t y, color&);\n  void get_pixel(pos_t x, pos_t y, color&);\n  void get_line(pos_t y, pos_t offset, pos_t width, color*);\n};\n\n#endif /* MEMORY_IMAGE */\n"
  },
  {
    "path": "src/image/virtual_image.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef VIRTUAL_IMAGE\n#define VIRTUAL_IMAGE\n\n#include <string.h>\n\n#include \"image/image_base.hpp\"\n\nclass virtual_image : public image_base {\nprivate:\n  image_ptr base;\n  pos_t x, y;\npublic:\n  virtual_image(pos_t w, pos_t h, image_ptr base, pos_t x, pos_t y) : image_base(w, h), base(base), x(x), y(y)\n  {\n  }\n  \n  void blend_pixel(pos_t x, pos_t y, color &c) {\n    base->blend_pixel(this->x + x, this->y + y, c);\n  }\n  \n  void set_pixel(pos_t x, pos_t y, color& c) {\n    base->set_pixel(this->x + x, this->y + y, c);\n  }\n  \n  void get_pixel(pos_t x, pos_t y, color& c) {\n    base->get_pixel(this->x + x, this->y + y, c);\n  }\n  \n  void get_line(pos_t y, pos_t x, pos_t width, color* c) {\n    pos_t o_x = this->x + x;\n    pos_t o_y = this->y + y;\n    pos_t p_width = 0;\n    \n    if (o_x > base->get_width()) { goto exit_zero; }\n    if (o_y > base->get_height()) { goto exit_zero; }\n    \n    p_width = std::min(base->get_width() - o_x, width);\n    \n    if (p_width == width) {\n      base->get_line(o_y, o_x, width, c);\n    }\n    else {\n      base->get_line(o_y, o_x, p_width, c);\n      // fill up the rest with zeroes\n      memset(c + p_width, 0x0, sizeof(color) * (width - p_width));\n    }\n\n    return;\n\nexit_zero:\n    memset(c, 0x0, sizeof(color) * width);\n  }\n};\n\n#endif /* VIRTUAL_IMAGE */\n"
  },
  {
    "path": "src/json.cpp",
    "content": "#include \"json.hpp\"\n\n#include <unc/unc.hpp>\n\nnamespace json {\n  void encode_string(std::ostream& os, std::string s) {\n    unc::ustring str = unc::decode<unc::utf8>(s);\n\n    unc::ustring::iterator it;\n    \n    os << \"\\\"\";\n\n    for (it = str.begin(); it != str.end(); it++) {\n      unc::codepoint_t c = *it;\n      \n      switch(c) {\n        case '\"': os << \"\\\\\\\"\"; break;\n        case '\\\\': os << \"\\\\\\\\\"; break;\n        case '/': os << \"\\\\/\"; break;\n        case '\\b': os << \"\\\\b\"; break;\n        case '\\f': os << \"\\\\f\"; break;\n        case '\\n': os << \"\\\\n\"; break;\n        case '\\r': os << \"\\\\r\"; break;\n        case '\\t': os << \"\\\\t\"; break;\n        default:\n          std::string s;\n          unc::encode_codepoint<unc::utf8>(c, s);\n          os << s;\n          break;\n      }\n    }\n\n    os << \"\\\"\";\n  }\n}\n"
  },
  {
    "path": "src/json.hpp",
    "content": "#ifndef _JSON_H_\n#define _JSON_H_\n\n#include <map>\n#include <string>\n#include <vector>\n\n#include <ostream>\n\nnamespace json {\n  enum json_type {\n    String,\n    Number,\n    Object,\n    Array,\n    None\n  };\n\n  class string;\n  class number;\n  class object;\n  class array;\n  \n  template<typename T>\n  struct Trait {\n    const static json_type type = None;\n  };\n  \n  template<>\n  struct Trait<string> {\n    const static enum json_type type = String;\n  };\n  \n  template<>\n  struct Trait<number> {\n    const static enum json_type type = Number;\n  };\n\n  template<>\n  struct Trait<object> {\n    const static enum json_type type = Object;\n  };\n  \n  template<>\n  struct Trait<array> {\n    const static enum json_type type = Array;\n  };\n  \n  void encode_string(std::ostream& os, std::string s);\n\n  class basic_json {\n    public:\n      virtual ~basic_json() {};\n      virtual void write(std::ostream& os) = 0;\n      virtual json_type get_type() = 0;\n  };\n  \n  class string : public basic_json {\n    private:\n      std::string s;\n    public:\n      const static json_type type = Trait<string>::type;\n      json_type get_type() { return Trait<string>::type; }\n      \n      string(std::string s) : s(s) {}\n      void write(std::ostream& os) {\n        encode_string(os, s);\n      }\n  };\n\n  class number : public basic_json {\n    private:\n      int v;\n    public:\n      const static json_type type = Trait<number>::type;\n      json_type get_type() { return Trait<number>::type; }\n\n      number(int v) : v(v) {}\n      void write(std::ostream& os) {\n        os << v;\n      }\n  };\n  \n  class object : public basic_json {\n    private:\n      std::map<std::string, basic_json*> a;\n    public:\n      const static json_type type = Trait<object>::type;\n      json_type get_type() { return Trait<object>::type; }\n      \n      void put(std::string k, basic_json* o) {\n        a[k] = o;\n      }\n      \n      void write(std::ostream& os) {\n        os << \"{\";\n\n        unsigned int i = 0;\n        \n        std::map<std::string, basic_json*>::iterator it;\n        \n        for (it = a.begin(); it != a.end(); it++) {\n          encode_string(os, (*it).first);\n          os << \":\";\n          (*it).second->write(os);\n          if (++i < a.size()) os << \",\";\n        }\n        \n        os << \"}\";\n      }\n      \n      friend std::ostream& operator<<(std::ostream& os, object& w) {\n        w.write(os);\n        return os;\n      }\n      \n      ~object() {\n        std::map<std::string, basic_json*>::iterator it;\n        \n        for (it = a.begin(); it != a.end(); it++) {\n          delete (*it).second;\n        }\n      }\n  };\n  \n  class array : public basic_json {\n    private:\n      std::vector<basic_json*> a;\n    public:\n      const static json_type type = Trait<array>::type;\n      json_type get_type() { return Trait<array>::type; }\n      \n      void push(basic_json* o) { a.push_back(o); }\n      void push(basic_json& o) { a.push_back(&o); }\n      \n      void write(std::ostream& os) {\n        os << \"[\";\n\n        unsigned int i = 0;\n        \n        std::vector<basic_json*>::iterator it;\n        \n        for (it = a.begin(); it != a.end(); it++) {\n          (*it)->write(os);\n          if (++i < a.size()) os << \",\";\n        }\n        \n        os << \"]\";\n      }\n      \n      friend std::ostream& operator<<(std::ostream& os, array& a) {\n        a.write(os);\n        return os;\n      }\n\n      ~array() {\n        std::vector<basic_json*>::iterator it;\n        for (it = a.begin(); it != a.end(); it++) {\n          delete *it;\n        }\n      }\n  };\n  \n  template<typename T>\n  T* cast(basic_json *b) {\n    return reinterpret_cast<T*>(b);\n  }\n}\n\n#endif /* _JSON_H_ */\n"
  },
  {
    "path": "src/main.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <errno.h>\n\n#include <sstream>\n#include <string>\n#include <list>\n#include <iostream>\n#include <iomanip>\n#include <fstream>\n\n#include \"config.hpp\"\n\n#include \"nullstream.hpp\"\n#include \"json.hpp\"\n#include \"marker.hpp\"\n\n#include \"image/memory_image.hpp\"\n#include \"image/image_base.hpp\"\n\n#include \"engine/engine_core.hpp\"\n\n#include \"generate_map.hpp\"\n#include \"generate_statistics.hpp\"\n\n#include <boost/filesystem.hpp>\n#include <boost/format.hpp>\n\n#include \"main_utils.hpp\"\n\nusing namespace std;\n\nnamespace fs = boost::filesystem;\n\ntypedef uint64_t pos_t;\n\nconst uint8_t ERROR_BYTE = 0x01;\nconst uint8_t RENDER_BYTE = 0x10;\nconst uint8_t COMP_BYTE = 0x20;\nconst uint8_t IMAGE_BYTE = 0x30;\nconst uint8_t PARSE_BYTE = 0x40;\nconst uint8_t END_BYTE = 0xF0;\n\ninline void cout_error(const string& message) {\n  cout << hex << std::setw(2) << setfill('0') << static_cast<int>(ERROR_BYTE)\n       << hex << message << flush;\n}\n\ninline void cout_end() {\n  cout << hex << std::setw(2) << setfill('0') << static_cast<int>(END_BYTE) << flush;\n}\n\n\nint do_help(ostream& out) {\n  out << \"This program was made possible because of the work and inspiration by ZomBuster and Firemark\" << endl;\n  out << \"\" << endl;\n  out << \"Written by Udoprog et al.\" << endl;\n  out << \"\" << endl;\n  out << \"The following libraries are in use for this program:\" << endl\n       << \"  zlib (compression)\"                  << endl\n       << \"    http://www.zlib.net\"               << endl\n       << \"  boost (thread, filesystem)\"          << endl\n       << \"    http://www.boost.org\"              << endl\n       << \"  libpng (portable network graphics)\"  << endl\n       << \"    http://www.libpng.org\"             << endl\n       << \"  libfreetype (font loading)\"          << endl\n       << \"    http://www.freetype.org\"           << endl\n       << \"\" << endl;\n# if defined(C10T_DISABLE_THREADS)\n  out << endl;\n  out << \"C10T_DISABLE_THREADS: Threads has been disabled for this build\" << endl;\n# endif\n  out << endl;\n  out << \"Usage: c10t [options]\" << endl;\n  out << \"Options:\" << endl\n       /*******************************************************************************/\n    << \"  -w, --world <world>       - use this world directory as input                \" << endl\n    << \"  -o, --output <output>     - use this file as output file for generated png   \" << endl\n    << \"  -S, --statistics <output> - create a statistics file of the entire world     \" << endl\n    << \"      --graph-block <blockid>                                                  \" << endl\n    << \"                            - make graph for block repartition by altitude     \" << endl\n    << \"                              with filename <output>_graph.png                 \" << endl\n    << endl\n    << \"  --log [file]              - Specify another location for logging warnings,   \" << endl\n    << \"                              defaults to `c10t.log'                           \" << endl\n    << \"  --no-log                  - Suppress logging of warnings                     \" << endl\n    << endl\n    << \"  -s, --silent              - execute silently, printing nothing except errors \" << endl\n    << \"  -h, --help                - display this help text                           \" << endl\n    << \"  -v, --version             - display version information                      \" << endl\n    << \"  -D, --debug               - display debug information while executing        \" << endl\n    << \"  -l, --list-colors         - list all available colors and block types        \" << endl\n    << endl\n    << \"Rendering options:\" << endl\n    << \"  -q, --oblique             - Oblique rendering                                \" << endl\n    << \"  -y, --oblique-angle       - Oblique angle rendering                          \" << endl\n    << \"  -z, --isometric           - Isometric rendering                              \" << endl\n    << \"  -Z, --fatiso              - A fat isometric rendering (very slow)            \" << endl\n    << \"  -r <degrees>              - rotate the rendering 90, 180 or 270 degrees CW   \" << endl\n    << endl\n    << \"  -n, --night               - Night-time rendering mode                        \" << endl\n    << \"  -H, --heightmap           - Heightmap rendering mode (black to white)        \" << endl\n    << endl\n    << \"Filtering options:\" << endl\n    << \"  -e, --exclude <blockid>   - Exclude block-id from render (multiple occurences\" << endl\n    << \"                              is possible)                                     \" << endl\n    << \"  -i, --include <blockid>   - Include only this block-id in render (multiple   \" << endl\n    << \"                              occurences is possible)                          \" << endl\n    << \"  -a, --hide-all            - Show no blocks except those specified with '-i'  \" << endl\n    << \"  -c, --cave-mode           - Cave mode - top down until solid block found,    \" << endl\n    << \"                              then render bottom outlines only                 \" << endl\n    << \"      --hell-mode           - Hell mode - top down until non-solid block found,\" << endl\n    << \"                              then render normally (a.k.a. nether)             \" << endl\n    << endl\n    << \"  -t, --top <int>           - Splice from the top, must be less than 128       \" << endl\n    << \"  -b, --bottom <int>        - Splice from the bottom, must be greater than or  \" << endl\n    << \"                              equal to zero.                                   \" << endl\n    << \"  -L, --limits <int-list>   - Limit render to certain area. int-list form:     \" << endl\n    << \"                              North,South,East,West, e.g.                      \" << endl\n    << \"                              -L 0,100,-10,20 limiting between 0 and 100 in the\" << endl\n    << \"                              north-south direction and between -10 and 20 in  \" << endl\n    << \"                              the east-west direction.                         \" << endl\n    << \"                              Note: South and West are the positive directions.\" << endl\n    << \"  -R, --radius <int>        - Limit render to a specific radius, useful when   \" << endl\n    << \"                              your map is absurdly large and you want a 'fast' \" << endl\n    << \"                              limiting option.                                 \" << endl\n    << \"                              The default maximum radius is 1000 chunks.       \" << endl\n    << \"      --center <x>,<z>      - Offset the map centering on limits by chunks <x> \" << endl\n    << \"                              and <z>.                                         \" << endl\n    << endl\n    << \"  -N, --no-check            - Ignore missing <world>/level.dat                 \" << endl\n       /*******************************************************************************/\n    << endl\n    << \"Performance options:\" << endl\n    << \"  -M, --memory-limit <MB>   - Will limit the memory usage caching operations to\" << endl\n    << \"                              file when necessary                              \" << endl\n    << \"  -C, --swap-file <file>    - Swap file to use when memory limit `-M' is       \" << endl\n    << \"                              reached, defaults to `swap.bin'                  \" << endl\n    << \"  -m, --threads <int>       - Specify the amount of threads to use, for maximum\" << endl\n    << \"                              efficency, this should match the amount of cores \" << endl\n    << \"                              on your machine                                  \" << endl\n    << \"      --prebuffer <int>     - Specify how many jobs to prebuffer for each      \" << endl\n    << \"                              individual thread                                \" << endl\n    << \"                                                                               \" << endl\n    << \"  -B <set>                  - Specify the base color for a specific block name \" << endl\n    << \"                              or legacy id; <set> has the format               \" << endl\n    << \"                              `<block>=<color>'; <8 digit hex> specifies the   \" << endl\n    << \"                              RGBA values as `<int>,<int>,<int>[,<int>]'.      \" << endl\n    << \"                              example: `-B minecraft:grass=0,255,0,120'        \" << endl\n    << \"                              example: `-B 2=0,255,0,120'                      \" << endl\n    << \"                              DEPRECATED: Use json palette files instead       \" << endl\n    << \"  --side <set>              - Specify the side color for a specific block name \" << endl\n    << \"                              or legacy id; <set> has the format               \" << endl\n    << \"                              `<block>=<color>'; <8 digit hex> specifies the   \" << endl\n    << \"                              RGBA values as `<int>,<int>,<int>[,<int>]'.      \" << endl\n    << \"                              example: `--side minecraft:grass=0,255,0,120'    \" << endl\n    << \"                              example: `--side 2=0,255,0,120'                  \" << endl\n    << \"                              DEPRECATED: Use json palette files instead       \" << endl\n    << \"  -p, --split 'px1 px2 ..'  - Split the render into parts which must be pxX    \" << endl\n    << \"                              pixels squared. `output' name must contain three \" << endl\n    << \"                              format specifiers `%d' for `level' x and y       \" << endl\n    << \"                              position. Supports multiple splits which will be \" << endl\n    << \"                              placed on specific `level's.                     \" << endl\n    << \"  --split-base dim          - Resize each tile generated by --split to `dim'   \" << endl\n    << \"                              pixels squared (default: tiles are pxX pixels    \" << endl\n    << \"                              squared)                                         \" << endl\n       /*******************************************************************************/\n    << endl\n    << \"Other Options:\" << endl\n    << \"  -x, --binary              - Will output progress information in binary form, \" << endl\n    << \"                              good for integration with third party tools      \" << endl\n    << \"  --require-all             - Will force c10t to require all chunks or fail    \" << endl\n    << \"                              not ignoring bad chunks                          \" << endl\n    << \"  --show-players[=NICKLIST] - Will draw out player position and names from the \" << endl\n    << \"                              players database in <world>/players              \" << endl\n    << \"                              it is possible to define which nicks to show by  \" << endl\n    << \"                              specifying a comma separated list of nicks       \" << endl\n    << \"  --show-signs[=PREFIX]     - Will draw out signs from all chunks, if PREFIX   \" << endl\n    << \"                              is specified, only signs matching the prefix will\" << endl\n    << \"                              be drawn                                         \" << endl\n    << \"  --strip-sign-prefix       - When drawing sign text, removes the match prefix \" << endl\n    << \"  --show-warps=<file>       - Will draw out warp positions from the specified  \" << endl\n    << \"                              warps.txt file, as used by hey0's mod            \" << endl\n    << \"  --show-coordinates        - Will draw out each chunks expected coordinates   \" << endl\n    << \"  -P <file>                 - Use <file> as custom palette, in JSON format     \" << endl\n    << \"  -W <file>                 - Dump default palette to <file>, in JSON format   \" << endl\n    << \"                              The default palette is no longer built-it and is \" << endl\n    << \"                              available as `palette.json'                      \" << endl\n    << \"  --pedantic-broad-phase    - Will enforce that all level chunks are parsable  \" << endl\n    << \"                              during broad phase by getting x/y/z positions    \" << endl\n    << \"                              from a quick parsing                             \" << endl\n    << \"  --no-alpha                - Set non-invisible blocks color alpha channel to  \" << endl\n    << \"                              fully opaque (solid)                             \" << endl\n    << \"  --striped-terrain         - Darken every other block on a vertical basis     \" << endl\n    << \"                              which helps to distinguish heights               \" << endl\n    << \"  --write-json <file>       - Write markers to <file> in JSON format instead of\" << endl\n    << \"                              printing them on map                             \" << endl\n    << \"  --write-js <file>         - Same as `write-json' with the exception that the \" << endl\n    << \"                              result will be a valid javascript file containing\" << endl\n    << \"                              a declaration for `var c10t_json'                \" << endl\n       /*******************************************************************************/\n    << endl\n    << \"Font Options:\" << endl\n    << \"  --ttf-path <font>         - Use the following ttf file when drawing text.    \" << endl\n    << \"                              defaults to `font.ttf'                           \" << endl\n    << \"  --ttf-size <size>         - Use the specified font size when drawing text.   \" << endl\n    << \"                              defaults to `12'                                 \" << endl\n    << \"  --ttf-color <color>       - Use the specified color when drawing text.       \" << endl\n    << \"                              defaults to `0,0,0,255' (black)                  \" << endl\n    << \"  --sign-color <color>      - Use the specified color when drawing signs.      \" << endl\n    << \"                              defaults to <ttf-color>                          \" << endl\n    << \"  --player-color <color>    - Use the specified color when showing players.    \" << endl\n    << \"                              defaults to <ttf-color>                          \" << endl\n    << \"  --warp-color <color>      - Use the specified color when showing warps.      \" << endl\n    << \"                              defaults to <ttf-color>                          \" << endl\n    << \"  --coordinate-color <color>                                                   \" << endl\n    << \"                            - Use the specified color when drawing coordinates.\" << endl\n    << \"                              defaults to <ttf-color>                          \" << endl\n    << \"  --cache-key <key>         - Indicates that c10t should cache operations using\" << endl\n    << \"                              the unique cache key <key>, this should represent\" << endl\n    << \"                              an unique combination of options. The cache files\" << endl\n    << \"                              will be put in                                   \" << endl\n    << \"                              <cache-dir>/<cache-key>/c.<coord>.cmap           \" << endl\n    << \"  --cache-dir <dir>         - Use the following directory as cache directory   \" << endl\n    << \"                              defaults to 'cache' if not specified             \" << endl\n    << \"  --cache-compress          - Compress the cache files using zlib compression  \" << endl\n       /*******************************************************************************/\n    << endl;\n  out << endl;\n  out << \"Typical usage:\" << endl;\n  out << \"    c10t -w /path/to/world -o /path/to/png.png\" << endl;\n  out << endl;\n  out << \"  Utilize render cache and apply a 256 MB memory restriction (rest will be written to image.dat):\" << endl;\n  out << \"    c10t -w /path/to/world -o /path/to/png.png --cache-key='compressed' --cache-compress -M 256 -C image.dat\" << endl;\n  out << endl;\n  out << \"  Print out player positions using the font `example.ttf'\" << endl;\n  out << \"    c10t -w /path/to/world -o /path/to/png.png --show-players --ttf-font example.ttf\" << endl;\n  out << endl;\n  out << \"  Split the result into multiple files, using 10 chunks across in each file, the two number formatters will be replaced with the x/z positions of the chunks\" << endl;\n  out << \"    c10t -w /path/to/world -o /path/to/%d.%d.%d.png --split 10\" << endl;\n  out << endl;\n  return 0;\n}\n\nint do_version(ostream& out) {\n  out << \"c10t - a cartography tool for minecraft\" << endl;\n# if defined(C10T_DISABLE_THREADS)\n  out << endl;\n  out << \"C10T_DISABLE_THREADS: Threads have been disabled for this build\" << endl;\n  out << endl;\n# endif\n  out << \"version: \" << C10T_VERSION << \", built on \" << __DATE__ << endl;\n  out << \"by: \" << C10T_CONTACT << endl;\n  out << \"site: \" << C10T_SITE << endl;\n  return 0;\n}\n\nint main(int argc, char *argv[]){\n    nullstream nil;\n    ostream out(cout.rdbuf());\n    ofstream out_log;\n\n    vector<string> hints;\n\n    out.precision(2);\n    out.setf(ios_base::fixed);\n\n    mc::initialize_constants();\n\n    fs::path executable_dir = fs::system_complete(fs::path(argv[0]).remove_filename());\n    settings_t s(executable_dir);\n\n    if (!read_opts(s, argc, argv)) {\n        goto exit_error;\n    }\n\n    if (!do_read_palette(s, s.palette_read_path)) {\n        goto exit_error;\n    }\n    out << \"Successfully read palette from \" << s.palette_read_path << endl;\n\n    BOOST_FOREACH(std::string exclude, s.excluded) {\n        mc::MaterialT *material;\n        if (!get_blocktype(exclude, material)) {\n            error << \"Unkown material for exclusion \" << exclude << endl;\n            goto exit_error;\n        }\n        material->enabled = false;\n    }\n\n    BOOST_FOREACH(std::string include, s.included) {\n        mc::MaterialT *material;\n        if (!get_blocktype(include, material)) {\n            error << \"Unkown material for inclusion \" << include << endl;\n            goto exit_error;\n        }\n        material->enabled = true;\n    }\n\n    BOOST_FOREACH(std::string top_override, s.top_color_overrides) {\n        if (!do_base_color_set(top_override.c_str())) {\n            error << \"Invalid top color override \" << top_override << endl;\n            goto exit_error;\n        }\n    }\n\n    BOOST_FOREACH(std::string side_override, s.side_color_overrides) {\n        if (!do_side_color_set(side_override.c_str())) {\n            error << \"Invalid side color override \" << side_override << endl;\n            goto exit_error;\n        }\n    }\n\n    if(s.disable_alpha) {\n        for (size_t i = 0; i < mc::MaterialTable.size(); i++) {\n            if (!mc::MaterialTable[i].top.is_invisible()) {\n                mc::MaterialTable[i].top.a = color_i_to_f[255];\n            }\n            if (!mc::MaterialTable[i].side.is_invisible()) {\n                mc::MaterialTable[i].side.a = color_i_to_f[255];\n            }\n        }\n    }\n\n    switch(s.action) {\n    case Version:\n        return do_version(out);\n    case Help:\n        return do_help(out);\n    case ListColors:\n        return do_colors(out);\n    case WritePalette:\n        if (!do_write_palette(s, s.palette_write_path)) {\n            goto exit_error;\n        }\n\n        out << \"Successfully wrote palette to \" << s.palette_write_path << endl;\n        return 0;\n    case None:\n        error << \"No action specified, please type `c10t -h' for help\";\n        goto exit_error;\n    default:\n        break;\n    }\n\n    if (s.binary) {\n        out.rdbuf(out_log.rdbuf());\n    }\n\n    if (s.silent) {\n        out.rdbuf(nil.rdbuf());\n    }\n\n    if (!s.no_log) {\n        out_log.open(path_string(s.output_log).c_str());\n        out_log << \"START LOG\" << endl;\n    }\n\n    if (s.memory_limit_default) {\n        hints.push_back(\"To use less memory, specify a memory limit with `-M <MB>', if it is reached c10t will swap to disk instead\");\n    }\n\n    if (s.cache_use) {\n        if (!fs::is_directory(s.cache_dir)) {\n            error << \"Directory required for caching: \" << path_string(s.cache_dir);\n            goto exit_error;\n        }\n\n        // then create the subdirectory using cache_key\n        s.cache_dir = s.cache_dir / s.cache_key;\n\n        if (!fs::is_directory(s.cache_dir)) {\n            out << \"Creating directory for caching: \" << path_string(s.cache_dir) << endl;\n            fs::create_directories(s.cache_dir);\n        }\n\n        {\n            out << \"Caching to directory: \" << s.cache_dir << std::endl;\n            out << \"Cache compression: \" << (s.cache_compress ? \"ON\" : \"OFF\")    << std::endl;\n        }\n    }\n\n    if (s.world_path.empty())\n    {\n        error << \"You must specify a world to render using `-w <directory>'\";\n        goto exit_error;\n    }\n\n    if (!s.nocheck)\n    {\n        fs::path level_dat = s.world_path / \"level.dat\";\n\n        if (!fs::exists(level_dat)) {\n            error << \"Does not exist: \" << path_string(level_dat);\n            goto exit_error;\n        }\n    }\n\n    /* hell mode requires entering the subdirectory DIM-1 */\n    if (s.hellmode)\n    {\n        s.world_path = s.world_path / \"DIM-1\";\n    }\n\n    if (!fs::is_directory(s.world_path))\n    {\n        if (!fs::is_directory(s.world_path)) {\n            error << \"Does not exist: \" << path_string(s.world_path);\n            goto exit_error;\n        }\n    }\n\n    switch(s.action) {\n    case GenerateWorld:\n        /* do some nice sanity checking prior to generating since this might\n         * catch a couple of errors */\n\n        if (s.output_path.empty()) {\n            error << \"You must specify output file using `-o <file>'\";\n            goto exit_error;\n        }\n\n        if (!fs::is_directory(s.output_path.parent_path())) {\n            error << \"Output directory does not exist: \" << s.output_path;\n            goto exit_error;\n        }\n\n        if (s.use_split) {\n            try {\n                boost::format(s.output_path.stem().string()) % 0 % 0;\n            } catch (boost::io::too_many_args& e) {\n                error << \"The `-o' parameter must contain two number format specifiers `%d' (x and y coordinates) - example: -o out/base.%d.%d.png\";\n                goto exit_error;\n            }\n        }\n\n        if (!generate_map(out, out_log, error, s, hints, s.world_path, s.output_path)) {\n            goto exit_error;\n        }\n        break;\n    case GenerateStatistics:\n        if (!generate_statistics(out, out_log, error, s, hints, s.world_path, s.statistics_path)) {\n            goto exit_error;\n        }\n        break;\n    default:\n        error << \"No action specified\";\n        goto exit_error;\n    }\n\n    if (hints.size() > 0 || warnings.size() > 0) {\n        int i = 1;\n\n        for (vector<std::string>::iterator it = warnings.begin(); it != warnings.end(); it++) {\n            out << \"WARNING \" << i++ << \": \" << *it << endl;\n        }\n\n        i = 1;\n        for (vector<std::string>::iterator it = hints.begin(); it != hints.end(); it++) {\n            out << \"Hint \" << i++ << \": \" << *it << endl;\n        }\n\n        out << endl;\n    }\n\n    if (s.binary) {\n        cout_end();\n    }\n    else {\n        out << argv[0] << \": all done!\" << endl;\n    }\n\n    mc::deinitialize_constants();\n\n    if (!s.no_log) {\n        out << \"Log written to \" << path_string(s.output_log) << endl;\n        out_log << \"END LOG\" << endl;\n        out_log.close();\n    }\n\n    return 0;\nexit_error:\n    if (s.binary) {\n        cout_error(error.str());\n    }\n    else {\n        out << argv[0] << \": \" << error.str() << endl;\n    }\n\n    mc::deinitialize_constants();\n\n    if (!s.no_log) {\n        out << \"Log written to \" << path_string(s.output_log) << endl;\n        out_log << \"END LOG\" << endl;\n        out_log.close();\n    }\n\n    return 1;\n}\n"
  },
  {
    "path": "src/main_utils.cpp",
    "content": "#include \"main_utils.hpp\"\n\n#include <getopt.h>\n\n#include <unistd.h>\n\n#include <sstream>\n#include <fstream>\n#include <iomanip>\n\n#include <boost/property_tree/json_parser.hpp>\n#include <boost/tokenizer.hpp>\n#include <boost/lexical_cast.hpp>\n#include <boost/foreach.hpp>\n\n#include \"mc/blocks.hpp\"\n\nbool parse_color(const std::string value, color& c);\nbool parse_set(const char* set_str, int& blockid, color& c);\n\n// Convert a string such as \"-30,40,50,30\" to the corresponding N,S,E,W integers,\n// and fill in the min/max settings.\nbool parse_limits(const std::string& limits_str, settings_t& s);\nbool read_set(std::set<std::string>& set, const std::string s);\n\nbool do_write_palette(settings_t& s, const boost::filesystem::path& path);\nbool do_read_palette(settings_t& s, const boost::filesystem::path& path);\n\nnamespace fs = boost::filesystem;\n\nusing namespace std;\nusing namespace boost;\n\nvector<std::string> hints;\nvector<std::string> warnings;\nstringstream error;\n\ntemplate<typename C>\nvoid boost_split(C& collection, const string& s)\n{\n    char_separator<char> sep(\" \\t\\n\\r,:\");\n    typedef tokenizer<boost::char_separator<char> > tokenizer;\n    tokenizer tokens(s, sep);\n\n    for (tokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) {\n        collection.insert(collection.end(), *tok_iter);\n    }\n}\n\nbool get_blocktype(const std::string& block_string, mc::MaterialT*& block_type)\n{\n    // First attempt modern name lookup\n    std::map<std::string, mc::MaterialT*>::iterator it = mc::MaterialMap.find(block_string);\n    if (it == mc::MaterialMap.end()) {\n        // Perhaps it is an old identifier then\n        // TODO: also accept id:meta format\n        try {\n            int id = lexical_cast<int>(block_string);\n            int meta = 0;\n            boost::optional<mc::MaterialT*> material = mc::get_material_legacy(id, meta);\n            if (material) {\n                block_type = material.get();\n                return true;\n            }\n        } catch(const bad_lexical_cast& e) {\n            // ignore string to integer translation errors\n        }\n        error << \"Block is nither a known block name nor a known numeric block identifier; \" << block_string;\n        return false;\n    } else {\n        block_type = it->second;\n        return true;\n    }\n}\n\nbool parse_color(const string value, color& c)\n{\n    std::vector<std::string> parts;\n\n    boost_split(parts, value);\n\n    int cr, cg, cb, ca=0xff;\n\n    if (parts.size() < 3) {\n        error << \"Color sets must be of the form <red>,<green>,<blue>[,<alpha>] but was: \" << value;\n        return false;\n    }\n\n    try {\n        cr = lexical_cast<int>(parts[0]);\n        cg = lexical_cast<int>(parts[1]);\n        cb = lexical_cast<int>(parts[2]);\n        if (parts.size() == 4) {\n            ca = lexical_cast<int>(parts[3]);\n        }\n    } catch(const bad_lexical_cast& e) {\n        error << \"Cannot be converted to a color: \" << value;\n        return false;\n    }\n\n    if (!(\n            cr >= 0 && cr <= 0xff &&\n            cg >= 0 && cg <= 0xff &&\n            cb >= 0 && cb <= 0xff &&\n            ca >= 0 && ca <= 0xff)) {\n        error << \"Color values must be between 0-255: \" << value;\n        return false;\n    }\n\n    c.r = color_i_to_f[cr];\n    c.g = color_i_to_f[cg];\n    c.b = color_i_to_f[cb];\n    c.a = color_i_to_f[ca];\n\n    return true;\n}\n\nbool parse_set(const char* set_str, mc::MaterialT*& block_type, color& c)\n{\n    istringstream iss(set_str);\n    string block_name, color_string;\n\n    assert(getline(iss, block_name, '='));\n    assert(getline(iss, color_string));\n\n    if (!get_blocktype(block_name, block_type)) {\n        return false;\n    }\n\n    if (!parse_color(color_string, c)) {\n        return false;\n    }\n\n    return true;\n}\n\nbool do_base_color_set(const char *set_str)\n{\n    mc::MaterialT *material;\n    color color_top;\n\n    if (parse_set(set_str, material, color_top)) {\n        material->top = color_top;\n        return true;\n    }\n    return false;\n}\n\nbool do_side_color_set(const char *set_str)\n{\n    mc::MaterialT *material;\n    color color_side;\n\n    if (parse_set(set_str, material, color_side)) {\n        material->side = color_side;\n        return true;\n    }\n    return false;\n}\n\n// Convert a string such as \"-30,40,50,30\" to the corresponding N,S,E,W integers,\n// and fill in the min/max settings.\nbool parse_limits(const string& limits_str, settings_t& s)\n{\n    std::vector<std::string> limits;\n\n    boost_split(limits, limits_str);\n\n    if (limits.size() != 4) {\n        error << \"Limit argument must of format: <N>,<S>,<E>,<W>\";\n        return false;\n    }\n\n    try {\n        s.min_x = lexical_cast<int>(limits[0]);\n        s.max_x = lexical_cast<int>(limits[1]);\n        s.min_z = lexical_cast<int>(limits[2]);\n        s.max_z = lexical_cast<int>(limits[3]);\n    } catch(const bad_lexical_cast& e) {\n        error << \"Cannot be converted to set of numbers: \" << limits_str;\n        return false;\n    }\n\n    return true;\n}\n\nbool parse_tuple(const string& str, settings_t& s, int& a, int& b)\n{\n    std::vector<std::string> parts;\n\n    boost_split(parts, str);\n\n    if (parts.size() != 2) {\n        error << \"Tuple must be of format: <num>,<num>\";\n        return false;\n    }\n\n    try {\n        a = lexical_cast<int>(parts[0]);\n        b = lexical_cast<int>(parts[1]);\n    } catch(const bad_lexical_cast& e) {\n        error << \"Cannot be converted to set of numbers: \" << str;\n        return false;\n    }\n\n    return true;\n}\n\nbool read_set(std::set<string>& set, const string s)\n{\n    boost_split(set, s);\n\n    if (set.size() == 0) {\n        error << \"List must specify items separated by comma `,'\";\n        return false;\n    }\n\n    return true;\n}\n\nbool do_write_palette(settings_t& s, const fs::path& path)\n{\n    std::ofstream pal(path.string().c_str());\n\n    mc::MaterialMode_tr_to_string materialmode_tr;\n\n    bool first_material = true;\n    pal << \"[\" << std::endl;\n    BOOST_FOREACH(mc::MaterialT &material, mc::MaterialTable) {\n        if (!material.enabled) {\n            continue;\n        }\n        if (first_material) {\n            first_material = false;\n        } else {\n            pal << \",\" << std::endl;\n        }\n        pal << \"  {\" << std::endl;\n        pal << \"    \\\"namespace\\\": \\\"\" << material.mc_namespace << \"\\\",\" << std::endl;\n        pal << \"    \\\"material\\\": \\\"\" << material.name << \"\\\",\" << std::endl;\n        pal << \"    \\\"mode\\\": \\\"\" << materialmode_tr.get_value(material.mode).get() << \"\\\",\" << std::endl;\n        pal << \"    \\\"top_color\\\": [\" << material.top << \"],\" << std::endl;\n        pal << \"    \\\"side_color\\\": [\" << material.side << \"],\" << std::endl;\n        pal << \"    \\\"darken\\\": false,\" << std::endl;\n        if (material.legacy_ids.size() == 1) {\n            pal << \"    \\\"legacy_id\\\": \" << material.legacy_ids[0] << \",\" << std::endl;\n        } else if (material.legacy_ids.size() > 1) {\n            pal << \"    \\\"legacy_id\\\": [\";\n            bool first_id = true;\n            BOOST_FOREACH(int i, material.legacy_ids) {\n                if (first_id) {\n                    first_id = false;\n                } else {\n                    pal << \", \";\n                }\n                pal << i;\n            }\n            pal << \"]\" << std::endl;\n        }\n        if (material.legacy_ids.size() > 0) {\n            pal << \"    \\\"legacy_meta\\\": \" << material.legacy_meta << std::endl;\n        }\n        pal << \"  }\";\n    }\n    pal << \"]\" << std::endl;\n\n    if (pal.fail()) {\n        error << \"Failed to write palette to \" << path;\n        return false;\n    }\n\n    return true;\n}\n\nint do_colors(std::ostream& out)\n{\n  out << \"List of material Colors (total: \" << mc::MaterialTable.size() << \")\" << endl;\n\n  BOOST_FOREACH(mc::MaterialT &material, mc::MaterialTable) {\n    bool print_separator = false;\n    BOOST_FOREACH(int i, material.legacy_ids) {\n      if (print_separator) {\n        out << \", \";\n      }\n      out << i << \":\" << material.legacy_meta;\n      print_separator = true;\n    }\n    if (print_separator) {\n      out << \"; \";\n    }\n    out << material.mc_namespace << \":\" << material.name << \" = top(\" << material.top << \"), side(\" << material.side << \")\" << endl;\n  }\n\n  return 0;\n}\n\nstd::vector<int> int_vector_from_json(boost::property_tree::ptree parsed_json)\n{\n    std::vector<int> result = std::vector<int>();\n    boost::optional<int> single = parsed_json.get_value_optional<int>();\n    if (single) {\n        result = { single.get() };\n    } else {\n        result.reserve(4);\n        BOOST_FOREACH(boost::property_tree::ptree::value_type &entry, parsed_json) {\n            single = entry.second.get_value_optional<int>();\n            if (entry.first.empty() && single) {\n                result.push_back(single.get());\n            } else {\n                error << \"Error while parsing integer array\" << std::endl;\n            }\n        }\n        result.shrink_to_fit();\n    }\n    return result;\n}\n\ncolor color_from_json(const boost::property_tree::ptree color_json)\n{\n    boost::property_tree::ptree::const_iterator it = color_json.begin();\n    if (it == color_json.end()) {\n       throw \"not a color\";\n    }\n    int r = it->second.get_value<int>();\n    it++;\n    if (it == color_json.end()) {\n       throw \"not a color\";\n    }\n    int g = it->second.get_value<int>();\n    it++;\n    if (it == color_json.end()) {\n       throw \"not a color\";\n    }\n    int b = it->second.get_value<int>();\n    it++;\n    if (it == color_json.end()) {\n       throw \"not a color\";\n    }\n    int a = it->second.get_value<int>();\n    it++;\n    if (it != color_json.end()) {\n       throw \"not a color\";\n    }\n    return color(r, g, b, a);\n}\n\nstruct color_translator\n{\n    typedef boost::property_tree::ptree internal_type;\n    typedef color external_type;\n\n    boost::optional<color> get_value(const boost::property_tree::ptree &pt) {\n        try {\n            return boost::optional<color>(color_from_json(pt));\n        } catch(...) {\n        }\n        return boost::optional<color>();\n    }\n};\n\nbool do_read_palette(settings_t& s, const fs::path& path)\n{\n    boost::property_tree::ptree parsed_json;\n    try {\n        std::ifstream json_src(path.string().c_str());\n        boost::property_tree::read_json(json_src, parsed_json);\n        json_src.close();\n    } catch(boost::property_tree::json_parser::json_parser_error& e) {\n        return false;\n    }\n    BOOST_FOREACH(boost::property_tree::ptree::value_type &mc_block_entry, parsed_json) {\n      // flat JSON list expected, of which entries have no name (.first).\n      boost::property_tree::ptree block_entry = mc_block_entry.second;\n      boost::optional<std::string> mc_namespace = block_entry.get_optional<std::string>(\"namespace\");\n      boost::optional<std::string> material = block_entry.get_optional<std::string>(\"material\");\n      mc::MaterialMode_tr_from_string materialmode_tr;\n      boost::optional<mc::MaterialMode> mode = block_entry.get_optional<mc::MaterialMode>(\"mode\", materialmode_tr);\n      color_translator color_tr;\n      boost::optional<color> top_color = boost::optional<color>();\n      if (boost::optional<boost::property_tree::ptree&> node = block_entry.get_child_optional(\"top_color\")) {\n        top_color = color_tr.get_value(node.get());\n      }\n      boost::optional<color> side_color = boost::optional<color>();\n      if (boost::optional<boost::property_tree::ptree&> node = block_entry.get_child_optional(\"side_color\")) {\n        side_color = color_tr.get_value(node.get());\n      }\n      boost::optional<bool> darken_side = block_entry.get_optional<bool>(\"darken\");\n      std::vector<int> legacy_id;\n      if (boost::optional<boost::property_tree::ptree&> node = block_entry.get_child_optional(\"legacy_id\")) {\n        legacy_id = int_vector_from_json(node.get());\n      }\n      boost::optional<int> legacy_meta = block_entry.get_optional<int>(\"legacy_meta\");\n      if (mc_namespace && material) {\n        if (legacy_id.size() == 0 && legacy_meta) {\n           error << \"Invalid entry; \" << mc_namespace.get() << \":\" << material.get() << \" has invalid legacy attributes.\" << std::endl;\n        } else if(!mode) {\n          error << \"Invalid entry; \" << mc_namespace.get() << \":\" << material.get() << \" is missing the material mode attribute.\" << std::endl;\n        } else if (legacy_meta && (legacy_meta.get() < 0 || legacy_meta.get() >= 16)) {\n          error << \"Invalid entry; \" << mc_namespace.get() << \":\" << material.get() << \" has an invalid legacy meta value, it must be >= 0 and < 16.\" << std::endl;\n        } else if (mode.get() == mc::MaterialMode::LegacySlab && legacy_id.size() != 2) {\n          error << \"Invalid entry; \" << mc_namespace.get() << \":\" << material.get() << \" has invalid legacy mode; exactly two legacy ids are required.\" << std::endl;\n        } else {\n          if (!top_color) {\n            error << \"Warning; block \" << mc_namespace.get() << \":\" << material.get() << \" has no top color set\" << std::endl;\n          }\n          color top = top_color.value_or(mc::SharedDefaultColor);\n          color side = side_color.value_or(top);\n          if (!darken_side || darken_side.get()) {\n            side.darken(0x20);\n          }\n          mc::MaterialTable.push_back(mc::MaterialT { mc_namespace.get(), material.get(), mode.get(), top, side, legacy_id, legacy_meta.value_or(0), s.enable_all_blocks });\n        }\n      } else {\n        error << \"Invalid entry; entry is missing namespace or material attribute.\" << std::endl;\n      }\n    }\n\n    // Whenever the MaterialTable is changed the palette lookup\n    // tables needs to be regenerated.\n    mc::reload_palette();\n\n    return true;\n}\n\nint flag;\n\nstruct option long_options[] =\n {\n        {\"world\",                                                             required_argument,     0,             'w'},\n        {\"output\",                                                            required_argument,     0,             'o'},\n        {\"top\",                                                                 required_argument,     0,             't'},\n        {\"bottom\",                                                            required_argument,     0,             'b'},\n        {\"limits\",                                                            required_argument,     0,             'L'},\n        {\"radius\",                                                            required_argument,     0,             'R'},\n        {\"memory-limit\",                                                required_argument,     0,             'M'},\n        {\"cache-file\",                                                    required_argument,     0,             'C'},\n        {\"swap-file\",                                                     required_argument,     0,             'C'},\n        {\"exclude\",                                                         required_argument,     0,             'e'},\n        {\"include\",                                                         required_argument,     0,             'i'},\n        {\"rotate\",                                                            required_argument,     0,             'r'},\n        {\"threads\",                                                         required_argument,     0,             'm'},\n        {\"help\",                                                                no_argument,                 0,             'h'},\n        {\"silent\",                                                            no_argument,                 0,             's'},\n        {\"version\",                                                         no_argument,                 0,             'v'},\n        {\"debug\",                                                             no_argument,                 0,             'D'},\n        {\"list-colors\",                                                 no_argument,                 0,             'l'},\n        {\"hide-all\",                                                        no_argument,                 0,             'a'},\n        {\"no-check\",                                                        no_argument,                 0,             'N'},\n        {\"oblique\",                                                         no_argument,                 0,             'q'},\n        {\"oblique-angle\",                                             no_argument,                 0,             'y'},\n        {\"isometric\",                                                     no_argument,                 0,             'z'},\n        {\"fatiso\",                                                            no_argument,                 0,             'Z'},\n        {\"cave-mode\",                                                     no_argument,                 0,             'c'},\n        {\"night\",                                                             no_argument,                 0,             'n'},\n        {\"heightmap\",                                                     no_argument,                 0,             'H'},\n        {\"binary\",                                                            no_argument,                 0,             'x'},\n        {\"require-all\",                                                 no_argument,                 &flag,     0},\n        {\"show-players\",                                                optional_argument,     &flag,     1},\n        {\"ttf-path\",                                                        required_argument,     &flag,     2},\n        {\"ttf-size\",                                                        required_argument,     &flag,     3},\n        {\"ttf-color\",                                                     required_argument,     &flag,     4},\n        {\"show-coordinates\",                                        no_argument,                 &flag,     5},\n        {\"pedantic-broad-phase\",                                no_argument,                 &flag,     6},\n        {\"show-signs\",                                                    optional_argument,     &flag,     7},\n        {\"sign-color\",                                                    required_argument,     &flag,     8},\n        {\"player-color\",                                                required_argument,     &flag,     9},\n        {\"coordinate-color\",                                        required_argument,     &flag,     10},\n        {\"cache-key\",                                                     required_argument,     &flag,     11},\n        {\"cache-dir\",                                                     required_argument,     &flag,     12},\n        {\"cache-compress\",                                            no_argument,                 &flag,     13},\n        {\"no-alpha\",                                                        no_argument,                 &flag,     14},\n        {\"striped-terrain\",                                         no_argument,                 &flag,     15},\n        {\"write-json\",                                                    required_argument,     &flag,     16},\n        {\"write-js\",                                                        required_argument,     &flag,     26},\n        {\"write-markers\",                                             required_argument,     &flag,     21},\n        {\"split\",                                                             required_argument,     0,             'p'},\n        {\"split-base\",                                                    required_argument,     &flag,     27},\n        {\"show-warps\",                                                    required_argument,     &flag,     18},\n        {\"warp-color\",                                                    required_argument,     &flag,     19},\n        {\"prebuffer\",                                                     required_argument,     &flag,     20},\n        {\"hell-mode\",                                                     no_argument,                 &flag,     22},\n        {\"statistics\",                                                    optional_argument,     0,             'S'},\n        {\"log\",                                                                 required_argument,     &flag,     24},\n        {\"no-log\",                                                            no_argument,                 &flag,     25},\n        {\"center\",                                                            required_argument,     &flag,     30},\n        {\"graph-block\",                                                 required_argument,     &flag,     31},\n        {\"strip-sign-prefix\",                                     no_argument,                 &flag,     32},\n        {\"engine\",                                                            required_argument,     &flag,     64},\n        {\"side\",                                                   required_argument,     &flag,     65},\n        {0,                                                                         0,                                     0,             0}\n};\n\nbool read_opts(settings_t& s, int argc, char* argv[])\n{\n    int c;\n    int option_index;\n\n    while ((c = getopt_long(argc, argv, \"DNvxcnHqzZyalshM:C:L:R:w:o:e:t:b:i:m:r:W:P:B:S:p:\", long_options, &option_index)) != -1)\n    {\n        if (c == 0) {\n            switch (flag) {\n            case 0:\n                s.require_all = true;\n                break;\n            case 1:\n                s.show_players = true;\n                if (optarg != NULL) {\n                    if (!read_set(s.show_players_set, optarg)) {\n                        return false;\n                    }\n                }\n                break;\n            case 2:\n                s.ttf_path = optarg;\n\n                if (access(optarg, R_OK) == -1) {\n                    error << \"ttf path cannot be accessed\";\n                    return false;\n                }\n\n                break;\n            case 3:\n                s.ttf_size = atoi(optarg);\n\n                if (s.ttf_size <= 0) {\n                    error << \"ttf-size must be greater than 0\";\n                    return false;\n                }\n\n                break;\n            case 4:\n                if (!parse_color(optarg, s.ttf_color)) {\n                    return false;\n                }\n                break;\n            case 5:\n                s.show_coordinates = true;\n                break;\n            case 6:\n                s.pedantic_broad_phase = true;\n                break;\n            case 7:\n                s.show_signs = true;\n\n                if (optarg) {\n                    s.show_signs_filter = optarg;\n\n                    if (s.show_signs_filter.empty()) {\n                        error << \"Sign filter must not be empty string\";\n                        return false;\n                    }\n                }\n\n                break;\n            case 8:\n                if (!parse_color(optarg, s.sign_color)) {\n                    return false;\n                }\n\n                s.has_sign_color = true;\n                break;\n            case 9:\n                if (!parse_color(optarg, s.player_color)) {\n                    return false;\n                }\n\n                s.has_player_color = true;\n                break;\n            case 10:\n                if (!parse_color(optarg, s.coordinate_color)) {\n                    return false;\n                }\n\n                s.has_coordinate_color = true;\n                break;\n            case 11:\n                s.cache_use = true;\n                s.cache_key = optarg;\n                break;\n            case 12:\n                s.cache_dir = optarg;\n                break;\n            case 13:\n                s.cache_compress = true;\n                break;\n            case 14:\n                s.disable_alpha = true;\n                break;\n            case 15:\n                s.striped_terrain = true;\n                break;\n            case 21:\n                hints.push_back(\"`--write-markers' has been deprecated in favour of `--write-json' - use that instead and note the new json structure\");\n            case 16:\n                s.write_json = true;\n\n                s.write_json_path = fs::system_complete(fs::path(optarg));\n\n                {\n                    fs::path parent = s.write_json_path.parent_path();\n\n                    if (!fs::is_directory(parent)) {\n                        error << \"Not a directory: \" << parent.string();\n                        return false;\n                    }\n                }\n\n                break;\n            case 26:\n                s.write_js = true;\n\n                s.write_js_path = fs::system_complete(fs::path(optarg));\n\n                {\n                    fs::path parent = s.write_js_path.parent_path();\n\n                    if (!fs::is_directory(parent)) {\n                        error << \"Not a directory: \" << parent.string();\n                        return false;\n                    }\n                }\n\n                break;\n            case 27:\n                try {\n                    s.split_base = boost::lexical_cast<int>(optarg);\n                } catch(boost::bad_lexical_cast& e) {\n                    error << \"Cannot be converted to number: \" << optarg;\n                    return false;\n                }\n\n                if (!(s.split_base >= 1)) {\n                    error << \"split argument must be greater or equal to one\";\n                    return false;\n                }\n                break;\n            case 18:\n                s.show_warps = true;\n                s.show_warps_path = fs::system_complete(fs::path(optarg));\n                break;\n            case 19:\n                if (!parse_color(optarg, s.warp_color)) {\n                    return false;\n                }\n\n                s.has_warp_color = true;\n                break;\n            case 20:\n                s.prebuffer = atoi(optarg);\n\n                if (s.prebuffer <= 0) {\n                    error << \"Number of prebuffered jobs must be more than 0\";\n                    return false;\n                }\n\n                break;\n            case 22:\n                s.hellmode = true;\n                break;\n            case 24:\n                s.output_log = fs::system_complete(fs::path(optarg));\n                break;\n            case 25:\n                s.no_log = true;\n                break;\n            case 30:\n                if (!parse_tuple(optarg, s, s.center_x, s.center_z)) {\n                    return false;\n                }\n                break;\n            case 31:\n                s.graph_block = optarg;\n                break;\n            case 32:\n                s.strip_sign_prefix = true;\n                break;\n            case 64:\n                s.engine_path = fs::system_complete(fs::path(optarg));\n\n                if (!fs::is_regular_file(s.engine_path)) {\n                    error << optarg << \": not a file\";\n                    return false;\n                }\n\n                s.engine_use = true;\n                break;\n            case 65:\n                s.side_color_overrides.push_back(optarg);\n            }\n\n            continue;\n        }\n\n        switch (c)\n        {\n        case 'v':\n            s.action = Version;\n            break;\n        case 'h':\n            s.action = Help;\n            break;\n        case 'm':\n            s.threads = atoi(optarg);\n\n            if (s.threads <= 0) {\n                error << \"Number of worker threads must be more than 0\";\n                return false;\n            }\n\n            break;\n        case 'q':\n            s.mode = Oblique;\n            break;\n        case 'z':\n            s.mode = Isometric;\n            break;\n        case 'Z':\n            s.mode = FatIso;\n            break;\n        case 'D':\n            s.debug = true;\n            break;\n        case 'y':\n            s.mode = ObliqueAngle;\n            break;\n        case 'a':\n            s.enable_all_blocks = false;\n            break;\n        case 'i':\n            s.included.push_back(optarg);\n            break;\n        case 'e':\n            s.excluded.push_back(optarg);\n            break;\n        case 'w':\n            s.world_path = fs::system_complete(fs::path(optarg));\n            break;\n        case 'o':\n            s.action = GenerateWorld;\n            s.output_path = fs::system_complete(fs::path(optarg));\n            break;\n        case 's':\n            s.silent = true;\n            break;\n        case 'x':\n            s.binary = true;\n            break;\n        case 'r':\n            s.rotation = atoi(optarg) % 360;\n            if (s.rotation < 0) {\n                s.rotation += 360;\n            }\n            if (s.rotation % 90 != 0) {\n                error << \"Rotation must be a multiple of 90 degrees\";\n                return false;\n            }\n\n            break;\n        case 'N': s.nocheck = true; break;\n        case 'n': s.night = true; break;\n        case 'H': s.heightmap = true; break;\n        case 'c': s.cavemode = true; break;\n        case 't':\n            s.top = atoi(optarg);\n\n            if (!(s.top > s.bottom && s.top < mc::MapY)) {\n                error << \"Top limit must be between `<bottom limit> - \" << mc::MapY << \"', not \" << s.top;\n                return false;\n            }\n\n            break;\n        case 'L':\n            if (!parse_limits(optarg, s)) {\n                return false;\n            }\n            break;\n        case 'R':\n            s.max_radius = boost::lexical_cast<uint64_t>(optarg);\n\n            if (s.max_radius < 1) {\n                error << \"Radius must be greater than zero\";\n                return false;\n            }\n\n            if (s.max_radius > 0xffffffff) {\n                error << \"Radius too big\";\n                return false;\n            }\n            break;\n        case 'b':\n            s.bottom = atoi(optarg);\n\n            if (!(s.bottom < s.top && s.bottom >= 0)) {\n                error << \"Bottom limit must be between `0 - <top limit>', not \" << s.bottom;\n                return false;\n            }\n\n            break;\n        case 'l':\n            s.action = ListColors;\n            break;\n        case 'M':\n            {\n                s.memory_limit = boost::lexical_cast<int>(optarg);\n\n                if (s.memory_limit <= 0) {\n                    error << \"Memory limit must be non-negative value, not \" << s.memory_limit;\n                    return false;\n                }\n\n                s.memory_limit_default = false;\n            }\n            break;\n        case 'C':\n            s.swap_file = fs::system_complete(fs::path(optarg));\n            break;\n        case 'W':\n            s.palette_write_path = optarg;\n            break;\n        case 'P':\n            s.palette_read_path = optarg;\n            break;\n        case 'B':\n            s.top_color_overrides.push_back(optarg);\n        case 'S':\n            s.action = GenerateStatistics;\n\n            if (optarg != NULL) {\n                s.statistics_path = fs::system_complete(fs::path(optarg));\n            }\n            break;\n        case 'p':\n            {\n                std::list<std::string> result;\n                std::string split_string(optarg);\n                boost_split(result, split_string);\n\n                BOOST_FOREACH(std::string str, result) {\n                    unsigned int split_int = 0;\n\n                    try {\n                        split_int = boost::lexical_cast<int>(str);\n                    } catch(boost::bad_lexical_cast& e) {\n                        error << \"Cannot be converted to number: \" << str;\n                        return false;\n                    }\n\n                    if (!(split_int >= 1)) {\n                        error << \"split argument must be greater or equal to one\";\n                        return false;\n                    }\n\n                    s.split.push_back(split_int);\n                }\n\n                s.use_split = true;\n            }\n            break;\n        case '?':\n            if (optopt == 'c')\n                error << \"Option -\" << optopt << \" requires an argument\";\n            else if (isprint (optopt))\n                error << \"Unknown option `-\" << optopt << \"'\";\n            else\n                error << \"Unknown option character `\\\\x\" << std::hex << static_cast<int>(optopt) << \"'.\";\n\n             return false;\n        default:\n             error << \"Unknown getopt error : ) - congrats, you broke it\";\n             return false;\n        }\n    }\n\n    if (!s.palette_write_path.empty()) {\n        s.action = WritePalette;\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "src/main_utils.hpp",
    "content": "#ifndef __MAIN_UTILS_HPP__\n#define __MAIN_UTILS_HPP__\n\n#include <string>\n#include <set>\n#include <sstream>\n#include <vector>\n#include <string>\n\n#include \"image/color.hpp\"\n#include \"settings_t.hpp\"\n#include \"mc/blocks.hpp\"\n\n#include <boost/filesystem.hpp>\n\nclass application_error : std::exception\n{\n  private:\n    const char* message;\n  public:\n    application_error(const char* message) : message(message) {}\n\n    const char* what() const throw() {\n      return message;\n    }\n};\n\nbool do_write_palette(settings_t& s, const boost::filesystem::path& path);\nbool do_read_palette(settings_t& s, const boost::filesystem::path& path);\n\nbool get_blocktype(const std::string& block_string, mc::MaterialT*& block_type);\n\nbool read_opts(settings_t& s, int argc, char* argv[]);\n\nint do_colors(std::ostream& out);\n\nbool do_base_color_set(const char *set_str);\nbool do_side_color_set(const char *set_str);\n\nextern std::vector<std::string> hints;\nextern std::vector<std::string> warnings;\nextern std::stringstream error;\n\n#endif /* __MAIN_UTILS_HPP__ */\n"
  },
  {
    "path": "src/marker.cpp",
    "content": "#include \"marker.hpp\"\n\nmarker::marker(std::string text, std::string type, text::font_face font, int x, int y, int z)\n    : text(text),\n      type(type),\n      font(font),\n      x(x),\n      y(y),\n      z(z)\n{\n}\n\nstd::string marker::get_text() {\n  return text;\n}\n\nstd::string marker::get_type() {\n  return type;\n}\n\ntext::font_face marker::get_font() {\n  return font;\n}\n\nint marker::get_x() {\n  return x;\n}\n\nint marker::get_y() {\n  return y;\n}\n\nint marker::get_z() {\n  return z;\n}\n"
  },
  {
    "path": "src/marker.hpp",
    "content": "#ifndef __MARKER_HPP__\n#define __MARKER_HPP__\n\n#include <string>\n#include <ostream>\n\n#include <boost/foreach.hpp>\n\n#include \"settings_t.hpp\"\n\n#include \"text.hpp\"\n#include \"players.hpp\"\n\n#include \"mc/blocks.hpp\"\n#include \"mc/marker.hpp\"\n#include \"mc/level_info.hpp\"\n#include \"mc/rotated_level_info.hpp\"\n#include \"mc/world.hpp\"\n\nstruct marker {\npublic:\n  marker(std::string text, std::string type, text::font_face font, int x, int y, int z);\n\n  std::string get_text();\n  std::string get_type();\n  text::font_face get_font();\n\n  int get_x();\n  int get_y();\n  int get_z();\nprivate:\n  std::string text;\n  std::string type;\n  text::font_face font;\n  int x;\n  int y;\n  int z;\n};\n\n#endif /*__MARKER_HPP__*/\n"
  },
  {
    "path": "src/mc/CMakeLists.txt",
    "content": "add_library(\n  c10t-mc\n  blocks.cpp\n  level.cpp\n  utils.cpp\n  world.cpp\n  region.cpp\n  level_info.cpp\n  region_iterator.cpp\n  rotated_level_info.cpp\n  dynamic_buffer.cpp\n  marker.cpp\n)\n\nset_target_properties(c10t-mc PROPERTIES COMPILE_FLAGS \"-O3 -Wall -pedantic -g\")\n"
  },
  {
    "path": "src/mc/blocks.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n\n#include <boost/property_tree/json_parser.hpp>\n#include <boost/foreach.hpp>\n#include <boost/optional.hpp>\n#include <iostream>\n#include \"blocks.hpp\"\n\nnamespace mc {\n  const color SharedInvisColor = color(0, 0, 0, 0);\n  const color SharedDefaultColor = color(0, 0, 0, 0xff);\n\n  const int MapX = 0x10;\n  const int MapZ = 0x10;\n  const int MapY = 0x100;\n\n  std::vector<MaterialT> MaterialTable;\n  std::map<std::string, MaterialT*> MaterialMap;\n  std::vector<std::vector<MaterialT*>> MaterialPaletteLegacy;\n\n  // Regenerate the internal lookup tables for materials (by name and by legacy id+meta).\n  // The internal lookup tables use direct pointer into the primary material list;\n  // therfore any changes to the size of that list must be directly followed by a call\n  // to this method or undefined behaviour can be expected.\n  void reload_palette() {\n    MaterialMap.clear();\n    MaterialPaletteLegacy.clear();\n    MaterialTable.shrink_to_fit();\n    MaterialPaletteLegacy.resize(MaterialTable.size());\n    MaterialT *materials = MaterialTable.data();\n    for (size_t i = 0; i < MaterialTable.size(); i++) {\n      MaterialT *material = &materials[i];\n      std::string fq_material = material->mc_namespace + \":\" + material->name;\n      std::pair<std::map<std::string, MaterialT*>::iterator, bool> const& result =\n        MaterialMap.insert(std::map<std::string, MaterialT*>::value_type(fq_material, material));\n      if (!result.second) {\n        std::cerr << \"Palette loader: Duplicated name \" << fq_material << std::endl;\n        // For now the last parsed material shall take precedence, this is similar\n        // to the legacy loader below.\n        result.first->second = material;\n      }\n      BOOST_FOREACH(int j, material->legacy_ids) {\n        if (material->legacy_meta >= 0 && material->legacy_meta < 16) {\n            if (MaterialPaletteLegacy[j].size() == 0 && material->legacy_meta == 0) {\n              MaterialPaletteLegacy[j].resize(1);\n            } else if (MaterialPaletteLegacy[j].size() <= static_cast<size_t>(material->legacy_meta)) {\n              MaterialPaletteLegacy[j].resize(16);\n            }\n            if (MaterialPaletteLegacy[j][material->legacy_meta]) {\n              MaterialT *previous = MaterialPaletteLegacy[j][material->legacy_meta];\n              std::cerr << \"Legacy Palette loader: \" << fq_material << \" is overwriting \" << previous->mc_namespace << \":\" << previous->name << std::endl;\n            }\n            MaterialPaletteLegacy[j][material->legacy_meta] = material;\n        } else {\n          // This code should not be reached; unless a programming error is present or memory corruption occurred.\n          // JSON loader code shall refuse to load blocks that would result in this state.\n          std::cerr << \"Legacy Palette loader: Invalid internal state for \" << fq_material << \", legacy lookup cannot be initailized.\" << std::endl;\n        }\n      }\n    }\n  }\n\n  void initialize_constants() {\n  }\n\n  void deinitialize_constants() {\n    MaterialMap.clear();\n    MaterialPaletteLegacy.clear();\n  }\n}\n"
  },
  {
    "path": "src/mc/blocks.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef _BLOCKS_H_\n#define _BLOCKS_H_\n\n#include <iostream>\n#include <map>\n\n#include <boost/optional.hpp>\n\n#include \"image/color.hpp\"\n\nnamespace mc {\n  enum MaterialMode {\n    Block,\n    HalfBlock,\n    TorchBlock,\n    LargeFlowerBlock,\n    LogBlock,\n    LegacySlab,\n    LegacyLeaves\n  };\n\n  enum LegacyBlocks {\n    Air = 0x00,\n    Grass = 0x02,\n    Leaves = 0x12\n  };\n\n  const char MATERIAL_MODE_BLOCK[] = \"block\";\n  const char MATERIAL_MODE_HALF_BLOCK[] = \"half_block\";\n  const char MATERIAL_MODE_TORCH_BLOCK[] = \"torch_block\";\n  const char MATERIAL_MODE_LARGE_FLOWER_BLOCK[] = \"large_plant_block\";\n  const char MATERIAL_MODE_LOG_BLOCK[] = \"log_block\";\n  const char MATERIAL_MODE_LEGACY_SLAB[] = \"legacy_slab_block\";\n  const char MATERIAL_MODE_LEGACY_LEAVES[] = \"legacy_leaf_block\";\n\n  struct MaterialMode_tr_to_string {\n    typedef MaterialMode internal_type;\n    typedef std::string external_type;\n\n    boost::optional<std::string> get_value(const MaterialMode &m) {\n      switch(m) {\n      case MaterialMode::Block:\n        return boost::make_optional<std::string>(MATERIAL_MODE_BLOCK);\n        break;\n      case MaterialMode::HalfBlock:\n        return boost::make_optional<std::string>(MATERIAL_MODE_HALF_BLOCK);\n        break;\n      case MaterialMode::TorchBlock:\n        return boost::make_optional<std::string>(MATERIAL_MODE_TORCH_BLOCK);\n        break;\n      case MaterialMode::LargeFlowerBlock:\n        return boost::make_optional<std::string>(MATERIAL_MODE_LARGE_FLOWER_BLOCK);\n        break;\n      case MaterialMode::LogBlock:\n        return boost::make_optional<std::string>(MATERIAL_MODE_LOG_BLOCK);\n        break;\n      case MaterialMode::LegacySlab:\n        return boost::make_optional<std::string>(MATERIAL_MODE_LEGACY_SLAB);\n        break;\n      case MaterialMode::LegacyLeaves:\n        return boost::make_optional<std::string>(MATERIAL_MODE_LEGACY_LEAVES);\n        break;\n      default:\n        return boost::optional<std::string>();\n      }\n    }\n  };\n\n  struct MaterialMode_tr_from_string {\n    typedef std::string internal_type;\n    typedef MaterialMode external_type;\n\n    boost::optional<MaterialMode> get_value(const std::string &s) {\n      if (MATERIAL_MODE_BLOCK == s) {\n        return boost::make_optional<MaterialMode>(MaterialMode::Block);\n      } else if (MATERIAL_MODE_HALF_BLOCK == s) {\n        return boost::make_optional<MaterialMode>(MaterialMode::HalfBlock);\n      } else if (MATERIAL_MODE_TORCH_BLOCK == s) {\n        return boost::make_optional<MaterialMode>(MaterialMode::TorchBlock);\n      } else if (MATERIAL_MODE_LARGE_FLOWER_BLOCK == s) {\n        return boost::make_optional<MaterialMode>(MaterialMode::LargeFlowerBlock);\n      } else if (MATERIAL_MODE_LOG_BLOCK == s) {\n        return boost::make_optional<MaterialMode>(MaterialMode::LogBlock);\n      } else if (MATERIAL_MODE_LEGACY_SLAB == s) {\n        return boost::make_optional<MaterialMode>(MaterialMode::LegacySlab);\n      } else if (MATERIAL_MODE_LEGACY_LEAVES == s) {\n        return boost::make_optional<MaterialMode>(MaterialMode::LegacyLeaves);\n      }\n      return boost::optional<MaterialMode>();\n    }\n  };\n\n  void reload_palette();\n  void initialize_constants();\n  void deinitialize_constants();\n\n  extern const color SharedInvisColor;\n  extern const color SharedDefaultColor;\n\n  extern const int MapY;\n  extern const int MapX;\n  extern const int MapZ;\n\n  typedef struct {\n    std::string mc_namespace;\n    std::string name;\n    MaterialMode mode;\n    color top;\n    color side;\n    std::vector<int> legacy_ids;\n    int legacy_meta;\n    bool enabled;\n  } MaterialT;\n  extern std::vector<MaterialT> MaterialTable;\n  extern std::map<std::string, MaterialT*> MaterialMap;\n  extern std::vector<std::vector<MaterialT*>> MaterialPaletteLegacy;\n\n  inline boost::optional<MaterialT*> get_material_legacy(int material, int data) {\n    // Legacy lookup needs to aggressivly fallback to the first metadata\n    // variant when possible, this is because some blocks have either only\n    // one variant with multiple states or even multiple\n    // variants with multiple states.\n    if (material >= 0 && static_cast<unsigned int>(material) < MaterialPaletteLegacy.size()) {\n        if (data < 0) {\n          data = 0;\n        }\n        unsigned int udata = static_cast<unsigned int>(data);\n        std::vector<MaterialT*> subpallet = MaterialPaletteLegacy[material];\n        if (subpallet.size() == 1) {\n          udata = 0;\n        }\n        if (udata < subpallet.size() && subpallet[udata]) {\n          return boost::optional<MaterialT*>(subpallet[udata]);\n        } else if(subpallet.size() > 0 && subpallet[0]) {\n          return subpallet[0];\n        }\n    }\n    std::cout << \"Unkown legacy material (\" << std::hex << material << \":\" << std::hex << data << \")\" << std::endl;\n    return boost::optional<MaterialT*>();\n  }\n\n  inline color get_color_legacy(int material, int data) {\n    boost::optional<MaterialT*> blocktype = get_material_legacy(material, data);\n    if (blocktype) {\n      return blocktype.get()->top;\n    } else {\n      return SharedDefaultColor;\n    }\n  }\n\n  inline color get_side_color_legacy(int material, int data) {\n    boost::optional<MaterialT*> blocktype = get_material_legacy(material, data);\n    if (blocktype) {\n      return blocktype.get()->side;\n    } else {\n      return SharedDefaultColor;\n    }\n  }\n\n  inline color get_color_legacy(int material) {\n    return get_color_legacy(material, 0);\n  }\n\n  inline color get_side_color_legacy(int material) {\n    return get_side_color_legacy(material, 0);\n  }\n}\n\n#endif /* _BLOCKS_H_ */\n"
  },
  {
    "path": "src/mc/dynamic_buffer.cpp",
    "content": "#include \"mc/dynamic_buffer.hpp\"\n\n#include <string.h>\n\nnamespace mc {\n  dynamic_buffer::dynamic_buffer(size_t size)\n    : factor(1), factor_max(DEFAULT_FACTOR_MAX),\n      size(size), buffer_size(size), buffer(new char[size])\n  {\n  }\n\n  dynamic_buffer::dynamic_buffer(size_t size, int factor_max)\n    : factor(1), factor_max(factor_max),\n      size(size), buffer_size(size), buffer(new char[size])\n  {\n  }\n\n  dynamic_buffer::~dynamic_buffer() {\n    delete [] buffer;\n  }\n\n  size_t dynamic_buffer::get_size() {\n    return buffer_size;\n  }\n\n  char* dynamic_buffer::get() {\n    return buffer;\n  }\n\n  /**\n   * Expand the buffer and return the amount it has been expanded with.\n   */\n  size_t dynamic_buffer::expand() {\n    if (factor >= factor_max) {\n      return 0;\n    }\n\n    factor += 1;\n\n    size_t new_size = factor * size;\n    char* new_buffer = new char[new_size];\n\n    memcpy(new_buffer, buffer, buffer_size);\n    delete[] buffer;\n\n    size_t expanded_size = new_size - buffer_size;\n\n    buffer = new_buffer;\n    buffer_size = new_size;\n    return expanded_size;\n  }\n}\n"
  },
  {
    "path": "src/mc/dynamic_buffer.hpp",
    "content": "#ifndef _MC_DYNAMIC_BUFFER_HPP\n#define _MC_DYNAMIC_BUFFER_HPP\n\n#include <unistd.h>\n\nnamespace mc {\n  /*\n   * A dynamic buffer can be used when you need a fixed sized buffer that can\n   * be expanded.\n   *\n   * This is useful if you have a shared buffer of optimal size which might\n   * expand, but won't in the normal case.\n   */\n  class dynamic_buffer {\n  public:\n    enum {\n      DEFAULT_FACTOR_MAX = 16\n    };\n\n    dynamic_buffer(size_t size);\n    dynamic_buffer(size_t size, int factor_max);\n    ~dynamic_buffer();\n\n    size_t get_size();\n    char* get();\n\n    /**\n     * Expand the buffer and return the amount it has been expanded with.\n     */\n    size_t expand();\n  private:\n    int factor;\n    int factor_max;\n    size_t size;\n    size_t buffer_size;\n    char* buffer;\n  };\n}\n\n#endif /* _MC_DYNAMIC_BUFFER_HPP */\n"
  },
  {
    "path": "src/mc/level.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"mc/level.hpp\"\n\n#include \"nbt/nbt.hpp\"\n#include \"mc/region.hpp\"\n#include \"mc/level_info.hpp\"\n\n#include <boost/shared_array.hpp>\n#include <boost/shared_ptr.hpp>\n\n/*\nCompound() {\n  Compound(Level) {\n    List(Entities, TAG_Byte, 0): [ ]\n    ByteArray(Biomes): (256 bytes)\n    Long(LastUpdate): 7446079\n    Int(xPos): -1\n    Int(zPos): -1\n    List(TileEntities, TAG_Compound, 0): [ ]\n    Byte(TerrainPopulated): 0x1\n    IntArray(HeightMap): (256 ints)\n    List(Sections, TAG_Compound, 1): [\n      Compound() {\n        ByteArray(SkyLight): (2048 bytes)\n        ByteArray(BlockLight): (2048 bytes)\n        Byte(Y): 0x0\n        ByteArray(BlockStates): (4096 bytes)\n      }\n    ]\n  }\n}\n*/\n\nnamespace mc {\n  enum section_name {\n    Level,\n    Sections,\n    None\n  };\n\n  struct level_context {\n    boost::shared_ptr<Level_Compound> Level;\n    \n    bool error;\n    size_t error_where;\n    const char* error_why;\n\n    Section_Compound* tmp_Section;\n\n    section_name p[64];\n    int pos;\n\n    level_context() : error(false), error_where(0), error_why(\"\")\n    {\n      this->Level.reset(new Level_Compound);\n      this->pos = 0;\n    }\n  };\n\n  inline bool in_level_section(level_context* C) {\n    return   C->pos == 4\n          && C->p[0] == None\n          && C->p[1] == Level\n          && C->p[2] == Sections\n          && C->p[3] == None;\n  }\n\n  void begin_compound(level_context* C, nbt::String name) {\n    if (name.compare(\"Level\") == 0) {\n      C->p[C->pos++] = Level;\n      return;\n    }\n\n    C->p[C->pos++] = None;\n\n    if (in_level_section(C)) {\n        C->tmp_Section = new Section_Compound;\n        C->tmp_Section->Y = 0;\n    }\n  }\n\n  void end_compound(level_context* C, nbt::String name) {\n    if (in_level_section(C)) {\n        if (!C->tmp_Section->Data) {\n            std::cout << \"missing Data\" << std::endl;\n        }\n\n        if (!C->tmp_Section->SkyLight) {\n            std::cout << \"missing SkyLight\" << std::endl;\n        }\n\n        if (!C->tmp_Section->BlockLight) {\n            std::cout << \"missing BlockLight\" << std::endl;\n        }\n\n        if (!C->tmp_Section->Blocks) {\n            std::cout << \"missing Blocks\" << std::endl;\n        }\n\n        C->Level->Sections.push_back(C->tmp_Section);\n        C->tmp_Section = NULL;\n    }\n\n    --C->pos;\n  }\n\n  void begin_list(level_context* C, nbt::String name, nbt::Byte type, nbt::Int count) {\n    if (name.compare(\"Sections\") == 0) {\n      C->p[C->pos++] = Sections;\n      return;\n    }\n\n    C->p[C->pos++] = None;\n  }\n\n  void end_list(level_context* C, nbt::String name) {\n    --C->pos;\n  }\n\n  void register_string(level_context* C, nbt::String name, nbt::String value) {\n  }\n\n  void register_byte(level_context* C, nbt::String name, nbt::Byte value) {\n    if (in_level_section(C))\n    {\n      if (name.compare(\"Y\") == 0) {\n        C->tmp_Section->Y = value;\n        return;\n      }\n    }\n  }\n\n  void register_int(level_context* C, nbt::String name, nbt::Int i) {\n  }\n\n  void register_int_array(level_context* C, nbt::String name, nbt::IntArray* int_array) {\n  }\n\n  void register_byte_array(level_context* C, nbt::String name, nbt::ByteArray* byte_array) {\n    if (in_level_section(C))\n    {\n      if (name.compare(\"Data\") == 0) {\n        C->tmp_Section->Data.reset(byte_array);\n        return;\n      }\n\n      if (name.compare(\"SkyLight\") == 0) {\n        C->tmp_Section->SkyLight.reset(byte_array);\n        return;\n      }\n\n      if (name.compare(\"BlockLight\") == 0) {\n        C->tmp_Section->BlockLight.reset(byte_array);\n        return;\n      }\n\n      if (name.compare(\"Blocks\") == 0) {\n        C->tmp_Section->Blocks.reset(byte_array);\n        return;\n      }\n    }\n\n    delete byte_array;\n  }\n\n  void register_long_array(level_context* C, nbt::String name, nbt::LongArray* long_array) {\n\n    delete long_array;\n  }\n  \n  void error_handler(level_context* C, size_t where, const char *why) {\n    C->error = true;\n    C->error_where = where;\n    C->error_why = why;\n  }\n\n  level::~level(){\n  }\n\n  level::level(level_info_ptr _level_info) : _level_info(_level_info) {}\n\n  std::string level::get_path() {\n    return _level_info->get_path();\n  }\n\n  bool level::operator<(const level& other) const {\n    return _level_info->get_coord() < other._level_info->get_coord();\n  }\n\n  time_t level::modification_time()\n  {\n    return _level_info->modification_time();\n  }\n\n  boost::shared_ptr<Level_Compound> level::get_level() {\n    return Level;\n  }\n\n  /**\n   * might throw invalid_file if the file is not gramatically correct\n   */\n  void level::read(dynamic_buffer& buffer)\n  {\n    level_context context;\n    \n    nbt::Parser<level_context> parser(&context);\n    \n    parser.register_byte_array = register_byte_array;\n    parser.register_int_array = register_int_array;\n    parser.register_long_array = register_long_array;\n    parser.register_byte = register_byte;\n    parser.register_string = register_string;\n    parser.register_int = register_int;\n    parser.begin_compound = begin_compound;\n    parser.begin_list = begin_list;\n    parser.end_list = end_list;\n    parser.end_compound = end_compound;\n    parser.error_handler = error_handler;\n\n    std::stringstream oss;\n\n    uint32_t len;\n\n    try {\n      len = _level_info->get_region()->read_data(_level_info->get_x(),\n          _level_info->get_z(), buffer);\n    } catch(mc::bad_region& e) {\n      throw invalid_file(e.what());\n    }\n\n    std::string chunk_data = oss.str();\n\n    parser.parse_buffer(buffer.get(), len);\n    \n    if (context.error) {\n      throw invalid_file(context.error_why);\n    }\n    \n    if (!context.Level) {\n      throw invalid_file(\"not a level data file\");\n    }\n\n    Level = context.Level;\n  }\n}\n"
  },
  {
    "path": "src/mc/level.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef __MC_LEVEL_HPP__\n#define __MC_LEVEL_HPP__\n\n#include <boost/filesystem.hpp>\n#include <boost/shared_ptr.hpp>\n#include <boost/ptr_container/ptr_vector.hpp>\n\n#include \"mc/dynamic_buffer.hpp\"\n#include \"mc/utils.hpp\"\n#include \"mc/marker.hpp\"\n\n#include \"nbt/types.hpp\"\n\nnamespace mc {\n  namespace fs = boost::filesystem;\n\n  class level_info;\n  class level;\n  class region;\n\n  typedef boost::shared_ptr<level_info> level_info_ptr;\n  typedef boost::shared_ptr<level> level_ptr;\n  typedef boost::shared_ptr<region> region_ptr;\n\n  class invalid_file : std::exception {\n    private:\n      const char* message;\n    public:\n      invalid_file(const char* message) : message(message) {}\n\n      const char* what() const throw() {\n        return message;\n      }\n  };\n\n  struct Section_Compound {\n    boost::shared_ptr<nbt::ByteArray> Blocks;\n    boost::shared_ptr<nbt::ByteArray> Data;\n    boost::shared_ptr<nbt::ByteArray> SkyLight;\n    boost::shared_ptr<nbt::ByteArray> BlockLight;\n    nbt::Byte Y;\n  };\n\n  struct Level_Compound {\n    nbt::Int xPos;\n    nbt::Int zPos;\n    boost::shared_ptr<nbt::IntArray> HeightMap;\n    boost::ptr_vector<Section_Compound> Sections;\n  };\n\n  class level\n  {\n    public:\n      level(level_info_ptr _level_info);\n      ~level();\n\n      std::string get_path();\n      time_t modification_time();\n\n      /*\n       * might throw invalid_file if the file is not gramatically correct\n       */\n      void read(dynamic_buffer& buffer);\n\n      boost::shared_ptr<Level_Compound> get_level();\n\n      bool operator<(const level& other) const;\n    private:\n      level_info_ptr _level_info;\n\n      // these must be public for the parser to be able to reach them.\n      std::vector<marker> signs;\n\n      boost::shared_ptr<Level_Compound> Level;\n  };\n}\n\n#endif /* __MC_LEVEL_HPP__ */\n"
  },
  {
    "path": "src/mc/level_info.cpp",
    "content": "#include \"mc/level_info.hpp\"\n#include \"mc/region.hpp\"\n\nnamespace mc {\n  level_info::level_info() : coord() {\n  }\n\n  level_info::level_info(region_ptr _region, int x, int z) : _region(_region), coord(x, z) {\n  }\n\n  level_info::level_info(region_ptr _region, utils::level_coord coord) : _region(_region) {\n    utils::level_coord rc = utils::path_to_region_coord(_region->get_path());\n    this->coord = utils::level_coord(rc.get_x() + coord.get_x(),\n                                     rc.get_z() + coord.get_z());\n  }\n\n  std::string level_info::get_path() {\n    std::stringstream ss;\n    ss << _region->get_path().string() << \"(\" << coord.get_x() << \",\" << coord.get_z() << \")\";\n    return ss.str();\n  }\n\n  time_t level_info::modification_time() {\n    return _region->read_modification_time(coord.get_x(), coord.get_z());\n  }\n\n  region_ptr level_info::get_region() {\n    return _region;\n  }\n\n  bool level_info::operator<(const level_info& other) const {\n    return coord < other.coord;\n  }\n\n  level_info level_info::rotate(int degrees) {\n    return level_info(_region, coord.rotate(degrees));\n  }\n\n  int level_info::get_x() {\n    return coord.get_x();\n  }\n\n  int level_info::get_z() {\n    return coord.get_z();\n  }\n\n  const utils::level_coord level_info::get_coord() {\n    return coord;\n  }\n}\n"
  },
  {
    "path": "src/mc/level_info.hpp",
    "content": "#ifndef _MC_LEVEL_INFO_HPP\n#define _MC_LEVEL_INFO_HPP\n\n#include <sstream>\n\n#include \"mc/utils.hpp\"\n\n#include <boost/shared_ptr.hpp>\n\nnamespace mc {\n  class level_info;\n  class region;\n\n  class level_info {\n    public:\n      typedef boost::shared_ptr<region> region_ptr;\n      typedef boost::shared_ptr<level_info> level_info_ptr;\n\n      level_info();\n      level_info(region_ptr _region, int x, int z);\n      level_info(region_ptr _region, utils::level_coord coord);\n\n      std::string get_path();\n\n      region_ptr get_region();\n      time_t modification_time();\n      \n      bool operator<(const level_info& other) const;\n\n      level_info rotate(int degrees);\n      \n      int get_x();\n      int get_z();\n      const utils::level_coord get_coord();\n    private:\n      region_ptr _region;\n      utils::level_coord coord;\n      fs::path path;\n  };\n}\n\n#endif /* _MC_LEVEL_INFO_HPP */\n"
  },
  {
    "path": "src/mc/marker.cpp",
    "content": "#include \"mc/marker.hpp\"\n\nnamespace mc {\n  marker::marker(std::string text, int x, int y, int z) :\n      text(text), x(x), y(y), z(z)\n  {\n  }\n\n  std::string marker::get_text() {\n    return text;\n  }\n\n  int marker::get_x() {\n    return x;\n  }\n\n  int marker::get_y() {\n    return y;\n  }\n\n  int marker::get_z() {\n    return z;\n  }\n}\n"
  },
  {
    "path": "src/mc/marker.hpp",
    "content": "#ifndef _MC_MARKER_HPP\n#define _MC_MARKER_HPP\n\n#include <string>\n\nnamespace mc {\n  /*\n   * designates a text related to a position\n   * Possible usages:\n   *   Signs\n   *   Player Positions\n   *   Custom Markers\n   **/\n  class marker {\n  public:\n    marker(std::string text, int x, int y, int z);\n    std::string get_text();\n    int get_x();\n    int get_y();\n    int get_z();\n  private:\n    std::string text;\n    int x;\n    int y;\n    int z;\n  };\n}\n\n#endif /* _MC_MARKER_HPP */\n"
  },
  {
    "path": "src/mc/region.cpp",
    "content": "#include \"mc/region.hpp\"\n\n#include <zlib.h>\n\n#include <fstream>\n#include <boost/scoped_ptr.hpp>\n\nnamespace mc {\n  class zerror : public std::exception {\n    private:\n      const char* message;\n    public:\n      zerror(const char* message) \n        : message(message)\n      {\n      }\n\n      ~zerror() throw() {  }\n\n      const char* what() const throw() {\n        return message;\n      }\n  };\n\n  class zstream \n  {\n  public:\n    zstream() : strm(new z_stream)\n    {\n      strm->zalloc = (alloc_func)NULL;\n      strm->zfree = (free_func)NULL;\n      strm->opaque = NULL;\n      inflateInit(strm.get());\n    }\n\n    ~zstream()\n    {\n      inflateEnd(strm.get());\n    }\n\n    uint32_t get_avail_out()\n    {\n      return strm->avail_out;\n    }\n\n    uint32_t get_avail_in()\n    {\n      return strm->avail_in;\n    }\n\n    void set_in(Bytef* b, uint32_t len)\n    {\n      strm->next_in = b;\n      strm->avail_in = len;\n    }\n\n    void set_out(Bytef* b, uint32_t len)\n    {\n      strm->next_out = b;\n      strm->avail_out = len;\n    }\n\n    bool in_empty()\n    {\n      return strm->avail_in <= 0;\n    }\n\n    bool out_empty()\n    {\n      return strm->avail_out <= 0;\n    }\n\n    void inflate()\n    {\n      int status = ::inflate(strm.get(), Z_NO_FLUSH);\n\n      switch (status) {\n        case Z_ERRNO:\n          throw zerror(\"failed to inflate data (Z_ERRNO)\");\n        case Z_STREAM_ERROR:\n          throw zerror(\"failed to inflate data (Z_STREAM_ERROR)\");\n        case Z_DATA_ERROR:\n          throw zerror(\"failed to inflate data (Z_DATA_ERROR)\");\n        case Z_MEM_ERROR:\n          throw zerror(\"failed to inflate data (Z_MEM_ERROR)\");\n        case Z_BUF_ERROR:\n          throw zerror(\"failed to inflate data (Z_BUF_ERROR)\");\n        case Z_VERSION_ERROR:\n          throw zerror(\"failed to inflate data (Z_VERSION_ERROR)\");\n        default:\n          break;\n      }\n    }\n  private:\n    boost::scoped_ptr<z_stream> strm;\n  };\n\n  region::region(fs::path path)\n      : path(path), in_buffer(CHUNK_MAX)\n  {\n  }\n\n  void region::read_header()\n  {\n    header.reset(new char[HEADER_SIZE]);\n\n    std::fstream fp(path.string().c_str(), std::ios::in | std::ios::binary);\n\n    if (fp.fail()) {\n      throw bad_region(path, \"failed to open region\");\n    }\n\n    fp.read(header.get(), HEADER_SIZE);\n\n    if (fp.fail()) {\n      throw bad_region(path, \"failed to read header area\");\n    }\n  }\n\n  inline unsigned int region::get_offset(unsigned int x, unsigned int z) const\n  {\n    return 4 * ((x&31) + (z&31) * REGION_SIZE);\n  }\n\n  chunk_offset region::read_chunk_offset(unsigned int x, unsigned int z) const\n  {\n    if (!header) {\n      throw bad_region(path, \"header has not been loaded\");\n    }\n\n    int o = get_offset(x, z);\n\n    uint8_t buf[HEADER_RECORD_SIZE];\n\n    ::memcpy(reinterpret_cast<char*>(buf), &header[o], HEADER_RECORD_SIZE);\n\n    chunk_offset co;\n\n    co.sector_number = ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8)) >> 8;\n    co.sector_count = uint8_t(buf[3]);\n\n    return co;\n  }\n\n  time_t region::read_modification_time(unsigned int x, unsigned int z) const\n  {\n    if (!header) {\n      throw bad_region(path, \"header has not been loaded\");\n    }\n\n    int o = get_offset(x, z) + RECORD_SIZE;\n\n    uint8_t buf[HEADER_RECORD_SIZE];\n\n    ::memcpy(reinterpret_cast<char*>(buf), &header[o], HEADER_RECORD_SIZE);\n\n    uint32_t mtime = ((buf[0] << 24) || (buf[1] << 16) || (buf[2] << 8)) || buf[3];\n    return mtime;\n  }\n\n  uint32_t region::read_data(int x, int z, dynamic_buffer& buffer)\n  {\n    chunk_offset co = read_chunk_offset(x, z);\n    \n    uint8_t buf[5];\n\n    std::fstream fp(path.string().c_str(), std::ios::in | std::ios::binary);\n\n    if (fp.fail()) {\n      throw bad_region(path, \"failed to open file\");\n    }\n\n    fp.seekg(RECORD_SIZE * co.sector_number);\n\n    if (fp.fail()) {\n      throw bad_region(path, \"could not seek\");\n    }\n\n    fp.read(reinterpret_cast<char*>(buf), 5);\n\n    if (fp.fail()) {\n      throw bad_region(path, \"could not read chunk header\");\n    }\n\n    uint32_t len = (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + (buf[3]);\n    uint8_t version = buf[4];\n\n    if (version != 2) {\n      throw bad_region(path, \"bad chunk version\");\n    }\n\n    while (len > in_buffer.get_size()) {\n      if (in_buffer.expand() == 0) {\n        throw bad_region(path, \"region input buffer requires too much memory\");\n      }\n    }\n\n    fp.read(in_buffer.get(), len);\n\n    if (fp.fail()) {\n      throw bad_region(path, \"could not read chunk\");\n    }\n\n    fp.close();\n\n    zstream strm;\n\n    size_t pos = 0;\n\n    strm.set_in(reinterpret_cast<Bytef*>(in_buffer.get()), len - 1);\n    strm.set_out(reinterpret_cast<Bytef*>(buffer.get() + pos), buffer.get_size());\n\n    do {\n      try {\n        strm.inflate();\n      } catch(const zerror& e) {\n        throw bad_region(path, e.what());\n      }\n\n      if (!strm.in_empty()) {\n        uint32_t expanded = buffer.expand();\n\n        if (expanded == 0) {\n          throw bad_region(path, \"region output buffer requires too much memory\");\n        }\n\n        pos += expanded;\n        strm.set_out(reinterpret_cast<Bytef*>(buffer.get() + pos), expanded);\n      }\n    } while(!strm.in_empty());\n\n    return buffer.get_size() - strm.get_avail_out();\n  }\n\n  fs::path region::get_path() {\n    return path;\n  }\n}\n"
  },
  {
    "path": "src/mc/region.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef _MC_REGION_HPP_\n#define _MC_REGION_HPP_\n\n#include <boost/filesystem.hpp>\n#include <boost/shared_array.hpp>\n#include <boost/scoped_array.hpp>\n\n#include \"mc/utils.hpp\"\n#include \"mc/dynamic_buffer.hpp\"\n\n#include <fstream>\n#include <cstring>\n#include <exception>\n#include <unistd.h>\n\nnamespace fs = boost::filesystem;\n\nnamespace mc {\n  class bad_region : public std::exception {\n    private:\n      const fs::path path;\n      const char* message;\n    public:\n      bad_region(const fs::path path, const char* message) \n        : path(path), message(message)\n      {\n      }\n\n      ~bad_region() throw() {  }\n\n      const char* what() const throw() {\n        return message;\n      }\n      \n      const fs::path where() {\n        return path;\n      }\n  };\n\n  typedef struct chunk_offset {\n    uint32_t sector_number;\n    uint8_t sector_count;\n  } chunk_offset;\n\n  class region;\n\n  typedef boost::shared_ptr<region> region_ptr;\n\n  class region {\n  public:\n    enum {\n      HEADER_SIZE = 8192,\n      REGION_SIZE = 32,\n      HEADER_RECORD_SIZE = 4,\n      RECORD_SIZE = 4096,\n      CHUNK_MAX = 1024 * 128\n    } constants;\n  private:\n    fs::path path;\n    boost::shared_array<char> header;\n    dynamic_buffer in_buffer;\n  public:\n    region(fs::path path);\n\n    void read_header();\n    inline unsigned int get_offset(unsigned int x, unsigned int z) const;\n\n    chunk_offset read_chunk_offset(unsigned int x, unsigned int z) const;\n    time_t read_modification_time(unsigned int x, unsigned int z) const;\n\n    template<typename T>\n    void read_coords(T& coll) const\n    {\n      using mc::utils::level_coord;\n\n      for (int z = 0; z < REGION_SIZE; z++) {\n        for (int x = 0; x < REGION_SIZE; x++) {\n          chunk_offset co = read_chunk_offset(x, z);\n\n          if (co.sector_number != 0) {\n            level_coord c(x, z);\n            coll.push_back(c);\n          }\n        }\n      }\n    }\n\n    uint32_t read_data(int x, int z, dynamic_buffer& buffer);\n    fs::path get_path();\n  };\n}\n\n#endif /*_MC_REGION_HPP_*/\n"
  },
  {
    "path": "src/mc/region_inspect.cpp",
    "content": "#include \"mc/region.hpp\"\n#include \"mc/utils.hpp\"\n\n#include \"nbt/nbt.hpp\"\n\n#include <list>\n\n#include <boost/foreach.hpp>\n#include <iostream>\n#include <iomanip>\n\nusing namespace std;\n\nstruct inspect_context {\n  int width;\n};\n\nvoid begin_compound(inspect_context* inspect, nbt::String name) {\n  cout << setw(inspect->width) << \"\"\n       << \"Compound(\" << name << \") {\" << endl;\n  inspect->width += 2;\n}\n\nvoid end_compound(inspect_context* inspect, nbt::String name) {\n  inspect->width -= 2;\n  cout << setw(inspect->width) << \"\"\n       << \"}\" << endl;\n}\n\nvoid begin_list(inspect_context* inspect, nbt::String name, nbt::Byte type, nbt::Int length) {\n  cout << setw(inspect->width) << \"\"\n       << \"List(\" << name << \", \" << nbt::tag_string_map[type] << \", \" << length << \"): [\" << endl;\n  inspect->width += 2;\n}\n\nvoid end_list(inspect_context* inspect, nbt::String name) {\n  inspect->width -= 2;\n  cout << setw(inspect->width) << \"\"\n       << \"]\" << endl;\n}\n\nvoid register_long(inspect_context* inspect, nbt::String name, nbt::Long value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Long(\" << name << \"): \" << dec << value << endl;\n}\n\nvoid register_short(inspect_context* inspect, nbt::String name, nbt::Short value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Short(\" << name << \"): \" << value << endl;\n}\n\nvoid register_string(inspect_context* inspect, nbt::String name, nbt::String value) {\n  cout << setw(inspect->width) << \"\"\n       << \"String(\" << name << \"): \" << value << endl;\n}\n\nvoid register_float(inspect_context* inspect, nbt::String name, nbt::Float value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Float(\" << name << \"): \" << value << endl;\n}\n\nvoid register_double(inspect_context* inspect, nbt::String name, nbt::Double value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Double(\" << name << \"): \" << value << endl;\n}\n\nvoid register_int(inspect_context* inspect, nbt::String name, nbt::Int value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Int(\" << name << \"): \" << dec << value << endl;\n}\n\nvoid register_byte(inspect_context* inspect, nbt::String name, nbt::Byte value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Byte(\" << name << \"): 0x\" << hex << (int)value << endl;\n}\n\nvoid register_byte_array(inspect_context* inspect, nbt::String name, nbt::ByteArray* value) {\n  cout << setw(inspect->width) << \"\"\n       << \"ByteArray(\" << name << \"): \" << \"(\" << dec << int(value->length) << \" bytes)\" << endl;\n  delete value;\n}\n\nvoid register_int_array(inspect_context* inspect, nbt::String name, nbt::IntArray* value) {\n  cout << setw(inspect->width) << \"\"\n       << \"IntArray(\" << name << \"): \" << \"(\" << dec << int(value->length) << \" ints)\" << endl;\n  delete value;\n}\n\nvoid register_long_array(inspect_context* inspect, nbt::String name, nbt::LongArray* value) {\n  cout << setw(inspect->width) << \"\"\n       << \"LongArray(\" << name << \"): \" << \"(\" << dec << int(value->length) << \" longs)\" << endl;\n  delete value;\n}\n\nvoid error_handler(inspect_context* ctx, size_t where, const char* why) {\n  std::cout << where << \":\" << why << std::endl;\n}\n\nint main(int argc, char* argv[]) {\n  using mc::utils::level_coord;\n\n  if (argc < 2) {\n    return 1;\n  }\n\n  inspect_context ctx;\n  \n  nbt::Parser<inspect_context> parser(&ctx);\n\n  parser.error_handler = error_handler;\n  parser.begin_compound = begin_compound;\n  parser.end_compound = end_compound;\n  parser.begin_list = begin_list;\n  parser.end_list = end_list;\n  parser.register_long = register_long;\n  parser.register_short = register_short;\n  parser.register_string = register_string;\n  parser.register_float = register_float;\n  parser.register_double = register_double;\n  parser.register_int = register_int;\n  parser.register_byte = register_byte;\n  parser.register_byte_array = register_byte_array;\n  parser.register_int_array = register_int_array;\n  parser.register_long_array = register_long_array;\n\n  mc::region region(argv[1]);\n\n  list<level_coord> coords;\n\n  std::cout << \"Reading Header\" << std::endl;\n\n  try {\n    region.read_header();\n  } catch(mc::bad_region& e) {\n    std::cout << region.get_path() << \": \" << e.what() << std::endl;\n    return 1;\n  }\n\n  region.read_coords(coords);\n\n  mc::dynamic_buffer buffer(mc::region::CHUNK_MAX);\n\n  BOOST_FOREACH(level_coord c, coords) {\n    std::cout << \"BUFFER SIZE = \" << std::dec << buffer.get_size() << std::endl;\n\n    try {\n      int len = region.read_data(c.get_x(), c.get_z(), buffer);\n      std::cout << \"CHUNK SIZE: \" << std::dec << int(len) << std::endl;\n      ctx.width = 0;\n      parser.parse_buffer(buffer.get(), len);\n    } catch(mc::bad_region& e) {\n      std::cout << region.get_path() << \": \" << e.what() << std::endl;\n    }\n  }\n}\n"
  },
  {
    "path": "src/mc/region_iterator.cpp",
    "content": "#include \"mc/region_iterator.hpp\"\n#include \"mc/region.hpp\"\n#include \"dirlist.hpp\"\n\nbool dir_filter(const std::string& name)\n{\n  if (name.compare(0, 3, \"DIM\") == 0) return false;\n  if (name.compare(\"players\") == 0) return false;\n  return true;\n}\n\nbool file_filter(const std::string& name) {\n  if (name.length() < 8) return false;\n  if (name.compare(name.length() - 4, 4, \".mca\") != 0) return false;\n  if (name.compare(0, 2, \"r.\") != 0) return false;\n  return true;\n}\n\nnamespace mc {\n  region_iterator::region_iterator(const fs::path path)\n    : root(path), lister(new dirlist(path))\n  {\n  }\n  \n  bool region_iterator::has_next()\n  {\n    if (!lister->has_next(dir_filter, file_filter)) {\n      return false;\n    }\n\n    fs::path next = lister->next();\n    current_region.reset(new region(next));\n    return true;\n  }\n  \n  region_ptr region_iterator::next() {\n    return current_region;\n  }\n}\n"
  },
  {
    "path": "src/mc/region_iterator.hpp",
    "content": "#ifndef _MC_REGION_ITERATOR_HPP\n#define _MC_REGION_ITERATOR_HPP\n\n#include <list>\n\n#include <boost/shared_ptr.hpp>\n#include <boost/filesystem.hpp>\n\nclass dirlist;\n\nnamespace fs = boost::filesystem;\n\nnamespace mc {\n  class level_info;\n  class region;\n\n  /**\n   * Dynamically iterates over, and instantiates regions.\n   */\n  class region_iterator {\n    public:\n      typedef boost::shared_ptr<region> region_ptr;\n      typedef boost::shared_ptr<level_info> level_info_ptr;\n\n      region_iterator(const fs::path path);\n      bool has_next();\n      boost::shared_ptr<region> next();\n    private:\n      fs::path root;\n      boost::shared_ptr<dirlist> lister;\n      std::list<level_info_ptr> current_levels;\n      region_ptr current_region;\n  };\n}\n\n#endif /* _MC_REGION_ITERATOR_HPP */\n"
  },
  {
    "path": "src/mc/rotated_level_info.cpp",
    "content": "#include \"mc/rotated_level_info.hpp\"\n#include \"mc/level_info.hpp\"\n\nnamespace mc {\n  rotated_level_info::rotated_level_info(\n      level_info_ptr level,\n      utils::level_coord coord\n      )\n      : level(level), coord(coord)\n  {\n  }\n    \n  bool rotated_level_info::operator<(const rotated_level_info& other) const {\n    return coord < other.coord;\n  }\n\n  rotated_level_info::level_info_ptr rotated_level_info::get_level()\n  {\n    return level;\n  }\n\n  utils::level_coord rotated_level_info::get_coord()\n  {\n    return coord;\n  }\n}\n"
  },
  {
    "path": "src/mc/rotated_level_info.hpp",
    "content": "#ifndef _MC_ROTATED_LEVEL_INFO_HPP\n#define _MC_ROTATED_LEVEL_INFO_HPP\n\n#include <boost/shared_ptr.hpp>\n\n#include \"mc/utils.hpp\"\n\nnamespace mc {\n  class level_info;\n\n  class rotated_level_info {\n  public:\n    typedef boost::shared_ptr<level_info> level_info_ptr;\n    \n    rotated_level_info(level_info_ptr level, utils::level_coord coord);\n    bool operator<(const rotated_level_info& other) const;\n    level_info_ptr get_level();\n    utils::level_coord get_coord();\n  private:\n    level_info_ptr level;\n    mc::utils::level_coord coord;\n  };\n}\n\n#endif /* _MC_ROTATED_LEVEL_INFO_HPP */\n"
  },
  {
    "path": "src/mc/utils.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"mc/utils.hpp\"\n\n#include <sstream>\n#include <vector>\n#include <stdlib.h>\n#include <errno.h>\n\nnamespace mc {\n  namespace utils {\n    using std::string;\n    \n    void split(std::vector<std::string>& v, const std::string& str, char delim)\n    {\n      std::stringstream ss(str);\n      std::string item;\n      \n      while(std::getline(ss, item, delim)) {\n        v.push_back(item);\n      }\n    }\n    \n    const char *b36alphabet = \"0123456789abcdefghijklmnopqrstuvwxyz\";\n      \n    string b36encode(int number) {\n      if (number == 0) {\n        return string(\"0\");\n      }\n      \n      std::stringstream ss; \n      \n      if (number < 0) {\n        ss << \"-\";\n        number = -number;\n      }\n      \n      std::vector<char> v;\n\n      while (number != 0) {\n        div_t d = div(number, 36);\n        v.push_back(b36alphabet[d.rem]);\n        number = d.quot;\n      }\n\n      for (std::vector<char>::reverse_iterator it = v.rbegin(); it!=v.rend(); ++it) {\n        ss << *it;\n      }\n      \n      return ss.str();\n    }\n    \n    int b36decode(const string num) {\n      if (num.empty()) throw bad_cast();\n      long int res = strtol(num.c_str(), NULL, 36);\n      if (errno == ERANGE) throw bad_cast();\n      return res;\n    }\n\n    int b10decode(const string num) {\n      if (num.empty()) throw bad_cast();\n      long int res = strtol(num.c_str(), NULL, 10);\n      if (errno == ERANGE) throw bad_cast();\n      return res;\n    }\n    \n    fs::path level_dir(const fs::path base, int x, int z)\n    {\n      int modx = x % 64;\n      if (modx < 0) modx += 64;\n      int modz = z % 64;\n      if (modz < 0) modz += 64;\n      return base / b36encode(modx) / b36encode(modz);\n    }\n    \n    fs::path level_path(const fs::path base, int x, int z, const string prefix, const string suffix)\n    {\n      return level_dir(base, x, z) / ((prefix + \".\") + b36encode(x) + \".\" + b36encode(z) + (\".\" + suffix));\n    }\n\n    level_coord path_to_level_coord(const fs::path path) {\n      if (!fs::is_regular_file(path)) {\n        throw invalid_argument(\"not a regular file\");\n      }\n      \n      string extension = path.extension().string();\n      \n      std::vector<string> parts;\n      split(parts, path.stem().string(), '.');\n      \n      if (parts.size() != 3 || extension.compare(\".dat\") != 0) {\n        throw invalid_argument(\"level data file name does not match <x>.<z>.dat\");\n      }\n      \n      try {\n        return level_coord(b36decode(parts.at(1)), b36decode(parts.at(2)));\n      } catch(const bad_cast& e) {\n        throw invalid_argument(\"could not decode coordinates from file name\");\n      }\n    }\n\n    level_coord path_to_region_coord(const fs::path path) {\n      if (!fs::is_regular_file(path)) {\n        throw invalid_argument(\"not a regular file\");\n      }\n      \n      string extension = path.extension().string();\n      \n      std::vector<string> parts;\n      split(parts, path.stem().string(), '.');\n      \n      if (parts.size() != 3 || extension.compare(\".mca\") != 0) {\n        throw invalid_argument(\"level data file name does not match <x>.<z>.mca\");\n      }\n      \n      try {\n        return level_coord(b10decode(parts.at(1)) * 32, b10decode(parts.at(2)) * 32);\n      } catch(const bad_cast& e) {\n        throw invalid_argument(\"could not decode coordinates from file name\");\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/mc/utils.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef __MC_UTILS_HPP__\n#define __MC_UTILS_HPP__\n\n#include <exception>\n\n#include <boost/filesystem.hpp>\n\nnamespace fs = boost::filesystem;\n\nnamespace mc {\n  namespace utils {\n    /**\n     * The fastest portable split I could find, only\n     * limitation is that it splits on only one character, but that's O.K.\n     * And yes - this actually has an effective impact on performance since\n     * it is heavily used during broad phase scanning.\n     **/\n    void split(std::vector<std::string>& v, const std::string& str, char delim);\n    \n    class invalid_argument : public std::exception {\n      private:\n        const char* message;\n      public:\n        invalid_argument(const char* message) : message(message) {}\n\n        const char* what() const throw() {\n          return message;\n        }\n    };\n    \n    class bad_cast : public std::exception {};\n    \n    std::string b36encode(int number);\n    int b36decode(const std::string number);\n    \n    fs::path level_dir(const fs::path base, int x, int z);\n    fs::path level_path(const fs::path base, int x, int z, const std::string prefix, const std::string suffix);\n    \n    /*\n     * Used to indicate a level coordinate.\n     */\n    struct level_coord {\n      private:\n        int x;\n        int z;\n      public:\n        level_coord() : x(0), z(0) {}\n        level_coord(int x, int z) : x(x), z(z) {}\n        \n        int get_x() const { return x; };\n        int get_z() const { return z; };\n\n        level_coord add_x(int x)\n        {\n          return level_coord(this->x + x, this->z);\n        };\n\n        level_coord add_z(int z)\n        {\n          return level_coord(this->x, this->z + z);\n        };\n        \n        level_coord rotate(int rotation) const {\n          int x = this->x;\n          int z = this->z;\n          int t = x;\n          \n          switch (rotation % 360) {\n            case 270:\n              x = z;\n              z = -t;\n              break;\n            case 180:\n              x = -x;\n              z = -z;\n              break;\n            case 90:\n              x = -z;\n              z = t;\n              break;\n          }\n          \n          return level_coord(x, z);\n        }\n        \n        bool operator<(const level_coord& other) const {\n          if (z < other.z) {\n            return true;\n          }\n          \n          if (z > other.z) {\n            return false;\n          }\n          \n          return x < other.x;\n        }\n    };\n    \n    /* \n     * Take a path to a level chunk file, and return the coordinates.\n     * Indicate that no coordinates are viable by throwing invalid_argument\n     **/\n    level_coord path_to_level_coord(const fs::path path);\n    level_coord path_to_region_coord(const fs::path path);\n  }\n}\n\n#endif /* __MC_UTILS_HPP__ */\n"
  },
  {
    "path": "src/mc/world.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"world.hpp\"\n\n#include \"dirlist.hpp\"\n#include \"mc/utils.hpp\"\n#include \"mc/blocks.hpp\"\n#include \"mc/region_iterator.hpp\"\n#include \"mc/level_info.hpp\"\n\nnamespace mc {\n  world::world(fs::path world_path)\n    : world_path(world_path), min_x(INT_MAX), min_z(INT_MAX), max_x(INT_MIN), max_z(INT_MIN), chunk_x(0), chunk_y(0)\n  { }\n  \n  region_iterator world::get_iterator() {\n    return region_iterator(world_path);\n  }\n\n  void world::update(utils::level_coord coord) {\n    min_x = std::min(min_x, coord.get_x());\n    max_x = std::max(max_x, coord.get_x());\n    min_z = std::min(min_z, coord.get_z());\n    max_z = std::max(max_z, coord.get_z());\n    \n    diff_x = max_x - min_x;\n    diff_z = max_z - min_z;\n    min_xp = min_x * mc::MapX;\n    min_zp = min_z * mc::MapZ;\n  }\n}\n"
  },
  {
    "path": "src/mc/world.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef __MC_WORLD_HPP__\n#define __MC_WORLD_HPP__\n\n#include <stdlib.h>\n#include <limits.h>\n\n#include <string>\n#include <queue>\n#include <list>\n\n#include \"fileutils.hpp\"\n\n#include <boost/ptr_container/ptr_map.hpp>\n#include <boost/filesystem.hpp>\n\n#include <mc/utils.hpp>\n#include <mc/region.hpp>\n\nnamespace mc {\n  namespace fs = boost::filesystem;\n\n  class level_info;\n  class region_iterator;\n  \n  class iterator_error : public std::exception {\n    private:\n      const char* message;\n    public:\n      iterator_error(const char* message) \n        : message(message)\n      {\n      }\n\n      ~iterator_error() throw() {  }\n\n      const char* what() const throw() {\n        return message;\n      }\n  };\n  \n  class world {\n  public:\n    fs::path world_path;\n    \n    int min_x, min_z, max_x, max_z;\n    // the difference between min_* and max_*\n    int diff_x, diff_z;\n    // min_* as a point\n    int min_xp, min_zp;\n    int chunk_x, chunk_y;\n    \n    world(fs::path path);\n    region_iterator get_iterator();\n    void update(utils::level_coord coord);\n  };\n}\n\n#endif /* __MC_WORLD_HPP__ */\n"
  },
  {
    "path": "src/nbt/CMakeLists.txt",
    "content": "add_library(c10t-nbt\n  nbt.cpp\n  ${ZLIB_LIBRARIES})\n\nset_target_properties(c10t-nbt PROPERTIES COMPILE_FLAGS \"-O3 -Wall -pedantic -g\")\n"
  },
  {
    "path": "src/nbt/nbt.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"nbt.hpp\"\n\nbool nbt::is_big_endian() {\n  int32_t i = 1;\n  return ((int8_t*)(&i))[0] == 0;\n}\n"
  },
  {
    "path": "src/nbt/nbt.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef _NBT_H_\n#define _NBT_H_\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <errno.h>\n#include <zlib.h>\n#include <setjmp.h>\n\n#include <string.h>\n#include <exception>\n#include <string>\n#include <stack>\n#include <list>\n#include <iostream>\n\n#include <boost/ptr_container/ptr_vector.hpp>\n#include <boost/shared_ptr.hpp>\n\n#include \"nbt/types.hpp\"\n\nnamespace nbt {\n  class bad_grammar : std::exception {};\n  #define NBT_STACK_SIZE 100\n\n  #define nbt_assert_error(exc_env, file, cond, why)    \\\n  do {                                                  \\\n  if (!(cond)) {                                        \\\n    size_t where = file->tell();                         \\\n    error_handler(context, where, why);                 \\\n    longjmp(exc_env, 1);                                \\\n  }                                                     \\\n  } while(0)\n  \n  #define assert_error_c(exc_env, file, cond, why, cleanup)   \\\n  do {                                                        \\\n  if (!(cond)) {                                              \\\n    size_t where = file->tell();                               \\\n    error_handler(context, where, why);                       \\\n    cleanup;                                                  \\\n    longjmp(exc_env, 1);                                      \\\n  }                                                           \\\n  } while(0)\n\n  class input_buffer {\n  public:\n    typedef int pos_t;\n\n    virtual pos_t read(void* target, pos_t len) = 0;\n    virtual pos_t tell() = 0;\n    virtual pos_t flush(pos_t len) = 0;\n    virtual bool empty() = 0;\n    virtual bool ok() = 0;\n\n    virtual ~input_buffer()\n    {\n    }\n  };\n\n  typedef boost::shared_ptr<input_buffer> input_buffer_ptr;\n\n  class memory_buffer : public input_buffer {\n  private:\n    const char* buffer;\n    pos_t offs;\n    pos_t size;\n  public:\n    memory_buffer(const char* buffer, pos_t size) : buffer(buffer), offs(0), size(size) {\n    }\n\n    virtual pos_t read(void* target, pos_t len)\n    {\n      if (!(offs + len <= size)) {\n        return -1;\n      }\n\n      ::memcpy(target, &buffer[offs], len);\n      offs += len;\n      return len;\n    }\n\n    virtual pos_t tell()\n    {\n      return offs;\n    }\n\n    virtual pos_t flush(pos_t len)\n    {\n      if (!(offs + len <= size)) {\n        return -1;\n      }\n      \n      offs += len;\n      \n      return len;\n    }\n\n    virtual bool empty()\n    {\n      return offs == size;\n    }\n\n    virtual bool ok()\n    {\n      return true;\n    }\n  };\n\n  class gzfile_buffer : public input_buffer {\n  private:\n    const char* path;\n    const pos_t flush_buffer_size;\n    char* flush_buffer;\n    gzFile file;\n    enum\n    {\n      FILE_READY,\n      // Special case for resolving gzeof behaviour in empty test.\n      FLUSH_BUFFER_SINGLE_BYTE,\n      END_OF_FILE\n    } file_state;\n  public:\n    gzfile_buffer(const char* path)\n      : path(path),\n        flush_buffer_size(1024),\n        flush_buffer(new char[flush_buffer_size]),\n        file_state(FILE_READY)\n    {\n      file = gzopen(path, \"rb\");\n    }\n\n    virtual ~gzfile_buffer()\n    {\n      if (file != NULL)\n      {\n        gzclose(file);\n      }\n\n      delete [] flush_buffer;\n    }\n\n    virtual pos_t read(void* target, pos_t len)\n    {\n      char* c_target = reinterpret_cast<char*>(target);\n\n      pos_t read = 0;\n\n      if (file_state == FLUSH_BUFFER_SINGLE_BYTE && len > 0)\n      {\n        c_target[0] = flush_buffer[0];\n        file_state = FILE_READY;\n        read++;\n      }\n\n      while (read < len)\n      {\n        pos_t in = gzread(file, c_target + read, len - read);\n\n        if (in == 0)\n        {\n          return -1;\n        }\n\n        read += in;\n      }\n\n      return len;\n    }\n\n    virtual pos_t tell()\n    {\n      off_t offset = 0;\n      if (file_state == FLUSH_BUFFER_SINGLE_BYTE)\n      {\n        offset = -1;\n      }\n      return gztell(file) + offset;\n    }\n\n    virtual pos_t flush(pos_t len)\n    {\n      pos_t flushed = 0;\n\n      while (flushed < len)\n      {\n        pos_t in = read(flush_buffer, std::min(len - flushed, flush_buffer_size));\n\n        if (in == -1)\n        {\n          return -1;\n        }\n\n        flushed += in;\n      }\n\n      return len;\n    }\n\n    virtual bool empty()\n    {\n      if (file_state == FILE_READY)\n      {\n      \t // gzeof will not return EOF until EOF has previously been detected\n      \t // during a read.\n      \t pos_t in = read(flush_buffer, 1);\n\n        if (in == -1)\n        {\n          file_state = END_OF_FILE;\n        }\n        else\n        {\n          file_state = FLUSH_BUFFER_SINGLE_BYTE;\n        }\n      }\n      return gzeof(file) == 1;\n    }\n\n    virtual bool ok()\n    {\n      return file != NULL;\n    }\n  };\n  \n  const Byte TAG_End = 0x0;\n  const Byte TAG_Byte = 0x1;\n  const Byte TAG_Short = 0x2;\n  const Byte TAG_Int = 0x3;\n  const Byte TAG_Long = 0x4;\n  const Byte TAG_Float = 0x5;\n  const Byte TAG_Double = 0x6;\n  const Byte TAG_Byte_Array = 0x7;\n  const Byte TAG_String = 0x8;\n  const Byte TAG_List = 0x9;\n  const Byte TAG_Compound = 0xa;\n  const Byte TAG_Int_Array = 0xb;\n  const Byte TAG_Long_Array = 0xc;\n  \n  const std::string TAG_End_str(\"TAG_End\");\n  const std::string TAG_Byte_str(\"TAG_Byte\");\n  const std::string TAG_Short_str(\"TAG_Short\");\n  const std::string TAG_Int_str(\"TAG_Int\");\n  const std::string TAG_Long_str(\"TAG_Long\");\n  const std::string TAG_Float_str(\"TAG_Float\");\n  const std::string TAG_Double_str(\"TAG_Double\");\n  const std::string TAG_Byte_Array_str(\"TAG_Byte_Array\");\n  const std::string TAG_String_str(\"TAG_String\");\n  const std::string TAG_List_str(\"TAG_List\");\n  const std::string TAG_Compound_str(\"TAG_Compound\");\n  const std::string TAG_Int_Array_str(\"TAG_Int_Array\");\n  const std::string TAG_Long_Array_str(\"TAG_Long_Array\");\n  \n  const std::string tag_string_map[] = {\n    TAG_End_str,\n    TAG_Byte_str,\n    TAG_Short_str,\n    TAG_Int_str,\n    TAG_Long_str,\n    TAG_Float_str,\n    TAG_Double_str,\n    TAG_Byte_Array_str,\n    TAG_String_str,\n    TAG_List_str,\n    TAG_Compound_str,\n    TAG_Int_Array_str,\n    TAG_Long_Array_str\n  };\n  \n  bool is_big_endian();\n  \n  template <class C>\n  void default_begin_compound(C* context, nbt::String name) {\n  }\n\n  template <class C>\n  void default_end_compound(C* context, String name) {\n  }\n\n  template <class C>\n  void default_begin_list(C* context, nbt::String name, nbt::Byte type, nbt::Int length) {\n  }\n\n  template <class C>\n  void default_end_list(C* context, nbt::String name) {\n  }\n\n  template <class C>\n  void default_error_handler(C* context, size_t where, const char *why) {\n    std::cerr << \"Unhandled nbt parser error at byte \" << where << \": \" << why << std::endl;\n    exit(1);\n  }\n  \n  template <class C>\n  class Parser {\n    private:\n      jmp_buf exc_env;\n      bool running;\n      C *context;\n      \n      inline Byte read_byte(input_buffer_ptr file) {\n        Byte b;\n        nbt_assert_error(exc_env, file, file->read(&b, sizeof(Byte)) == sizeof(Byte), \"Buffer too short to read Byte\");\n        return b;\n      }\n      \n      inline Short read_short(input_buffer_ptr file) {\n        uint8_t b[2];\n        nbt_assert_error(exc_env, file, file->read(b, sizeof(b)) == sizeof(b), \"Buffer to short to read Short\");\n        Short s = (b[0] << 8) + b[1];\n        return s;\n      }\n\n      inline Int read_int(input_buffer_ptr file) {\n        Int i;\n        \n#ifdef BOOST_BIG_ENDIAN\n        nbt_assert_error(exc_env, file, file->read(&i, sizeof(b)) == sizeof(b), \"Buffer to short to read Int\");\n#else\n        Byte b[sizeof(i)];\n        nbt_assert_error(exc_env, file, file->read(b, sizeof(b)) == sizeof(b), \"Buffer to short to read Int\");\n        Int *ip = &i;\n        *((Byte*)ip) = b[3];\n        *((Byte*)ip + 1) = b[2];\n        *((Byte*)ip + 2) = b[1];\n        *((Byte*)ip + 3) = b[0];\n#endif\n        \n        return i;\n      }\n      \n      inline String read_string(input_buffer_ptr file) {\n        Short s = read_short(file);\n        nbt_assert_error(exc_env, file, s >= 0, \"String specified with invalid length < 0\");\n        uint8_t *str = new uint8_t[s + 1];\n        assert_error_c(exc_env, file, file->read(str, s) == s, \"Buffer to short to read String\", delete str);\n        String so((const char*)str, s);\n        delete [] str;\n        return so;\n      }\n      \n      inline void flush_string(input_buffer_ptr file) {\n        Short s = read_short(file);\n        nbt_assert_error(exc_env, file, file->flush(s) != -1, \"Buffer to short to flush String\");\n      }\n      \n      inline Float read_float(input_buffer_ptr file)\n      {\n        Float f;\n        \n#ifdef BOOST_BIG_ENDIAN\n        nbt_assert_error(exc_env, file, file->read(&f, sizeof(f)) == sizeof(f), \"Buffer to short to read Float\");\n#else\n        Byte b[sizeof(f)];\n        nbt_assert_error(exc_env, file, file->read(b, sizeof(f)) == sizeof(f), \"Buffer to short to read Float\");\n        Float *fp = &f;\n        *((Byte*)fp) = b[3];\n        *((Byte*)fp + 1) = b[2];\n        *((Byte*)fp + 2) = b[1];\n        *((Byte*)fp + 3) = b[0];\n#endif\n        \n        return f;\n      }\n      \n      inline Long read_long(input_buffer_ptr file) {\n        Long l;\n        \n#ifdef BOOST_BIG_ENDIAN\n        nbt_assert_error(exc_env, file, file->read(&l, sizeof(b)) == sizeof(b), \"Buffer to short to read Long\");\n#else\n        Byte b[sizeof(l)];\n        nbt_assert_error(exc_env, file, file->read(b, sizeof(b)) == sizeof(b), \"Buffer to short to read Long\");\n        Long *lp = &l;\n        *((Byte*)lp) = b[7];\n        *((Byte*)lp + 1) = b[6];\n        *((Byte*)lp + 2) = b[5];\n        *((Byte*)lp + 3) = b[4];\n        *((Byte*)lp + 4) = b[3];\n        *((Byte*)lp + 5) = b[2];\n        *((Byte*)lp + 6) = b[1];\n        *((Byte*)lp + 7) = b[0];\n#endif\n        \n        return l;\n      }\n      \n      inline Double read_double(input_buffer_ptr file) {\n        Double d;\n        \n#ifdef BOOST_BIG_ENDIAN\n        nbt_assert_error(exc_env, file, file->read(&d, sizeof(d)) == sizeof(d), \"Buffer to short to read Double\");\n#else\n        Byte b[sizeof(d)];\n        nbt_assert_error(exc_env, file, file->read(b, sizeof(d)) == sizeof(d), \"Buffer to short to read Double\");\n        Double *dp = &d;\n        *((Byte*)dp) = b[7];\n        *((Byte*)dp + 1) = b[6];\n        *((Byte*)dp + 2) = b[5];\n        *((Byte*)dp + 3) = b[4];\n        *((Byte*)dp + 4) = b[3];\n        *((Byte*)dp + 5) = b[2];\n        *((Byte*)dp + 6) = b[1];\n        *((Byte*)dp + 7) = b[0];\n#endif\n        \n        return d;\n      }\n      \n      inline Byte read_tagType(input_buffer_ptr file) {\n        Byte type = read_byte(file);\n\n        nbt_assert_error(exc_env, file, type >= 0 && type <= TAG_Long_Array,\n                \"Not a valid tag type\");\n\n        return type;\n      }\n      \n      inline void flush_byte_array(input_buffer_ptr file) {\n        Int length = read_int(file);\n        nbt_assert_error(exc_env, file, file->flush(length) != -1,\n          \"Buffer to short to flush ByteArray\");\n\n      }\n      \n      inline void handle_byte_array(String name, input_buffer_ptr file) {\n        Int length = read_int(file);\n        Byte *values = new Byte[length];\n\n        nbt_assert_error(exc_env, file, file->read(values, length) == length,\n                \"Buffer to short to read ByteArray\");\n\n        ByteArray *array = new ByteArray();\n        array->values = values;\n        array->length = length;\n        register_byte_array(context, name, array);\n      }\n\n      inline void flush_int_array(input_buffer_ptr file) {\n        Int length = read_int(file);\n\n        nbt_assert_error(exc_env, file, file->flush(length * sizeof(Int)) != -1,\n          \"Buffer to short to flush IntArray\");\n      }\n\n      inline void handle_int_array(String name, input_buffer_ptr file) {\n        Int length = read_int(file);\n        Int *values = new Int[length];\n\n        for (Int i = 0; i < length; i++) {\n            values[i] = read_int(file);\n        }\n\n        IntArray *array = new IntArray();\n        array->values = values;\n        array->length = length;\n        register_int_array(context, name, array);\n      }\n    \n      inline void flush_long_array(input_buffer_ptr file) {\n        Int length = read_int(file);\n \n        nbt_assert_error(exc_env, file, file->flush(length * sizeof(Long)) != -1,\n          \"Buffer to short to flush LongArray\");\n      }\n\n      inline void handle_long_array(String name, input_buffer_ptr file) {\n        Int length = read_int(file);\n        Long *values = new Long[length];\n\n        for (Int i = 0; i < length; i++) {\n            values[i] = read_long(file);\n        }\n\n        LongArray *array = new LongArray();\n        array->values = values;\n        array->length = length;\n        register_long_array(context, name, array);\n      }\n    public:\n      typedef void (*begin_compound_t)(C*, String name);\n      typedef void (*end_compound_t)(C*, String name);\n      \n      typedef void (*begin_list_t)(C*, String name, Byte type, Int length);\n      typedef void (*end_list_t)(C*, String name);\n      \n      typedef void (*register_long_t)(C*, String name, Long l);\n      typedef void (*register_short_t)(C*, String name, Short l);\n      typedef void (*register_string_t)(C*, String name, String l);\n      typedef void (*register_float_t)(C*, String name, Float l);\n      typedef void (*register_double_t)(C*, String name, Double l);\n      typedef void (*register_int_t)(C*, String name, Int l);\n      typedef void (*register_byte_t)(C*, String name, Byte b);\n      typedef void (*register_byte_array_t)(C*, String name, ByteArray* array);\n      typedef void (*register_int_array_t)(C*, String name, IntArray* array);\n      typedef void (*register_long_array_t)(C*, String name, LongArray* array);\n      typedef void (*error_handler_t)(C*, size_t where, const char *why);\n      \n      register_long_t register_long;\n      register_short_t register_short;\n      register_string_t register_string;\n      register_float_t register_float;\n      register_double_t register_double;\n      register_int_t register_int;\n      register_byte_t register_byte;\n      register_byte_array_t register_byte_array;\n      register_int_array_t register_int_array;\n      register_long_array_t register_long_array;\n\n      begin_compound_t begin_compound;\n      end_compound_t end_compound;\n      begin_list_t begin_list;\n      end_list_t end_list;\n      error_handler_t error_handler;\n      \n      Parser() :\n        context(NULL),\n        register_long(NULL),\n        register_short(NULL),\n        register_string(NULL),\n        register_float(NULL),\n        register_double(NULL),\n        register_int(NULL),\n        register_byte(NULL),\n        register_byte_array(NULL),\n        register_int_array(NULL),\n        register_long_array(NULL),\n        begin_compound(&default_begin_compound<C>),\n        end_compound(&default_end_compound<C>),\n        begin_list(&default_begin_list<C>),\n        end_list(&default_end_list<C>),\n        error_handler(&default_error_handler<C>)\n      {\n      }\n      \n      Parser(C *context) :\n        context(context),\n        register_long(NULL),\n        register_short(NULL),\n        register_string(NULL),\n        register_float(NULL),\n        register_double(NULL),\n        register_int(NULL),\n        register_byte(NULL),\n        register_byte_array(NULL),\n        register_int_array(NULL),\n        register_long_array(NULL),\n        begin_compound(&default_begin_compound<C>),\n        end_compound(&default_end_compound<C>),\n        begin_list(&default_begin_list<C>),\n        end_list(&default_end_list<C>),\n        error_handler(&default_error_handler<C>)\n      {\n        this->context = context;\n      }\n      \n      void stop() {\n        running = false;\n      }\n\n      void parse(input_buffer_ptr file)\n      {\n        running = true;\n        stack_entry *stack = new stack_entry[NBT_STACK_SIZE];\n        int stack_p = 0;\n        stack_entry *root = stack + 0;\n        \n        if (setjmp(exc_env) == 1) {\n          delete [] stack;\n          return;\n        }\n\n        nbt_assert_error(exc_env, file, file->ok(), \"Underlying input problem\");\n        \n        root->type = read_tagType(file);\n        nbt_assert_error(exc_env, file, root->type == TAG_Compound, \"Expected TAG_Compound at root\");\n        root->name = read_string(file);\n        \n        begin_compound(context, root->name);\n        \n        while(running && stack_p >= 0) {\n          nbt_assert_error(exc_env, file, stack_p < NBT_STACK_SIZE, \"Stack cannot be larger than NBT_STACK_SIZE\");\n          \n          stack_entry* top = stack + stack_p;\n          \n          Byte type;\n          String name(\"\");\n          \n          // if top is of Compound type, we must read the item name first\n          if (top->type == TAG_Compound) {\n            type = read_tagType(file);\n            \n            if (type == TAG_End) {\n              end_compound(context, top->name);\n              --stack_p;\n              continue;\n            }\n            \n            name = read_string(file);\n          }\n          \n          // if top of stack is of type list, the type must be inferred, name is assumed to be \"\" (empty string)\n          else if (top->type == TAG_List) {\n            if (top->list_read >= top->list_count) {\n              end_list(context, top->name);\n              --stack_p;\n              continue;\n            }\n            \n            type = top->list_type;\n            top->list_read++;\n          }\n          \n          else {\n            nbt_assert_error(exc_env, file, 1, \"Unknown stack type\");\n            continue;\n          }\n          \n          switch(type) {\n          case TAG_Long:\n            if (register_long == NULL) {\n              nbt_assert_error(exc_env, file, file->flush(sizeof(nbt::Long)) != -1,\n                \"Buffer too short to flush long\");\n            } else {\n              register_long(context, name, read_long(file));\n            }\n            break;\n          case TAG_Short:\n            if (register_short == NULL) {\n              nbt_assert_error(exc_env, file, file->flush(sizeof(nbt::Short)) != -1,\n                \"Buffer too short to flush short\");\n            } else {\n              register_short(context, name, read_short(file));\n            }\n            break;\n          case TAG_String:\n            if (register_string == NULL) {\n              flush_string(file);\n            } else {\n              register_string(context, name, read_string(file));\n            }\n            break;\n          case TAG_Float:\n            if (register_float == NULL) {\n              nbt_assert_error(exc_env, file, file->flush(sizeof(nbt::Float)) != -1,\n                \"Buffer too short to flush float\");\n            } else {\n              register_float(context, name, read_float(file));\n            }\n            break;\n          case TAG_Double:\n            if (register_double == NULL) {\n              nbt_assert_error(exc_env, file, file->flush(sizeof(nbt::Double)) != -1,\n                \"Buffer too short to flush double\");\n            } else {\n              register_double(context, name, read_double(file));\n            }\n            break;\n          case TAG_Int:\n            if (register_int == NULL) {\n              nbt_assert_error(exc_env, file, file->flush(sizeof(nbt::Int)) != -1,\n                \"Buffer too short to flush int\");\n            } else {\n              register_int(context, name, read_int(file));\n            }\n            break;\n          case TAG_Byte:\n            if (register_byte == NULL) {\n              nbt_assert_error(exc_env, file, file->flush(sizeof(nbt::Byte)) != -1,\n                \"Buffer too short to flush byte\");\n            } else {\n              register_byte(context, name, read_byte(file));\n            }\n            break;\n          case TAG_List:\n            {\n              stack_entry* c = stack + ++stack_p;\n              \n              c->list_read = 0;\n              c->list_type = read_tagType(file);\n              c->list_count = read_int(file);\n              c->name = name;\n              c->type = TAG_List;\n              \n              begin_list(context, name, c->list_type, c->list_count);\n            }\n            break;\n          case TAG_Compound:\n            {\n              begin_compound(context, name);\n              stack_entry* c = stack + ++stack_p;\n              \n              c->list_read = 0;\n              c->list_count = 0;\n              c->list_type = -1;\n              c->name = name;\n              c->type = TAG_Compound;\n            }\n            break;\n          case TAG_Byte_Array:\n            if (register_byte_array == NULL) {\n              flush_byte_array(file);\n            } else {\n              handle_byte_array(name, file);\n            }\n            break;\n          case TAG_Int_Array:\n            if (register_int_array == NULL) {\n              flush_int_array(file);\n            } else {\n              handle_int_array(name, file);\n            }\n            break;\n          case TAG_Long_Array:\n            if (register_long_array == NULL) {\n              flush_long_array(file);\n            } else {\n              handle_long_array(name, file);\n            }\n            break;\n          default:\n            nbt_assert_error(exc_env, file, 0, \"Encountered unknown type\");\n            break;\n          }\n        }\n\n        nbt_assert_error(exc_env, file, file->empty(), \"input buffer is not empty\");\n\n        delete [] stack;\n      }\n\n      void parse_buffer(const char* buffer, unsigned int size)\n      {\n        input_buffer_ptr file(new memory_buffer(buffer, size));\n        parse(file);\n      }\n      \n      void parse_file(const char *path)\n      {\n        input_buffer_ptr file(new gzfile_buffer(path));\n        parse(file);\n      }\n  };\n}\n\n#endif /* _NBT_H_ */\n"
  },
  {
    "path": "src/nbt/nbt_inspect.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"nbt/nbt.hpp\"\n\n#include <iostream>\n#include <iomanip>\n\nusing namespace std;\n\nstruct inspect_context {\n  int width;\n};\n\nvoid begin_compound(inspect_context* inspect, nbt::String name) {\n  cout << setw(inspect->width) << \"\"\n       << \"BEGIN Compound(\" << name << \")\" << endl;\n  inspect->width += 2;\n}\n\nvoid end_compound(inspect_context* inspect, nbt::String name) {\n  inspect->width -= 2;\n  cout << setw(inspect->width) << \"\"\n       << \"END Compound(\" << name << \")\" << endl;\n}\n\nvoid begin_list(inspect_context* inspect, nbt::String name, nbt::Byte type, nbt::Int length) {\n  cout << setw(inspect->width) << \"\"\n       << \"BEGIN List(\" << name << \", \" << nbt::tag_string_map[type] << \", \" << length << \")\" << endl;\n  inspect->width += 2;\n}\n\nvoid end_list(inspect_context* inspect, nbt::String name) {\n  inspect->width -= 2;\n  cout << setw(inspect->width) << \"\"\n       << \"END List(\" << name << \")\" << endl;\n}\n\nvoid register_long(inspect_context* inspect, nbt::String name, nbt::Long value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Long(\" << name << \"): \" << dec << value << endl;\n}\n\nvoid register_short(inspect_context* inspect, nbt::String name, nbt::Short value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Short(\" << name << \"): \" << value << endl;\n}\n\nvoid register_string(inspect_context* inspect, nbt::String name, nbt::String value) {\n  cout << setw(inspect->width) << \"\"\n       << \"String(\" << name << \"): \" << value << endl;\n}\n\nvoid register_float(inspect_context* inspect, nbt::String name, nbt::Float value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Float(\" << name << \"): \" << value << endl;\n}\n\nvoid register_double(inspect_context* inspect, nbt::String name, nbt::Double value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Double(\" << name << \"): \" << value << endl;\n}\n\nvoid register_int(inspect_context* inspect, nbt::String name, nbt::Int value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Int(\" << name << \"): \" << dec << value << endl;\n}\n\nvoid register_byte(inspect_context* inspect, nbt::String name, nbt::Byte value) {\n  cout << setw(inspect->width) << \"\"\n       << \"Byte(\" << name << \"): 0x\" << hex << (int)value << endl;\n}\n\nvoid register_byte_array(inspect_context* inspect, nbt::String name, nbt::ByteArray* value) {\n  cout << setw(inspect->width) << \"\"\n       << \"ByteArray(\" << name << \"): \" << \"(binary blob)\" << endl;\n  delete value;\n}\n\nvoid register_long_array(inspect_context* inspect, nbt::String name, nbt::LongArray* value) {\n  cout << setw(inspect->width) << \"\"\n       << \"LongArray(\" << name << \"): \" << \"(binary blob)\" << endl;\n  delete value;\n}\n\nint main(int argc, char* argv[]) {\n  if (argc < 2) {\n    return 1;\n  }\n\n  inspect_context ctx;\n  ctx.width = 0;\n  \n  nbt::Parser<inspect_context> parser(&ctx);\n\n  parser.begin_compound = begin_compound;\n  parser.end_compound = end_compound;\n  parser.begin_list = begin_list;\n  parser.end_list = end_list;\n  parser.register_long = register_long;\n  parser.register_short = register_short;\n  parser.register_string = register_string;\n  parser.register_float = register_float;\n  parser.register_double = register_double;\n  parser.register_int = register_int;\n  parser.register_byte = register_byte;\n  parser.register_byte_array = register_byte_array;\n  parser.register_long_array = register_long_array;\n  \n  parser.parse_file(argv[1]);\n  return 0;\n}\n"
  },
  {
    "path": "src/nbt/types.hpp",
    "content": "#ifndef _NBT_TYPES_HPP\n#define _NBT_TYPES_HPP\n\n#include <stdint.h>\n#include <string>\n\nnamespace nbt {\n  typedef int8_t Byte;\n  typedef int16_t Short;\n  typedef int32_t Int;\n  typedef int64_t Long;\n  typedef std::string String;\n  typedef float Float;\n  typedef double Double;\n  \n  struct ByteArray {\n    Int length;\n    Byte *values;\n    ~ByteArray() {\n      delete [] values;\n    }\n  };\n\n  struct IntArray {\n    Int length;\n    Int *values;\n    ~IntArray() {\n      delete [] values;\n    }\n  };\n\n \n  struct LongArray {\n    Int length;\n    Long *values;\n    ~LongArray() {\n      delete [] values;\n    }\n  };\n\n  struct stack_entry {\n    Byte type;\n    String name;\n    Int list_count, list_read;\n    Byte list_type;\n  };\n}\n\n#endif /* _NBT_TYPES_HPP */\n"
  },
  {
    "path": "src/nullstream.cpp",
    "content": "#include \"nullstream.hpp\"\n\nnullstream::nullstream()\n : std::ios(0), std::ostream(0)\n{\n}\n"
  },
  {
    "path": "src/nullstream.hpp",
    "content": "#ifndef __NULLSTREAM_HPP__\n#define __NULLSTREAM_HPP__\n\n#include <ostream>\n#include <iomanip>\n\nstruct nullstream : std::ostream {\n  nullstream();\n};\n\n#endif /* __NULLSTREAM_HPP__ */\n"
  },
  {
    "path": "src/players.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n\n#include \"players.hpp\"\n\nnamespace fs = boost::filesystem;\n\nvoid error_handler(player *p, size_t where, const char* why) {\n  p->error_where = where;\n  p->error_why = why;\n  p->error = true;\n}\n\nvoid begin_list(player *p, std::string name, nbt::Byte, nbt::Int) {\n  if (name.compare(\"Pos\") == 0) {\n    p->in_pos = true;\n  }\n}\n\nvoid end_list(player *p, std::string name) {\n  if (name.compare(\"Pos\") == 0) {\n    p->in_pos = false;\n  }\n}\n\nvoid register_double(player *p, std::string name, nbt::Double value) {\n  if (p->in_pos) {\n    switch (p->pos_c) {\n      case 0: p->xPos = value; break;\n      case 1: p->yPos = value; break;\n      case 2: p->zPos = value; break;\n    }\n    \n    p->pos_c++;\n  }\n}\n\nplayer::player(const fs::path path) :\n  path(path),\n  name(path.stem().string()),\n  error(false), error_where(0), error_why(\"\"), in_pos(false),\n  pos_c(0), xPos(0), yPos(0), zPos(0)\n{\n  nbt::Parser<player> parser(this);\n  parser.error_handler = error_handler;\n  parser.begin_list = begin_list;\n  parser.end_list = end_list;\n  parser.register_double = register_double;\n  parser.parse_file(path.string().c_str());\n}\n\nplayers_db::players_db(fs::path path, std::set<std::string> set)\n  : path(path), filter_set(set)\n{\n}\n\nvoid players_db::read(std::vector<player>& players) const\n{\n  fs::path full_path = fs::system_complete( path );\n  \n  if (!fs::is_directory(full_path)) {\n    throw players_db_exception(\"database does not exist\");\n  }\n  \n  fs::directory_iterator end_iter;\n  \n  for ( fs::directory_iterator dir_itr( full_path );\n        dir_itr != end_iter;\n        ++dir_itr )\n  {\n    player p(dir_itr->path());\n\n    if (filter_set.size() > 0) {\n      if (filter_set.find(p.name) == filter_set.end()) {\n        continue;\n      }\n    }\n\n    players.push_back(p);\n  }\n}\n"
  },
  {
    "path": "src/players.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef _PLAYERS_H_\n#define _PLAYERS_H_\n\n#include <string>\n#include <vector>\n#include <set>\n#include <exception>\n\n#include <boost/filesystem/operations.hpp>\n#include <boost/filesystem/path.hpp>\n#include <boost/filesystem.hpp>\n\n#include \"settings_t.hpp\"\n#include \"nbt/nbt.hpp\"\n\nclass players_db_exception : public std::exception {\n  private:\n    const char* message;\n  public:\n    players_db_exception(const char* message) : message(message) { }\n    const char* what() throw() {\n      return message;\n    }\n};\n\nclass player {\npublic:\n  boost::filesystem::path path;\n  std::string name;\n  \n  bool error;\n  size_t error_where;\n  std::string error_why;\n  bool in_pos;\n  int pos_c;\n  nbt::Int xPos, yPos, zPos;\n  \n  player(const boost::filesystem::path path);\n};\n\nclass players_db {\n  private:\n    const boost::filesystem::path path;\n    const std::set<std::string> filter_set;\n  public:\n    players_db(const boost::filesystem::path path, std::set<std::string> set);\n    void read(std::vector<player>&) const;\n};\n\n#endif /* _PLAYERS_H_ */\n"
  },
  {
    "path": "src/settings_t.cpp",
    "content": "#include \"settings_t.hpp\"\n\n#include \"mc/blocks.hpp\"\n\nsettings_t::settings_t(fs::path& install_path)\n{\n  this->excluded.push_back(\"minecraft:air\");\n\n  this->threads = 1;\n  this->prebuffer = 4;\n\n  this->split_base = 0;\n  this->use_split = false;\n  this->cavemode = false;\n  this->hellmode = false;\n  this->top = 127;\n  this->bottom = 0;\n  this->mode = Top;\n  this->nocheck = false;\n  this->silent = false;\n  this->show_players = false;\n  this->show_coordinates = false;\n  this->show_signs = false;\n  this->strip_sign_prefix = false;\n  this->show_warps = false;\n  this->require_all = false;\n  this->striped_terrain = false;\n  this->rotation = 0;\n  this->binary = false;\n  this->night = false;\n  this->heightmap = false;\n  this->debug = false;\n  this->swap_file = \"swap.bin\";\n  this->memory_limit = 1000;\n  this->memory_limit_default = true;\n  this->min_x = -10000;\n  this->max_x = 10000;\n  this->min_z = -10000;\n  this->max_z = 10000;\n  this->max_radius = 1000;\n  this->ttf_path = fs::path(\"font.ttf\");\n  this->ttf_size = 12;\n  this->ttf_color = color(0, 0, 0, 0xff);\n  this->sign_color = color(0, 0, 0, 0xff);\n  this->player_color = color(0, 0, 0, 0xff);\n  this->has_player_color = false;\n  this->has_sign_color = false;\n  this->has_coordinate_color = false;\n  this->has_warp_color = false;\n  this->coordinate_color = color(0, 0, 0, 0xff);\n  this->warp_color = color(0, 0, 0, 0xff);\n  this->pedantic_broad_phase = false;\n  this->cache_use = false;\n  this->cache_key = \"\";\n  this->cache_dir = \"cache\";\n  this->cache_compress = false;\n  this->write_json = false;\n  this->write_js = false;\n  this->no_log = false;\n  this->disable_alpha = false;\n  this->enable_all_blocks = true;\n  this->install_path = install_path;\n  this->output_log = fs::system_complete(fs::path(\"c10t.log\"));\n  this->output_path = fs::system_complete(fs::path(\"out.png\"));\n  this->statistics_path = fs::system_complete(fs::path(\"statistics.txt\"));\n  this->palette_read_path = install_path /= fs::path(\"palette.json\");\n  this->action = None;\n\n  this->center_x = 0;\n  this->center_z = 0;\n\n  this->engine_use = false;\n}\n\nbool settings_t::coord_out_of_range(mc::utils::level_coord& coord)\n{\n  int x = coord.get_x() - center_x;\n  int z = coord.get_z() - center_z;\n\n  uint64_t x2 = uint64_t(x) * uint64_t(x);\n  uint64_t z2 = uint64_t(z) * uint64_t(z);\n  uint64_t r2 = max_radius * max_radius;\n\n  return x < min_x\n      || x > max_x\n      || z < min_z\n      || z > max_z\n      || (x2 + z2) > r2+1;\n}\n"
  },
  {
    "path": "src/settings_t.hpp",
    "content": "#ifndef __SETTINGS_T_HPP__\n#define __SETTINGS_T_HPP__\n\n#include <string>\n#include <set>\n\n#include <boost/filesystem.hpp>\n\n#include \"image/color.hpp\"\n#include \"mc/utils.hpp\"\n\nenum mode {\n  Top = 0x0,\n  Oblique = 0x1,\n  ObliqueAngle = 0x2,\n  Isometric = 0x3,\n  FatIso = 0x4\n};\n\nenum action {\n  None,\n  Version,\n  Help,\n  GenerateWorld,\n  GenerateStatistics,\n  ListColors,\n  WritePalette\n};\n\nstruct settings_t {\n  settings_t(fs::path& install_path);\n\n  bool binary;\n  bool cache_compress;\n  bool cache_use;\n  bool cavemode;\n  bool debug;\n  bool has_coordinate_color;\n  bool has_player_color;\n  bool has_sign_color;\n  bool has_warp_color;\n  bool heightmap;\n  bool hellmode;\n  bool memory_limit_default;\n  bool night;\n  bool nocheck;\n  bool no_log;\n  bool pedantic_broad_phase;\n  bool require_all;\n  bool show_coordinates;\n  bool show_players;\n  bool show_signs;\n  bool show_warps;\n  bool silent;\n  bool strip_sign_prefix;\n  bool striped_terrain;\n  bool use_split;\n  bool write_js;\n  bool write_json;\n  bool disable_alpha;\n  bool enable_all_blocks;\n  std::list<std::string> included;\n  std::list<std::string> excluded;\n  std::list<std::string> top_color_overrides;\n  std::list<std::string> side_color_overrides;\n  color coordinate_color;\n  color player_color;\n  color sign_color;\n  color ttf_color;\n  color warp_color;\n  enum mode mode;\n  boost::filesystem::path install_path;\n  boost::filesystem::path cache_dir;\n  boost::filesystem::path output_log;\n  boost::filesystem::path output_path;\n  boost::filesystem::path palette_read_path;\n  boost::filesystem::path palette_write_path;\n  boost::filesystem::path show_warps_path;\n  boost::filesystem::path statistics_path;\n  boost::filesystem::path swap_file;\n  boost::filesystem::path ttf_path;\n  boost::filesystem::path world_path;\n  boost::filesystem::path write_json_path;\n  boost::filesystem::path write_js_path;\n  boost::filesystem::path engine_path;\n  bool engine_use;\n  int bottom;\n  uint64_t max_radius;\n  int64_t min_x;\n  int64_t max_x;\n  int64_t min_z;\n  int64_t max_z;\n  int top;\n  int ttf_size;\n  size_t memory_limit;\n  std::list<unsigned int> split;\n  std::set<std::string> show_players_set;\n  std::string cache_key;\n  std::string show_signs_filter;\n  // top/bottom used for slicing\n  unsigned int prebuffer;\n  unsigned int rotation;\n  unsigned int split_base;\n  unsigned int threads;\n\n  std::string graph_block;\n\n  int center_x;\n  int center_z;\n\n  enum action action;\n\n  bool coord_out_of_range(mc::utils::level_coord& coord);\n};\n\n#endif /*__SETTINGS_T_HPP__*/\n"
  },
  {
    "path": "src/text.cpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#include \"text.hpp\"\n#include <unc/unc.hpp>\n\nnamespace text {\n  font_face::font_face(const fs::path font_path, int size, color base)\n      : font_path(font_path),\n        size(size),\n        base(base),\n        initialized(false)\n  {\n  }\n\n  void font_face::init()\n  {\n    int error;\n    \n    error = FT_Init_FreeType(&library);\n\n    if (error) {\n      throw text_error(\"Failed to initialize the freetype2 library\");\n    }\n\n    error = FT_New_Face(library, font_path.string().c_str(), 0, &face);\n\n    if (error == FT_Err_Unknown_File_Format) {\n      throw text_error(\"Could not open file - unknown file format: \" + font_path.string());\n    }\n    else if (error) {\n      throw text_error(\"Could not open file: \" + font_path.string());\n    }\n\n    set_size(size);\n\n    initialized = true;\n  }\n\n  void font_face::set_size(int size)\n  {\n    if (FT_Set_Pixel_Sizes(face, 0, size)) {\n      throw text_error(\"Failed to set font resolution\");\n    }\n    \n    this->size = size;\n  }\n  \n  void font_face::draw_bitmap(image_ptr image, FT_Bitmap* bitmap, pos_t pen_x, pos_t pen_y) const\n  {\n    assert(bitmap->pixel_mode == FT_PIXEL_MODE_GRAY);\n    \n    uint8_t* buffer = bitmap->buffer;\n\n    pos_t s_bitmap_rows =\n      boost::numeric_cast<pos_t>(bitmap->rows);\n    \n    pos_t s_bitmap_width =\n      boost::numeric_cast<pos_t>(bitmap->width);\n    \n    for (pos_t y = 0; y < s_bitmap_rows && y < image->get_height() + pen_y; y++) {\n      for (pos_t x = 0; x < s_bitmap_width && x < image->get_width() + pen_x; x++) {\n        color c(base);\n        c.a = color_i_to_f[buffer[x + y * bitmap->width]];\n        image->safe_blend_pixel(pen_x + x, pen_y + y, c);\n      }\n    }\n  }\n  \n  void font_face::draw(image_ptr image, const std::string rawtext, int x, int y) const\n  {\n    FT_GlyphSlot slot = face->glyph;\n\n    int error;\n\n    int pen_x = x, pen_y = y;\n    \n    unc::ustring text = unc::decode<unc::utf8>(rawtext);\n    \n    for (unc::ustring::iterator it = text.begin(); it != text.end(); it++ ) {\n      uint32_t cc = *it;\n      \n      if (cc == '\\n') {\n        pen_x = x;\n        pen_y += size + 2;\n        continue;\n      }\n      \n      error = FT_Load_Char( face, cc, FT_LOAD_RENDER ); \n      if ( error ) continue;\n      \n      draw_bitmap(image, &slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top);\n      \n      /* increment pen position */\n      pen_x += slot->bitmap.width + 2;\n    }\n  }\n\n  void font_face::set_color(color& c)\n  {\n    base = c;\n  }\n  \n  bool font_face::is_initialized()\n  {\n    return initialized;\n  }\n}\n"
  },
  {
    "path": "src/text.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef _TEXT_H_\n#define _TEXT_H_\n\n#include <exception>\n\n#include <boost/numeric/conversion/cast.hpp>\n#include <boost/filesystem.hpp>\n#include <boost/shared_ptr.hpp>\n\n#include <ft2build.h>\n#include FT_FREETYPE_H \n\nnamespace fs = boost::filesystem;\n\n#include \"image/image_base.hpp\"\n#include <assert.h>\n\nnamespace text {\n  class text_error : public std::exception {\n  private:\n    const std::string error;\n  public:\n    text_error(const std::string error) : error(error) {};\n\n    virtual ~text_error() throw() {};\n    \n    virtual const char* what() const throw()\n    {\n      return error.c_str();\n    }\n  };\n\n  class font_face {\n  private:\n    const fs::path font_path;\n    int size;\n    color base;\n    bool initialized;\n    FT_Library library;\n    FT_Face face;\n  public:\n    font_face(const fs::path font_path, int size, color base);\n\n    void init();\n\n    void set_size(int size);\n    \n    void draw_bitmap(image_ptr image, FT_Bitmap* bitmap, pos_t pen_x, pos_t pen_y) const;\n    \n    void draw(image_ptr image, const std::string rawtext, int x, int y) const;\n\n    void set_color(color& c);\n\n    bool is_initialized();\n  };\n}\n\n#endif \n"
  },
  {
    "path": "src/threads/renderer.hpp",
    "content": "#ifndef __THREADS__RENDERER_HPP__\n#define __THREADS__RENDERER_HPP__\n\n#include \"mc/utils.hpp\"\n#include \"mc/world.hpp\"\n#include \"mc/level.hpp\"\n\n#include <boost/shared_ptr.hpp>\n#include <boost/filesystem.hpp>\n#include <boost/format.hpp>\n\n#include <vector>\n\n#include \"cache.hpp\"\n#include \"image/image_operations.hpp\"\n#include \"engine/engine_core.hpp\"\n\n#include \"threads/threadworker.hpp\"\n#include \"threads/renderer_settings.hpp\"\n\nnamespace fs = boost::filesystem;\n\nstruct render_result {\n  boost::shared_ptr<mc::level> level;\n  image_base_ptr image;\n  bool fatal;\n  std::string fatal_why;\n  std::vector<mc::marker> signs;\n  bool cache_hit;\n  mc::utils::level_coord coord;\n  fs::path path;\n  \n  render_result() : fatal(false), fatal_why(\"(no error)\") {}\n\n  bool operator<(const render_result& other) const {\n    return coord < other.coord;\n  }\n};\n\nstruct render_job {\n  int32_t order;\n  boost::shared_ptr<mc::level> level;\n  boost::shared_ptr<engine_core> engine;\n  mc::utils::level_coord coord;\n  fs::path path;\n};\n\nclass renderer : public threadworker<render_job, render_result> {\npublic:\n  renderer_settings& r;\n  \n  renderer(renderer_settings r, int n, int total)\n    : threadworker<render_job, render_result>(n, total), r(r) {\n  }\n  \n  render_result work(render_job job) {\n    render_result p;\n    \n    p.coord = job.coord;\n    p.operations.reset(new image_operations(job.order));\n    p.level = job.level;\n    p.cache_hit = false;\n\n    p.path = job.path;\n    \n    time_t mod = p.level->modification_time();\n    std::stringstream ss;\n    ss << boost::format(\"%d.%d.cmap\") % job.coord.get_x() % job.coord.get_z();\n    std::string basename = ss.str();\n\n    cache_file cache(mc::utils::level_dir(r.cache_dir, job.coord.get_x(), job.coord.get_z()), basename, mod, r.cache_compress);\n    \n    if (r.cache_use) {\n      if (cache.exists()) {\n        if (cache.read(p.operations)) {\n          p.cache_hit = true;\n          return p;\n        }\n        \n        cache.clear();\n      }\n    }\n    \n    //p.signs = job.level->get_signs();\n    job.engine->render(job.level, p.operations);\n\n    //p.operations->optimize();\n    \n    if (r.cache_use) {\n      // create the necessary directories required when caching\n      cache.create_directories();\n      \n      // ignore failure while writing the operations to cache\n      if (!cache.write(p.operations)) {\n        // on failure, remove the cache file - this will prompt c10t to regenerate it next time\n        cache.clear();\n      }\n    }\n    \n    return p;\n  }\n};\n\n#endif /* __THREADS__RENDERER_HPP__ */\n"
  },
  {
    "path": "src/threads/renderer_settings.hpp",
    "content": "#ifndef _THREADS_RENDERER_SETTINGS_HPP\n#define _THREADS_RENDERER_SETTINGS_HPP\n\n#include <boost/filesystem.hpp>\n\nnamespace fs = boost::filesystem;\n\nstruct renderer_settings {\n  bool cache_use;\n  fs::path cache_dir;\n  bool cache_compress;\n};\n\n#endif /* _THREADS_RENDERER_SETTINGS_HPP */\n"
  },
  {
    "path": "src/threads/threadworker.hpp",
    "content": "// Distributed under the BSD License, see accompanying LICENSE.txt\n// (C) Copyright 2010 John-John Tedro et al.\n#ifndef _THREADWORKER_H_\n#define _THREADWORKER_H_\n#include <assert.h>\n\n#include <queue>\n#include <list>\n\n// I admit, this is pretty drastic, but I was desperate\n// now I just keep it for the sake of having it available to new\n// platforms.\n#if !defined(C10T_DISABLE_THREADS)\n#include \"threads/threadworker_impl.hpp\"\n#else\n#include \"threads/threadworker_fake.hpp\"\n#endif\n\n#endif /* _THREADWORKER_H_ */\n"
  },
  {
    "path": "src/threads/threadworker_fake.hpp",
    "content": "#ifndef __THREADWORKER_SUB_HPP__\n#define __THREADWORKER_SUB_HPP__\n\ntemplate <class I, class O>\nclass threadworker\n{\nprivate:\n  std::queue<I> in;\n  \n  const int thread_count;\npublic:\n  threadworker(int c) : thread_count(c) {\n  }\n  \n  virtual ~threadworker() {\n  }\n  \n  void give(I t) {\n    in.push(t);\n  }\n  \n  void start() {\n  }\n  \n  void run(int id) {\n  }\n\n  virtual O work(I) = 0;\n  \n  O get() {\n    I i = in.front();\n    in.pop();\n    return work(i);\n  }\n  \n  void join() {\n  }\n};\n\n#endif /*__THREADWORKER_SUB_HPP__*/\n"
  },
  {
    "path": "src/threads/threadworker_impl.hpp",
    "content": "#ifndef __THREADWORKER_SUB_HPP__\n#define __THREADWORKER_SUB_HPP__\n\n#include <boost/detail/atomic_count.hpp>\n#include <boost/thread/mutex.hpp>\n#include <boost/thread/condition.hpp>\n#include <boost/thread.hpp>\n#include <boost/bind.hpp>\n\nclass interrupted_exception : public std::exception {};\n\ntemplate<typename T>\nclass sync_queue {\n  private:\n    std::queue<T> q;\n    boost::mutex mutex;\n    boost::condition empty_cond;\n    volatile int count;\n    volatile bool interrupted;\n  public:\n    sync_queue() : count(0), interrupted(false) {}\n\n    void add(T o) {\n      boost::mutex::scoped_lock lock(mutex);\n      q.push(o);\n      empty_cond.notify_one();\n    }\n    \n    T take(int& pos) throw(interrupted_exception) {\n      boost::mutex::scoped_lock lock(mutex);\n      while (!interrupted && q.empty()) {\n        empty_cond.wait(lock);\n      }\n      \n      if (interrupted) {\n        throw interrupted_exception();\n      }\n      \n      T o = q.front();\n      q.pop();\n      pos = count++;\n      return o;\n    }\n    \n    bool empty() {\n      boost::mutex::scoped_lock lock(mutex);\n      return q.empty();\n    }\n    \n    void interrupt() {\n      boost::mutex::scoped_lock lock(mutex);\n      interrupted = true;\n      empty_cond.notify_all();\n    }\n};\n\ntemplate <class I, class O>\nclass threadworker\n{\nprivate:\n  const int total;\n  \n  sync_queue<I> in;\n  sync_queue<O> out;\n  boost::condition start_cond;\n  boost::condition input_cond;\n  boost::mutex start_mutex;\n  \n  const int thread_count;\n  \n  boost::detail::atomic_count input;\n  boost::detail::atomic_count output;\n  volatile bool started;\n  volatile bool interrupted;\n  \n  boost::scoped_array<boost::thread> threads;\npublic:\n  threadworker(int c, int total) : total(total), thread_count(c),\n    input(0), output(0), started(false), interrupted(false),\n    threads(new boost::thread[thread_count])\n  {\n    for (int i = 0; i < thread_count; i++) {\n      threads[i] = boost::thread(boost::bind(&threadworker::run, this, i));\n    }\n  }\n  \n  virtual ~threadworker() {\n    in.interrupt();\n    out.interrupt();\n    \n    interrupted = true;\n    \n    {\n      boost::mutex::scoped_lock lock(start_mutex);\n      start_cond.notify_all();\n    }\n    \n    for (int i = 0; i < thread_count; i++) {\n      threads[i].join();\n    }\n  }\n  \n  void give(I t) {\n    in.add(t);\n  }\n  \n  void start() {\n    boost::mutex::scoped_lock lock(start_mutex);\n    started = true;\n    start_cond.notify_all();\n  }\n\n  void internal_work() throw(interrupted_exception) {\n    int qp;\n    \n    I i = in.take(qp);\n    \n    O o = work(i);\n    \n    if (interrupted) {\n      throw interrupted_exception();\n    }\n    \n    out.add(o);\n    ++output;\n  }\n  \n  void run(int id) {\n    {\n      boost::mutex::scoped_lock lock(start_mutex);\n      \n      while (!interrupted && !started) {\n        start_cond.wait(lock);\n      }\n    }\n    \n    if (interrupted) {\n      return;\n    }\n    \n    while (++input <= total) {\n      try {\n        internal_work();\n      } catch(interrupted_exception& e) {\n        break;\n      }\n    }\n  }\n\n  virtual O work(I) = 0;\n  \n  O get() {\n    int t;\n    return out.take(t);\n  }\n  \n  void join() {\n  }\n};\n\n#endif /*__THREADWORKER_SUB_HPP__*/\n"
  },
  {
    "path": "src/warps.cpp",
    "content": "#include \"warps.hpp\"\n\n#include <fstream>\n\n#include <boost/algorithm/string.hpp>\n#include <boost/lexical_cast.hpp>\n\nusing namespace std;\n\nvoid warps_db::read(std::vector<warp>& warps)\n{\n  using ::boost::lexical_cast;\n  using ::boost::split;\n  \n  if (!fs::is_regular_file(path)) {\n    throw warps_db_exception(\"database does not exist\");\n  }\n  \n  ifstream fp(path.string().c_str());\n  \n  if (!fp.good())\n  {\n    throw warps_db_exception(\"could not open file\");\n  }\n  \n  while (!fp.eof())\n  {\n    string line;\n    getline(fp, line);\n    \n    if (line.empty()) continue;\n    \n    vector<string> parts;\n    split(parts, line, boost::is_any_of(\":\"));\n    \n    if (parts.size() < 4) continue;\n    \n    warp w;\n    \n    w.name = parts[0];\n    \n    try {\n      w.xPos = int(lexical_cast<double>(parts[1]));\n      w.yPos = int(lexical_cast<double>(parts[2]));\n      w.zPos = int(lexical_cast<double>(parts[3]));\n    } catch(...) {\n      // silently ignore\n      continue;\n    }\n    \n    warps.push_back(w);\n  }\n  \n  fp.close();\n}\n"
  },
  {
    "path": "src/warps.hpp",
    "content": "#ifndef _WARPS_H_\n#define _WARPS_H_\n\n#include <string>\n#include <vector>\n#include <exception>\n\n#include <boost/filesystem/operations.hpp>\n#include <boost/filesystem/path.hpp>\n#include <boost/filesystem.hpp>\n\n#include \"nbt/nbt.hpp\"\n\nnamespace fs = boost::filesystem;\n\nclass warps_db_exception : public std::exception {\n  private:\n    const char* why;\n  public:\n    warps_db_exception(const char* why) : why(why) { }\n    \n    const char* what() throw() {\n      return this->why;\n    }\n};\n\nclass warp {\npublic:\n  std::string name;\n  nbt::Int xPos, yPos, zPos;\n};\n\nclass warps_db {\npublic:\n  const fs::path path;\n  \n  warps_db(const fs::path path) : path(path) {}\n  void read(std::vector<warp>&);\n};\n\n#endif /* _WARPS_H_ */\n"
  },
  {
    "path": "src/win32/tss_cleanup_implemented.cpp",
    "content": "namespace boost {\n  void tss_cleanup_implemented() {}\n};\n"
  },
  {
    "path": "test/CMakeLists.txt",
    "content": "add_executable(c10t-test EXCLUDE_FROM_ALL test.cpp)\n\ntarget_link_libraries(c10t-test c10t-lib)\ntarget_link_libraries(c10t-test ${c10t_LIBRARIES})\ntarget_link_libraries(c10t-test boost_unit_test_framework)\n"
  },
  {
    "path": "test/test.cpp",
    "content": "#include \"color.hpp\"\n#include \"image.hpp\"\n#include \"2d/cube.hpp\"\n\n#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE c10t_tests\n#include <boost/test/unit_test.hpp>\n\n\n#include <iostream>\n\nBOOST_AUTO_TEST_CASE( test_cube_projection_1 )\n{\n  // x, y, z\n  Cube c(10, 10, 20);\n  point p1(0, 0, 0), p2(0, 0, 20), p3(10, 0, 20), p4(10, 0, 0);\n  int x, y;\n  \n  {\n    c.project_top(p1, x, y);\n    BOOST_REQUIRE(x == 0 && y == 0);\n    c.project_top(p2, x, y);\n    BOOST_REQUIRE(x == 0 && y == 20);\n    c.project_top(p3, x, y);\n    BOOST_REQUIRE(x == 10 && y == 20);\n    c.project_top(p4, x, y);\n    BOOST_REQUIRE(x == 10 && y == 0);\n  }\n  \n  {\n    c.project_oblique(p1, x, y);\n    BOOST_REQUIRE(x == 0 && y == 10);\n    c.project_oblique(p2, x, y);\n    BOOST_REQUIRE(x == 0 && y == 30);\n    c.project_oblique(p3, x, y);\n    BOOST_REQUIRE(x == 10 && y == 30);\n    c.project_oblique(p4, x, y);\n    BOOST_REQUIRE(x == 10 && y == 10);\n  }\n  \n  {\n    c.project_obliqueangle(p1, x, y);\n    BOOST_REQUIRE(x == 20 && y == 10);\n    c.project_obliqueangle(p2, x, y);\n    BOOST_REQUIRE(x == 0 && y == 30);\n    c.project_obliqueangle(p3, x, y);\n    BOOST_REQUIRE(x == 10 && y == 40);\n    c.project_obliqueangle(p4, x, y);\n    BOOST_REQUIRE(x == 30 && y == 20);\n  }\n}\n\nBOOST_AUTO_TEST_CASE( test_cube_projection_2 )\n{\n  // x, y, z\n  Cube c(20, 10, 10);\n  point p1(0, 0, 0), p2(0, 0, 10), p3(20, 0, 10), p4(20, 0, 0);\n  int x, y;\n  \n  {\n    c.project_top(p1, x, y);\n    BOOST_REQUIRE(x == 0 && y == 0);\n    c.project_top(p2, x, y);\n    BOOST_REQUIRE(x == 0 && y == 10);\n    c.project_top(p3, x, y);\n    BOOST_REQUIRE(x == 20 && y == 10);\n    c.project_top(p4, x, y);\n    BOOST_REQUIRE(x == 20 && y == 0);\n  }\n  \n  {\n    c.project_oblique(p1, x, y);\n    BOOST_REQUIRE(x == 0 && y == 10);\n    c.project_oblique(p2, x, y);\n    BOOST_REQUIRE(x == 0 && y == 20);\n    c.project_oblique(p3, x, y);\n    BOOST_REQUIRE(x == 20 && y == 20);\n    c.project_oblique(p4, x, y);\n    BOOST_REQUIRE(x == 20 && y == 10);\n  }\n  \n  {\n    c.project_obliqueangle(p1, x, y);\n    BOOST_REQUIRE(x == 10 && y == 10);\n    c.project_obliqueangle(p2, x, y);\n    BOOST_REQUIRE(x == 0 && y == 20);\n    c.project_obliqueangle(p3, x, y);\n    BOOST_REQUIRE(x == 20 && y == 40);\n    c.project_obliqueangle(p4, x, y);\n    BOOST_REQUIRE(x == 30 && y == 30);\n  }\n}\n"
  }
]