Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import argparse
- import struct
- import gzip
- import os
- import json
- import math
- # == Command line options ==
- parser = argparse.ArgumentParser(
- description='Convert NBT file to Fort Sizes',
- formatter_class=argparse.RawTextHelpFormatter
- )
- parser.add_argument('files', nargs=1, metavar='FILE',
- help='Specifies file to be processed.')
- parser.add_argument('outFile', nargs=1, metavar='OUTFILE',
- help='Specifies file to output to.')
- args = parser.parse_args()
- if len(args.files) < 1:
- exit("Please specify at least one file!")
- # == Necessary information for the parser ==
- # Enum containing all known Tag-types.
- class Tag:
- END = 0
- BYTE = 1
- SHORT = 2
- INT = 3
- LONG = 4
- FLOAT = 5
- DOUBLE = 6
- BYTE_ARRAY = 7
- STRING = 8
- LIST = 9
- COMPOUND = 10
- INT_ARRAY = 11
- # == Generic parsing functions ==
- def read_tag_start(f, assume_unnamed):
- """
- Parses a tag start (i.e. the beginning of a tag).
- * `f` -- The file object from which the tag should be read
- * `assume_unnamed` -- This flag should be set if we know that the tag which we are
- about to read is unnamed (see specs for more information)
- """
- tag_type = f.read(1)
- if len(tag_type) < 1:
- return { 'type': Tag.END, 'name_length': 0 }
- else:
- tag_type = struct.unpack('>B', tag_type)[0]
- if assume_unnamed or tag_type == Tag.END:
- return { 'type': tag_type, 'name_length': 0 }
- name_length = struct.unpack('>H', f.read(2))[0]
- return { 'type': tag_type, 'name_length': name_length }
- def read_tag_name(f, tag):
- """
- Get a tag's name from the file currently being read.
- * `f` -- The file being read
- * `tag` -- Tag information as extracted by `#read_tag_start
- """
- if(tag['name_length'] < 1):
- return ''
- return f.read(tag['name_length'])
- # == Tag type related functions ==
- # Note that these functions do not read a tag's header, but only its payload! The tag header
- # is read by `#read_tag_start`.
- def read_tag_type_string(f):
- """
- Expected string tag format:
- TAG_Short length
- <"length" bytes of ASCII characters>
- """
- length = struct.unpack('>H', f.read(2))[0]
- return f.read(length)
- def read_tag_type_list(f):
- """
- Expected list tag format:
- TAG_Byte tag_id
- TAG_Short length
- <"length" unnamed tags of type "tag_id">
- """
- tag_id = tag_functions[Tag.BYTE](f)
- length = tag_functions[Tag.INT](f)
- list = [ ]
- for i in range(0, length):
- list.append(tag_functions[tag_id](f))
- return list
- def read_tag_type_byte_array(f):
- """
- Expected byte array format:
- TAG_Int length
- <"length" bytes>
- """
- length = tag_functions[Tag.INT](f)
- list = [ ]
- for i in range(0, length):
- list.append(tag_functions[Tag.BYTE](f))
- return list
- def read_tag_type_int_array(f):
- """
- Expected int array format:
- TAG_Int length
- <"length" bytes>
- """
- length = tag_functions[Tag.INT](f)
- list = [ ]
- for i in range(0, length):
- list.append(tag_functions[Tag.INT](f))
- return list
- def read_tag_type_compound(f, assume_unnamed=False):
- """
- Expected compound tag format: a number of named tags until a Tag_END is found, i.e.:
- <named_tag_1..named_tag_N>
- TAG_end
- """
- current = { }
- while(True):
- tag = read_tag_start(f, assume_unnamed)
- name = read_tag_name(f, tag)
- if tag['type'] == Tag.COMPOUND:
- current[name] = tag_functions[tag['type']](f)
- elif tag['type'] == Tag.END:
- break
- else:
- current[name] = tag_functions[tag['type']](f)
- return current
- # def section(h, r=1):
- # return math.sqrt(r*r-h*h) if h < r else 0
- #
- # def g(x, h, r=1):
- # x = float(x)
- # return 0.5*(math.sqrt(1-x*x/(r*r))*x*r+r*r*math.asin(x/r)-2*h*x)
- #
- # def area(*args):
- # x0 = args[0]
- # x1 = args[1]
- # if len(args) == 4:
- # h = args[2]
- # r = args[3]
- # if x0 > x1:
- # x0,x1 = x1,x0
- # s = section(h, r)
- # return g(max(-s, min(s, x1)), h, r)-g(max(-s,min(s,x0)),h,r)
- # elif len(args) == 5:
- # y0 = args[2]
- # y1 = args[3]
- # r = args[4]
- # if y0 > y1:
- # y0,y1 = y1,y0
- # if y0 < 0:
- # if y1 < 0:
- # return area(x0, x1, -y0, -y1, r)
- # else:
- # return area(x0, x1, 0, -y0, r)+area(x0, x1, 0, y1, r)
- # else:
- # return area(x0, x1, y0, r)-area(x0, x1, y1, r)
- # elif len(args) == 7:
- # y0 = args[2]-args[5]
- # y1 = args[3]-args[5]
- # x0 -= args[4]
- # x1 -= args[4]
- # r = args[6]
- # return area(x0, x1, y0, y1, r)
- #
- #
- # def RectIntersect(a, b): # returns None if rectangles don't intersect RECT: [x0, x1, z0, z1]
- # Rect = [max(a[0],b[0]), min(a[1],b[1]), max(a[2],b[2]), min(a[3],b[3])]
- # return Rect if Rect[0] < Rect[1] and Rect[2] < Rect[3] else None
- #
- # def RectArea(Rect):
- # return (Rect[1]-Rect[0])*(Rect[3]-Rect[2]) if Rect is not None else 0
- # === Tag functions object ===
- # This object contains functions to parse all known tag types, accessible by `tag id`.
- # If you're not familiar with this idiom: it is used in a similar fashion to `switch`-statements
- # in other languages ([Stackoverflow](http://stackoverflow.com/questions/374239/why-doesnt-python-have-a-switch-statement))
- tag_functions = {
- Tag.END: lambda f: struct.unpack('>B', f.read(1))[0],
- Tag.BYTE: lambda f: struct.unpack('>B', f.read(1))[0],
- Tag.SHORT: lambda f: struct.unpack('>h', f.read(2))[0],
- Tag.INT: lambda f: struct.unpack('>i', f.read(4))[0],
- Tag.LONG: lambda f: struct.unpack('>q', f.read(8))[0],
- Tag.FLOAT: lambda f: struct.unpack('>f', f.read(4))[0],
- Tag.DOUBLE: lambda f: struct.unpack('>d', f.read(8))[0],
- Tag.BYTE_ARRAY: read_tag_type_byte_array,
- Tag.STRING: read_tag_type_string,
- Tag.LIST: read_tag_type_list,
- Tag.COMPOUND: read_tag_type_compound,
- Tag.INT_ARRAY: read_tag_type_int_array
- }
- # ---
- # ==== Invoke the parser ====
- #f = gzip.GzipFile(os.path.join(args.files[0], "data/Fortress.dat"), 'rb')
- f = gzip.GzipFile(args.files[0], 'rb')
- arr = tag_functions[Tag.COMPOUND](f)["Schematic"]
- with open(args.outFile[0], "w") as f:
- for y in range(0, arr["Height"]):
- for z in range(0, arr["Length"]):
- for x in range(0, arr["Width"]):
- i = (y*arr["Length"]+z)*arr["Width"]+x
- f.write("{},{},{},{},{}\n".format(x, y, z, arr["Blocks"][i], arr["Data"][i]))
- #maximum = max((Fort["BB"][3]-Fort["BB"][0])*(Fort["BB"][5]-Fort["BB"][2]) for Fort in x[""]["data"]["Features"].values())
- #
- #for Fort in x[""]["data"]["Features"].values():
- # if (Fort["BB"][3]-Fort["BB"][0])*(Fort["BB"][5]-Fort["BB"][2]) == maximum:
- # print(str(Fort["ChunkX"]) + "/" + str(Fort["ChunkZ"]) + ": " + str((Fort["BB"][3]-Fort["BB"][0])*(Fort["BB"][5]-Fort["BB"][2])))
- # maximum = 0
- # Intersections = []
- # Fortresses = []
- # maxdiff = 0
- #
- # for Fortress in x1[""]["data"]["Features"].values():
- # Fortresses.append([Fortress["BB"][:3], Fortress["BB"][3:]])
- #
- # for Fort in Fortresses:
- # if Fort[0][1] == 48:
- # height = Fort[1][1]-Fort[0][1]
- # if height > maxdiff:
- # minsize = min(Fort[1][0]-Fort[0][0], Fort[1][2]-Fort[0][2])/2
- # radius = math.sqrt(height*(256-height))
- # if radius < minsize:
- # print "Fortress: " + str(Fort) + "\nHeight:" + str(height) + "\nRadius: " + str(radius) + "\n"
- # maxdiff = height
- # for Fort0 in Fortresses:
- # for Fort1 in Fortresses:
- # Intersect = RectIntersect([Fort0[0], Fort0[1], Fort0[2], Fort0[3]], [Fort1[0], Fort1[1], Fort1[2], Fort1[3]])
- # if Intersect and Intersect not in Intersections and Intersect not in Fortresses:
- # Intersections.append(Intersect)
- #
- # radius = int(args.radius[0])
- #
- # for x in range(-radius, radius):
- # for y in range(-radius, radius):
- # score = 0
- # for Fort in Fortresses:
- # score += area(Fort[0], Fort[1], Fort[2], Fort[3], x*5, y*5, 128)-area(Fort[0], Fort[1], Fort[2], Fort[3], x*5, y*5, 70)
- # for Intersection in Intersections:
- # score += area(Intersection[0], Intersection[1], Intersection[2], Intersection[3], x*5, y*5, 70)-area(Intersection[0], Intersection[1], Intersection[2], Intersection[3], x*5, y*5, 128)
- # if score > maximum*0.875:
- # for x1 in range(x*5-5, x*5+5):
- # for y1 in range(y*5-5, y*5+5):
- # score = 0
- # for Fort in Fortresses:
- # score += area(Fort[0], Fort[1], Fort[2], Fort[3], x1, y1, 128)-area(Fort[0], Fort[1], Fort[2], Fort[3], x1, y1, 70)
- # for Intersection in Intersections:
- # score += area(Intersection[0], Intersection[1], Intersection[2], Intersection[3], x1, y1, 70)-area(Intersection[0], Intersection[1], Intersection[2], Intersection[3], x1, y1, 128)
- # if score > maximum:
- # maximum = score
- # print(str(x1) + "/" + str(y1) + ": " + str(score))
- # for x in range(-radius, radius):
- # for y in range(-radius, radius):
- # Rects = (
- # [x-127, x-87, y-18, y+18],
- # [x+87, x+127, y-18, y+18],
- # [x-18, x+18, y-127, y-87],
- # [x-18, x+18, y+87, y+127]
- # )
- # for Rect in Rects:
- # Filled = 0
- # for Fort in Fortresses:
- # Filled += RectArea(RectIntersect(Rect, Fort))
- # for Intersection in Intersections:
- # Filled -= RectArea(RectIntersect(Rect, Intersection))
- # if Filled != 1440:
- # break
- # else:
- # print("Candidate: " + str(x) + "/" + str(y))
- #off are 1;2;3;5;6;7
- #print(area(-13, 195, -6, 176, 109, 82, 128))
- #x = 109
- #y = 82
- #score = 0
- #for Fort in Fortresses:
- # if area(Fort[0], Fort[1], Fort[2], Fort[3], x, y, 128)-area(Fort[0], Fort[1], Fort[2], Fort[3], x, y, 70) != 0:
- # print str(Fort) + " " + str(area(Fort[0], Fort[1], Fort[2], Fort[3], x, y, 128)-area(Fort[0], Fort[1], Fort[2], Fort[3], x, y, 70))
- # score += area(Fort[0], Fort[1], Fort[2], Fort[3], x, y, 128)-area(Fort[0], Fort[1], Fort[2], Fort[3], x, y, 70)
- #for Intersection in Intersections:
- # score += area(Intersection[0], Intersection[1], Intersection[2], Intersection[3], x, y, 70)-area(Intersection[0], Intersection[1], Intersection[2], Intersection[3], x, y, 128)
- #if score > maximum:
- # maximum = score
- # print(str(x) + "/" + str(y) + ": " + str(score))
- #print(RectIntersect([-2, -1, -2, -1], [-3, -1.5, -3, -1.5]))
- # print(area(-10, 10, -10, 10, 0, 0, 1)) # unit circle completely inside a huge box, area of intersection is pi
- # print(area(-10, 0, -10, 10, 0, 0, 1)) # half of unit circle inside a large box, area of intersection is pi/2
- # print(area(0, 10, -10, 10, 0, 0, 1)) # half of unit circle inside a large box, area of intersection is pi/2
- # print(area(-10, 10, -10, 0, 0, 0, 1)) # half of unit circle inside a large box, area of intersection is pi/2
- # print(area(-10, 10, 0, 10, 0, 0, 1)) # half of unit circle inside a large box, area of intersection is pi/2
- # print(area(0, 1, 0, 1, 0, 0, 1)) # unit box covering one quadrant of the circle, area of intersection is pi/4
- # print(area(0, -1, 0, 1, 0, 0, 1)) # unit box covering one quadrant of the circle, area of intersection is pi/4
- # print(area(0, -1, 0, -1, 0, 0, 1)) # unit box covering one quadrant of the circle, area of intersection is pi/4
- # print(area(0, 1, 0, -1, 0, 0, 1)) # unit box covering one quadrant of the circle, area of intersection is pi/4
- # print(area(-.5, .5, -.5, .5, 0, 0, 10)) # unit box completely inside a huge circle, area of intersection is 1
- # print(area(-20, -10, -10, 10, 0, 0, 1)) # huge box completely outside a circle (left), area of intersection is 0
- # print(area(10, 20, -10, 10, 0, 0, 1)) # huge box completely outside a circle (right), area of intersection is 0
- # print(area(-10, 10, -20, -10, 0, 0, 1)) # huge box completely outside a circle (below), area of intersection is 0
- # print(area(-10, 10, 10, 20, 0, 0, 1)) # huge box completely outside a circle (above), area of intersection is 0
- # ==== Print the resulting JSON-string to stdout ====
- #print(json.JSONEncoder().encode(arr))
- #print(x)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement