/pigmap

Minecraft map generator

Primary LanguageC++GNU General Public License v3.0GPL-3.0

pigmap is a Minecraft map renderer, designed to be fast enough for very large worlds (like
the Aporkalypse Now server, hence the name).  It was inspired by Minecraft Overviewer and does
essentially the same thing, just faster and with fewer fancy options.  Features include:

-isometric projection; level of detail on max zoom is user-settable
-Google Maps tile output
-custom tilesets (supply your own terrain.png)
-ability to manually edit the isometric block images generated from terrain.png,
  for further beautification
-incremental map updates, but you must supply your own list of modified chunks (most
  likely via rsync or something similar)
-multithreading
-support for Alpha (chunk-based), Beta (.mcr), or Anvil (.mca) world formats
-ability to restrict rendering to a certain range of Y-values (heights)

pigmap is free under the GPL (please see the file COPYING).  I probably won't add too many
more features beyond whatever the Aporkalypse might need in the future, but hopefully it will
be useful to someone.

Michael J. Nelson, mike@thinkingpart.com ("equalpants" in Minecraft)

The files template.html and style.css contain code from Minecraft Overviewer (copyright
Andrew Brown and contributors).

The official pigmap repository is at:
https://github.com/equalpants/pigmap

---------------------------------------------------------------------------------------------------

Supported platforms are Linux and cygwin.  OS X should also be fine, but I haven't tried it
myself.  (I've heard reports of it working, though.)

Dependencies are zlib, libpng, pthreads, and some very basic system stuff: getopt, mkdir,
dirent.h.  If your platform has a separate development package for libpng (called libpng-dev,
libpng-devel, or something like that), you'll need that one, too.

Use supplied makefile to build with g++.

---------------------------------------------------------------------------------------------------

Change log (important stuff only):

1.2
-new blocks up to Minecraft 1.3
-chest.png, etc. now required
-some speed improvements
-block IDs >= 256 (from mods) now ignored rather than drawn as random blocks
-memory requirements increased--should now be just a little lower than pre-Anvil
  versions (roughly ~250-300 MB per thread)

1.1.2
-added inverted slabs

1.1.1
-fixed a stupid bug preventing incremental updates from working

1.1
-Anvil format support
-added -y and -Y params to specify minimum/maximum Y-coords for rendering
-memory requirements are about 15-20% lower due to better caching
-new blocks up to Minecraft 1.2.4: circle stone brick, new sandstone types, redstone lamps,
  new plank colors, upside-down stairs
-some display fixes for older blocks whose behavior has changed: fences, doors

1.0.1
-new blocks: jungle logs/leaves/saplings

1.0
-NOTE: users of jcornwellshiel's fork will need to regenerate their blocks-B.png
-new blocks all the way up through Minecraft 1.0
-endportal.png added; must be placed in images directory alongside terrain.png
-fixed some ugliness in the rendering of cross-shaped item blocks (saplings, etc.)
-improved rendering of large block sizes (B > 8)

0.7.4
-new blocks for Minecraft Beta 1.6: tall grass, ferns, dead shrubs, trapdoors

0.7.3
-new blocks for Minecraft Beta 1.4 and 1.5: locked chests, boosters, detectors,
  pine/birch saplings, webs

0.7.2
-support for big-endian platforms (like PowerPC)

0.7.1
-birch and pine leaves
-more error/logging messages

0.7
-Minecraft Beta 1.3 support: new region file format, beds, repeaters, slabs

0.6.1
-support for HD texture packs

0.6
-new block types for Minecraft Beta 1.2: lapis, cake, etc.
-remaining undrawn blocks from previous versions now drawn: fire, buttons, levers, ascending
  cart tracks
-fire.png added; must be placed in images directory alongside terrain.png
-some block image offsets changed; see note below if you have manually edited your blocks-B.png
-some drawing improvements; may want to redo all block images from terrain.png

0.5.1
-speed improvements
-previously, we would abort if the world was too absurdly large to deal with--i.e. if there were
  some chunks whose coordinates were well into the billions--but apparently there is a Minecraft
  bug that can create such chunks way off in space, even if the world is normally-sized, so now
  we just ignore any chunks that are too far out to handle

0.5
-initial version

---------------------------------------------------------------------------------------------------

Usage examples:

full render:

pigmap -B 6 -T 1 -Z 10 -i input/World1 -o output/World1 -g images -h 3

...builds a map with parameters B = 6, T = 1, baseZoom = 10, reading world data from the path
"input/World1", writing tiles out to the path "output/World1", reading terrain images from the path
"images", and using 3 threads.

incremental update:

pigmap -i input/World1 -o output/World1 -r regionlist -h 3 -x

...updates an existing map by redrawing any tiles touched by regions listed in the file "regionlist",
with the input and output dirs as before.  Terrain images are read from the path ".", and 3 threads
are used.  Map parameters are read from the existing map, and if the existing baseZoom is too small,
it will be incremented.

---------------------------------------------------------------------------------------------------

Error messages are written to stderr; normal output to stdout.  There isn't much (read: any) of a
progress indicator at the moment, but there are some statistics upon completion.

---------------------------------------------------------------------------------------------------

Explanation of command-line options:


1. Params for both full renders and incremental updates:

a. input path, output path (-i, -o)

The input path should be the top directory of the world data (i.e. where level.dat is).  The tile
output path should be the top of the Google Maps directory structure (i.e. where base.png is).  Tile
images will be written to the output path, along with a file "pigmap.params" which remembers what
parameters the map was drawn with.  For incremental updates, the output path must exist already, and
must contain the pigmap.params file.

Three world formats are supported: the current Anvil format (with .mca region files), the .mcr
region format that preceded it, and the even older chunk-based format.  If the input path contains
more than one format, then only the newer format will be used.

b. [optional (kind of)] HTML source path (-m)

This is where pigmap expects to find the files "template.html" and "style.css", which it will
use to construct a bare-bones HTML page for viewing the map.  These files are not optional, but
the -m parameter itself may be omitted, in which case "." is used as the HTML source path.

The map-viewing page is called "pigmap-default.html" and is written to the output path.  It doesn't have
any fancy capabilities (just plain old markers); it's meant only to demonstrate the JavaScript for
converting Minecraft coords to Google Maps latitude/longitude.  This file is rewritten with every
incremental update; make a copy if you need to add fancier abilities to it.

c. [optional (kind of)] image path (-g)

This is where pigmap expects to find either a copy of your tileset (terrain.png, etc.), or a copy of
blocks-B.png (substituting the actual numeric value of B; see below for definition of B), a
pigmap-generated file that contains the isometric renderings of each block.  These files are not
optional, but the -g parameter itself may be omitted, in which case "." is used as the image path.

Each blocks-B.png comes with a corresponding blocks-B.version, which remembers how many block images
are stored in blocks-B.png.  (As more blocks are added to the game, the version will change.)

The selection of block images works thusly:

-If blocks-B.png does not exist, then the tileset you provide will be used to create it.
-If blocks-B.png exists but has an old version, your tileset will be used to fill in any missing
  (i.e. new) blocks, but the existing portions of blocks-B.png will be preserved.
-If blocks-B.png exists and is up-to-date, its block images will be used.

This means that pigmap will need your tileset the first time it runs, so it can generate blocks-B.png;
subsequent runs will use the existing blocks-B.png, which can be manually edited if insufficiently
pretty, or for special effects, etc.

The following images are required to generate blocks-B.png:
-terrain.png, chest.png, largechest.png, enderchest.png: these files come from your tileset
  or minecraft.jar
-fire.png, endportal.png: these files are included with pigmap
All of these must be RGBA png files (not just RGB).

High-res tilesets are supported.  The textures in terrain.png, fire.png, and endportal.png can be
any size, as long as they remain square.  The textures in the chest pngs can be scaled up, but their
size must be an integer multiple of the original size.

d. [optional] number of threads (-h)

Defaults to 1.  Each thread requires around 250-300 MB of RAM (they work in different areas of the
map and keep separate caches of chunk data).  Returns from extra threads may diminish quickly as the
disk becomes a bottleneck.


2. Params for full renders only:

a. map parameters B, T, [optional] baseZoom (-B, -T, -Z):

B is an integer >= 2 which controls the size (in pixels) of the blocks in the base zoom level.  The
map projection lays out blocks on a hexagonal grid generated from the distances [+/-2B, +/-B] and
[0, +/-2B], and each individual block's bounding box is 4B x 4B.

T is the tile multiplier, an integer >= 1 which controls how many chunks wide a tile is.

The size of each generated tile is 64BT x 64BT.

(To match Minecraft Overviewer's highest zoom level, use B=6 and T=1, for a tile size of 384 x 384.
To match its second-highest zoom, use B=3 and T=2.)

baseZoom is the Google Maps zoom level that the base tiles should be placed on.  This is important
because Google Maps allows only 2^Z by 2^Z tiles for each zoom level Z; if baseZoom is not high enough,
some tiles will not fit on the Google Map.  (Out-of-bounds tiles will be noticed at the start of a
render, and the render aborted.)

If baseZoom is omitted, it will be set to the lowest value that can fit all the required tiles.

b. [optional] minimum/maximum Y-coords (-y, -Y)

By default, pigmap will draw all blocks present in the world data, but these parameters can be
used to restrict rendering to blocks within a particular height range.  -y is the minimum Y-coord
which will be drawn, and -Y is the maximum.

Note that these values, if used, will persist through incremental updates of the map (like B and T
do), even if the actual height limit in the game changes in the future.  So if you want the map to
always render all the way to the top, then *don't use* -Y, as opposed to using it but passing in
the *current* height limit.


3. Params for incremental updates only:

a. regionlist file (-r) or chunklist file (-c)

The name of a text file containing the filenames of regions or chunks that should be updated, one per
line.  Supplied filenames can have a relative or absolute path or can just be the file name; only the
name will be examined.

If the input world is in region format (either .mca or .mcr regions), then a regionlist must be used,
not a chunklist.  However, the extensions on the filenames in a regionlist do not matter--only the
coordinates from the filenames will be considered, and pigmap will always read the newest available
region.

The current format of the input world does *not* have to match the format used in the previous map
render--an incremental update will work fine even if the world data has been converted since the
last render.  (Of course it would be trickier to get a meaningful regionlist in such a case--to
distinguish the regions which have actually changed from those which have merely been converted--
but if you have such a list, then pigmap can use it.)

b. [optional] expand map if necessary (-x)

This is useful for frequently-updated maps: eventually, as the world expands outwards, it will become
too large for the current baseZoom, and an incremental update will fail.  If -x has been passed, then
if an incremental update fails due to out-of-bounds tiles, the map's baseZoom will be increased by
1, and the update retried.  (The baseZoom increase is *not* undone if the second attempt also fails.)

Note that increasing a map's baseZoom is quick: all the tiles are simply moved one level deeper in
the hierarchy, and the top two zoom levels redrawn.

---------------------------------------------------------------------------------------------------

What happens in a full render: the world data is scanned, and every chunk that exists on disk is noted.
All tiles that include any chunks are rendered and saved; any tiles that might exist already in the
output path are overwritten.

What happens in an incremental update: the chunklist is read and its chunks are considered "required";
the world data is not scanned.  (However, the input path must still contain the non-required chunks;
that is, you can't just use a partial copy of a world.  This is because each tile touches multiple
chunks; to render a required chunk, data from its non-required neighbors may be necessary.)  All tiles
that include required chunks are rendered and saved.  Base tiles that exist already in the output path
are overwritten, but those at lower zoom levels are merely modified--only the changed portions
are redrawn.

---------------------------------------------------------------------------------------------------

Special note for those who choose to manually edit blocks-B.png:

When new block types are introduced, their block images are added on to the end of blocks-B.png,
and the existing contents are preserved, so you don't need to worry about previous modifications
getting destroyed.  However, sometimes it may be necessary to remove existing block images and
replace them with new versions; when this happens, the old block image offset will no longer be
used, and a new block image will be added to the end of the file.

Example: prior to pigmap 0.6, the furnace block images were located at offsets 68, 69, and 149-152.
Starting with 0.6, they are instead located at 183-188.  (This is because the furnace graphics
were changed in Minecraft Beta 1.2.)  So if you modified the furnace block images while using a
pre-0.6 version of pigmap, your modified images can still be found at their old locations in your
blocks-B.png, but they must be copied to the new locations.

Complete list of block image moves:

--- pigmap 1.2 ---
gravel: 21->483
chests: 54->484, 177->485, 297->486, [173-176]->[487,490], [298-301]->[491-494]

--- pigmap 1.0 ---
beds: 232->281, 233->282, 234->283, 235->284, 236->285, 237->286, 238->287, 239->288
cake: 228->289

--- pigmap 0.6 ---
furnaces: 68->183, 69->186, 149->184, 150->185, 151->187, 152->188
fire: 48->189
buttons: 123->190, 124->191, 125->192, 126->193
levers: 104->194, 105->195, 106->196, 107->197, 108->198, 109->199
ascending tracks: 88->200, 89->201, 90->202, 91->203