Browse Source

save metadata as yaml

Discard minetestmapper numpy output after analyzing and saving relevant
data as YAML. Read YAML in php to get size of map tiles.
master
poikilos 9 years ago
committed by Jacob Gustafson
parent
commit
b818a95926
  1. 1
      README.md
  2. 477
      chunkymap-regen.py
  3. 170
      web/chunkymap.php
  4. 3
      web/index-example.php

1
README.md

@ -57,6 +57,7 @@ This program comes without any warranty, to the extent permitted by applicable l
* edit chunkymap_regen.py and change world_name to your world name * edit chunkymap_regen.py and change world_name to your world name
## Known Issues ## Known Issues
* index-example.php should read the size of the chunks -- see near is_file($chunk_genresult_path) in chunkymap.php
* Show player location (and optionally turn off) * Show player location (and optionally turn off)
* Make a php file that shows the map on an html5 canvas (refresh players every 10 seconds, check for new map chunks every minute) * Make a php file that shows the map on an html5 canvas (refresh players every 10 seconds, check for new map chunks every minute)
* Make players invisible if they stay in one spot too long (consider them logged out by that method alone since not requiring mods) * Make players invisible if they stay in one spot too long (consider them logged out by that method alone since not requiring mods)

477
chunkymap-regen.py

@ -1,6 +1,7 @@
#!/usr/bin/env python2 #!/usr/bin/env python2
import os import os
import subprocess import subprocess
import traceback
# REQUIRES: see README.md # REQUIRES: see README.md
# The way to do a full render is deleting all files from the folder self.chunkymap_data_path such as /var/www/html/minetest/chunkymapdata (or chunkymap in current directory on Windows) # The way to do a full render is deleting all files from the folder self.chunkymap_data_path such as /var/www/html/minetest/chunkymapdata (or chunkymap in current directory on Windows)
@ -15,12 +16,49 @@ import subprocess
class MTChunk: class MTChunk:
x = None x = None
z = None z = None
is_player_here = None is_player_in_this_chunk = None
is_fresh = None is_fresh = None
width = None
height = None
is_marked = None
is_marked_empty = None
image_w = None
image_h = None
image_left = None
image_top = None
image_right = None
image_bottom = None
def __init__(self): def __init__(self):
self.is_player_here = False self.is_player_in_this_chunk = False
self.is_fresh = False self.is_fresh = False
self.is_marked = False
self.is_marked_empty = False
def save_yaml(self, yml_path):
try:
outs = open(yml_path, 'w')
outs.write("is_marked_empty:"+str(self.is_marked_empty)+"\n")
outs.write("is_marked:"+str(self.is_marked)+"\n")
if self.width is not None:
outs.write("width:"+str(self.width)+"\n")
if self.height is not None:
outs.write("height:"+str(self.height)+"\n")
if self.image_w is not None:
outs.write("image_w:"+str(self.image_w)+"\n")
if self.image_h is not None:
outs.write("image_h:"+str(self.image_h)+"\n")
if self.image_left is not None:
outs.write("image_left:"+str(self.image_left)+"\n")
if self.image_top is not None:
outs.write("image_top:"+str(self.image_top)+"\n")
if self.image_right is not None:
outs.write("image_right:"+str(self.image_right)+"\n")
if self.image_bottom is not None:
outs.write("image_bottom:"+str(self.image_bottom)+"\n")
outs.close()
except:
print("Could not finish saving chunk metadata to '"+str(yml_path)+"': "+str(traceback.format_exc()))
class MTChunks: class MTChunks:
@ -44,7 +82,7 @@ class MTChunks:
chunkz_min = 0 chunkz_min = 0
chunkx_max = 0 chunkx_max = 0
chunkz_max = 0 chunkz_max = 0
chunk_size = 80 chunk_size = None
#values for command arguments: #values for command arguments:
maxheight = 50 maxheight = 50
minheight = -25 minheight = -25
@ -53,6 +91,8 @@ class MTChunks:
#total_generated_count = 0 #total_generated_count = 0
#endregion values to save to YAML #endregion values to save to YAML
world_blacklist = None
def __init__(self): #formerly checkpaths() in global scope def __init__(self): #formerly checkpaths() in global scope
self.chunks = {} self.chunks = {}
self.username = "owner" self.username = "owner"
@ -87,25 +127,29 @@ class MTChunks:
self.worlds_path = os.path.join(self.dotminetest_path,"worlds") self.worlds_path = os.path.join(self.dotminetest_path,"worlds")
self.world_path = os.path.join(self.worlds_path, self.world_name) self.world_path = os.path.join(self.worlds_path, self.world_name)
auto_chosen_world = False auto_chosen_world = False
self.world_blacklist = list()
self.world_blacklist.append("abiyahhgamebv7world1")
if not os.path.isdir(self.world_path): if not os.path.isdir(self.world_path):
#for item in os.walk(self.worlds_path): #for item in os.walk(self.worlds_path):
print ("LOOKING FOR WORLDS IN " + self.worlds_path) print ("LOOKING FOR WORLDS IN " + self.worlds_path)
for dirname, dirnames, filenames in os.walk(self.worlds_path): for dirname, dirnames, filenames in os.walk(self.worlds_path):
index = 0 #index = 0
for j in range(0,len(dirnames)): #for j in range(0,len(dirnames)):
i = len(dirnames) - 0 - 1 # i = len(dirnames) - 0 - 1
if dirnames[i][0] == ".": # if dirnames[i][0] == ".":
print (" SKIPPING "+dirnames[i]) # print (" SKIPPING "+dirnames[i])
dirnames.remove_at(i) # dirnames.remove_at(i)
for subdirname in dirnames: for subdirname in dirnames:
print (" EXAMINING "+subdirname) print (" EXAMINING "+subdirname)
if (index == len(dirnames)-1): # skip first one because the one on my computer is big if subdirname[0]!=".":
self.world_name = subdirname #if (index == len(dirnames)-1): # skip first one because the one on my computer is big
self.world_path = os.path.join(dirname, subdirname) # os.path.join(self.worlds_path, "try7amber") if subdirname not in self.world_blacklist:
print (" CHOSE "+self.world_path) self.world_name = subdirname
auto_chosen_world = True self.world_path = os.path.join(dirname, subdirname) # os.path.join(self.worlds_path, "try7amber")
break print (" CHOSE "+self.world_path)
index += 1 auto_chosen_world = True
break
#index += 1
if auto_chosen_world: if auto_chosen_world:
break break
self.python_exe_path = "python" self.python_exe_path = "python"
@ -132,11 +176,82 @@ class MTChunks:
self.chunkx_max = 0 self.chunkx_max = 0
self.chunkz_max = 0 self.chunkz_max = 0
self.chunk_size = 80 self.chunk_size = 16
self.maxheight = 50 self.maxheight = 64
self.minheight = -25 self.minheight = -32
self.pixelspernode = 1 self.pixelspernode = 1
def set_from_genresult(self, mtchunk, chunk_luid):
dest_genresult_path = self.get_chunk_genresult_path(chunk_luid)
result = False
if os.path.isfile(dest_genresult_path):
#may have data such as:
#Result image (w=80 h=80) will be written to chunk_x0z0.png
#Unknown node names: meze:meze default:stone_with_iron air default:dirt_with_snow default:stone_with_copper default:snow
#Unknown node ids: 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7
#Drawing image
#Saving to: chunk_x0z0.png
#('PNG Region: ', [0, 64, 0, 64])
#('Pixels PerNode: ', 1)
#('border: ', 0)
mtchunk.is_marked = True
ins = open(dest_genresult_path, 'r')
line = True
while line:
line = ins.readline()
if line:
line_strip = line.strip()
if "data does not exist" in line_strip:
mtchunk.is_marked_empty = True
break
elif "Result image" in line_strip:
oparen_index = line_strip.find("(")
if (oparen_index>-1):
cparen_index = line_strip.find(")", oparen_index+1)
if (cparen_index>-1):
operations_string = line_strip[oparen_index+1:cparen_index]
operation_list = operations_string.split(" ")
#if len(operation_list)==2:
for operation_string in operation_list:
if "=" in operation_string:
chunks = operation_string.split("=")
if len(chunks)==2:
if chunks[0].strip()=="w":
try:
mtchunk.image_w=int(chunks[1].strip())
except:
print("Bad value for image w:"+str(chunks[1]))
elif chunks[0].strip()=="h":
try:
mtchunk.image_h=int(chunks[1].strip())
except:
print("Bad value for image h:"+str(chunks[1]))
else:
print("Bad name for image variable so ignoring variable named '"+str(chunks[0])+"'")
else:
print("Bad assignment (not 2 sides) so ignoring command '"+operation_string+"'")
else:
print("Bad assignment (operator) so ignoring command '"+operation_string+"'")
#else:
# print("Bad assignment count so ignoring operations string '"+operations_string+"'")
elif "PNG Region" in line_strip:
obracket_index = line_strip.find("[")
if obracket_index>-1:
cbracket_index = line_strip.find("]", obracket_index+1)
if cbracket_index>-1:
rect_values_string = line_strip[obracket_index+1:cbracket_index]
rect_values_list = rect_values_string.split(",")
if len(rect_values_list)==4:
#pngregion=[pngminx, pngmaxx, pngminz, pngmaxz] #from minetestmapper-numpy.py
mtchunk.image_left=int(rect_values_list[0].strip())
mtchunk.image_right=int(rect_values_list[1].strip())
mtchunk.image_top=int(rect_values_list[2].strip())
mtchunk.image_bottom=int(rect_values_list[3].strip())
else:
print("Bad map rect, so ignoring: "+rect_values_string)
ins.close()
def get_dict_from_conf_file(self, path,assignment_operator="="): def get_dict_from_conf_file(self, path,assignment_operator="="):
results = None results = None
print ("Checking "+str(path)+" for settings...") print ("Checking "+str(path)+" for settings...")
@ -196,22 +311,67 @@ class MTChunks:
def get_chunk_genresult_tmp_path(self, chunk_luid): def get_chunk_genresult_tmp_path(self, chunk_luid):
return os.path.join(os.path.dirname(__file__), self.get_chunk_genresult_name(chunk_luid)) return os.path.join(os.path.dirname(__file__), self.get_chunk_genresult_name(chunk_luid))
def get_chunk_yaml_name(self, chunk_luid):
return "chunk_"+chunk_luid+".yml"
def is_chunk_yaml_present(self, chunk_luid):
return os.path.isfile(self.get_chunk_yaml_path(chunk_luid))
def get_chunk_yaml_path(self, chunk_luid):
return os.path.join(self.chunkymap_data_path, self.get_chunk_yaml_name(chunk_luid))
def is_chunk_yaml_marked(self, chunk_luid):
yaml_path = self.get_chunk_yaml_path(chunk_luid)
result = False
if os.path.isfile(yaml_path):
result = True
#ins = open(yaml_path, 'r')
#line = True
#while line:
# line = ins.readline()
# if line:
# line_strip = line.strip()
# if "is_marked_empty:" in line_strip:
# result = True
# break
#ins.close()
return result
def is_chunk_yaml_marked_empty(self, chunk_luid):
yaml_path = self.get_chunk_yaml_path(chunk_luid)
result = False
if os.path.isfile(yaml_path):
ins = open(yaml_path, 'r')
line = True
while line:
line = ins.readline()
if line:
line_strip = line.strip()
prevalue_string="is_marked_empty:"
if line_strip[:len(prevalue_string)]==prevalue_string:
result = bool(line_strip[len(prevalue_string):].strip())
break
ins.close()
return result
def get_chunk_genresult_path(self, chunk_luid): def get_chunk_genresult_path(self, chunk_luid):
return os.path.join(self.chunkymap_data_path, self.get_chunk_genresult_name(chunk_luid)) return os.path.join(self.chunkymap_data_path, self.get_chunk_genresult_name(chunk_luid))
#deprecated
def is_genresult_marked(self, chunk_luid): def is_genresult_marked(self, chunk_luid):
result = False result = False
dest_genresult_path = self.get_chunk_genresult_path(chunk_luid) dest_genresult_path = self.get_chunk_genresult_path(chunk_luid)
#is_empty_chunk = False
if os.path.isfile(dest_genresult_path): if os.path.isfile(dest_genresult_path):
result = True result = True
return result return result
#deprecated
def is_genresult_marked_empty(self, chunk_luid): def is_genresult_marked_empty(self, chunk_luid):
dest_genresult_path = self.get_chunk_genresult_path(chunk_luid) dest_genresult_path = self.get_chunk_genresult_path(chunk_luid)
result = False result = False
if os.path.isfile(dest_genresult_path): if os.path.isfile(dest_genresult_path):
ins = open(dest_genresult_path) ins = open(dest_genresult_path, 'r')
line = True line = True
while line: while line:
line = ins.readline() line = ins.readline()
@ -233,29 +393,29 @@ class MTChunks:
def remove_chunk_image(self, chunk_luid): def remove_chunk_image(self, chunk_luid):
result = False result = False
png_path = self.get_chunk_image_path(chunk_luid) tmp_png_path = self.get_chunk_image_path(chunk_luid)
if os.path.isfile(png_path): if os.path.isfile(tmp_png_path):
result = True result = True
os.remove(png_path) os.remove(tmp_png_path)
return result return result
def remove_chunk(self, chunk_luid): def remove_chunk(self, chunk_luid):
result = False result = False
out_path = self.get_chunk_genresult_path(chunk_luid) out_path = self.get_chunk_genresult_path(chunk_luid)
png_path = self.get_chunk_image_path(chunk_luid) tmp_png_path = self.get_chunk_image_path(chunk_luid)
if os.path.isfile(out_path): if os.path.isfile(out_path):
os.remove(out_path) os.remove(out_path)
result = True result = True
if os.path.isfile(png_path): if os.path.isfile(tmp_png_path):
os.remove(png_path) os.remove(tmp_png_path)
result = True result = True
return result return result
def is_chunk_rendered_on_dest(self, chunk_luid): #formerly is_chunk_empty_on_dest (reversed) def is_chunk_rendered_on_dest(self, chunk_luid): #formerly is_chunk_empty_on_dest (reversed)
is_rendered = False is_rendered = False
#is_chunk_out_empty = self.is_genresult_marked_empty(chunk_luid) #is_chunk_out_empty = self.is_chunk_yaml_marked_empty(chunk_luid)
#dest_genresult_path = self.get_chunk_genresult_path(chunk_luid) #dest_genresult_path = self.get_chunk_genresult_path(chunk_luid)
dest_png_path = self.get_chunk_image_name(chunk_luid) dest_png_path = self.get_chunk_image_path(chunk_luid)
if os.path.isfile(dest_png_path): if os.path.isfile(dest_png_path):
#os.remove(dest_genresult_path) #os.remove(dest_genresult_path)
is_rendered = True is_rendered = True
@ -269,7 +429,7 @@ class MTChunks:
result = False result = False
chunk_luid = self.get_chunk_luid(x,z) chunk_luid = self.get_chunk_luid(x,z)
png_name = self.get_chunk_image_name(chunk_luid) png_name = self.get_chunk_image_name(chunk_luid)
png_path = self.get_chunk_image_tmp_path(chunk_luid) tmp_png_path = self.get_chunk_image_tmp_path(chunk_luid)
cmd_suffix = "" cmd_suffix = ""
genresult_name = self.get_chunk_genresult_name(chunk_luid) genresult_name = self.get_chunk_genresult_name(chunk_luid)
genresult_path = self.get_chunk_genresult_tmp_path(chunk_luid) genresult_path = self.get_chunk_genresult_tmp_path(chunk_luid)
@ -281,13 +441,13 @@ class MTChunks:
z_max = z * self.chunk_size + self.chunk_size - 1 z_max = z * self.chunk_size + self.chunk_size - 1
#print ("generating x = " + str(x_min) + " to " + str(x_max) + " , z = " + str(z_min) + " to " + str(z_max)) #print ("generating x = " + str(x_min) + " to " + str(x_max) + " , z = " + str(z_min) + " to " + str(z_max))
cmd_string = self.python_exe_path + " \""+self.mtmn_path + "\" --region " + str(x_min) + " " + str(x_max) + " " + str(z_min) + " " + str(z_max) + " --maxheight "+str(self.maxheight)+" --minheight "+str(self.minheight)+" --pixelspernode "+str(self.pixelspernode)+" \""+self.world_path+"\" \""+png_path+"\"" + cmd_suffix cmd_string = self.python_exe_path + " \""+self.mtmn_path + "\" --region " + str(x_min) + " " + str(x_max) + " " + str(z_min) + " " + str(z_max) + " --maxheight "+str(self.maxheight)+" --minheight "+str(self.minheight)+" --pixelspernode "+str(self.pixelspernode)+" \""+self.world_path+"\" \""+tmp_png_path+"\"" + cmd_suffix
dest_png_path = self.get_chunk_image_path(chunk_luid) dest_png_path = self.get_chunk_image_path(chunk_luid)
dest_genresult_path = self.get_chunk_genresult_path(chunk_luid) dest_genresult_path = self.get_chunk_genresult_path(chunk_luid)
#is_empty_chunk = is_genresult_marked(chunk_luid) and is_genresult_marked_empty(chunk_luid) #is_empty_chunk = is_chunk_yaml_marked(chunk_luid) and is_chunk_yaml_marked_empty(chunk_luid)
print (cmd_string) print (cmd_string)
subprocess.call(cmd_string, shell=True) # TODO: remember not to allow arbitrary command execution, which could happen if input contains ';' when using shell=True subprocess.call(cmd_string, shell=True) # TODO: remember not to allow arbitrary command execution, which could happen if input contains ';' when using shell=True
if os.path.isfile(png_path): if os.path.isfile(tmp_png_path):
result = True result = True
try: try:
if (os.path.isfile(dest_png_path)): if (os.path.isfile(dest_png_path)):
@ -295,24 +455,34 @@ class MTChunks:
except: except:
print ("Could not finish deleting '"+dest_png_path+"'") print ("Could not finish deleting '"+dest_png_path+"'")
try: try:
os.rename(png_path, dest_png_path) os.rename(tmp_png_path, dest_png_path)
print("(moved to '"+dest_png_path+"')") print("(moved to '"+dest_png_path+"')")
self.prepare_chunk_meta(chunk_luid) self.prepare_chunk_meta(chunk_luid)
self.chunks[chunk_luid].is_fresh = True self.chunks[chunk_luid].is_fresh = True
except: except:
print ("Could not finish moving '"+png_path+"' to '"+dest_png_path+"'") print ("Could not finish moving '"+tmp_png_path+"' to '"+dest_png_path+"'")
try: try:
if (os.path.isfile(dest_genresult_path)): if (os.path.isfile(dest_genresult_path)):
os.remove(dest_genresult_path) os.remove(dest_genresult_path)
if self.is_save_output_ok: if self.is_save_output_ok:
os.rename(genresult_path, dest_genresult_path)
print("(moved to '"+dest_genresult_path+"')") #os.rename(genresult_path, dest_genresult_path)
#print("(moved to '"+dest_genresult_path+"')")
tmp_chunk = MTChunk()
self.set_from_genresult(tmp_chunk,chunk_luid)
chunk_yaml_path = self.get_chunk_yaml_path(chunk_luid)
tmp_chunk.save_yaml(chunk_yaml_path)
print("(saved yaml to '"+chunk_yaml_path+"')")
os.remove(genresult_path)
else: else:
if os.path.isfile(genresult_path): if os.path.isfile(genresult_path):
os.remove(genresult_path) os.remove(genresult_path)
except: except:
print ("Could not finish deleting/moving output") print ("Could not finish deleting/moving output")
return result return result
def check_players(self): def check_players(self):
@ -325,64 +495,81 @@ class MTChunks:
if not os.path.isfile(htaccess_path): if not os.path.isfile(htaccess_path):
self.deny_http_access(chunkymap_players_path) self.deny_http_access(chunkymap_players_path)
players_path = os.path.join(self.world_path, "players") players_path = os.path.join(self.world_path, "players")
for dirname, dirnames, filenames in os.walk(players_path): player_count = 0
for filename in filenames: player_written_count = 0
file_fullname = os.path.join(players_path,filename) for dirname, dirnames, filenames in os.walk(players_path):
#print (" EXAMINING "+filename) for filename in filenames:
badstart_string = "." file_fullname = os.path.join(players_path,filename)
player_name = None #print (" EXAMINING "+filename)
player_position = None badstart_string = "."
if (filename[:len(badstart_string)]!=badstart_string): player_name = None
ins = open(file_fullname) player_position = None
line = True if (filename[:len(badstart_string)]!=badstart_string):
has_enough_data = False ins = open(file_fullname, 'r')
while line: line = True
line = ins.readline() is_enough_data = False
if line: while line:
ao_index = line.find("=") line = ins.readline()
if ao_index > 0: if line:
found_name = line[:ao_index].strip() ao_index = line.find("=")
found_value = line[ao_index+1:].strip() if ao_index > 0:
if found_name=="name": found_name = line[:ao_index].strip()
player_name = found_value found_value = line[ao_index+1:].strip()
elif found_name=="position": if found_name=="name":
player_position = found_value player_name = found_value
elif found_name=="position":
if (player_name is not None) and (player_position is not None): player_position = found_value
has_enough_data = True
break if (player_name is not None) and (player_position is not None):
ins.close() is_enough_data = True
player_dest_path = os.path.join(chunkymap_players_path,filename+".yml") break
ins.close()
player_dest_path = os.path.join(chunkymap_players_path,filename+".yml")
if player_position is not None:
# mark chunk
tuple_noparen_pos_string = player_position.strip("() \n\r")
pos_strings = tuple_noparen_pos_string.split(",")
if len(pos_strings) == 3:
player_x = None
player_y = None
player_z = None
try:
player_x = float(pos_strings[0])
player_y = float(pos_strings[1])
player_z = float(pos_strings[2])
except:
player_x = int(pos_strings[0])
player_y = int(pos_strings[1])
player_z = int(pos_strings[2])
chunk_x = int((float(player_x)/self.chunk_size))
chunk_y = int((float(player_y)/self.chunk_size))
chunk_z = int((float(player_z)/self.chunk_size))
chunk_luid = self.get_chunk_luid(chunk_x, chunk_z)
self.prepare_chunk_meta(chunk_luid)
self.chunks[chunk_luid].is_player_in_this_chunk = True
else:
print("Player '"+filename+"' has bad position data--should be 3-length (x,y,z) in position value: "+str(pos_strings))
#if is_enough_data:
#if player_name!="singleplayer":
map_player_dict = self.get_dict_from_conf_file(player_dest_path,":")
if (map_player_dict is None) or (map_player_dict["position"]!=player_position):
outs = open(player_dest_path, 'w')
if player_name is not None:
outs.write("name:"+player_name+"\n") # python automatically uses correct newline for your os when you put "\n"
if player_position is not None: if player_position is not None:
# mark chunk outs.write("position:"+player_position+"\n")
tuple_noparen_pos_string = player_position.strip("() \n\r") outs.write("is_enough_data:"+str(is_enough_data))
pos_strings = tuple_noparen_pos_string.split(",") outs.close()
if len(pos_strings) == 3: player_written_count += 1
player_x = int(pos_strings[player_x]) player_count += 1
player_y = int(pos_strings[player_y])
player_z = int(pos_strings[player_z])
chunk_x = int((float(player_x)/self.chunk_size))
chunk_y = int((float(player_y)/self.chunk_size))
chunk_z = int((float(player_z)/self.chunk_size))
chunk_luid = self.get_chunk_luid(chunk_x, chunk_z)
self.prepare_chunk_meta()
self.chunks[chunk_luid].is_player_here = True
else:
print("Player '"+filename+"' has bad position data--should be 3-length (x,y,z) in position value: "+str(pos_strings))
if has_enough_data:
#if player_name!="singleplayer":
map_player_dict = self.get_dict_from_conf_file(player_dest_path,":")
if (map_player_dict is None) or (map_player_dict["position"]!=player_position):
outs = open(player_dest_path, 'w')
outs.write("name:"+player_name+"\n") # python automatically uses correct newline for your os when you put "\n"
outs.write("position:"+player_position+"\n")
outs.close()
def is_player_at_luid(self, chunk_luid): def is_player_at_luid(self, chunk_luid):
result = False result = False
if chunk_luid in self.chunks.keys(): if chunk_luid in self.chunks.keys():
result = self.chunks[chunk_luid].is_player_here result = self.chunks[chunk_luid].is_player_in_this_chunk
return result return result
def is_chunk_fresh(self, chunk_luid): def is_chunk_fresh(self, chunk_luid):
@ -396,7 +583,7 @@ class MTChunks:
self.check_players() self.check_players()
self.chunkymap_data_path=os.path.join(self.website_root,"chunkymapdata") self.chunkymap_data_path=os.path.join(self.website_root,"chunkymapdata")
yaml_name = "generated.yml" yaml_name = "generated.yml"
yaml_path = os.path.join(self.chunkymap_data_path, yaml_name) world_yaml_path = os.path.join(self.chunkymap_data_path, yaml_name)
if not os.path.isdir(self.chunkymap_data_path): if not os.path.isdir(self.chunkymap_data_path):
os.mkdir(self.chunkymap_data_path) os.mkdir(self.chunkymap_data_path)
@ -406,29 +593,42 @@ class MTChunks:
if not os.path.isfile(htaccess_path): if not os.path.isfile(htaccess_path):
self.deny_http_access(self.chunkymap_data_path) self.deny_http_access(self.chunkymap_data_path)
mapvars = self.get_dict_from_conf_file(yaml_path,":") mapvars = self.get_dict_from_conf_file(world_yaml_path,":")
#is_testonly == (os_name=="windows") #is_testonly == (os_name=="windows")
if mapvars is not None and set(['self.world_name']).issubset(mapvars): if mapvars is not None and set(['world_name']).issubset(mapvars):
#print (" (FOUND self.world_name)") #print (" (FOUND self.world_name)")
if mapvars["self.world_name"] != self.world_name: if mapvars["world_name"] != self.world_name:
print ("REMOVING data since from different world (map '"+str(mapvars["self.world_name"])+"' is not '"+str(self.world_name)+"')...") print ("REMOVING data since from different world (map '"+str(mapvars["world_name"])+"' is not '"+str(self.world_name)+"')...")
for dirname, dirnames, filenames in os.walk(self.chunkymap_data_path): for dirname, dirnames, filenames in os.walk(self.chunkymap_data_path):
index = 0 #index = 0
for j in range(0,len(filenames)): #for j in range(0,len(filenames)):
i = len(filenames) - 0 - 1 # i = len(filenames) - 0 - 1
if filenames[i][0] == ".": # if filenames[i][0] == ".":
print (" SKIPPING "+filenames[i]) # print (" SKIPPING "+filenames[i])
filenames.remove_at(i) # filenames.remove_at(i)
for filename in filenames: for filename in filenames:
file_fullname = os.path.join(self.chunkymap_data_path,filename) if filename[0] != ".":
print (" EXAMINING "+filename) file_fullname = os.path.join(self.chunkymap_data_path,filename)
badstart_string = "chunk" print (" EXAMINING "+filename)
if (len(filename) >= len(badstart_string)) and (filename[:len(badstart_string)]==badstart_string): badstart_string = "chunk"
os.remove(file_fullname) if (len(filename) >= len(badstart_string)) and (filename[:len(badstart_string)]==badstart_string):
elif filename==yaml_name: os.remove(file_fullname)
os.remove(file_fullname) elif filename==yaml_name:
os.remove(file_fullname)
for dirname, dirnames, filenames in os.walk(os.path.join(self.chunkymap_data_path, "players")):
#for j in range(0,len(filenames)):
# i = len(filenames) - 0 - 1
# if filenames[i][0] == ".":
# print (" SKIPPING "+filenames[i])
# filenames.remove_at(i)
for filename in filenames:
if filename[0] != ".":
file_fullname = os.path.join(self.chunkymap_data_path,filename)
print (" EXAMINING "+filename)
badend_string = ".yml"
if (len(filename) >= len(badend_string)) and (filename[len(filename)-len(badend_string):]==badend_string):
os.remove(file_fullname)
self.chunkx_min = 0 self.chunkx_min = 0
self.chunkz_min = 0 self.chunkz_min = 0
self.chunkx_max = 0 self.chunkx_max = 0
@ -437,6 +637,12 @@ class MTChunks:
newchunk_luid_list = list() newchunk_luid_list = list()
outline_generates_count = 1 outline_generates_count = 1
is_changed = False
is_different_world = False
#if str(self.world_name) != str(mapvars["world_name"]):
# is_different_world = True
# print("FULL RENDER since chosen world name '"+self.world_name+"' does not match previously rendered world name '"+mapvars["world_name"]+"'")
while outline_generates_count > 0: while outline_generates_count > 0:
outline_generates_count = 0 outline_generates_count = 0
for z in range (self.chunkz_min,self.chunkz_max+1): for z in range (self.chunkz_min,self.chunkz_max+1):
@ -449,32 +655,44 @@ class MTChunks:
if is_outline: if is_outline:
chunk_luid = self.get_chunk_luid(x,z) chunk_luid = self.get_chunk_luid(x,z)
is_player_here = self.is_player_at_luid(chunk_luid) #if (is_different_world): #instead, see above where all chunk files and player files are deleted
# self.remove_chunk(chunk_luid)
is_player_in_this_chunk = self.is_player_at_luid(chunk_luid)
is_render_needed = False is_render_needed = False
if not self.is_chunk_fresh(chunk_luid): if not self.is_chunk_fresh(chunk_luid):
if is_player_here: if is_player_in_this_chunk:
if self.is_genresult_marked(chunk_luid): if self.is_chunk_yaml_marked(chunk_luid):
if self.is_genresult_marked_empty(chunk_luid): if self.is_chunk_yaml_marked_empty(chunk_luid):
is_render_needed = True is_render_needed = True
print (chunk_luid+": RENDERING non-fresh marked empty chunk (player present in it)") print (chunk_luid+": RENDERING nonfresh previously marked empty (player in it)")
else: else:
print (chunk_luid+": SKIPPING non-fresh marked chunk (player present in it)") print (chunk_luid+": SKIPPING nonfresh previously marked (player in it)")
else: else:
is_render_needed = True is_render_needed = True
print (chunk_luid+": RENDERING non-fresh unmarked chunk (player present in it)") print (chunk_luid+": RENDERING nonfresh unmarked (player in it)")
else: else:
if (not self.is_genresult_marked(chunk_luid)): if (not self.is_chunk_yaml_marked(chunk_luid)):
is_render_needed = True is_render_needed = True
print (chunk_luid+": RENDERING non-fresh unmarked chunk (skipped other checks since player not present in it)") print (chunk_luid+": RENDERING nonfresh unmarked (simple check since has no player)")
else: else:
print (chunk_luid+": SKIPPING non-fresh marked chunk (skipped other checks since player not present in it)") print (chunk_luid+": SKIPPING nonfresh previously marked (simple check since has no player)")
else: else:
print (chunk_luid+": SKIPPING fresh chunk") print (chunk_luid+": SKIPPING fresh chunk")
#if (not self.is_genresult_marked(chunk_luid)): #if (not self.is_chunk_yaml_marked(chunk_luid)):
#is_render_needed = True #is_render_needed = True
# This should never happen since keeping the output of minetestmapper-numpy.py (after analyzing that output) is deprecated:
#if self.is_genresult_marked(chunk_luid) and not self.is_chunk_yaml_present(chunk_luid):
# tmp_chunk = MTChunk()
# self.set_from_genresult(tmp_chunk,chunk_luid)
# chunk_yaml_path = self.get_chunk_yaml_path(chunk_luid)
# tmp_chunk.save_yaml(chunk_yaml_path)
# print("(saved yaml to '"+chunk_yaml_path+"')")
if is_render_needed: if is_render_needed:
if (self.render_chunk(x,z)): if (self.render_chunk(x,z)):
total_generated_count += 1 total_generated_count += 1
@ -483,10 +701,12 @@ class MTChunks:
if self.is_chunk_rendered_on_dest(chunk_luid): if self.is_chunk_rendered_on_dest(chunk_luid):
total_generated_count += 1 total_generated_count += 1
outline_generates_count += 1 outline_generates_count += 1
png_path = self.get_chunk_image_path(chunk_luid) tmp_png_path = self.get_chunk_image_path(chunk_luid)
print(chunk_luid+": Skipping existing map tile file " + png_path + " (delete it to re-render)") print(chunk_luid+": Skipping existing map tile file " + tmp_png_path + " (delete it to re-render)")
#elif is_empty_chunk: #elif is_empty_chunk:
#print("Skipping empty chunk " + chunk_luid) #print("Skipping empty chunk " + chunk_luid)
#else:
#print(chunk_luid+": Not rendered on dest.")
print ("") # blank line before next z so output is more readable print ("") # blank line before next z so output is more readable
self.chunkx_min -= 1 self.chunkx_min -= 1
self.chunkz_min -= 1 self.chunkz_min -= 1
@ -506,22 +726,21 @@ class MTChunks:
new_map_dict["world_path"]=str(self.world_path) new_map_dict["world_path"]=str(self.world_path)
new_map_dict["chunkymap_data_path"]=str(self.chunkymap_data_path) new_map_dict["chunkymap_data_path"]=str(self.chunkymap_data_path)
new_map_dict["total_generated_count"]=str(total_generated_count) new_map_dict["total_generated_count"]=str(total_generated_count)
is_changed = False
if mapvars is None: if mapvars is None:
print ("SAVING '" + yaml_path + "' since nothing was loaded or it did not exist") print ("SAVING '" + world_yaml_path + "' since nothing was loaded or it did not exist")
is_changed = True is_changed = True
else: else:
for this_key in new_map_dict.iterkeys(): for this_key in new_map_dict.iterkeys():
if (this_key not in mapvars.keys()): if (this_key not in mapvars.keys()):
is_changed = True is_changed = True
print ("SAVING '" + yaml_path + "' since " + str(this_key) + " not in mapvars") print ("SAVING '" + world_yaml_path + "' since " + str(this_key) + " not in mapvars")
break break
elif (str(mapvars[this_key]) != str(new_map_dict[this_key])): elif (str(mapvars[this_key]) != str(new_map_dict[this_key])):
is_changed = True is_changed = True
print ("SAVING '" + yaml_path + "' since new " + this_key + " value " + str(mapvars[this_key]) + " not same as saved value " + str(mapvars[this_key]) + "") print ("SAVING '" + world_yaml_path + "' since new " + this_key + " value " + str(new_map_dict[this_key]) + " not same as saved value " + str(mapvars[this_key]) + "")
break break
if is_changed: if is_changed:
outs = open(yaml_path, 'w') outs = open(world_yaml_path, 'w')
outs.write("world_name:"+str(self.world_name) + "\n") outs.write("world_name:"+str(self.world_name) + "\n")
outs.write("chunk_size:"+str(self.chunk_size) + "\n") outs.write("chunk_size:"+str(self.chunk_size) + "\n")
outs.write("pixelspernode:"+str(self.pixelspernode) + "\n") outs.write("pixelspernode:"+str(self.pixelspernode) + "\n")
@ -538,7 +757,7 @@ class MTChunks:
outs.write("total_generated_count:"+str(total_generated_count) + "\n") outs.write("total_generated_count:"+str(total_generated_count) + "\n")
outs.close() outs.close()
else: else:
print ("(Not saving '"+yaml_path+"' since same value of each current variable is already in file as loaded)") print ("(Not saving '"+world_yaml_path+"' since same value of each current variable is already in file as loaded)")
else: else:
print ("failed since this folder must contain colors.txt and minetestmapper-numpy.py") print ("failed since this folder must contain colors.txt and minetestmapper-numpy.py")

170
web/chunkymap.php

@ -2,6 +2,7 @@
ini_set('display_errors', 1); ini_set('display_errors', 1);
ini_set('display_startup_errors', 1); ini_set('display_startup_errors', 1);
error_reporting(E_ALL); error_reporting(E_ALL);
//NOTE: for parse errors, MUST add the following line to php.ini (such as /etc/php5/apache2/php.ini): display_errors = on //NOTE: for parse errors, MUST add the following line to php.ini (such as /etc/php5/apache2/php.ini): display_errors = on
if (is_file('browser.php')) { if (is_file('browser.php')) {
include_once('browser.php'); include_once('browser.php');
@ -259,6 +260,65 @@ function echo_chunkymap_table() {
$chunkz_min = 0; $chunkz_min = 0;
$chunkx_max = 0; $chunkx_max = 0;
$chunkz_max = 0; $chunkz_max = 0;
global $showplayers;
$players = array();
$player_count = 0;
if ($showplayers==true) {
$chunkymap_players_path = $chunkymapdata_path."/players";
if ($handle = opendir($chunkymap_players_path)) {
while (false !== ($file = readdir($handle))) {
if (substr($file, 0, 1) != ".") {
$file_lower = strtolower($file);
if (endsWith($file_lower, ".yml")) {
$player_id=substr($file,0,strlen($file)-4); //-4 for .yml
$file_path = $chunkymap_players_path."/".$file;
$player_dict = get_dict_from_conf($file_path);
$player_dict["id"]=$player_id;
//$players[$player_count]=get_dict_from_conf($file_path);
//$players[$player_count]["id"]=$player_id;
if (isset($player_dict["position"])) {
$tuple_string=trim($player_dict["position"]);
if ( startsWith($tuple_string, "(") and endsWith($tuple_string, ")") ) {
$tuple_string=substr($tuple_string,1,strlen($tuple_string)-2);
}
$coordinates = explode(",", $tuple_string);
if (count($coordinates)==3) {
$chunk_luid = "x".$x."z".$z;
if (!isset($chunk_assoc[$chunk_luid])) {
$chunk_assoc[$chunk_luid] = array();
}
if (!isset($chunk_assoc[$chunk_luid]["players"])) {
$chunk_assoc[$chunk_luid]["players"] = array();
}
if (!isset($chunk_assoc[$chunk_luid]["players_count"])) {
$chunk_assoc[$chunk_luid]["players_count"] = 0;
}
if (isset($player_dict["name"])) {
$chunk_assoc[$chunk_luid][ "players" ][ $chunk_assoc[$chunk_luid]["players_count"] ][ "name" ] = $player_dict["name"]
}
else {
$chunk_assoc[$chunk_luid][ "players" ][ $chunk_assoc[$chunk_luid]["players_count"] ][ "name" ] = $player_dict["id"]
}
$chunk_assoc[$chunk_luid]["players_count"] += 1;
}
else {
echo_error("Bad coordinates $tuple_string for player.");
}
}
//$player_count++;
}
}
}
}
}
if (isset($chunk_assoc[$chunk_luid]["players_count"])) {
$nonprivate_name_beginning_char_count = 2;
for ($player_count=0; $player_count<$chunk_assoc[$chunk_luid]["players_count"]; $player_count++) {
//echo "<div >".substr($chunk_assoc[$chunk_luid]["players"][$player_count]["name"], 0, $nonprivate_name_beginning_char_count)."</div>";
}
}
//if ($map_dict != null) { //if ($map_dict != null) {
// $chunkx_min = $map_dict["chunkx_min"]; // $chunkx_min = $map_dict["chunkx_min"];
// $chunkz_min = $map_dict["chunkz_min"]; // $chunkz_min = $map_dict["chunkz_min"];
@ -281,7 +341,10 @@ function echo_chunkymap_table() {
$z = substr($file_lower, $z_opener_index + strlen($z_opener), $z_len); $z = substr($file_lower, $z_opener_index + strlen($z_opener), $z_len);
if (is_int_string($x) and is_int_string($z)) { if (is_int_string($x) and is_int_string($z)) {
$chunk_luid = "x".$x."z".$z; $chunk_luid = "x".$x."z".$z;
$chunk_assoc[$chunk_luid] = true; if (!isset($chunk_assoc[$chunk_luid])) {
$chunk_assoc[$chunk_luid] = array();
}
$chunk_assoc[$chunk_luid]["is_rendered"] = true;
if ($is_verbose) echo "$chunk_luid,"; if ($is_verbose) echo "$chunk_luid,";
if ($x<$chunkx_min) { if ($x<$chunkx_min) {
$chunkx_min=(int)$x; $chunkx_min=(int)$x;
@ -320,22 +383,123 @@ function echo_chunkymap_table() {
$scale=(float)$chunkymap_view_zoom_multiplier; // no longer /100 $scale=(float)$chunkymap_view_zoom_multiplier; // no longer /100
$zoomed_w=(int)((float)$chunkymap_tile_original_w*$scale+.5); $zoomed_w=(int)((float)$chunkymap_tile_original_w*$scale+.5);
$zoomed_h=(int)((float)$chunkymap_tile_original_h*$scale+.5); $zoomed_h=(int)((float)$chunkymap_tile_original_h*$scale+.5);
$genresult_suffix_then_dot_then_ext="_mapper_result.txt";
$dot_yaml=".yml";
while ($z >= $chunkz_min) { while ($z >= $chunkz_min) {
echo_hold( " <tr>\r\n"); echo_hold( " <tr>\r\n");
$x = (int)$chunkx_min; $x = (int)$chunkx_min;
while ($x <= $chunkx_max) { while ($x <= $chunkx_max) {
echo_hold( " <td width=\"1\" style=\"padding:0px; background-color:lightgray\">"); $this_zoomed_w = $zoomed_w;
$this_zoomed_h = $zoomed_h;
$chunk_yaml_name = $x_opener.$x.$z_opener.$z.$dot_yaml;
$chunk_yaml_path = $chunkymapdata_path.'/'.$chunk_yaml_name;
//$chunk_genresult_name = $x_opener.$x.$z_opener.$z.$genresult_suffix_then_dot_then_ext;
//$chunk_genresult_path = $chunkymapdata_path.'/'.$chunk_img_name;
$td_style_suffix="";
$element_align_style_suffix="";
$alignment_comment="";
//if (is_file($chunk_genresult_path)) {
// contains lines such as:
// Result image (w=80 h=64) will be written to chunk_x0z1.png
// ('PNG Region: ', [0, 64, 80, 128])
// ('Pixels PerNode: ', 1)
// where PNG Region's list value is an exclusive rect ordered as x1, y1, x2, y2
//$found_original_w = null;
//$found_original_h = null;
//$this_zoomed_w=(int)((float)$found_original_w*$scale+.5);
//this_zoomed_h=(int)((float)$found_original_h*$scale+.5);
//}
if (is_file($chunk_yaml_path)) {
// contains lines such as:
//is_marked_empty:False
//is_marked:True
//image_w:80
//image_h:80
//image_left:0
//image_top:64
//image_right:-80
//image_bottom:-16
// where if is_marked_empty, the remaining values don't exist
$expected_left = (int)$x * (int)$chunkymap_tile_original_w;
$expected_top = (int)$z * (int)$chunkymap_tile_original_h;
$expected_right = (int)$x + (int)$chunkymap_tile_original_w;
$expected_bottom = (int)$z + (int)$chunkymap_tile_original_h;
$chunk_dict = get_dict_from_conf($chunk_yaml_path,":");
if (isset($chunk_dict["image_w"])) {
$this_zoomed_w=(int)((float)$chunk_dict["image_w"]*$scale+.5);
}
if (isset($chunk_dict["image_h"])) {
$this_zoomed_h=(int)((float)$chunk_dict["image_h"]*$scale+.5);
}
//TODO: use image_* to determine (if the doesn't touch certain sides of image_w x image_h rect, change the following accordingly)
if (isset($chunk_dict["image_left"])) {
if (isset($chunk_dict["image_right"])) {
if ( (int)$chunk_dict["image_left"] > $expected_left ) {
$td_style_suffix.="text-align:right;";
$alignment_comment.="<!-- image_left:".$chunk_dict["image_left"]." is greater than expected $expected_left-->";
}
//elseif ( (int)$chunk_dict["image_right"] < $expected_right ) {
// $td_style_suffix.="text-align:left;";
//}
else {
$td_style_suffix.="text-align:left;";
$alignment_comment.="<!-- image_left:".$chunk_dict["image_left"]." was the expected $expected_left-->";
}
}
}
//if (isset($chunk_dict["image_right"])) {
// if ( (int)$chunk_dict["image_right"] != $expected_right ) {
// $td_style_suffix.="text-align:left;";
// }
// //else {
// // $td_style_suffix.="text-align:left;";
// //}
//}
if (isset($chunk_dict["image_top"])) {
if (isset($chunk_dict["image_bottom"])) {
if ( (int)$chunk_dict["image_top"] > $expected_top) {
$element_align_style_suffix.="vertical-align:bottom;";
$alignment_comment.="<!-- image_top:".$chunk_dict["image_top"]." is greater than expected $expected_top-->";
}
//elseif ( (int)$chunk_dict["image_bottom"] < $expected_bottom) {
// $element_align_style_suffix.="vertical-align:top;";
//}
else {
$element_align_style_suffix.="vertical-align:top;";
$alignment_comment.="<!-- image_top:".$chunk_dict["image_top"]." was the expected $expected_top-->";
}
}
}
//if (isset($chunk_dict["image_bottom"])) {
// if ( (int)$chunk_dict["image_bottom"] != $expected_bottom) {
// $element_align_style_suffix.="vertical-align:top;";
// }
// //else {
// // $element_align_style_suffix.="vertical-align:bottom;";
// //}
//}
//$element_align_style_suffix.="vertical-align:left;";
}
echo_hold( " <td width=\"1\" style=\"padding:0px; background-color:lightgray; $td_style_suffix $element_align_style_suffix\">");
$chunk_luid = "x".$x."z".$z; $chunk_luid = "x".$x."z".$z;
$chunk_img_name = $x_opener.$x.$z_opener.$z."$dot_and_ext"; $chunk_img_name = $x_opener.$x.$z_opener.$z."$dot_and_ext";
$chunk_img_path = $chunkymapdata_path.'/'.$chunk_img_name; $chunk_img_path = $chunkymapdata_path.'/'.$chunk_img_name;
if (is_file($chunk_img_path)) { if (is_file($chunk_img_path)) {
echo_hold( "<img style=\"width:$zoomed_w; height:$zoomed_h\" class=\"maptileimg\" src=\"$chunk_img_path\""); echo_hold( "<img class=\"maptileimg\" style=\"width:$this_zoomed_w; height:$this_zoomed_h;\" src=\"$chunk_img_path\"/>");
} }
else { else {
//echo_hold( "<span style=\"font-size:1px\">&nbsp;</span>"); //echo_hold( "<span style=\"font-size:1px\">&nbsp;</span>");
} }
//echo " <br/>".$x.",0,".$z; //echo " <br/>".$x.",0,".$z;
echo_hold($alignment_comment);
echo_hold( "</td>\r\n"); echo_hold( "</td>\r\n");
$x++; $x++;
} }

3
web/index-example.php

@ -2,6 +2,9 @@
<title>Chunkymap Example Page</title> <title>Chunkymap Example Page</title>
<body style="font-family:calibri,sans"> <body style="font-family:calibri,sans">
<?php <?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
//echo "php started..."; //echo "php started...";
if (is_file('chunkymap.php')) { if (is_file('chunkymap.php')) {
//echo "including..."; //echo "including...";

Loading…
Cancel
Save