Git Product home page Git Product logo

minecraft-overviewer's Introduction

Minecraft Overviewer Build Status

By Andrew Brown and contributors (see CONTRIBUTORS.rst).

Documentation:

http://docs.overviewer.org

Github code repository:

https://github.com/overviewer/Minecraft-Overviewer

Travis-CI:

https://travis-ci.org/overviewer/Minecraft-Overviewer

Blog:

https://overviewer.org/blog/

PLEASE NOTE: Overviewer is currently unmaintained. PRs will not be merged and issues will not be addressed. The website and repository will remain online and accessible.

The Minecraft Overviewer is a command-line tool for rendering high-resolution maps of Minecraft worlds. It generates a set of static html and image files and uses Leaflet to display a nice interactive map.

The Overviewer has been in active development for several years and has many features, including day and night lighting, cave rendering, mineral overlays, and many plugins for even more features! It is written mostly in Python with critical sections in C as an extension module.

Getting Started

All documentation has been consolidated at our documentation site. For information on downloading, compiling, installing, and running The Overviewer, visit the docs site.

http://docs.overviewer.org

A few helpful tips are below, but everyone is going to want to visit the documentation site for the most up-to-date and complete set of instructions!

Alternatively, the docs are also in the docs/ directory of the source download. Look in there if you can't access the docs site.

Examples

See examples of The Overviewer in action!

https://github.com/overviewer/Minecraft-Overviewer/wiki/Map-examples

Disclaimers

Before you dive into using this, just be aware that, for large maps, there is a lot of data to parse through and process. If your world is very large, expect the initial render to take at least an hour, possibly more. (Since Minecraft maps are practically infinite, the maximum time this could take is also infinite!)

If you press ctrl-C, it will stop. The next run will pick up where it left off.

Once your initial render is done, subsequent renderings will be MUCH faster due to all the caching that happens behind the scenes. Just use the same output directory and it will only update the tiles it needs to.

There are probably some other minor glitches along the way, hopefully they will be fixed soon. See the Bugs section below.

Viewing the Results

Within the output directory you will find two things: an index.html file, and a directory hierarchy full of images. To view your world, simply open index.html in a web browser.

You can throw these files up to a web server to let others view your map.

Bedrock and other formats

Minecraft Overviewer only supports the world format from the Java edition of Minecraft. Minecraft Bedrock (the Windows 10 version) is not supported by Overviewer, but users have reported success using Amulet to convert Bedrock worlds to the Java format, and then used Overviewer to render the converted worlds.

Bugs

For a current list of issues, visit https://github.com/overviewer/Minecraft-Overviewer/issues

Feel free to comment on issues, report new issues, and vote on issues that are important to you.

minecraft-overviewer's People

Contributors

agrif avatar aheadley avatar alexjurkiewicz avatar astraluma avatar auron956 avatar brownan avatar buscher avatar contre avatar counterpillow avatar eanmclaughlin avatar eminence avatar fabiann avatar gmcnew avatar greatmastermario avatar gshort avatar incredibleholg avatar interfect avatar ion1 avatar joe-mojo avatar jonnyjd avatar lother avatar masterofjokers avatar pibm avatar pironic avatar redsparr0w avatar rmccue avatar rmrector avatar steadbytes avatar tswsl1989 avatar wunkolo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

minecraft-overviewer's Issues

Scroll wheel zooming is reversed

I've just found this project, and took a look at some of those online examples. The first thing I noticed is that mouse wheel actions are reversed. In other words, scrolling up does a zoom out, while in Google Maps and most other mapping software, it zooms in.

Tile caching

Similar to how I cache chunks when rendered and only re-render them if they change, I should do the same for tiles. This will greatly speed up generating all the tiles subsequent times (although not the first time)

"Your map is way too big!"

A couple of days ago I was able to get a map rendered (http://novylen.net/~minecraft/) (I've now removed the outlying chunks at ~1000000,0 btw, so it needs to recalculate the zoom levels). On attempting to do an incremental update, it got through rendering the new/updated chunks, and then complained that the map was now too large. :(

I suppose I crossed some magic threshold somewhere.

178000/178830 chunks rendered
Done!
Traceback (most recent call last):
File "gmap.py", line 70, in
main()
File "gmap.py", line 46, in main
q = quadtree.QuadtreeGen(w, destdir)
File "/home/minecraft/brownan-Minecraft-Overviewer-72090ff/quadtree.py", line 51, in init
raise ValueError("Your map is waaaay to big!")
ValueError: Your map is waaaay to big!

"North" is lower left, expected to be upper left or upper right

Entering on behalf of a few user comments on the SA MC thread. In short, they expect the community-accepted north (the direction clouds move towards) to be either upper left or upper right. Currently, north is the lower-left corner of the map.

My own suggestion would be for north being in the upper-left corner, as most people are right-handed and that's the way one would normally orient a piece of paper for reading/writing (obviously not to the extreme of the isometric view, but you get the idea.)

[PATCH] Add timestamps to log messages

diff --git a/quadtree.py b/quadtree.py
index 970c9a3..997e1c8 100644
--- a/quadtree.py
+++ b/quadtree.py
@@ -21,6 +21,7 @@ import hashlib
 import functools
 import re
 import shutil
+import time

 from PIL import Image

@@ -241,8 +242,8 @@ class QuadtreeGen(object):
             # get() instead of wait() so we can see errors
             result.get()
             if i > 0 and (i % 100 == 0 or 100 % i == 0):
-                print "{0}/{1} tiles complete on level 1/{2}".format(
-                        i, len(results), self.p)
+                print "{0} {1}/{2} tiles complete on level 1/{3}".format(
+                        time.strftime("%Y:%m:%d %H:%M:%S"), i, len(results), self.p)
         print "Done"

         # Now do the other layers
@@ -265,8 +266,8 @@ class QuadtreeGen(object):
                 # get() instead of wait() so we can see errors
                 result.get()
                 if i > 0 and (i % 100 == 0 or 100 % i == 0):
-                    print "{0}/{1} tiles complete for level {2}/{3}".format(
-                            i, len(results), level, self.p)
+                    print "{0} {1}/{2} tiles complete for level {3}/{4}".format(
+                            time.strftime("%Y:%m:%d %H:%M:%S"), i, len(results), level, self.p)
             print "Done"

         # Do the final one right here:
diff --git a/world.py b/world.py
index 4e906b1..ac54204 100644
--- a/world.py
+++ b/world.py
@@ -17,6 +17,7 @@ import functools
 import os
 import os.path
 import multiprocessing
+import time

 from PIL import Image

@@ -117,7 +118,7 @@ class WorldRenderer(object):
                 results[(col, row)] = result
                 if i > 0:
                     if 1000 % i == 0 or i % 1000 == 0:
-                        print "{0}/{1} chunks rendered".format(i, len(chunks))
+                        print "{0}: {1}/{2} chunks rendered".format(time.strftime("%Y:%m:%d %H:%M:%S"), i, len(chunks))
         else:
             print "Rendering chunks in {0} processes".format(processes)
             pool = multiprocessing.Pool(processes=processes)
@@ -134,7 +135,7 @@ class WorldRenderer(object):
                 results[(col, row)] = result.get()
                 if i > 0:
                     if 1000 % i == 0 or i % 1000 == 0:
-                        print "{0}/{1} chunks rendered".format(i, len(chunks))
+                        print "{0}: {1}/{2} chunks rendered".format(time.strftime("%Y:%m:%d %H:%M:%S"), i, len(chunks))

             pool.join()
         print "Done!"

Map annotation

On Google maps, you can do annotations - put up markers with comments. Naming towns, for instance. I'd probably write a script that put all existing member-rank warp points up on the map by coordinate, if possible.

I'd like to be able to do that. Low priority compared to bugfixes but very nice.

Don't delete tiles before they can be replaced.

I noticed gmap.py deletes old tiles at the start now. Since our map takes 10hrs to generate fully it means I can't generate the map on top of the live copy without 10hrs of it being mostly missing. Can you please change this so tiles are only deleted when the new copy is ready to put in place?

Cave mode shows too much water

A cave mode image renders the bottom of the oceans, which can block cave systems. Right now the cave renderer detects caves by only rendering blocks which have no sunlight hitting them (which is easy since sunlight info is stored in the datafiles). But apparently no sunlight hits the bottom of the ocean either. Perhaps a hard-coded exception is in order.

bug: tile problems

i'm not really sure how to even describe this problem, but have a look:

http://smp.em32.net/map.bug/

here's a screenshot in case what i'm seeing isn't what you're seeing: http://smp.em32.net/map.bug/ss.png

i didn't change (as far as i can tell) how i ran overviewer. the only thing that i can think of that might have changed between the execution that generated this buggy map and the prior one is that my world may have been identical (that is, no updated chunks).

Feature: Mineral overlay

Now that I'm using google maps, I'd like to put in mineral overlays for various minerals, so one can tell where they are.

support mutli-node parallelisation

to facilitate the rendering of really large maps, it would be nice to support parallelisation on multiple nodes in a cluster (assuming some type of shared storage).

chunk rendering seems easy to do. not so sure about image tiling.

Omit blank tiles

I should check to see if a tile is blank and just... not save it. Right now it generates probably hundreds of completely transparent tiles especially around the edges that take up space.

Invalid tiles left in place when updating gmap

In the event the entire map needs to be re-rendered when running gmap.py as an update, any time there is a tile from the previous render and the new tile would be blank, the old tile is left in place, making for some erroneous displays.

To demonstrate: Create a world, leave it small. Render it. Go running in one direction. Re-render. The old view would fill up most of the bounds, leaving few blank tiles. The new world will have many blank tiles, since you only went in one direction. Where the new blanks overlap with the old non-blanks, you get the old tiles.

error

71000/71508 chunks rendered
Done!
Your map seemes to have expanded beyond its previous bounds.
Doing some tile re-arrangements... just a sec...
Traceback (most recent call last):
 File "/home/aj/qt3-minecraft-server/Minecraft-Overviewer/quadtree.py", line 27, in newfunc
   return func(*args, **kwargs)
 File "/home/aj/qt3-minecraft-server/Minecraft-Overviewer/quadtree.py", line 435, in render_worldtile
   os.makedirs(dirdest)
 File "/usr/lib/python2.6/os.py", line 157, in makedirs
   mkdir(name, mode)
OSError: [Errno 17] File exists: 'imgs/tiles/0/2/3/3/3/0/1/2/3'
    Computing the tile ranges and starting tile processers for inner-most tiles...

Absolute anchor for center of world

It's become apparent to me that, instead of splitting the world in half, I need to have the center point be anchored somehow, probably to the origin at chunk (0,0)

Why? If the world expands one or two units in either direction, the new midpoint will shift, and all tiles will be re-generated since the existing tiles no longer match with the new tiles.

Instead of doing an initial split at the midpoint, I think I'll change it to split at the origin.

Improve terrain.png location

Instead of searching $CWD, search the same directory as texture.py is in.

Patch:
~/Minecraft-Overviewer $ git diff
diff --git a/textures.py b/textures.py
index b857781..c9546e4 100644
--- a/textures.py
+++ b/textures.py
@@ -9,9 +9,10 @@ import numpy
from PIL import Image, ImageEnhance

 def _get_terrain_image():
-    # Check the current directory for terrain.png first:
-    if os.path.isfile("terrain.png"):
-        return Image.open("terrain.png")
+    # See if terrain.png is in the application directory
+    t = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])),"terrain.png")
+    if os.path.isfile(t):
+        return Image.open(t)

     if "darwin" in sys.platform:
         # On Macs, terrain.png could lie at

Some blocks render funny

For sprites like flowers and torches, they are still rendered as a block. I need to put in an exception for these blocks so I don't get a cube with a torch drawn on it.

Fix typo

diff --git a/world.py b/world.py
index d480173..4863544 100644
--- a/world.py
+++ b/world.py
@@ -329,15 +329,15 @@ def generate_quadtree(chunkmap, colstart, colend, rowstart, rowend, prefix):

     return p

-def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadrent):
+def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadrant):
     """Recursive method that generates a quadtree.
     A single call generates, saves, and returns an image with the range
     specified by colstart,colend,rowstart, and rowend.

-    The image is saved as os.path.join(prefix, quadrent+".png")
+    The image is saved as os.path.join(prefix, quadrant+".png")

     If the requested range is larger than a certain threshold, this method will
-    instead make 4 calls to itself to render the 4 quadrents of the image. The
+    instead make 4 calls to itself to render the 4 quadrants of the image. The
     four pieces are then resized and pasted into one image that is saved and
     returned.

@@ -347,19 +347,19 @@ def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadr
     The path "prefix" should be a directory where this call should save its
     image.

-    quadrent is used in recursion. If it is "base", the image is saved in the
-    directory named by prefix, and recursive calls will have quadrent set to
+    quadrant is used in recursion. If it is "base", the image is saved in the
+    directory named by prefix, and recursive calls will have quadrant set to
     "0" "1" "2" or "3" and prefix will remain unchanged.

-    If quadrent is anything else, the tile will be saved just the same, but for
-    recursive calls a directory named quadrent will be created (if it doesn't
-    exist) and prefix will be set to os.path.join(prefix, quadrent)
+    If quadrant is anything else, the tile will be saved just the same, but for
+    recursive calls a directory named quadrant will be created (if it doesn't
+    exist) and prefix will be set to os.path.join(prefix, quadrant)

-    So the first call will have prefix "tiles" (e.g.) and quadrent "base" and
+    So the first call will have prefix "tiles" (e.g.) and quadrant "base" and
     will save its image as "tiles/base.png"
-    The second call will have prefix "tiles" and quadrent "0" and will save its
+    The second call will have prefix "tiles" and quadrant "0" and will save its
     image as "tiles/0.png". It will create the directory "tiles/0/"
-    The third call will have prefix "tiles/0", quadrent "0" and will save its image as
+    The third call will have prefix "tiles/0", quadrant "0" and will save its image as
     "tile/0/0.png"

     Each tile outputted is always 384 by 384 pixels.
@@ -369,10 +369,10 @@ def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadr
     If the tile is blank, path will be None.

     """
-    if 0 and prefix == "/tmp/testrender/2/1/0/1/3" and quadrent == "1":
+    if 0 and prefix == "/tmp/testrender/2/1/0/1/3" and quadrant == "1":
         print "Called with {0},{1} {2},{3}".format(colstart, colend, rowstart, rowend)
         print "  prefix:", prefix
-        print "  quadrent:", quadrent
+        print "  quadrant:", quadrant
     cols = colend - colstart
     rows = rowend - rowstart

@@ -380,7 +380,7 @@ def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadr
     # function invocation is destined to recurse, or whether we end up calling
     # render_worldtile(), the hash will help us short circuit a lot of pixel
     # copying.
-    hashpath = os.path.join(prefix, quadrent+".hash")
+    hashpath = os.path.join(prefix, quadrant+".hash")
     if os.path.exists(hashpath):
         oldhash = open(hashpath, "rb").read()
     else:
@@ -396,7 +396,7 @@ def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadr
         raise Exception("Something went wrong, this tile is too small. (Please send "
                 "me the traceback so I can fix this)")
     else:
-        # Recursively generate each quadrent for this tile
+        # Recursively generate each quadrant for this tile

         # Find the midpoint
         colmid = (colstart + colend) // 2
@@ -412,11 +412,11 @@ def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadr
         assert (rowmid - rowstart) % 4 == 0
         assert (rowend - rowmid) % 4 == 0

-        if quadrent == "base":
+        if quadrant == "base":
             newprefix = prefix
         else:
             # Make the directory for the recursive subcalls
-            newprefix = os.path.join(prefix, quadrent)
+            newprefix = os.path.join(prefix, quadrant)
             if not os.path.exists(newprefix):
                 os.mkdir(newprefix)

@@ -424,7 +424,7 @@ def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadr
         # oldhash from above, skip rendering this tile
         hasher = hashlib.md5()

-        # Recurse to generate each quadrent of images
+        # Recurse to generate each quadrant of images
         quad0file, hash0 = quadtree_recurse(chunkmap, 
                 colstart, colmid, rowstart, rowmid,
                 newprefix, "0")
@@ -454,7 +454,7 @@ def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadr
         newhash = hasher.digest()
         if newhash == oldhash:
             # Nothing left to do, this tile already exists and hasn't changed.
-            return os.path.join(prefix, quadrent+".png"), oldhash
+            return os.path.join(prefix, quadrant+".png"), oldhash

         img = Image.new("RGBA", (384, 384))

@@ -476,13 +476,13 @@ def quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, quadr
     assert bool(img)

     # Save the image
-    path = os.path.join(prefix, quadrent+".png")
+    path = os.path.join(prefix, quadrant+".png")
     img.save(path)

     print "Saving image", path

     # Save the hash
-    with open(os.path.join(prefix, quadrent+".hash"), 'wb') as hashout:
+    with open(os.path.join(prefix, quadrant+".hash"), 'wb') as hashout:
         hashout.write(newhash)

     # Return the location and hash of this tile

Windows EXE

Going ahead and putting an issue in for this. I got most of the way through getting py2exe to work, but then my computer died.

Making an exe actually isn't that hard, but there are a couple changes to the code I need to make. Easy stuff.

  1. add multiprocessing.freeze_support() to the beginning of the entry point in gmap.py
  2. Eliminate references to the built in global var __file__, since it's undefined for frozen executables.

Cave mode for gmap tiles

It's easy to generate a separate set of tiles, that's just one flag. But I'd like to figure out how to generate a separate layer and toggle between them.

Choke during quad tree phase on Windows 7

Running py-2.7, the following command:

python C:\Users\Munki\Desktop\Minecraft-Overviewer\gmap.py -p 4 C:\Users\Munki\AppData\Roaming.minecraft\saves\World1\ C:\Users\Munki\Desktop\World1\

Produces the following traceback:

Traceback (most recent call last):
File "C:\Users\Munki\Desktop\Minecraft-Overviewer\gmap.py", line 76, in
main()
File "C:\Users\Munki\Desktop\Minecraft-Overviewer\gmap.py", line 60, in main
world.generate_quadtree(results, mincol, maxcol, minrow, maxrow, tiledir, options.procs)
File "C:\Users\Munki\Desktop\Minecraft-Overviewer\world.py", line 382, in generate_quadtree
quadtree_recurse(chunkmap, colstart, colend, rowstart, rowend, prefix, "base", sem)
File "C:\Users\Munki\Desktop\Minecraft-Overviewer\world.py", line 547, in quadtree_recurse
quad0result.start()
File "C:\Users\Munki\Desktop\Minecraft-Overviewer\world.py", line 668, in start
multiprocessing.Process.start(self)
File "C:\Python27\lib\multiprocessing\process.py", line 104, in start
self._popen = Popen(self)
File "C:\Python27\lib\multiprocessing\forking.py", line 244, in init
dump(process_obj, to_child, HIGHEST_PROTOCOL)
File "C:\Python27\lib\multiprocessing\forking.py", line 167, in dump
ForkingPickler(file, protocol).dump(obj)
File "C:\Python27\lib\pickle.py", line 224, in dump
self.save(obj)
File "C:\Python27\lib\pickle.py", line 331, in save
self.save_reduce(obj=obj, *rv)
File "C:\Python27\lib\pickle.py", line 419, in save_reduce
save(state)
File "C:\Python27\lib\pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "C:\Python27\lib\pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
save(v)
File "C:\Python27\lib\pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "C:\Python27\lib\pickle.py", line 562, in save_tuple
save(element)
File "C:\Python27\lib\pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "C:\Python27\lib\pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
save(v)
File "C:\Python27\lib\pickle.py", line 331, in save
self.save_reduce(obj=obj, *rv)
File "C:\Python27\lib\pickle.py", line 419, in save_reduce
save(state)
File "C:\Python27\lib\pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "C:\Python27\lib\pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
save(v)
File "C:\Python27\lib\pickle.py", line 331, in save
self.save_reduce(obj=obj, *rv)
File "C:\Python27\lib\pickle.py", line 419, in save_reduce
save(state)
File "C:\Python27\lib\pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "C:\Python27\lib\pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
save(v)
File "C:\Python27\lib\pickle.py", line 331, in save
self.save_reduce(obj=obj, *rv)
File "C:\Python27\lib\pickle.py", line 396, in save_reduce
save(cls)
File "C:\Python27\lib\pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "C:\Python27\lib\pickle.py", line 748, in save_global
(obj, module, name))
pickle.PicklingError: Can't pickle <type 'thread.lock'>: it's not found as thread.lock
Traceback (most recent call last):
File "", line 1, in
File "C:\Python27\lib\multiprocessing\forking.py", line 347, in main
self = load(from_parent)
File "C:\Python27\lib\pickle.py", line 1378, in load
return Unpickler(file).load()
File "C:\Python27\lib\pickle.py", line 858, in load
dispatchkey
File "C:\Python27\lib\pickle.py", line 880, in load_eof
raise EOFError
EOFError

Optimizations

Going through the code, I noted some definite opportunities for improvement:

  1. The directory structure is badly balanced. Currently, each folder will have a maximum of 12 files in it, while optimal would be ~300 files per directory. Having several zoom levels in the same directory (underscores!) would fix this.

  2. .hash is a bad idea. Filesystems generally do not handle thousands of 16 byte files gracefully-- a dictionary, pickled on completion or KeyboardInterrupt, would be much faster, and 41,000 entries is a small dictionary. Use multiprocessing.Monitor to handle the shared memory. (N.B.: thousands of ~5KB files make minecraft saves load much slower than they would if instead of tiny 16x16x128 chunks they were 64x64x128 chunks)

  3. Chunk rendering could be improved. In particular, ChunkRenderer._find_oldimage gives horrible O(n^2) performance-- just determine the directory directly from the chunk's xPos and zPos attributes (it's base36, I have some code snippets if you'd fine them useful). Saving the rendered chunks to a separate directory (the output one?) would be a good idea as well (this may already be a feature)

Corrupt images crash the program

If you cancel a render, a chunk image file may be half written. Next time, it will see it exists and try to open it, and the imaging library will crash. I need to catch this and re-render the chunk.

Allow for less detailed "bottom" view

I currently run a SMP server with a 250MB save folder, after a few hours of rendering, it produced a google map that worked, but had something like 40,000 files and took up 1.5GB of disk space. When I cut down the zoom levels, it just cropped the map, rather than just not allowing you to zoom in as far.

This had the desired effect of reducing disk usage of the map, but didn't actually show the whole map. It would be nice to have an option for this to account for really large servers.

Memory issues?

With the recent re-structuring of the program from recursive to iterative, the memory requirements went up a bit. I don't know how much exactly, it may have been negligible, but I wanted to open this issue to get feedback on it.

I have a couple ideas to improve memory efficiency, and I can also change it so that otherwise empty directories are not created saving disk space. But if none of this is a problem, then I'd rather focus on other things.

alexjurkiewicz, you were going to do a test on memory? Should I make improving memory usage a priority?

Cactuses have a "funny" top

It looks like maybe they just need to be added to the list of transparent blocks. Cactuses aren't actually full blocks, but are instead 1 or 2 texels narrower.

The effect in the renderer is that the side faces are all the way out to fill the block, and the top face is surrounded by a narrow ring of sand, because the texture isn't expected to extend out that far on the top (but it is correct on the bottom.)

Blocks under planted saplings not rendered

The dirt block underneath a planted sapling isn't rendered, making it appear the sapling is floating above a hole. Readily visible if you plant a group of saplings all touching each other on a layer of dirt 1 block deep, with stone or something recognizable underneath.

RFE: specify location for chunk cache

currently Overviewer requires write permissions to the world directory to write out the rendered chunks. this makes rendering a read-only copy of a world impossible (for example, a read-only ZFS snapshot).

RFE: add a new option --cache-dir to allow the user to specify a writable location for the chunk cache

Water transparency

I want to put in an exception to not render water block faces that are adjacent to another water block. This should fix the odd transparency issues.

unrecognized data stream contents when reading image file

I'm lost, could be an issue, could be me.

5900/16384 tiles complete on level 1/7
6000/16384 tiles complete on level 1/7
Traceback (most recent call last):
File "/usr/share/minecraft-overviewer/quadtree.py", line 42, in newfunc
return func(_args, *_kwargs)
File "/usr/share/minecraft-overviewer/quadtree.py", line 515, in render_worldtile
tileimg.paste(chunkimg.convert("RGB"), (xpos, ypos), chunkimg)
File "/usr/lib/python2.6/dist-packages/PIL/Image.py", line 679, in convert
self.load()
File "/usr/lib/python2.6/dist-packages/PIL/ImageFile.py", line 215, in load
raise_ioerror(e)
File "/usr/lib/python2.6/dist-packages/PIL/ImageFile.py", line 52, in raise_ioerror
raise IOError(message + " when reading image file")
IOError: unrecognized data stream contents when reading image file
Traceback (most recent call last):
File "/usr/share/minecraft-overviewer/gmap.py", line 123, in
main()
File "/usr/share/minecraft-overviewer/gmap.py", line 82, in main
q.go(options.procs)
File "/usr/share/minecraft-overviewer/quadtree.py", line 242, in go
result.get()
File "/usr/lib/python2.6/multiprocessing/pool.py", line 422, in get
raise self._value
IOError: unrecognized data stream contents when reading image file

[PATCH] Print fewer chunk render progress messages

From e80020a5695c4b752eff4192486a60bdcc3b1d05 Mon Sep 17 00:00:00 2001
From: Alex Jurkiewicz <[email protected]>
Date: Sun, 12 Sep 2010 11:57:14 +1000
Subject: [PATCH] Print fewer chunk render progress messages

---
gmap.py |    4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/gmap.py b/gmap.py
index 1101e1c..a1c7df4 100755
--- a/gmap.py
+++ b/gmap.py
@@ -39,7 +39,9 @@ def main():
results = world.render_chunks_async(chunks, False, options.procs)
for i, (col, row, filename) in enumerate(chunks):
results[col, row].wait()
-        print "{0}/{1} chunks rendered".format(i, len(chunks))
+        if i > 0:
+            if 1000 % i == 0 or i % 1000 == 0:
+                print "{0}/{1} chunks rendered".format(i, len(chunks))

print "Writing out html file"
if not os.path.exists(destdir):
--
1.7.0.4

Waterfalls don't look right

Since water is only rendered as a single top texture it looks very odd when it's vertical, like with a waterfall or when a body of water is at the edges of a map.

Support changing texture packs

If one changes their texture pack and re-renders the tiles, the cache will prevent the tiles from being re-rendered. Even if the chunk cache is cleared, the hashes will be the same and the tiles will not change.

I should put in a function to erase the hash files from the dest directory, forcing all the tiles to be rerendered.

visual "updated" chunk indication

A minor feature request that might appeal to some:

I update the map daily at 2am, it would be nice to have some way of indicating updated chunks, perhaps through a lighter colour. Some kind of transform that gets removed the next time it processes.

Doing it by date would work, too - any tile newer than a day could be highlighted.

Tile Generation Parallelization isn't perfect

Some situations can leave a single process to finish a large branch of the recursive tree, while the other processes wait for it.

Under normal circumstances, the tile generation algorithm is recursive. A shared semaphore is used to determine if a recursive call can spawn a new process, or if it should be done "inline" (in the same process).

Each recursive call makes 4 calls to itself (to process each quadrant). The first 3 check the semaphore and may possibly spawn a subprocess to complete that task if a process is available. The 4th call is always done inline.

The problem is: what if recursive call 1 is really expensive, but calls 2, 3, and 4 are cheap? With 2 processes allowed, it will spawn a process for the first call, and do the other 3 itself. Since the other 3 are cheap, it will finish quickly. Then it will sit and wait while the first call does the expensive part all by itself.

I've described the issue, now to think of a solution!

Add support for terrain.png in CWD

From 2de06046fa19e10b4e682895c9f06cf44eacc24f Mon Sep 17 00:00:00 2001
From: Alex Jurkiewicz [email protected]
Date: Sun, 29 Aug 2010 14:59:16 +1000
Subject: [PATCH] Add support for opening terrain.png in CWD. Useful for servers running on headless boxes without the client unpacked.


textures.py | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/textures.py b/textures.py
index f2ad7cc..4224c96 100644
--- a/textures.py
+++ b/textures.py
@@ -9,6 +9,11 @@ import numpy
from PIL import Image, ImageEnhance

def _get_terrain_image():

  • if os.path.isfile('terrain.png'):
  •    textures = open("terrain.png","r")
    
  •    buffer = StringIO(textures.read())
    
  •    return Image.open(buffer)
    

    if "darwin" in sys.platform:
    # On Macs, terrain.png could lie at
    # "/Applications/minecraft/terrain.png" for custom terrain. Try this

    1.7.0.4

Celery?

Wouldn't it be bangin' to use celery and a real task queue to do the heavy lifting? It'd be dead simple to spin up new worker nodes on as many different machines as one has. I think this is the real way to go for people that want to run this on a server.

I don't think I want celery to be a requirement though. It requires an actual AMQP server such as RabbitMQ to be set up, and that makes this program just that much harder to use. Maybe I'll make it an option, or make a celery branch that uses celery tasks.

Thoughts?

minecraft.jar location in debian/linux

Hey, to start off, so glad you added the cachedir option. I've just about got this running but ran into a brick wall here and I don't know python too well.

Upon searching all the dirs you have listed it won't find my minecraft.jar file. Is there someway I can specify a static location. Even when putting it in the working folder or $HOME/.minecraft/bin/
I can't get it past this point.

Here's the output I get.
Traceback (most recent call last):
File "/usr/share/minecraft-overviewer/gmap.py", line 27, in
import world
File "/usr/share/minecraft-overviewer/world.py", line 23, in
import chunk
File "/usr/share/minecraft-overviewer/chunk.py", line 23, in
import textures
File "/usr/share/minecraft-overviewer/textures.py", line 105, in
terrain_images = _split_terrain(_get_terrain_image())
File "/usr/share/minecraft-overviewer/textures.py", line 88, in _get_terrain_image
return _load_image("terrain.png")
File "/usr/share/minecraft-overviewer/textures.py", line 83, in _load_image
fileobj = _find_file(filename)
File "/usr/share/minecraft-overviewer/textures.py", line 79, in _find_file
raise IOError("Could not find the file {0}. Is Minecraft installed? If so, I couldn't find the minecraft.jar file.".format(filename))
IOError: Could not find the file terrain.png. Is Minecraft installed? If so, I couldn't find the minecraft.jar file.

Thanks a million. I love what you're doing.

Setting -p = 1 crashes gmap.py

As follows:

$ python ~/Desktop/Minecraft-Overviewer/gmap.py -p 1 ~/Library/Application\ Support/minecraft/saves/World5/ ~/Sites/MCMap/
Scanning chunks
Rendering chunks
Rendering chunks synchronously since you requested 1 process
0/1168 chunks rendered
1/1168 chunks rendered

...(snip)...

1166/1168 chunks rendered
1167/1168 chunks rendered
Traceback (most recent call last):
File "/Users/munki/Desktop/Minecraft-Overviewer/gmap.py", line 76, in
main()
File "/Users/munki/Desktop/Minecraft-Overviewer/gmap.py", line 47, in main
results['pool'].join()
KeyError: 'pool'

Parallelize the tiling routine

When generating a set of google map tiles, the routine is currently serial, and can take quite a while. I'd like to use multiprocessing to render the tiles in parallel, this will probably speed things up quite a bit.

(For anyone wondering, the chunk rendering is parallel, but the tile rendering is not)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.