Merge branch 'master' of git://github.com/overviewer/Minecraft-Overviewer into JSObserver
This commit is contained in:
5
.mailmap
Normal file
5
.mailmap
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Andrew Brown <brownan@gmail.com> <andrew@fry.(none)>
|
||||||
|
Alex Headley <aheadley@waysaboutstuff.com> <aheadley@nexcess.net>
|
||||||
|
Alex Headley <aheadley@waysaboutstuff.com> aheadley
|
||||||
|
Michael Fallows <michael@fallo.ws> redorkulated
|
||||||
|
Maciej Malecki <maciej.malecki@hotmail.com> Maciej Małecki
|
||||||
@@ -39,28 +39,45 @@ Short-term Contributions
|
|||||||
These contributors have made specific changes for a particular bug fix or
|
These contributors have made specific changes for a particular bug fix or
|
||||||
feature.
|
feature.
|
||||||
|
|
||||||
|
* Albireo <kappa7194@hotmail.it>
|
||||||
* arrai <array.of.intellect@gmail.com>
|
* arrai <array.of.intellect@gmail.com>
|
||||||
|
* asmodai <asmodai@in-nomine.org>
|
||||||
|
* Mark Barnes <mark.e.barnes@gmail.com>
|
||||||
* Kyle Brantley <kyle@averageurl.com>
|
* Kyle Brantley <kyle@averageurl.com>
|
||||||
* but2002 <barryt_9@hotmail.com>
|
* but2002 <barryt_9@hotmail.com>
|
||||||
* Eric Carr <eric@carr.no>
|
* Eric Carr <eric@carr.no>
|
||||||
* cbarber <CraigBarber@taryx.com>
|
* cbarber <CraigBarber@taryx.com>
|
||||||
|
* Carter Charbonneau <zcarterc@gmail.com>
|
||||||
* Alex Cline <cline@vivisimo.com>
|
* Alex Cline <cline@vivisimo.com>
|
||||||
* Andrew Clunis <andrew@orospakr.ca>
|
* Andrew Clunis <andrew@orospakr.ca>
|
||||||
* CounterPillow <spam@tes-cheese.ch>
|
* CounterPillow <spam@tes-cheese.ch>
|
||||||
|
* Johannes Dewender <github@JonnyJD.net>
|
||||||
* Michael Fallows <michael@fallo.ws>
|
* Michael Fallows <michael@fallo.ws>
|
||||||
|
* Ryan Finnie <ryan@feh.colobox.com>
|
||||||
* Stephen Fluin <stephen@mistuph.com>
|
* Stephen Fluin <stephen@mistuph.com>
|
||||||
|
* Pierre Guinoiseau <pierre@guinoiseau.eu>
|
||||||
|
* Lucas Hereld <duckman@piratehook.com>
|
||||||
* Benjamin Herr <ben@0x539.de>
|
* Benjamin Herr <ben@0x539.de>
|
||||||
* Ryan Hitchman <hitchmanr@gmail.com>
|
* Ryan Hitchman <hitchmanr@gmail.com>
|
||||||
* Jenny <jennytoo@gmail.com>
|
* Jenny <jennytoo@gmail.com>
|
||||||
* Michael Jensen <emjay1988@gmail.com>
|
* Michael Jensen <emjay1988@gmail.com>
|
||||||
|
* Sean Kilgore <krystalogik@gmail.com>
|
||||||
* Johan Kiviniemi <devel@johan.kiviniemi.name>
|
* Johan Kiviniemi <devel@johan.kiviniemi.name>
|
||||||
|
* Philip Kovac <pkovac@cs.uml.edu>
|
||||||
* Thomas Lake <tswsl1989@sucs.org>
|
* Thomas Lake <tswsl1989@sucs.org>
|
||||||
* Maciej Malecki <maciej.malecki@hotmail.com>
|
* Maciej Malecki <maciej.malecki@hotmail.com>
|
||||||
* Ryan McCue <ryanmccue@cubegames.net>
|
* Ryan McCue <ryanmccue@cubegames.net>
|
||||||
|
* Zach McCullough <nosrepa@gmail.com>
|
||||||
|
* Mike <mike@snowcrash.ca>
|
||||||
* Morlok8k <otis.spankmeyer@gmail.com>
|
* Morlok8k <otis.spankmeyer@gmail.com>
|
||||||
|
* Richard Pastrick <rpastric@contre.us>
|
||||||
* Ryan Rector <rmrector@gmail.com>
|
* Ryan Rector <rmrector@gmail.com>
|
||||||
* Jason Scheirer <jason.scheirer@gmail.com>
|
* Jason Scheirer <jason.scheirer@gmail.com>
|
||||||
* Gregory Short <gshort2@gmail.com>
|
* Gregory Short <gshort2@gmail.com>
|
||||||
* Sam Steele <sam@sigbox.c99.org>
|
* Sam Steele <sam@sigbox.c99.org>
|
||||||
|
* stoneLeaf <owi.stoneleaf@gmail.com>
|
||||||
* timwolla <timwolla@mail.develfusion.com>
|
* timwolla <timwolla@mail.develfusion.com>
|
||||||
|
* TJ09 <TJ09@localhost>
|
||||||
|
* untergrundbiber <untergrundbiber@github>
|
||||||
|
* Philippe Villiers <kissifrot@gmail.com>
|
||||||
* Jeffrey Warren <warren@mit.edu>
|
* Jeffrey Warren <warren@mit.edu>
|
||||||
|
|||||||
116
contrib/contributors.py
Executable file
116
contrib/contributors.py
Executable file
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/python2
|
||||||
|
"""Update the contributor list
|
||||||
|
|
||||||
|
Alias handling is done by git with .mailmap
|
||||||
|
New contributors are merged in the short-term list.
|
||||||
|
Moving them to a "higher" list should be a manual process.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import fileinput
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
def format_contributor(contributor):
|
||||||
|
return " * {0} {1}".format(
|
||||||
|
" ".join(contributor["name"]),
|
||||||
|
contributor["email"])
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# generate list of contributors
|
||||||
|
contributors = []
|
||||||
|
p_git = Popen(["git", "shortlog", "-se"], stdout=PIPE)
|
||||||
|
for line in p_git.stdout:
|
||||||
|
contributors.append({
|
||||||
|
'count': int(line.split("\t")[0].strip()),
|
||||||
|
'name': line.split("\t")[1].split()[0:-1],
|
||||||
|
'email': line.split("\t")[1].split()[-1]
|
||||||
|
})
|
||||||
|
|
||||||
|
# cache listed contributors
|
||||||
|
old_contributors = []
|
||||||
|
with open("CONTRIBUTORS.rst", "r") as contrib_file:
|
||||||
|
for line in contrib_file:
|
||||||
|
if "@" in line:
|
||||||
|
old_contributors.append({
|
||||||
|
'name': line.split()[1:-1],
|
||||||
|
'email': line.split()[-1]
|
||||||
|
})
|
||||||
|
|
||||||
|
old = map(lambda x: (x['name'], x['email']), old_contributors)
|
||||||
|
old_emails = map(lambda x: x['email'], old_contributors)
|
||||||
|
old_names = map(lambda x: x['name'], old_contributors)
|
||||||
|
|
||||||
|
# check which contributors are new
|
||||||
|
new_contributors = []
|
||||||
|
update_mailmap = False
|
||||||
|
for contributor in contributors:
|
||||||
|
if (contributor['name'], contributor['email']) in old:
|
||||||
|
# this exact combination already in the list
|
||||||
|
pass
|
||||||
|
elif (contributor['email'] not in old_emails
|
||||||
|
and contributor['name'] not in old_names):
|
||||||
|
# name AND email are not in the list
|
||||||
|
new_contributors.append(contributor)
|
||||||
|
elif contributor['email'] in old_emails:
|
||||||
|
# email is listed, but with another name
|
||||||
|
old_name = filter(lambda x: x['email'] == contributor['email'],
|
||||||
|
old_contributors)[0]['name']
|
||||||
|
print "new alias %s for %s %s ?" % (
|
||||||
|
" ".join(contributor['name']),
|
||||||
|
" ".join(old_name),
|
||||||
|
contributor['email'])
|
||||||
|
update_mailmap = True
|
||||||
|
elif contributor['name'] in old_names:
|
||||||
|
# probably a new email for a previous contributor
|
||||||
|
other_mail = filter(lambda x: x['name'] == contributor['name'],
|
||||||
|
old_contributors)[0]['email']
|
||||||
|
print "new email %s for %s %s ?" % (
|
||||||
|
contributor['email'],
|
||||||
|
" ".join(contributor['name']),
|
||||||
|
other_mail)
|
||||||
|
update_mailmap = True
|
||||||
|
if update_mailmap:
|
||||||
|
print "Please update .mailmap"
|
||||||
|
|
||||||
|
# sort on the last word of the name
|
||||||
|
new_contributors = sorted(new_contributors,
|
||||||
|
key=lambda x: x['name'][-1].lower())
|
||||||
|
|
||||||
|
# show new contributors to be merged to the list
|
||||||
|
if new_contributors:
|
||||||
|
print "inserting:"
|
||||||
|
for contributor in new_contributors:
|
||||||
|
print format_contributor(contributor)
|
||||||
|
|
||||||
|
# merge with alphabetical (by last part of name) contributor list
|
||||||
|
i = 0
|
||||||
|
short_term_found = False
|
||||||
|
for line in fileinput.input("CONTRIBUTORS.rst", inplace=1):
|
||||||
|
if not short_term_found:
|
||||||
|
print line,
|
||||||
|
if "Short-term" in line:
|
||||||
|
short_term_found = True
|
||||||
|
else:
|
||||||
|
if i >= len(new_contributors) or "@" not in line:
|
||||||
|
print line,
|
||||||
|
else:
|
||||||
|
listed_name = line.split()[-2].lower()
|
||||||
|
contributor = new_contributors[i]
|
||||||
|
# insert all new contributors that fit here
|
||||||
|
while listed_name > contributor["name"][-1].lower():
|
||||||
|
print format_contributor(contributor)
|
||||||
|
i += 1
|
||||||
|
if i < len(new_contributors):
|
||||||
|
contributor = new_contributors[i]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
print line,
|
||||||
|
# append remaining contributors
|
||||||
|
with open("CONTRIBUTORS.rst", "a") as contrib_file:
|
||||||
|
while i < len(new_contributors):
|
||||||
|
contrib_file.write(format_contributor(new_contributors[i]) + "\n")
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -70,7 +70,7 @@ A more complicated example
|
|||||||
|
|
||||||
renders["survivalnight"] = {
|
renders["survivalnight"] = {
|
||||||
"world": "survival",
|
"world": "survival",
|
||||||
"title": "Survival Daytime",
|
"title": "Survival Nighttime",
|
||||||
"rendermode": smooth_night,
|
"rendermode": smooth_night,
|
||||||
"dimension": "overworld",
|
"dimension": "overworld",
|
||||||
}
|
}
|
||||||
@@ -115,6 +115,57 @@ individual renders to apply to just those renders.
|
|||||||
See the ``sample_config.py`` file included in the repository for another
|
See the ``sample_config.py`` file included in the repository for another
|
||||||
example.
|
example.
|
||||||
|
|
||||||
|
A dynamic config file
|
||||||
|
=====================
|
||||||
|
|
||||||
|
It might be handy to dynamically retrieve parameters. For instance, if you
|
||||||
|
periodically render your last map backup which is located in a timestamped
|
||||||
|
directory, it is not convenient to edit the config file each time to fit the
|
||||||
|
new directory name.
|
||||||
|
|
||||||
|
Using environment variables, you can easily retrieve a parameter which has
|
||||||
|
been set by, for instance, your map backup script. In this example, Overviewer
|
||||||
|
is called from a *bash* script, but it can be done from other shell scripts
|
||||||
|
and languages.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
## Add these lines to your bash script
|
||||||
|
|
||||||
|
# Setting up an environment variable that child processes will inherit.
|
||||||
|
# In this example, the map's path is not static and depends on the
|
||||||
|
# previously set $timestamp var.
|
||||||
|
MYWORLD_DIR=/path/to/map/backup/$timestamp/YourWorld
|
||||||
|
export MYWORLD_DIR
|
||||||
|
|
||||||
|
# Running the Overviewer
|
||||||
|
overviewer.py --config=/path/to/yourConfig.py
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The environment variable will only be local to the process and its child
|
||||||
|
processes. The Overviewer, when run by the script, will be able to access
|
||||||
|
the variable since it becomes a child process.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
## A config file example
|
||||||
|
|
||||||
|
# Importing the os python module
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Retrieving the environment variable set up by the bash script
|
||||||
|
worlds["My world"] = os.environ['MYWORLD_DIR']
|
||||||
|
|
||||||
|
renders["normalrender"] = {
|
||||||
|
"world": "My world",
|
||||||
|
"title": "Normal Render of My World",
|
||||||
|
}
|
||||||
|
|
||||||
|
outputdir = "/home/username/mcmap"
|
||||||
|
|
||||||
Config File Specifications
|
Config File Specifications
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
@@ -389,6 +440,20 @@ values. The valid configuration keys are listed below.
|
|||||||
|
|
||||||
**Default:** ``95``
|
**Default:** ``95``
|
||||||
|
|
||||||
|
``optimizeimg``
|
||||||
|
This option specifies which additional tools overviewer should use to
|
||||||
|
optimize the filesize of png tiles.
|
||||||
|
The tools used must be placed somewhere, where overviewer can find them, for
|
||||||
|
example the "PATH" environment variable or a directory like /usr/bin.
|
||||||
|
This should be an integer between 0 and 3.
|
||||||
|
* ``1 - Use pngcrush``
|
||||||
|
* ``2 - Use advdef``
|
||||||
|
* ``3 - Use pngcrush and advdef (Not recommended)``
|
||||||
|
Using this option may significantly increase render time, but will make
|
||||||
|
the resulting tiles smaller, with lossless image quality.
|
||||||
|
|
||||||
|
**Default:** ``0``
|
||||||
|
|
||||||
``bgcolor``
|
``bgcolor``
|
||||||
This is the background color to be displayed behind the map. Its value
|
This is the background color to be displayed behind the map. Its value
|
||||||
should be either a string in the standard HTML color syntax or a 4-tuple in
|
should be either a string in the standard HTML color syntax or a 4-tuple in
|
||||||
@@ -396,11 +461,12 @@ values. The valid configuration keys are listed below.
|
|||||||
|
|
||||||
**Default:** ``#1a1a1a``
|
**Default:** ``#1a1a1a``
|
||||||
|
|
||||||
.. _option_texture_pack:
|
.. _option_texturepath:
|
||||||
|
|
||||||
``texturepath``
|
``texturepath``
|
||||||
This is a where a specific texture pack can be found to be used during this render.
|
This is a where a specific texture pack can be found to be used during this render.
|
||||||
It can be either a folder or a directory. Its value should be a string.
|
It can be either a folder or a zip file containing the texture pack.
|
||||||
|
Its value should be a string.
|
||||||
|
|
||||||
.. _crop:
|
.. _crop:
|
||||||
|
|
||||||
@@ -509,6 +575,18 @@ values. The valid configuration keys are listed below.
|
|||||||
|
|
||||||
**Default:** ``[]`` (an empty list)
|
**Default:** ``[]`` (an empty list)
|
||||||
|
|
||||||
|
.. _option_overlay:
|
||||||
|
|
||||||
|
``overlay``
|
||||||
|
This specifies which renders that this render will be displayed on top of.
|
||||||
|
It should be a list of renders.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
At this time, this feature is not fully implemented.
|
||||||
|
|
||||||
|
**Default:** ``[]`` (an empty list)
|
||||||
|
|
||||||
``showspawn``
|
``showspawn``
|
||||||
This is a boolean, and defaults to ``True``. If set to ``False``, then the spawn
|
This is a boolean, and defaults to ``True``. If set to ``False``, then the spawn
|
||||||
icon will not be displayed on the rendered map.
|
icon will not be displayed on the rendered map.
|
||||||
@@ -593,6 +671,15 @@ Cave
|
|||||||
only_lit
|
only_lit
|
||||||
Only render lit caves. Default: False
|
Only render lit caves. Default: False
|
||||||
|
|
||||||
|
Hide
|
||||||
|
Hide blocks based on blockid. Blocks hidden in this way will be
|
||||||
|
treated exactly the same as air.
|
||||||
|
|
||||||
|
**Options**
|
||||||
|
|
||||||
|
minerals
|
||||||
|
A list of block ids, or (blockid, data) tuples to hide.
|
||||||
|
|
||||||
DepthTinting
|
DepthTinting
|
||||||
Tint blocks a color according to their depth (height) from bedrock. Useful
|
Tint blocks a color according to their depth (height) from bedrock. Useful
|
||||||
mainly for cave renders.
|
mainly for cave renders.
|
||||||
@@ -672,7 +759,7 @@ are referencing the previously defined list, not one of the built-in
|
|||||||
rendermodes.
|
rendermodes.
|
||||||
|
|
||||||
Built-in Rendermodes
|
Built-in Rendermodes
|
||||||
--------------------
|
====================
|
||||||
The built-in rendermodes are nothing but pre-defined lists of rendermode
|
The built-in rendermodes are nothing but pre-defined lists of rendermode
|
||||||
primitives for your convenience. Here are their definitions::
|
primitives for your convenience. Here are their definitions::
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ So let's get started!
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
This page is still under construction
|
This page is continually under construction
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ pre-rendered sprite (a small image). The basic idea is to iterate over the
|
|||||||
blocks of the world and draw these sprites to the appropriate location on the
|
blocks of the world and draw these sprites to the appropriate location on the
|
||||||
map.
|
map.
|
||||||
|
|
||||||
These are the high-level tasks The Overviewer must preform in rendering a map:
|
These are the high-level tasks The Overviewer must perform in rendering a map:
|
||||||
|
|
||||||
1. Render each block sprite from the textures
|
1. Render each block sprite from the textures
|
||||||
2. Scan the chunks of the world and determine which tiles need rendering
|
2. Scan the chunks of the world and determine which tiles need rendering
|
||||||
@@ -143,7 +143,7 @@ transformations can be chained together simply by multiplying the transformation
|
|||||||
matrices together, only one transformation is actually done.
|
matrices together, only one transformation is actually done.
|
||||||
|
|
||||||
This can be seen in the function
|
This can be seen in the function
|
||||||
:func:`overviewer_core.textures.transform_image`. It preforms three steps:
|
:func:`overviewer_core.textures.transform_image`. It performs three steps:
|
||||||
|
|
||||||
1. The texture is re-sized to 17 by 17 pixels. This is done because the diagonal
|
1. The texture is re-sized to 17 by 17 pixels. This is done because the diagonal
|
||||||
of a square with sides 17 is approximately 24, which is the target size for
|
of a square with sides 17 is approximately 24, which is the target size for
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ If you want or need to provide your own textures, you have several options:
|
|||||||
overviewer.exe.
|
overviewer.exe.
|
||||||
|
|
||||||
* Specify any terrain.png or texture pack you want with the
|
* Specify any terrain.png or texture pack you want with the
|
||||||
:ref:`texture_pack<option_texture_pack>` option.
|
:ref:`texturepath<option_texturepath>` option.
|
||||||
|
|
||||||
If you copy your world before you render it
|
If you copy your world before you render it
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|||||||
@@ -20,51 +20,97 @@ Filter Functions
|
|||||||
----------------
|
----------------
|
||||||
|
|
||||||
A filter function is a python function that is used to figure out if a given POI
|
A filter function is a python function that is used to figure out if a given POI
|
||||||
should be part of a markerSet of not. The function should accept one argument
|
should be part of a markerSet of not, and to control how it is displayed.
|
||||||
(a dictionary, also know as an associative array), and return a boolean::
|
The function should accept one argument (a dictionary, also know as an associative
|
||||||
|
array), and return a string representing the text to be displayed. For example::
|
||||||
|
|
||||||
def signFilter(poi):
|
def signFilter(poi):
|
||||||
"All signs"
|
if poi['id'] == 'Sign':
|
||||||
return poi['id'] == 'Sign'
|
return "\n".join([poi['Text1'], poi['Text2'], poi['Text3'], poi['Text4']])
|
||||||
|
|
||||||
|
If a POI doesn't match, the filter can return None (which is the default if a python
|
||||||
|
functions runs off the end without an explicit 'return').
|
||||||
|
|
||||||
The single argument will either a TileEntity, or an Entity taken directly from
|
The single argument will either a TileEntity, or an Entity taken directly from
|
||||||
the chunk file. In this example, this function returns true only if the type
|
the chunk file. It could also be a special entity representing a player's location
|
||||||
of entity is a sign. For more information of TileEntities and Entities, see
|
or a player's spawn. See below for more details.
|
||||||
|
|
||||||
|
In this example, this function returns all 4 lines from the sign
|
||||||
|
if the entity is a sign.
|
||||||
|
For more information of TileEntities and Entities, see
|
||||||
the `Chunk Format <http://www.minecraftwiki.net/wiki/Chunk_format>`_ page on
|
the `Chunk Format <http://www.minecraftwiki.net/wiki/Chunk_format>`_ page on
|
||||||
the Minecraft Wiki.
|
the Minecraft Wiki.
|
||||||
|
|
||||||
.. note::
|
A more complicated filter function can construct a more customized display text::
|
||||||
The doc string ("All signs" in this example) is important. It is the label
|
|
||||||
that appears in your rendered map
|
|
||||||
|
|
||||||
A more advanced filter may also look at other entity fields, such as the sign text::
|
def chestFilter(poi):
|
||||||
|
if poi['id'] == "Chest":
|
||||||
|
return "Chest with %d items" % len(poi['Items'])
|
||||||
|
|
||||||
def goldFilter(poi):
|
|
||||||
"Gold"
|
|
||||||
return poi['id'] == 'Sign' and (\
|
|
||||||
'gold' in poi['Text1'] or
|
|
||||||
'gold' in poi['Text2'])
|
|
||||||
|
|
||||||
This looks for the word 'gold' in either the first or second line of the signtext.
|
|
||||||
|
|
||||||
Since writing these filters can be a little tedious, a set of predefined filters
|
Since writing these filters can be a little tedious, a set of predefined filters
|
||||||
functions are provided. See the :ref:`predefined_filter_functions` section for
|
functions are provided. See the :ref:`predefined_filter_functions` section for
|
||||||
details.
|
details.
|
||||||
|
|
||||||
|
|
||||||
|
Special POIs
|
||||||
|
------------
|
||||||
|
|
||||||
|
There are currently two special types of POIs. They each have a special id:
|
||||||
|
|
||||||
|
PlayerSpawn
|
||||||
|
Used to indicate the spawn location of a player. The player's name is set
|
||||||
|
in the ``EntityId`` key, and the location is in the x,y,z keys
|
||||||
|
|
||||||
|
Player
|
||||||
|
Used to indicate the last known location of a player. The player's name is set
|
||||||
|
in the ``EntityId`` key, and the location is in the x,y,z keys.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
The player location is taken from level.dat (in the case of a single-player world)
|
||||||
|
or the player.dat files (in the case of a multi-player server). The locations are
|
||||||
|
only written to these files when the world is saved, so this won't give you real-time
|
||||||
|
player location information.
|
||||||
|
|
||||||
|
Here's an example that displays icons for each player::
|
||||||
|
|
||||||
|
def playerIcons(poi):
|
||||||
|
if poi['id'] == 'Player':
|
||||||
|
poi['icon'] = "http://overviewer.org/avatar/%s" % poi['EntityId']
|
||||||
|
return "Last known location for %s" % poi['EntityId']
|
||||||
|
|
||||||
|
Note how each POI can get a different icon by setting ``poi['icon']``
|
||||||
|
|
||||||
Render Dictionary Key
|
Render Dictionary Key
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
Each render can specify a list of zero or more filter functions. Each of these
|
Each render can specify a list of zero or more filter functions. Each of these
|
||||||
filter functions become a selectable item in the 'Signs' drop-down menu in the
|
filter functions become a selectable item in the 'Signs' drop-down menu in the
|
||||||
rendered map. For example::
|
rendered map. Previously, this used to be a list of functions. Now it is a list
|
||||||
|
of dictionaries. For example::
|
||||||
|
|
||||||
renders['myrender'] = {
|
renders['myrender'] = {
|
||||||
'world': 'myworld',
|
'world': 'myworld',
|
||||||
'title': "Example",
|
'title': "Example",
|
||||||
'markers': [allFilter, anotherFilter],
|
'markers': [dict(name="All signs", filterFunction=signFilter),
|
||||||
|
dict(name="Chests", filterFunction=chestFilter, icon="chest.png")]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
The following keys are accepted in the marker dictionary:
|
||||||
|
|
||||||
|
``name``
|
||||||
|
This is the text that is displayed in the 'Signs' dropdown.
|
||||||
|
|
||||||
|
``filterFunction``
|
||||||
|
This is the filter function. It must accept at least 1 argument (the POI to filter),
|
||||||
|
and it must return either None or a string.
|
||||||
|
|
||||||
|
``icon``
|
||||||
|
Optional. Specifies the icon to use for POIs in this group. If omitted, it defaults
|
||||||
|
to a signpost icon. Note that each POI can have different icon by setting the key 'icon'
|
||||||
|
on the POI itself (this can be done by modifying the POI in the filter function. See the
|
||||||
|
example above)
|
||||||
|
|
||||||
|
|
||||||
Generating the POI Markers
|
Generating the POI Markers
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ def main():
|
|||||||
help="Print less output. You can specify this option multiple times.")
|
help="Print less output. You can specify this option multiple times.")
|
||||||
parser.add_option("-v", "--verbose", dest="verbose", action="count", default=0,
|
parser.add_option("-v", "--verbose", dest="verbose", action="count", default=0,
|
||||||
help="Print more output. You can specify this option multiple times.")
|
help="Print more output. You can specify this option multiple times.")
|
||||||
|
parser.add_option("--simple-output", dest="simple", action="store_true", default=False,
|
||||||
|
help="Use a simple output format, with no colors or progress bars")
|
||||||
|
|
||||||
# create a group for "plugin exes" (the concept of a plugin exe is only loosly defined at this point)
|
# create a group for "plugin exes" (the concept of a plugin exe is only loosly defined at this point)
|
||||||
exegroup = OptionGroup(parser, "Other Scripts",
|
exegroup = OptionGroup(parser, "Other Scripts",
|
||||||
@@ -104,9 +106,9 @@ def main():
|
|||||||
if options.genpoi:
|
if options.genpoi:
|
||||||
# remove the "--genpoi" option from sys.argv before running genPI
|
# remove the "--genpoi" option from sys.argv before running genPI
|
||||||
sys.argv.remove("--genpoi")
|
sys.argv.remove("--genpoi")
|
||||||
sys.path.append(".")
|
#sys.path.append(".")
|
||||||
g = __import__("genPOI", {}, {})
|
g = __import__("overviewer_core.aux_files", {}, {}, ["genPOI"])
|
||||||
g.main()
|
g.genPOI.main()
|
||||||
return 0
|
return 0
|
||||||
if options.help:
|
if options.help:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
@@ -114,7 +116,8 @@ def main():
|
|||||||
|
|
||||||
# re-configure the logger now that we've processed the command line options
|
# re-configure the logger now that we've processed the command line options
|
||||||
logger.configure(logging.INFO + 10*options.quiet - 10*options.verbose,
|
logger.configure(logging.INFO + 10*options.quiet - 10*options.verbose,
|
||||||
options.verbose > 0)
|
verbose=options.verbose > 0,
|
||||||
|
simple=options.simple)
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# This section of main() runs in response to any one-time options we have,
|
# This section of main() runs in response to any one-time options we have,
|
||||||
@@ -233,7 +236,6 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Parse the config file
|
# Parse the config file
|
||||||
mw_parser = configParser.MultiWorldParser()
|
|
||||||
mw_parser.parse(options.config)
|
mw_parser.parse(options.config)
|
||||||
|
|
||||||
# Add in the command options here, perhaps overriding values specified in
|
# Add in the command options here, perhaps overriding values specified in
|
||||||
@@ -244,8 +246,12 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
|||||||
# Now parse and return the validated config
|
# Now parse and return the validated config
|
||||||
try:
|
try:
|
||||||
config = mw_parser.get_validated_config()
|
config = mw_parser.get_validated_config()
|
||||||
except Exception:
|
except Exception as ex:
|
||||||
|
if options.verbose:
|
||||||
logging.exception("An error was encountered with your configuration. See the info below.")
|
logging.exception("An error was encountered with your configuration. See the info below.")
|
||||||
|
else: # no need to print scary traceback! just
|
||||||
|
logging.error("An error was encountered with your configuration.")
|
||||||
|
logging.error(str(ex))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
@@ -302,6 +308,20 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
|||||||
if render.get('forcerender', False):
|
if render.get('forcerender', False):
|
||||||
render['renderchecks'] = 2
|
render['renderchecks'] = 2
|
||||||
|
|
||||||
|
# check if overlays are set, if so, make sure that those renders exist
|
||||||
|
if render.get('overlay', []) != []:
|
||||||
|
for x in render.get('overlay'):
|
||||||
|
if x != rname:
|
||||||
|
try:
|
||||||
|
renderLink = config['renders'][x]
|
||||||
|
except KeyError:
|
||||||
|
logging.error("Render %s's overlay is '%s', but I could not find a corresponding entry in the renders dictionary.",
|
||||||
|
rname, x)
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
logging.error("Render %s's overlay contains itself.", rname)
|
||||||
|
return 1
|
||||||
|
|
||||||
destdir = config['outputdir']
|
destdir = config['outputdir']
|
||||||
if not destdir:
|
if not destdir:
|
||||||
logging.error("You must specify the output directory in your config file.")
|
logging.error("You must specify the output directory in your config file.")
|
||||||
@@ -401,7 +421,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
|||||||
|
|
||||||
# only pass to the TileSet the options it really cares about
|
# only pass to the TileSet the options it really cares about
|
||||||
render['name'] = render_name # perhaps a hack. This is stored here for the asset manager
|
render['name'] = render_name # perhaps a hack. This is stored here for the asset manager
|
||||||
tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist","showspawn"])
|
tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist","showspawn", "overlay"])
|
||||||
tileSetOpts.update({"spawn": w.find_true_spawn()}) # TODO find a better way to do this
|
tileSetOpts.update({"spawn": w.find_true_spawn()}) # TODO find a better way to do this
|
||||||
tset = tileset.TileSet(rset, assetMrg, tex, tileSetOpts, tileset_dir)
|
tset = tileset.TileSet(rset, assetMrg, tex, tileSetOpts, tileset_dir)
|
||||||
tilesets.append(tset)
|
tilesets.append(tset)
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ directory.
|
|||||||
dump['CONST']['image'] = {
|
dump['CONST']['image'] = {
|
||||||
'defaultMarker': 'signpost.png',
|
'defaultMarker': 'signpost.png',
|
||||||
'signMarker': 'signpost_icon.png',
|
'signMarker': 'signpost_icon.png',
|
||||||
|
'bedMarker': 'bed.png',
|
||||||
'compass': 'compass_upper-left.png',
|
'compass': 'compass_upper-left.png',
|
||||||
'spawnMarker': 'http://google-maps-icons.googlecode.com/files/home.png',
|
'spawnMarker': 'http://google-maps-icons.googlecode.com/files/home.png',
|
||||||
'queryMarker': 'http://google-maps-icons.googlecode.com/files/regroup.png'
|
'queryMarker': 'http://google-maps-icons.googlecode.com/files/regroup.png'
|
||||||
|
|||||||
0
overviewer_core/aux_files/__init__.py
Normal file
0
overviewer_core/aux_files/__init__.py
Normal file
@@ -17,6 +17,7 @@ markers.js holds a list of which markerSets are attached to each tileSet
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
|
import sys
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
from overviewer_core import logger
|
from overviewer_core import logger
|
||||||
@@ -26,6 +27,7 @@ from overviewer_core import configParser, world
|
|||||||
|
|
||||||
def handleSigns(rset, outputdir, render, rname):
|
def handleSigns(rset, outputdir, render, rname):
|
||||||
|
|
||||||
|
# if we're already handled the POIs for this region regionset, do nothing
|
||||||
if hasattr(rset, "_pois"):
|
if hasattr(rset, "_pois"):
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -39,10 +41,64 @@ def handleSigns(rset, outputdir, render, rname):
|
|||||||
rset._pois['TileEntities'] += data['TileEntities']
|
rset._pois['TileEntities'] += data['TileEntities']
|
||||||
rset._pois['Entities'] += data['Entities']
|
rset._pois['Entities'] += data['Entities']
|
||||||
|
|
||||||
|
logging.info("Done.")
|
||||||
|
|
||||||
|
def handlePlayers(rset, render, worldpath):
|
||||||
|
if not hasattr(rset, "_pois"):
|
||||||
|
rset._pois = dict(TileEntities=[], Entities=[])
|
||||||
|
|
||||||
|
# only handle this region set once
|
||||||
|
if 'Players' in rset._pois:
|
||||||
|
return
|
||||||
|
dimension = {'overworld': 0,
|
||||||
|
'nether': -1,
|
||||||
|
'end': 1,
|
||||||
|
'default': 0}[render['dimension']]
|
||||||
|
playerdir = os.path.join(worldpath, "players")
|
||||||
|
if os.path.isdir(playerdir):
|
||||||
|
playerfiles = os.listdir(playerdir)
|
||||||
|
isSinglePlayer = False
|
||||||
|
else:
|
||||||
|
playerfiles = [os.path.join(worldpath, "level.dat")]
|
||||||
|
isSinglePlayer = True
|
||||||
|
|
||||||
|
rset._pois['Players'] = []
|
||||||
|
for playerfile in playerfiles:
|
||||||
|
try:
|
||||||
|
data = nbt.load(os.path.join(playerdir, playerfile))[1]
|
||||||
|
if isSinglePlayer:
|
||||||
|
data = data['Data']['Player']
|
||||||
|
except IOError:
|
||||||
|
logging.warning("Skipping bad player dat file %r", playerfile)
|
||||||
|
continue
|
||||||
|
playername = playerfile.split(".")[0]
|
||||||
|
if isSinglePlayer:
|
||||||
|
playername = 'Player'
|
||||||
|
if data['Dimension'] == dimension:
|
||||||
|
# Position at last logout
|
||||||
|
data['id'] = "Player"
|
||||||
|
data['EntityId'] = playername
|
||||||
|
data['x'] = int(data['Pos'][0])
|
||||||
|
data['y'] = int(data['Pos'][1])
|
||||||
|
data['z'] = int(data['Pos'][2])
|
||||||
|
rset._pois['Players'].append(data)
|
||||||
|
if "SpawnX" in data and dimension == 0:
|
||||||
|
# Spawn position (bed or main spawn)
|
||||||
|
spawn = {"id": "PlayerSpawn",
|
||||||
|
"EntityId": playername,
|
||||||
|
"x": data['SpawnX'],
|
||||||
|
"y": data['SpawnY'],
|
||||||
|
"z": data['SpawnZ']}
|
||||||
|
rset._pois['Players'].append(spawn)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
|
if os.path.basename(sys.argv[0]) == """genPOI.py""":
|
||||||
|
helptext = """genPOI.py
|
||||||
|
%prog --config=<config file> [--quiet]"""
|
||||||
|
else:
|
||||||
helptext = """genPOI
|
helptext = """genPOI
|
||||||
%prog --config=<config file>"""
|
%prog --genpoi --config=<config file> [--quiet]"""
|
||||||
|
|
||||||
logger.configure()
|
logger.configure()
|
||||||
|
|
||||||
@@ -97,26 +153,43 @@ def main():
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
for f in render['markers']:
|
for f in render['markers']:
|
||||||
markersets.add((f, rset))
|
d = dict(icon="signpost_icon.png")
|
||||||
name = f.__name__ + hex(hash(f))[-4:] + "_" + hex(hash(rset))[-4:]
|
d.update(f)
|
||||||
|
markersets.add(((d['name'], d['filterFunction']), rset))
|
||||||
|
name = f['name'].replace(" ","_") + hex(hash(f['filterFunction']))[-4:] + "_" + hex(hash(rset))[-4:]
|
||||||
try:
|
try:
|
||||||
l = markers[rname]
|
l = markers[rname]
|
||||||
l.append(dict(groupName=name, displayName = f.__doc__))
|
l.append(dict(groupName=name, displayName = f['name'], icon=d['icon']))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
markers[rname] = [dict(groupName=name, displayName=f.__doc__),]
|
markers[rname] = [dict(groupName=name, displayName=f['name'], icon=d['icon']),]
|
||||||
|
|
||||||
handleSigns(rset, os.path.join(destdir, rname), render, rname)
|
handleSigns(rset, os.path.join(destdir, rname), render, rname)
|
||||||
|
handlePlayers(rset, render, worldpath)
|
||||||
|
|
||||||
logging.info("Done scanning regions")
|
logging.info("Done scanning regions")
|
||||||
logging.info("Writing out javascript files")
|
logging.info("Writing out javascript files")
|
||||||
markerSetDict = dict()
|
markerSetDict = dict()
|
||||||
for (flter, rset) in markersets:
|
for (flter, rset) in markersets:
|
||||||
# generate a unique name for this markerset. it will not be user visible
|
# generate a unique name for this markerset. it will not be user visible
|
||||||
name = flter.__name__ + hex(hash(flter))[-4:] + "_" + hex(hash(rset))[-4:]
|
filter_name = flter[0]
|
||||||
markerSetDict[name] = dict(created=False, raw=[])
|
filter_function = flter[1]
|
||||||
|
|
||||||
|
name = filter_name.replace(" ","_") + hex(hash(filter_function))[-4:] + "_" + hex(hash(rset))[-4:]
|
||||||
|
markerSetDict[name] = dict(created=False, raw=[], name=filter_name)
|
||||||
for poi in rset._pois['TileEntities']:
|
for poi in rset._pois['TileEntities']:
|
||||||
if flter(poi):
|
result = filter_function(poi)
|
||||||
markerSetDict[name]['raw'].append(poi)
|
if result:
|
||||||
|
d = dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True)
|
||||||
|
if "icon" in poi:
|
||||||
|
d.update({"icon": poi['icon']})
|
||||||
|
markerSetDict[name]['raw'].append(d)
|
||||||
|
for poi in rset._pois['Players']:
|
||||||
|
result = filter_function(poi)
|
||||||
|
if result:
|
||||||
|
d = dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True)
|
||||||
|
if "icon" in poi:
|
||||||
|
d.update({"icon": poi['icon']})
|
||||||
|
markerSetDict[name]['raw'].append(d)
|
||||||
#print markerSetDict
|
#print markerSetDict
|
||||||
|
|
||||||
with open(os.path.join(destdir, "markersDB.js"), "w") as output:
|
with open(os.path.join(destdir, "markersDB.js"), "w") as output:
|
||||||
@@ -67,6 +67,8 @@ overviewer.util = {
|
|||||||
signs.registerEvents(signs);
|
signs.registerEvents(signs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var overlayControl = new overviewer.views.OverlayControlView();
|
||||||
|
|
||||||
var spawnmarker = new overviewer.views.SpawnIconView();
|
var spawnmarker = new overviewer.views.SpawnIconView();
|
||||||
|
|
||||||
// Update coords on mousemove
|
// Update coords on mousemove
|
||||||
@@ -85,6 +87,9 @@ overviewer.util = {
|
|||||||
compass.render();
|
compass.render();
|
||||||
spawnmarker.render();
|
spawnmarker.render();
|
||||||
|
|
||||||
|
// update list of spawn overlays
|
||||||
|
overlayControl.render();
|
||||||
|
|
||||||
// re-center on the last viewport
|
// re-center on the last viewport
|
||||||
var currentWorldView = overviewer.mapModel.get("currentWorldView");
|
var currentWorldView = overviewer.mapModel.get("currentWorldView");
|
||||||
if (currentWorldView.options.lastViewport) {
|
if (currentWorldView.options.lastViewport) {
|
||||||
@@ -117,8 +122,6 @@ overviewer.util = {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var worldSelector = new overviewer.views.WorldSelectorView({tagName:'DIV'});
|
|
||||||
overviewer.collections.worlds.bind("add", worldSelector.render, worldSelector);
|
|
||||||
|
|
||||||
// hook up some events
|
// hook up some events
|
||||||
|
|
||||||
@@ -129,6 +132,11 @@ overviewer.util = {
|
|||||||
// Jump to the hash if given
|
// Jump to the hash if given
|
||||||
overviewer.util.initHash();
|
overviewer.util.initHash();
|
||||||
|
|
||||||
|
// create this control after initHash so it can correctly select the current world
|
||||||
|
var worldSelector = new overviewer.views.WorldSelectorView({tagName:'DIV'});
|
||||||
|
overviewer.collections.worlds.bind("add", worldSelector.render, worldSelector);
|
||||||
|
|
||||||
|
|
||||||
overviewer.util.initializeMarkers();
|
overviewer.util.initializeMarkers();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -4,8 +4,19 @@ overviewer.views= {}
|
|||||||
overviewer.views.WorldView = Backbone.View.extend({
|
overviewer.views.WorldView = Backbone.View.extend({
|
||||||
initialize: function(opts) {
|
initialize: function(opts) {
|
||||||
this.options.mapTypes = [];
|
this.options.mapTypes = [];
|
||||||
|
this.options.overlayMapTypes = [];
|
||||||
this.options.mapTypeIds = [];
|
this.options.mapTypeIds = [];
|
||||||
|
this.options.overlayMapTypeIds = [];
|
||||||
|
|
||||||
|
var curTileSet = this.model.get("tileSets").at(0);
|
||||||
|
var spawn = curTileSet.get("spawn");
|
||||||
|
if (spawn == "false") {
|
||||||
|
var spawn = [0,64,0];
|
||||||
|
}
|
||||||
|
this.options.lastViewport = [spawn[0],spawn[1],spawn[2],curTileSet.get("defaultZoom")];
|
||||||
|
|
||||||
this.model.get("tileSets").each(function(tset, index, list) {
|
this.model.get("tileSets").each(function(tset, index, list) {
|
||||||
|
// ignore overlays:
|
||||||
var ops = {
|
var ops = {
|
||||||
getTileUrl: overviewer.gmap.getTileUrlGenerator(tset.get("path"), tset.get("base"), tset.get("imgextension")),
|
getTileUrl: overviewer.gmap.getTileUrlGenerator(tset.get("path"), tset.get("base"), tset.get("imgextension")),
|
||||||
'tileSize': new google.maps.Size(
|
'tileSize': new google.maps.Size(
|
||||||
@@ -20,11 +31,24 @@ overviewer.views.WorldView = Backbone.View.extend({
|
|||||||
newMapType.shortname = tset.get("name");
|
newMapType.shortname = tset.get("name");
|
||||||
newMapType.alt = "Minecraft " + tset.get("name") + " Map";
|
newMapType.alt = "Minecraft " + tset.get("name") + " Map";
|
||||||
newMapType.projection = new overviewer.classes.MapProjection();
|
newMapType.projection = new overviewer.classes.MapProjection();
|
||||||
|
newMapType._ov_tileSet = tset;
|
||||||
|
|
||||||
|
if (tset.get("isOverlay")) {
|
||||||
|
newMapType.tiles = tset.get("tilesets");
|
||||||
|
this.options.overlayMapTypes.push(newMapType);
|
||||||
|
this.options.overlayMapTypeIds.push(overviewerConfig.CONST.mapDivId + this.model.get("name") + tset.get("name"));
|
||||||
|
} else {
|
||||||
this.options.mapTypes.push(newMapType);
|
this.options.mapTypes.push(newMapType);
|
||||||
this.options.mapTypeIds.push(overviewerConfig.CONST.mapDivId + this.model.get("name") + tset.get("name"));
|
this.options.mapTypeIds.push(overviewerConfig.CONST.mapDivId + this.model.get("name") + tset.get("name"));
|
||||||
|
}
|
||||||
|
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
this.model.get("tileSets").each(function(tset, index, list) {
|
||||||
|
// ignore non-overlays:
|
||||||
|
if (!tset.get("isOverlay")) { return; };
|
||||||
|
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -33,6 +57,8 @@ overviewer.views.WorldView = Backbone.View.extend({
|
|||||||
overviewer.views.WorldSelectorView = Backbone.View.extend({
|
overviewer.views.WorldSelectorView = Backbone.View.extend({
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
if(overviewer.collections.worldViews.length > 1) {
|
if(overviewer.collections.worldViews.length > 1) {
|
||||||
|
$(this.el).addClass("customControl");
|
||||||
|
|
||||||
// a div will have already been created for us, we just
|
// a div will have already been created for us, we just
|
||||||
// need to register it with the google maps control
|
// need to register it with the google maps control
|
||||||
var selectBox = document.createElement('select');
|
var selectBox = document.createElement('select');
|
||||||
@@ -40,6 +66,9 @@ overviewer.views.WorldSelectorView = Backbone.View.extend({
|
|||||||
var o = document.createElement("option");
|
var o = document.createElement("option");
|
||||||
o.value = elem.model.get("name");
|
o.value = elem.model.get("name");
|
||||||
o.innerHTML = elem.model.get("name");
|
o.innerHTML = elem.model.get("name");
|
||||||
|
if (elem.model == overviewer.mapModel.get("currentWorldView").model) {
|
||||||
|
o.selected=true;
|
||||||
|
}
|
||||||
$(o).data("viewObj", elem);
|
$(o).data("viewObj", elem);
|
||||||
selectBox.appendChild(o);
|
selectBox.appendChild(o);
|
||||||
|
|
||||||
@@ -139,17 +168,16 @@ overviewer.views.GoogleMapView = Backbone.View.extend({
|
|||||||
var curWorld = this.model.get("currentWorldView").model;
|
var curWorld = this.model.get("currentWorldView").model;
|
||||||
|
|
||||||
var curTset = curWorld.get("tileSets").at(0);
|
var curTset = curWorld.get("tileSets").at(0);
|
||||||
|
var spawn = curTset.get("spawn");
|
||||||
|
if (spawn == "false") {
|
||||||
|
var spawn = [0,64,0];
|
||||||
|
}
|
||||||
|
var mapcenter = overviewer.util.fromWorldToLatLng(
|
||||||
|
spawn[0],
|
||||||
|
spawn[1],
|
||||||
|
spawn[2],
|
||||||
|
curTset);
|
||||||
|
|
||||||
/*
|
|
||||||
var defaultCenter = overviewer.util.fromWorldToLatLng(
|
|
||||||
overviewerConfig.map.center[0],
|
|
||||||
overviewerConfig.map.center[1],
|
|
||||||
overviewerConfig.map.center[2],
|
|
||||||
curTset.get("defaultZoom"));
|
|
||||||
*/
|
|
||||||
var lat = 0.62939453125;// TODO defaultCenter.lat();
|
|
||||||
var lng = 0.38525390625; // TODO defaultCenter.lng();
|
|
||||||
var mapcenter = new google.maps.LatLng(lat, lng);
|
|
||||||
|
|
||||||
this.options.mapTypes=[];
|
this.options.mapTypes=[];
|
||||||
this.options.mapTypeIds=[];
|
this.options.mapTypeIds=[];
|
||||||
@@ -208,7 +236,7 @@ overviewer.views.GoogleMapView = Backbone.View.extend({
|
|||||||
var gmapCurrent = overviewer.map.getMapTypeId();
|
var gmapCurrent = overviewer.map.getMapTypeId();
|
||||||
for (id in currentWorldView.options.mapTypeIds) {
|
for (id in currentWorldView.options.mapTypeIds) {
|
||||||
if (currentWorldView.options.mapTypeIds[id] == gmapCurrent) {
|
if (currentWorldView.options.mapTypeIds[id] == gmapCurrent) {
|
||||||
this.options.currentTileSet = currentWorldView.model.get("tileSets").at(id);
|
this.options.currentTileSet = currentWorldView.options.mapTypes[id]._ov_tileSet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,6 +248,114 @@ overviewer.views.GoogleMapView = Backbone.View.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OverlayControlView
|
||||||
|
*/
|
||||||
|
overviewer.views.OverlayControlView = Backbone.View.extend({
|
||||||
|
/** OverlayControlVIew::initialize
|
||||||
|
*/
|
||||||
|
initialize: function(opts) {
|
||||||
|
$(this.el).addClass("customControl");
|
||||||
|
overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(this.el);
|
||||||
|
},
|
||||||
|
registerEvents: function(me) {
|
||||||
|
overviewer.mapModel.bind("change:currentWorldView", me.render, me);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OverlayControlView::render
|
||||||
|
*/
|
||||||
|
render: function() {
|
||||||
|
this.el.innerHTML="";
|
||||||
|
|
||||||
|
// hide all visible overlays:
|
||||||
|
overviewer.map.overlayMapTypes.clear()
|
||||||
|
|
||||||
|
// if this world has no overlays, don't create this control
|
||||||
|
var mapTypes = overviewer.mapModel.get('currentWorldView').options.overlayMapTypes;
|
||||||
|
if (mapTypes.length == 0) { return; }
|
||||||
|
|
||||||
|
var controlText = document.createElement('DIV');
|
||||||
|
controlText.innerHTML = "Overlays";
|
||||||
|
|
||||||
|
var controlBorder = document.createElement('DIV');
|
||||||
|
$(controlBorder).addClass('top');
|
||||||
|
this.el.appendChild(controlBorder);
|
||||||
|
controlBorder.appendChild(controlText);
|
||||||
|
|
||||||
|
var dropdownDiv = document.createElement('DIV');
|
||||||
|
$(dropdownDiv).addClass('dropDown');
|
||||||
|
this.el.appendChild(dropdownDiv);
|
||||||
|
dropdownDiv.innerHTML='';
|
||||||
|
|
||||||
|
$(controlText).click(function() {
|
||||||
|
$(controlBorder).toggleClass('top-active');
|
||||||
|
$(dropdownDiv).toggle();
|
||||||
|
});
|
||||||
|
|
||||||
|
var currentTileSetPath = overviewer.mapView.options.currentTileSet.get('path');
|
||||||
|
|
||||||
|
for (i in mapTypes) {
|
||||||
|
var mt = mapTypes[i];
|
||||||
|
// if this overlay specifies a list of valid tilesets, then skip over any invalid tilesets
|
||||||
|
if ((mt.tiles.length > 0) && (mt.tiles.indexOf(currentTileSetPath) ==-1)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.addItem({label: mt.name,
|
||||||
|
name: mt.name,
|
||||||
|
mt: mt,
|
||||||
|
|
||||||
|
action: function(this_item, checked) {
|
||||||
|
if (checked) {
|
||||||
|
overviewer.map.overlayMapTypes.push(this_item.mt);
|
||||||
|
} else {
|
||||||
|
var idx_to_delete = -1;
|
||||||
|
overviewer.map.overlayMapTypes.forEach(function(e, j) {
|
||||||
|
if (e == this_item.mt) {
|
||||||
|
idx_to_delete = j;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (idx_to_delete >= 0) {
|
||||||
|
overviewer.map.overlayMapTypes.removeAt(idx_to_delete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
addItem: function(item) {
|
||||||
|
var itemDiv = document.createElement('div');
|
||||||
|
var itemInput = document.createElement('input');
|
||||||
|
itemInput.type='checkbox';
|
||||||
|
|
||||||
|
// if this overlay is already visible, set the checkbox
|
||||||
|
// to checked
|
||||||
|
overviewer.map.overlayMapTypes.forEach(function(e, j) {
|
||||||
|
if (e == item.mt) {
|
||||||
|
itemInput.checked=true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// give it a name
|
||||||
|
$(itemInput).attr("_mc_overlayname", item.name);
|
||||||
|
jQuery(itemInput).click((function(local_item) {
|
||||||
|
return function(e) {
|
||||||
|
item.action(local_item, e.target.checked);
|
||||||
|
};
|
||||||
|
})(item));
|
||||||
|
|
||||||
|
this.$(".dropDown")[0].appendChild(itemDiv);
|
||||||
|
itemDiv.appendChild(itemInput);
|
||||||
|
var textNode = document.createElement('text');
|
||||||
|
textNode.innerHTML = item.label + '<br/>';
|
||||||
|
|
||||||
|
itemDiv.appendChild(textNode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -285,7 +421,7 @@ overviewer.views.SignControlView = Backbone.View.extend({
|
|||||||
//var dataRoot = overviewer.collections.markerInfo[curMarkerSet];
|
//var dataRoot = overviewer.collections.markerInfo[curMarkerSet];
|
||||||
var dataRoot = markers[curMarkerSet];
|
var dataRoot = markers[curMarkerSet];
|
||||||
|
|
||||||
this.el.innerHTML=""
|
this.el.innerHTML="";
|
||||||
|
|
||||||
// if we have no markerSets for this tileset, do nothing:
|
// if we have no markerSets for this tileset, do nothing:
|
||||||
if (!dataRoot) { return; }
|
if (!dataRoot) { return; }
|
||||||
@@ -322,7 +458,6 @@ overviewer.views.SignControlView = Backbone.View.extend({
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
iconURL = overviewerConfig.CONST.image.signMarker;
|
|
||||||
//dataRoot['markers'] = [];
|
//dataRoot['markers'] = [];
|
||||||
//
|
//
|
||||||
for (i in dataRoot) {
|
for (i in dataRoot) {
|
||||||
@@ -330,15 +465,20 @@ overviewer.views.SignControlView = Backbone.View.extend({
|
|||||||
if (!markersDB[groupName].created) {
|
if (!markersDB[groupName].created) {
|
||||||
for (j in markersDB[groupName].raw) {
|
for (j in markersDB[groupName].raw) {
|
||||||
var entity = markersDB[groupName].raw[j];
|
var entity = markersDB[groupName].raw[j];
|
||||||
|
if (entity['icon']) {
|
||||||
|
iconURL = entity['icon'];
|
||||||
|
} else {
|
||||||
|
iconURL = dataRoot[i].icon;
|
||||||
|
}
|
||||||
var marker = new google.maps.Marker({
|
var marker = new google.maps.Marker({
|
||||||
'position': overviewer.util.fromWorldToLatLng(entity.x,
|
'position': overviewer.util.fromWorldToLatLng(entity.x,
|
||||||
entity.y, entity.z, overviewer.mapView.options.currentTileSet),
|
entity.y, entity.z, overviewer.mapView.options.currentTileSet),
|
||||||
'map': overviewer.map,
|
'map': overviewer.map,
|
||||||
'title': jQuery.trim(entity.Text1 + "\n" + entity.Text2 + "\n" + entity.Text3 + "\n" + entity.Text4),
|
'title': jQuery.trim(entity.text),
|
||||||
'icon': iconURL,
|
'icon': iconURL,
|
||||||
'visible': false
|
'visible': false
|
||||||
});
|
});
|
||||||
if (entity['id'] == 'Sign') {
|
if (entity.createInfoWindow) {
|
||||||
overviewer.util.createMarkerInfoWindow(marker);
|
overviewer.util.createMarkerInfoWindow(marker);
|
||||||
}
|
}
|
||||||
jQuery.extend(entity, {markerObj: marker});
|
jQuery.extend(entity, {markerObj: marker});
|
||||||
|
|||||||
BIN
overviewer_core/data/web_assets/bed.png
Normal file
BIN
overviewer_core/data/web_assets/bed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 631 B |
@@ -40,6 +40,17 @@ body {
|
|||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.customControl > select {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 160%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
border: 1px solid #A9BBDF;
|
||||||
|
border-radius: 2px 2px;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.347656) 2px 2px 3px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.customControl > div.top {
|
.customControl > div.top {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 160%;
|
line-height: 160%;
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ class ANSIColorFormatter(HighlightingFormatter):
|
|||||||
# No coloring if it's not to be highlighted or colored
|
# No coloring if it's not to be highlighted or colored
|
||||||
return logging.Formatter.format(self, record)
|
return logging.Formatter.format(self, record)
|
||||||
|
|
||||||
def configure(loglevel=logging.INFO, verbose=False):
|
def configure(loglevel=logging.INFO, verbose=False, simple=False):
|
||||||
"""Configures the root logger to our liking
|
"""Configures the root logger to our liking
|
||||||
|
|
||||||
For a non-standard loglevel, pass in the level with which to configure the handler.
|
For a non-standard loglevel, pass in the level with which to configure the handler.
|
||||||
@@ -267,15 +267,17 @@ def configure(loglevel=logging.INFO, verbose=False):
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
outstream = sys.stderr
|
outstream = sys.stdout
|
||||||
|
if simple:
|
||||||
|
formatter = DumbFormatter(verbose)
|
||||||
|
|
||||||
if platform.system() == 'Windows':
|
elif platform.system() == 'Windows':
|
||||||
# Our custom output stream processor knows how to deal with select ANSI
|
# Our custom output stream processor knows how to deal with select ANSI
|
||||||
# color escape sequences
|
# color escape sequences
|
||||||
outstream = WindowsOutputStream()
|
outstream = WindowsOutputStream(outstream)
|
||||||
formatter = ANSIColorFormatter(verbose)
|
formatter = ANSIColorFormatter(verbose)
|
||||||
|
|
||||||
elif sys.stderr.isatty():
|
elif outstream.isatty():
|
||||||
# terminal logging with ANSI color
|
# terminal logging with ANSI color
|
||||||
formatter = ANSIColorFormatter(verbose)
|
formatter = ANSIColorFormatter(verbose)
|
||||||
|
|
||||||
|
|||||||
@@ -188,6 +188,12 @@ class MineralOverlay(Overlay):
|
|||||||
'minerals' : ('a list of (blockid, (r, g, b)) tuples for coloring minerals', None),
|
'minerals' : ('a list of (blockid, (r, g, b)) tuples for coloring minerals', None),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Hide(RenderPrimitive):
|
||||||
|
name = "hide"
|
||||||
|
options = {
|
||||||
|
'blocks' : ('a list of blockids or (blockid, data) tuples of blocks to hide', []),
|
||||||
|
}
|
||||||
|
|
||||||
# Built-in rendermodes for your convenience!
|
# Built-in rendermodes for your convenience!
|
||||||
normal = [Base(), EdgeLines()]
|
normal = [Base(), EdgeLines()]
|
||||||
lighting = [Base(), EdgeLines(), Lighting()]
|
lighting = [Base(), EdgeLines(), Lighting()]
|
||||||
|
|||||||
@@ -75,10 +75,11 @@ renders = Setting(required=True, default=util.OrderedDict(),
|
|||||||
"nomarkers": Setting(required=False, validator=validateBool, default=None),
|
"nomarkers": Setting(required=False, validator=validateBool, default=None),
|
||||||
"texturepath": Setting(required=False, validator=validateTexturePath, default=None),
|
"texturepath": Setting(required=False, validator=validateTexturePath, default=None),
|
||||||
"renderchecks": Setting(required=False, validator=validateInt, default=None),
|
"renderchecks": Setting(required=False, validator=validateInt, default=None),
|
||||||
"rerenderprob": Setting(required=True, validator=validateFloat, default=0),
|
"rerenderprob": Setting(required=True, validator=validateRerenderprob, default=0),
|
||||||
"crop": Setting(required=False, validator=validateCrop, default=None),
|
"crop": Setting(required=False, validator=validateCrop, default=None),
|
||||||
"changelist": Setting(required=False, validator=validateStr, default=None),
|
"changelist": Setting(required=False, validator=validateStr, default=None),
|
||||||
"markers": Setting(required=False, validator=validateMarkers, default=[]),
|
"markers": Setting(required=False, validator=validateMarkers, default=[]),
|
||||||
|
"overlay": Setting(required=False, validator=validateOverlays, default=[]),
|
||||||
"showspawn": Setting(required=False, validator=validateBool, default=True),
|
"showspawn": Setting(required=False, validator=validateBool, default=True),
|
||||||
|
|
||||||
# Remove this eventually (once people update their configs)
|
# Remove this eventually (once people update their configs)
|
||||||
@@ -98,9 +99,10 @@ processes = Setting(required=True, validator=int, default=-1)
|
|||||||
# ends up adding overhead and isn't worth it.
|
# ends up adding overhead and isn't worth it.
|
||||||
memcached_host = Setting(required=False, validator=str, default=None)
|
memcached_host = Setting(required=False, validator=str, default=None)
|
||||||
|
|
||||||
if platform.system() == 'Windows' or not sys.stderr.isatty():
|
# TODO clean up this ugly in sys.argv hack
|
||||||
|
if platform.system() == 'Windows' or not sys.stdout.isatty() or "--simple" in sys.argv:
|
||||||
obs = LoggingObserver()
|
obs = LoggingObserver()
|
||||||
else:
|
else:
|
||||||
obs = ProgressBarObserver()
|
obs = ProgressBarObserver(fd=sys.stdout)
|
||||||
|
|
||||||
observer = Setting(required=True, validator=validateObserver, default=obs)
|
observer = Setting(required=True, validator=validateObserver, default=obs)
|
||||||
|
|||||||
@@ -45,12 +45,26 @@ def checkBadEscape(s):
|
|||||||
|
|
||||||
def validateMarkers(filterlist):
|
def validateMarkers(filterlist):
|
||||||
if type(filterlist) != list:
|
if type(filterlist) != list:
|
||||||
raise ValidationException("Markers must specify a list of filters")
|
raise ValidationException("Markers must specify a list of filters. This has recently changed, so check the docs.")
|
||||||
for x in filterlist:
|
for x in filterlist:
|
||||||
if not callable(x):
|
if type(x) != dict:
|
||||||
raise ValidationException("%r must be a function"% x)
|
raise ValidationException("Markers must specify a list of dictionaries. This has recently changed, so check the docs.")
|
||||||
|
if "name" not in x:
|
||||||
|
raise ValidationException("Must define a name")
|
||||||
|
if "filterFunction" not in x:
|
||||||
|
raise ValidationException("Must define a filter function")
|
||||||
|
if not callable(x['filterFunction']):
|
||||||
|
raise ValidationException("%r must be a function"% x['filterFunction'])
|
||||||
return filterlist
|
return filterlist
|
||||||
|
|
||||||
|
def validateOverlays(renderlist):
|
||||||
|
if type(renderlist) != list:
|
||||||
|
raise ValidationException("Overlay must specify a list of renders")
|
||||||
|
for x in renderlist:
|
||||||
|
if validateStr(x) == '':
|
||||||
|
raise ValidationException("%r must be a string"% x)
|
||||||
|
return renderlist
|
||||||
|
|
||||||
def validateWorldPath(worldpath):
|
def validateWorldPath(worldpath):
|
||||||
_, worldpath = checkBadEscape(worldpath)
|
_, worldpath = checkBadEscape(worldpath)
|
||||||
abs_path = os.path.abspath(os.path.expanduser(worldpath))
|
abs_path = os.path.abspath(os.path.expanduser(worldpath))
|
||||||
@@ -99,10 +113,10 @@ def validateNorthDirection(direction):
|
|||||||
raise ValidationException("%r is not a valid north direction" % direction)
|
raise ValidationException("%r is not a valid north direction" % direction)
|
||||||
return intdir
|
return intdir
|
||||||
|
|
||||||
def validateStochastic(s):
|
def validateRerenderprob(s):
|
||||||
val = float(s)
|
val = float(s)
|
||||||
if val < 0 or val > 1:
|
if val < 0 or val >= 1:
|
||||||
raise ValidationException("%r is not a valid stochastic value. Should be between 0.0 and 1.0" % s)
|
raise ValidationException("%r is not a valid rerender probability value. Should be between 0.0 and 1.0." % s)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def validateImgFormat(fmt):
|
def validateImgFormat(fmt):
|
||||||
|
|||||||
@@ -24,11 +24,6 @@
|
|||||||
|
|
||||||
#include "overviewer.h"
|
#include "overviewer.h"
|
||||||
|
|
||||||
/* like (a * b + 127) / 255), but much faster on most platforms
|
|
||||||
from PIL's _imaging.c */
|
|
||||||
#define MULDIV255(a, b, tmp) \
|
|
||||||
(tmp = (a) * (b) + 128, ((((tmp) >> 8) + (tmp)) >> 8))
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
Imaging image;
|
Imaging image;
|
||||||
|
|||||||
@@ -26,13 +26,18 @@
|
|||||||
|
|
||||||
// increment this value if you've made a change to the c extesion
|
// increment this value if you've made a change to the c extesion
|
||||||
// and want to force users to rebuild
|
// and want to force users to rebuild
|
||||||
#define OVERVIEWER_EXTENSION_VERSION 30
|
#define OVERVIEWER_EXTENSION_VERSION 33
|
||||||
|
|
||||||
/* Python PIL, and numpy headers */
|
/* Python PIL, and numpy headers */
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <Imaging.h>
|
#include <Imaging.h>
|
||||||
#include <numpy/arrayobject.h>
|
#include <numpy/arrayobject.h>
|
||||||
|
|
||||||
|
/* like (a * b + 127) / 255), but much faster on most platforms
|
||||||
|
from PIL's _imaging.c */
|
||||||
|
#define MULDIV255(a, b, tmp) \
|
||||||
|
(tmp = (a) * (b) + 128, ((((tmp) >> 8) + (tmp)) >> 8))
|
||||||
|
|
||||||
/* macro for getting a value out of various numpy arrays the 3D arrays have
|
/* macro for getting a value out of various numpy arrays the 3D arrays have
|
||||||
interesting, swizzled coordinates because minecraft (anvil) stores blocks
|
interesting, swizzled coordinates because minecraft (anvil) stores blocks
|
||||||
in y/z/x order for 3D, z/x order for 2D */
|
in y/z/x order for 3D, z/x order for 2D */
|
||||||
|
|||||||
@@ -29,46 +29,53 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* name;
|
const char* name;
|
||||||
|
|
||||||
float temperature;
|
float temperature;
|
||||||
float rainfall;
|
float rainfall;
|
||||||
|
|
||||||
|
unsigned int r, g, b;
|
||||||
} Biome;
|
} Biome;
|
||||||
|
|
||||||
/* each entry in this table is yanked *directly* out of the minecraft source
|
/* each entry in this table is yanked *directly* out of the minecraft source
|
||||||
* temp/rainfall are taken from what MCP calls setTemperatureRainfall
|
* temp/rainfall are taken from what MCP calls setTemperatureRainfall
|
||||||
*
|
*
|
||||||
|
* Some biomes, like Swamp, do a bit of post-processing by multiplying on a
|
||||||
|
* hard-coded color. The RGB tuple used follows the temp/rainfall.
|
||||||
|
* 255, 255, 255 is white, which means do nothing
|
||||||
|
*
|
||||||
* keep in mind the x/y coordinate in the color tables is found *after*
|
* keep in mind the x/y coordinate in the color tables is found *after*
|
||||||
* multiplying rainfall and temperature for the second coordinate, *and* the
|
* multiplying rainfall and temperature for the second coordinate, *and* the
|
||||||
* origin is in the lower-right. <3 biomes.
|
* origin is in the lower-right. <3 biomes.
|
||||||
*/
|
*/
|
||||||
static Biome biome_table[] = {
|
static Biome biome_table[] = {
|
||||||
/* 0 */
|
/* 0 */
|
||||||
{"Ocean", 0.5, 0.5},
|
{"Ocean", 0.5, 0.5, 255, 255, 255},
|
||||||
{"Plains", 0.8, 0.4},
|
{"Plains", 0.8, 0.4, 255, 255, 255},
|
||||||
{"Desert", 2.0, 0.0},
|
{"Desert", 2.0, 0.0, 255, 255, 255},
|
||||||
{"Extreme Hills", 0.2, 0.3},
|
{"Extreme Hills", 0.2, 0.3, 255, 255, 255},
|
||||||
{"Forest", 0.7, 0.8},
|
{"Forest", 0.7, 0.8, 255, 255, 255},
|
||||||
/* 5 */
|
/* 5 */
|
||||||
{"Taiga", 0.05, 0.8},
|
{"Taiga", 0.05, 0.8, 255, 255, 255},
|
||||||
{"Swampland", 0.8, 0.9},
|
{"Swampland", 0.8, 0.9, 205, 128, 255},
|
||||||
{"River", 0.5, 0.5},
|
{"River", 0.5, 0.5, 255, 255, 255},
|
||||||
{"Hell", 2.0, 0.0},
|
{"Hell", 2.0, 0.0, 255, 255, 255},
|
||||||
{"Sky", 0.5, 0.5},
|
{"Sky", 0.5, 0.5, 255, 255, 255},
|
||||||
/* 10 */
|
/* 10 */
|
||||||
{"FrozenOcean", 0.0, 0.5},
|
{"FrozenOcean", 0.0, 0.5, 255, 255, 255},
|
||||||
{"FrozenRiver", 0.0, 0.5},
|
{"FrozenRiver", 0.0, 0.5, 255, 255, 255},
|
||||||
{"Ice Plains", 0.0, 0.5},
|
{"Ice Plains", 0.0, 0.5, 255, 255, 255},
|
||||||
{"Ice Mountains", 0.0, 0.5},
|
{"Ice Mountains", 0.0, 0.5, 255, 255, 255},
|
||||||
{"MushroomIsland", 0.9, 1.0},
|
{"MushroomIsland", 0.9, 1.0, 255, 255, 255},
|
||||||
/* 15 */
|
/* 15 */
|
||||||
{"MushroomIslandShore", 0.9, 1.0},
|
{"MushroomIslandShore", 0.9, 1.0, 255, 255, 255},
|
||||||
{"Beach", 0.8, 0.4},
|
{"Beach", 0.8, 0.4, 255, 255, 255},
|
||||||
{"DesertHills", 2.0, 0.0},
|
{"DesertHills", 2.0, 0.0, 255, 255, 255},
|
||||||
{"ForestHills", 0.7, 0.8},
|
{"ForestHills", 0.7, 0.8, 255, 255, 255},
|
||||||
{"TaigaHills", 0.05, 0.8},
|
{"TaigaHills", 0.05, 0.8, 255, 255, 255},
|
||||||
/* 20 */
|
/* 20 */
|
||||||
{"Extreme Hills Edge", 0.2, 0.3},
|
{"Extreme Hills Edge", 0.2, 0.3, 255, 255, 255},
|
||||||
{"Jungle", 2.0, 0.45}, /* <-- GUESS, but a good one */
|
{"Jungle", 2.0, 0.45, 255, 255, 255}, /* <-- GUESS, but a good one */
|
||||||
{"Jungle Mountains", 2.0, 0.45}, /* <-- also a guess */
|
{"Jungle Mountains", 2.0, 0.45, 255, 255, 255}, /* <-- also a guess */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_BIOMES (sizeof(biome_table) / sizeof(Biome))
|
#define NUM_BIOMES (sizeof(biome_table) / sizeof(Biome))
|
||||||
@@ -206,16 +213,19 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (color_table) {
|
if (color_table) {
|
||||||
|
unsigned char biome;
|
||||||
int dx, dz;
|
int dx, dz;
|
||||||
unsigned char tablex, tabley;
|
unsigned char tablex, tabley;
|
||||||
float temp = 0.0, rain = 0.0;
|
float temp = 0.0, rain = 0.0;
|
||||||
|
unsigned int multr = 0, multg = 0, multb = 0;
|
||||||
|
int tmp;
|
||||||
PyObject *color = NULL;
|
PyObject *color = NULL;
|
||||||
|
|
||||||
if (self->use_biomes) {
|
if (self->use_biomes) {
|
||||||
/* average over all neighbors */
|
/* average over all neighbors */
|
||||||
for (dx = -1; dx <= 1; dx++) {
|
for (dx = -1; dx <= 1; dx++) {
|
||||||
for (dz = -1; dz <= 1; dz++) {
|
for (dz = -1; dz <= 1; dz++) {
|
||||||
unsigned char biome = get_data(state, BIOMES, state->x + dx, state->y, state->z + dz);
|
biome = get_data(state, BIOMES, state->x + dx, state->y, state->z + dz);
|
||||||
if (biome >= NUM_BIOMES) {
|
if (biome >= NUM_BIOMES) {
|
||||||
/* note -- biome 255 shows up on map borders.
|
/* note -- biome 255 shows up on map borders.
|
||||||
who knows what it is? certainly not I.
|
who knows what it is? certainly not I.
|
||||||
@@ -225,14 +235,24 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec
|
|||||||
|
|
||||||
temp += biome_table[biome].temperature;
|
temp += biome_table[biome].temperature;
|
||||||
rain += biome_table[biome].rainfall;
|
rain += biome_table[biome].rainfall;
|
||||||
|
multr += biome_table[biome].r;
|
||||||
|
multg += biome_table[biome].g;
|
||||||
|
multb += biome_table[biome].b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
temp /= 9.0;
|
temp /= 9.0;
|
||||||
rain /= 9.0;
|
rain /= 9.0;
|
||||||
|
multr /= 9;
|
||||||
|
multg /= 9;
|
||||||
|
multb /= 9;
|
||||||
} else {
|
} else {
|
||||||
/* don't use biomes, just use the default */
|
/* don't use biomes, just use the default */
|
||||||
temp = biome_table[DEFAULT_BIOME].temperature;
|
temp = biome_table[DEFAULT_BIOME].temperature;
|
||||||
rain = biome_table[DEFAULT_BIOME].rainfall;
|
rain = biome_table[DEFAULT_BIOME].rainfall;
|
||||||
|
multr = biome_table[DEFAULT_BIOME].r;
|
||||||
|
multg = biome_table[DEFAULT_BIOME].g;
|
||||||
|
multb = biome_table[DEFAULT_BIOME].b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* second coordinate is actually scaled to fit inside the triangle
|
/* second coordinate is actually scaled to fit inside the triangle
|
||||||
@@ -258,6 +278,11 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec
|
|||||||
g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1));
|
g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1));
|
||||||
b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2));
|
b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2));
|
||||||
Py_DECREF(color);
|
Py_DECREF(color);
|
||||||
|
|
||||||
|
/* do the after-coloration */
|
||||||
|
r = MULDIV255(r, multr, tmp);
|
||||||
|
g = MULDIV255(g, multg, tmp);
|
||||||
|
b = MULDIV255(b, multb, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* final coloration */
|
/* final coloration */
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ edge_lines_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, P
|
|||||||
Imaging img_i = imaging_python_to_c(state->img);
|
Imaging img_i = imaging_python_to_c(state->img);
|
||||||
unsigned char ink[] = {0, 0, 0, 255 * self->opacity};
|
unsigned char ink[] = {0, 0, 0, 255 * self->opacity};
|
||||||
unsigned short side_block;
|
unsigned short side_block;
|
||||||
|
int x = state->x, y = state->y, z = state->z;
|
||||||
|
|
||||||
int increment=0;
|
int increment=0;
|
||||||
if (state->block == 44 && ((state->block_data & 0x8) == 0 )) // half-step BUT no upsidown half-step
|
if (state->block == 44 && ((state->block_data & 0x8) == 0 )) // half-step BUT no upsidown half-step
|
||||||
@@ -46,15 +47,15 @@ edge_lines_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, P
|
|||||||
increment=9;
|
increment=9;
|
||||||
|
|
||||||
/* +X side */
|
/* +X side */
|
||||||
side_block = get_data(state, BLOCKS, state->x+1, state->y, state->z);
|
side_block = get_data(state, BLOCKS, x+1, y, z);
|
||||||
if (side_block != state->block && is_transparent(side_block)) {
|
if (side_block != state->block && (is_transparent(side_block) || render_mode_hidden(state->rendermode, x+1, y, z))) {
|
||||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
|
ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
|
||||||
ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
|
ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -Z side */
|
/* -Z side */
|
||||||
side_block = get_data(state, BLOCKS, state->x, state->y, state->z-1);
|
side_block = get_data(state, BLOCKS, x, y, z-1);
|
||||||
if (side_block != state->block && is_transparent(side_block)) {
|
if (side_block != state->block && (is_transparent(side_block) || render_mode_hidden(state->rendermode, x, y, z-1))) {
|
||||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
|
ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
|
||||||
ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
|
ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
117
overviewer_core/src/primitives/hide.c
Normal file
117
overviewer_core/src/primitives/hide.c
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Minecraft Overviewer.
|
||||||
|
*
|
||||||
|
* Minecraft Overviewer is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Minecraft Overviewer is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../overviewer.h"
|
||||||
|
|
||||||
|
struct HideRule {
|
||||||
|
unsigned short blockid;
|
||||||
|
unsigned char has_data;
|
||||||
|
unsigned char data;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct HideRule* rules;
|
||||||
|
} RenderPrimitiveHide;
|
||||||
|
|
||||||
|
static int
|
||||||
|
hide_start(void *data, RenderState *state, PyObject *support) {
|
||||||
|
PyObject *opt;
|
||||||
|
RenderPrimitiveHide* self = (RenderPrimitiveHide *)data;
|
||||||
|
self->rules = NULL;
|
||||||
|
|
||||||
|
if (!render_mode_parse_option(support, "blocks", "O", &(opt)))
|
||||||
|
return 1;
|
||||||
|
if (opt && opt != Py_None) {
|
||||||
|
Py_ssize_t blocks_size = 0, i;
|
||||||
|
|
||||||
|
if (!PyList_Check(opt)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "'blocks' must be a list");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks_size = PyList_GET_SIZE(opt);
|
||||||
|
self->rules = calloc(blocks_size + 1, sizeof(struct HideRule));
|
||||||
|
if (self->rules == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < blocks_size; i++) {
|
||||||
|
PyObject *block = PyList_GET_ITEM(opt, i);
|
||||||
|
|
||||||
|
if (PyInt_Check(block)) {
|
||||||
|
/* format 1: just a block id */
|
||||||
|
self->rules[i].blockid = PyInt_AsLong(block);
|
||||||
|
self->rules[i].has_data = 0;
|
||||||
|
} else if (PyArg_ParseTuple(block, "Hb", &(self->rules[i].blockid), &(self->rules[i].data))) {
|
||||||
|
/* format 2: (blockid, data) */
|
||||||
|
self->rules[i].has_data = 1;
|
||||||
|
} else {
|
||||||
|
/* format not recognized */
|
||||||
|
free(self->rules);
|
||||||
|
self->rules = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hide_finish(void *data, RenderState *state) {
|
||||||
|
RenderPrimitiveHide *self = (RenderPrimitiveHide *)data;
|
||||||
|
|
||||||
|
if (self->rules) {
|
||||||
|
free(self->rules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hide_hidden(void *data, RenderState *state, int x, int y, int z) {
|
||||||
|
RenderPrimitiveHide *self = (RenderPrimitiveHide *)data;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned short block;
|
||||||
|
|
||||||
|
if (self->rules == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
block = get_data(state, BLOCKS, x, y, z);
|
||||||
|
for (i = 0; self->rules[i].blockid != 0; i++) {
|
||||||
|
if (block == self->rules[i].blockid) {
|
||||||
|
unsigned char data;
|
||||||
|
|
||||||
|
if (!(self->rules[i].has_data))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
data = get_data(state, DATA, x, y, z);
|
||||||
|
if (data == self->rules[i].data)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderPrimitiveInterface primitive_hide = {
|
||||||
|
"hide",
|
||||||
|
sizeof(RenderPrimitiveHide),
|
||||||
|
hide_start,
|
||||||
|
hide_finish,
|
||||||
|
NULL,
|
||||||
|
hide_hidden,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
@@ -90,6 +90,7 @@ overlay_mineral_start(void *data, RenderState *state, PyObject *support) {
|
|||||||
/* now do custom initializations */
|
/* now do custom initializations */
|
||||||
self = (RenderPrimitiveMineral *)data;
|
self = (RenderPrimitiveMineral *)data;
|
||||||
|
|
||||||
|
// opt is a borrowed reference. do not deref
|
||||||
if (!render_mode_parse_option(support, "minerals", "O", &(opt)))
|
if (!render_mode_parse_option(support, "minerals", "O", &(opt)))
|
||||||
return 1;
|
return 1;
|
||||||
if (opt && opt != Py_None) {
|
if (opt && opt != Py_None) {
|
||||||
@@ -119,7 +120,6 @@ overlay_mineral_start(void *data, RenderState *state, PyObject *support) {
|
|||||||
} else {
|
} else {
|
||||||
self->minerals = default_minerals;
|
self->minerals = default_minerals;
|
||||||
}
|
}
|
||||||
Py_XDECREF(opt);
|
|
||||||
|
|
||||||
/* setup custom color */
|
/* setup custom color */
|
||||||
self->parent.get_color = get_color;
|
self->parent.get_color = get_color;
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ class Textures(object):
|
|||||||
if verbose: logging.info("Found %s in '%s'", filename, path)
|
if verbose: logging.info("Found %s in '%s'", filename, path)
|
||||||
return open(path, mode)
|
return open(path, mode)
|
||||||
|
|
||||||
raise IOError("Could not find the file `{0}'. Try specifying the 'texturepath' option in your config file. Set it to the directory where I can find {0}.".format(filename))
|
raise IOError("Could not find the file `{0}'. Try specifying the 'texturepath' option in your config file. Set it to the directory where I can find {0}. Also see <http://docs.overviewer.org/en/latest/running/#installing-the-textures>".format(filename))
|
||||||
|
|
||||||
def load_image(self, filename):
|
def load_image(self, filename):
|
||||||
"""Returns an image object"""
|
"""Returns an image object"""
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ from .util import roundrobin
|
|||||||
from . import nbt
|
from . import nbt
|
||||||
from .files import FileReplacer
|
from .files import FileReplacer
|
||||||
from .optimizeimages import optimize_image
|
from .optimizeimages import optimize_image
|
||||||
|
import rendermodes
|
||||||
import c_overviewer
|
import c_overviewer
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -507,6 +508,8 @@ class TileSet(object):
|
|||||||
"""
|
"""
|
||||||
def bgcolorformat(color):
|
def bgcolorformat(color):
|
||||||
return "#%02x%02x%02x" % color[0:3]
|
return "#%02x%02x%02x" % color[0:3]
|
||||||
|
isOverlay = not any(isinstance(x, rendermodes.Base) for x in self.options.get("rendermode"))
|
||||||
|
|
||||||
d = dict(name = self.options.get('title'),
|
d = dict(name = self.options.get('title'),
|
||||||
zoomLevels = self.treedepth,
|
zoomLevels = self.treedepth,
|
||||||
minZoom = 0,
|
minZoom = 0,
|
||||||
@@ -519,7 +522,11 @@ class TileSet(object):
|
|||||||
(" - " + self.options.get('dimension') if self.options.get('dimension') != 'default' else ''),
|
(" - " + self.options.get('dimension') if self.options.get('dimension') != 'default' else ''),
|
||||||
last_rendertime = self.max_chunk_mtime,
|
last_rendertime = self.max_chunk_mtime,
|
||||||
imgextension = self.imgextension,
|
imgextension = self.imgextension,
|
||||||
|
isOverlay = isOverlay
|
||||||
)
|
)
|
||||||
|
if isOverlay:
|
||||||
|
d.update({"tilesets": self.options.get("overlay")})
|
||||||
|
|
||||||
if (self.regionset.get_type() == "overworld" and self.options.get("showspawn", True)):
|
if (self.regionset.get_type() == "overworld" and self.options.get("showspawn", True)):
|
||||||
d.update({"spawn": self.options.get("spawn")})
|
d.update({"spawn": self.options.get("spawn")})
|
||||||
else:
|
else:
|
||||||
@@ -580,7 +587,6 @@ class TileSet(object):
|
|||||||
self.xradius = xradius
|
self.xradius = xradius
|
||||||
self.yradius = yradius
|
self.yradius = yradius
|
||||||
|
|
||||||
|
|
||||||
def _rearrange_tiles(self):
|
def _rearrange_tiles(self):
|
||||||
"""If the target size of the tree is not the same as the existing size
|
"""If the target size of the tree is not the same as the existing size
|
||||||
on disk, do some re-arranging
|
on disk, do some re-arranging
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ class World(object):
|
|||||||
if section['Y'] == targetSection:
|
if section['Y'] == targetSection:
|
||||||
blockArray = section['Blocks']
|
blockArray = section['Blocks']
|
||||||
return blockArray[inChunkX, inChunkZ, y % 16]
|
return blockArray[inChunkX, inChunkZ, y % 16]
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -483,6 +484,8 @@ class RegionSet(object):
|
|||||||
p = f.split(".")
|
p = f.split(".")
|
||||||
x = int(p[1])
|
x = int(p[1])
|
||||||
y = int(p[2])
|
y = int(p[2])
|
||||||
|
if abs(x) > 500000 or abs(y) > 500000:
|
||||||
|
logging.warning("Holy shit what is up with region file %s !?" % f)
|
||||||
yield (x, y, path)
|
yield (x, y, path)
|
||||||
|
|
||||||
class RegionSetWrapper(object):
|
class RegionSetWrapper(object):
|
||||||
|
|||||||
6
setup.py
6
setup.py
@@ -108,13 +108,13 @@ if py2exe is not None:
|
|||||||
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/web_assets', 'web_assets')
|
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/web_assets', 'web_assets')
|
||||||
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/js_src', 'js_src')
|
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/js_src', 'js_src')
|
||||||
setup_kwargs['data_files'] += recursive_data_files('contrib', 'contrib')
|
setup_kwargs['data_files'] += recursive_data_files('contrib', 'contrib')
|
||||||
setup_kwargs['data_files'] += [('', ['genPOI.py'])]
|
|
||||||
setup_kwargs['zipfile'] = None
|
setup_kwargs['zipfile'] = None
|
||||||
if platform.system() == 'Windows' and '64bit' in platform.architecture():
|
if platform.system() == 'Windows' and '64bit' in platform.architecture():
|
||||||
b = 3
|
b = 3
|
||||||
else:
|
else:
|
||||||
b = 1
|
b = 1
|
||||||
setup_kwargs['options']['py2exe'] = {'bundle_files' : b, 'excludes': 'Tkinter', 'includes':['fileinput', 'overviewer_core.items']}
|
setup_kwargs['options']['py2exe'] = {'bundle_files' : b, 'excludes': 'Tkinter', 'includes':
|
||||||
|
['fileinput', 'overviewer_core.items', 'overviewer_core.aux_files.genPOI']}
|
||||||
|
|
||||||
#
|
#
|
||||||
# py2app options
|
# py2app options
|
||||||
@@ -129,7 +129,7 @@ if py2app is not None:
|
|||||||
# script, package, and data
|
# script, package, and data
|
||||||
#
|
#
|
||||||
|
|
||||||
setup_kwargs['packages'] = ['overviewer_core']
|
setup_kwargs['packages'] = ['overviewer_core', 'overviewer_core/aux_files']
|
||||||
setup_kwargs['scripts'] = ['overviewer.py']
|
setup_kwargs['scripts'] = ['overviewer.py']
|
||||||
setup_kwargs['package_data'] = {'overviewer_core': recursive_package_data('data/textures') + recursive_package_data('data/web_assets') + recursive_package_data('data/js_src')}
|
setup_kwargs['package_data'] = {'overviewer_core': recursive_package_data('data/textures') + recursive_package_data('data/web_assets') + recursive_package_data('data/js_src')}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user