Last active
August 29, 2015 13:59
-
-
Save skairunner/10523846 to your computer and use it in GitHub Desktop.
gen.py and mcworldgen
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math | |
from enum import Enum | |
class Block(Enum): | |
upperShell = 1 | |
lowerShell = 2 | |
upperInterior = 3 | |
lowerInterior = 4 | |
upperInnerShell = 5 | |
lowerInnerShell = 6 | |
#Von Neumann in 3D | |
neighbors = [ ( 1, 0, 0), (-1, 0, 0), (0 , 1, 0), ( 0,-1, 0), ( 0, 0, 1), ( 0, 0,-1) ] | |
def add(t1, t2): | |
if len(t1) != len(t2): | |
raise ArithmeticError("Length of tuples do not match") | |
result = [a + b for a, b in zip(t1, t2)] | |
return result | |
def sphereDistanceSquared(x, y, z, c): | |
return (x-c)**2 + (y-c)**2 + (z-c)**2 | |
class BlockCircle: | |
def __init__(self, r, depth = 1): | |
self.r = r | |
self.side = r + 1 # The actual cube space is 2 larger on every side | |
self.depth = depth | |
self.blueprint = list() | |
self.drawBlueprint() | |
def getBlock(self, coord): | |
if (0 <= coord[0] < 2 * self.side+1 and 0 <= coord[1] < 2 * self.side+1 and 0 <= coord[2] < 2 * self.side+1): | |
return self.blueprint[coord[0]][coord[1]][coord[2]] | |
else: | |
raise KeyError("Coords (%d,%d,%d) out of bounds" % (coord[0],coord[1],coord[2])) | |
def setBlock(self, coord, value): | |
self.blueprint[coord[0]][coord[1]][coord[2]] = value | |
def drawBlueprint(self): | |
print "Starting sphere " + str(self.side) | |
# Dimensions of the cube circumscribing the sphere is (2s+1)*(2s+1)*(2s+1) | |
self.blueprint = [[[0 for x in xrange(2 * self.side + 1)] for y in xrange(2 * self.side + 1)] for z in xrange(2 * self.side + 1)] | |
# If the block selected is not in the sphere (whose center is (r+2,r+2,r+2)), set it as 0. Else, set it as 1. | |
for z in xrange(2 * self.side + 1): | |
for y in xrange(2 * self.side + 1): | |
for x in xrange(2 * self.side + 1): | |
if sphereDistanceSquared(x,y,z,self.side + 1) <= self.r**2 : | |
if z > self.side: | |
self.blueprint[z][y][x] = Block.upperInterior | |
else: | |
self.blueprint[z][y][x] = Block.lowerInterior | |
print "\tFloodfilling..." | |
# Next, set all boundary blocks as 2. | |
for z in xrange(2 * self.side + 1): | |
for y in xrange(2 * self.side + 1): | |
for x in xrange(2 * self.side + 1): | |
# For starters, the top layer and the bottom layer is always a boundary | |
# Same for x or y boundaries | |
if (z == 0 or z == 2 * self.side or y == 0 or y == 2 * self.side or x == 0 or x == 2 * self.side) and self.blueprint[z][y][x] == 1: # The selected space must also be part of the sphere | |
if z > self.side: | |
self.blueprint[z][y][x] = Block.upperShell | |
else: | |
self.blueprint[z][y][x] = Block.lowerShell | |
continue | |
if self.blueprint[z][y][x] == 0: # If an Air tile can reach a stone tile, it is a boundary. | |
current = (z, y, x) | |
for deltaCoord in neighbors: | |
neighbor = add(current, deltaCoord) | |
try: | |
if self.getBlock(neighbor) == Block.upperInterior or self.getBlock(neighbor) == Block.lowerInterior: | |
if neighbor[0] > self.side: | |
self.setBlock(neighbor, Block.upperShell) | |
else: | |
self.setBlock(neighbor, Block.lowerShell) | |
except KeyError: | |
"" # Do nothing, just move on to the next item in the work queue | |
except: | |
raise | |
# Flood fill for inner boundaries | |
for z in xrange(2 * self.side + 1): | |
for y in xrange(2 * self.side + 1): | |
for x in xrange(2 * self.side + 1): | |
if self.blueprint[z][y][x] == Block.upperShell or self.blueprint[z][y][x] == Block.lowerShell: # If a Boundary tile can reach a stone tile, it is an inner boundary. (3) | |
current = (z, y, x) | |
for deltaCoord in neighbors: | |
neighbor = add(current, deltaCoord) | |
try: | |
if self.getBlock(neighbor) == Block.upperInterior or self.getBlock(neighbor) == Block.lowerInterior: # | |
if neighbor[0] > self.side: | |
self.setBlock(neighbor, Block.upperInnerShell) | |
else: | |
self.setBlock(neighbor, Block.lowerInnerShell) | |
except KeyError: | |
"" # Do nothing, just move on to the next item in the work queue | |
except: | |
raise |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from planetoid import Planetoid | |
import pickle | |
import json | |
import random | |
import sys | |
noOutput = False | |
noPrompts = False | |
if "-s" in sys.argv: | |
noOutput = True | |
if "-n" in sys.argv: | |
noPrompts = True | |
blueprints = dict() | |
planetoids = list() | |
def exportLeveldat(): | |
level = {} | |
level["dataType"] = "level" | |
level["allowCommands"] = "true" | |
level["hardcore"] = "false" | |
level["MapFeatures"] = "false" | |
level["GameType"] = 1 | |
level["SpawnX"] = 0 | |
level["SpawnY"] = 6 | |
level["SpawnZ"] = 0 | |
level["rainAllowed"] = "true" | |
level["thunderAllowed"] = "true" | |
level["RandomSeed"] = "12345" | |
level["generatorName"] = "default" | |
level["generatorOptions"] = "" | |
level["LevelName"] = "Test" | |
gamerules = {} | |
gamerules["commandBlockOutput"] = "true" | |
gamerules["doDaylightCycle"] = "true" | |
gamerules["doFireTick"] = "true" | |
gamerules["doMobLoot"] = "true" | |
gamerules["doMobSpawning"] = "true" | |
gamerules["doTileDrops"] = "true" | |
gamerules["keepInventory"] = "false" | |
gamerules["mobGriefing"] = "true" | |
gamerules["naturalRegeneration"] ="true" | |
level["GameRules"] = gamerules | |
if not noOutput: | |
sys.stdout.write(json.dumps(level)) | |
def exportBedrock(planets, mapwidth, bedrock=True, water=True): | |
minx, miny, maxx, maxy = mapwidth, mapwidth, -1, -1 | |
# figure out the boundaries | |
for p in planets: | |
if p.center[1]-p.r-1 < miny: | |
miny = p.center[1]-p.r-1 | |
if p.center[1]+p.r+1 > maxy: | |
maxy = p.center[1]+p.r+1 | |
if p.center[2]-p.r-1 < minx: | |
minx = p.center[2]-p.r-1 | |
if p.center[2]+p.r+1 > maxx: | |
maxx = p.center[2]+p.r+1 | |
blocksData = {} | |
blocksData["dataType"] = "blocks" | |
blocksData["dimension"] = 0 | |
blocksData["xOffset"] = 0 | |
blocksData["yOffset"] = 0 | |
blocksData["zOffset"] = 0 | |
blocksData["biomes"] = [] | |
height = 0 | |
if not bedrock and not water: | |
return | |
if bedrock and not water: | |
height = 1 | |
if not bedrock and water: | |
return | |
if bedrock and water: | |
height = 3 | |
blocks = [[[0 for x in xrange(maxx-minx)] for y in xrange(maxy-miny)] for z in xrange(height)] | |
for y in xrange(maxy - miny): | |
for x in xrange(maxx - minx): | |
#if bedrock: # by this point it's assured that bedrock is true | |
blocks[0][y][x] = 7 # bedrock! | |
if water: | |
blocks[1][y][x] = 8 | |
blocks[2][y][x] = 8 | |
blocksData["blocks"] = blocks | |
sys.stdout.write(json.dumps(blocksData)) | |
def exportCube(coord, width, planetoid): | |
blocksData = dict() | |
blocksData["dataType"] = "blocks" | |
blocksData["dimension"] = 0 | |
blocksData["biomes"] = [] | |
blocksData["xOffset"] = coord[2] | |
blocksData["yOffset"] = coord[1] | |
blocksData["zOffset"] = coord[0] | |
blocksData["blocks"] = [[[-1 for x in xrange(width)] for y in xrange(width)] for z in xrange(width)] | |
blocksData["decorate"] = True | |
planetoid.rasterize(blocksData["blocks"], blueprints, True) | |
if not noOutput: | |
sys.stdout.write(json.dumps(blocksData)) # No whitespace | |
numSpheres = 10 | |
mapwidth = 256 | |
# Spawn the planetoids | |
for x in xrange(numSpheres): | |
r = random.randint(10, 20) | |
x = random.randint(r, mapwidth - r - 2) | |
y = random.randint(r, mapwidth - r - 2) | |
z = random.randint(r, 256 - r - 1) | |
planetoid = Planetoid(r, (z, y, x)) | |
chance = random.randint(0,1) | |
if chance==0: | |
planetoid.shell = "test" | |
planetoid.innershell = "test" | |
planetoid.contents = "ore" | |
elif chance==1: | |
planetoid.shell = "leaves" | |
planetoid.innershell = "leaves" | |
planetoid.contents = "wood" | |
planetoids.append(planetoid) | |
### New JSON commands method of output | |
for p in planetoids: | |
exportCube(p.center, 2*(p.r+1)+1, p) | |
exportBedrock(planetoids, mapwidth) | |
sys.stdout.write(json.dumps({"dataType":"exportAllRegions"})) | |
#sys.stdout.write(json.dumps({"dataType":"thanks"})) | |
"""# Place the actual blocks | |
blockmap = Map(mapwidth) | |
for planetoid in planetoids: | |
planetoid.rasterize(blockmap, blueprints)""" | |
"""# Output into json | |
output = dict() | |
dimension = dict() | |
dimension["biomes"] = [] | |
dimension["decorate"] = False | |
dimension["blocks"] = blockmap.map | |
output["dimensions"] = dict() | |
output["dimensions"]["0"] = dimension | |
output["level"] = level | |
if noOutput: | |
if not noPrompts: | |
print 'Done' | |
else: | |
print json.dumps(output)""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from random import uniform, randint | |
from enum import Enum | |
import pickle | |
from blockcircle import BlockCircle | |
### Load resource files | |
equalChanceDict = dict() # name: id | |
uneqChanceDict = dict() # name: (id, prob) | |
lotterySums = dict() | |
eqClasses = ["wood", "leaves", "stone", "earth"] | |
uneqClasses = ["ores", "liquid"] | |
# Get a random block of blocktype from uneqChanceDict | |
def getUnequalChanceBlock(blocktype): | |
num = uniform(0, lotterySums[blocktype]) | |
result = None | |
counter = 0 | |
keys = uneqChanceDict["ores"].keys() | |
while num > 0: | |
result = uneqChanceDict["ores"][keys[counter]] | |
num -= result[1] | |
counter += 1 | |
return result[0] | |
# Same, but for equal chance blocks like wood type | |
def getEqualChanceBlock(blocktype): | |
lim = len(lotterySums[blocktype]) | |
num = randint(0, lim-1) | |
return equalChanceDict[blocktype][equalChanceDict[blocktype].keys()[num]] | |
def getBlock(blocktype): | |
if blocktype == "air": | |
return 0 | |
if blocktype in eqClasses: | |
return getEqualChanceBlock(blocktype) | |
elif blocktype in uneqClasses: | |
return getUnequalChanceBlock(blocktype) | |
else: | |
raise TypeError("Could not find classification \"" + blocktype + "\"") | |
for c in eqClasses: | |
with open("resources/" + c, "r") as f: | |
equalChanceDict[c] = dict() | |
first = True | |
for line in f: | |
if first: | |
first = False | |
continue | |
line = line[:-1] | |
words = line.split("\t") | |
if len(words[1].split(":")) > 1: #ie, it is a id:damage pair | |
split = words[1].split(":") | |
id_damage = [int(split[0]), int(split[1])] | |
equalChanceDict[c][words[0]] = id_damage | |
else: | |
equalChanceDict[c][words[0]] = int(words[1]) | |
# Ores, etc, are not equal probability. | |
for c in uneqClasses: | |
with open("resources/" + c, "r") as f: | |
uneqChanceDict[c] = dict() | |
lotterySums[c] = 0 | |
first = True | |
for line in f: | |
if first: | |
first = False | |
continue | |
line = line[:-1] | |
words = line.split("\t") | |
uneqChanceDict[c][words[0]] = (int(words[1]), float(words[2])) | |
lotterySums[c] += float(words[2]) | |
class SchemaKey(Enum): | |
schema= 0 | |
upperShell = 1 | |
lowerShell = 2 | |
upperInterior = 3 | |
lowerInterior = 4 | |
upperInnerShell = 5 | |
lowerInnerShell = 6 | |
satellite = 7 | |
huge = 8 | |
description = 9 | |
schemata = dict() | |
# load schemata | |
with open("resources/schemata", "r") as f: | |
for line in f: | |
line = line[:-1] | |
things = line.split("\t") | |
schemata[things[0]] = things | |
class Planetoid: | |
def __init__(self, r, coord, schema="none"): | |
self.r = r | |
self.schema = schema | |
self.center = coord | |
self.attributes = dict() | |
# Retrieve values from tables. | |
# If the upper and lower things are the same classification, they get the same block type | |
self.attributes["upperShell"] = getBlock(schemata[schema][SchemaKey.upperShell]) | |
if schemata[schema][SchemaKey.lowerShell] == schemata[schema][SchemaKey.upperShell]: | |
self.attributes["lowerShell"] = self.attributes["upperShell"] | |
else: | |
self.attributes["lowerShell"] = getBlock(schemata[schema][SchemaKey.lowerShell]) | |
self.attributes["upperInnerShell"] = getBlock(schemata[schema][SchemaKey.upperInnerShell]) | |
if schemata[schema][SchemaKey.upperInnerShell] == schemata[schema][SchemaKey.lowerInnerShell]: | |
self.attributes["lowerInnerShell"] = self.attributes["upperInnerShell"] | |
else: | |
self.attributes["lowerInnerShell"] = getBlock(schemata[schema][SchemaKey.lowerInnerShell]) | |
self.attributes["upperInterior"] = schemata[schema][SchemaKey.upperInterior] | |
if schemata[schema][SchemaKey.upperInterior] == schemata[schema][SchemaKey.lowerInterior]: | |
self.attributes["lowerInterior"] = self.attributes["upperInterior"] | |
else: | |
self.attributes["lowerInterior"] = getBlock(schemata[schema][SchemaKey.upperInterior]) | |
self.attributes["satellite"] = schemata[schema][SchemaKey.satellite] | |
self.attributes["huge"] = schemata[schema][SchemaKey.huge] | |
self.oreprob = .5 # Hardcoded for now. | |
def getOreBlock(self, blockType): | |
num = uniform(0.0, 1.0) | |
if num < self.oreprob: | |
return self.attributes[SchemaKey(blockType)] | |
return 1 # stone | |
def getBlock(self, blockType): | |
if blockType == 0: | |
return 0 | |
elif blockType == None: | |
raise TypeError("blockType is not defined.") | |
blockClass = schemata[self.schema][blockType] | |
if blockClass == "ores": # get a random block if ores | |
return getOreBlock(self) | |
else: | |
return self.attributes[SchemaKey(blockType)] | |
# if relative=True, don't translate the center of the cube | |
def rasterize(self, blockmap, blueprints, relative = False): | |
if not (self.r in blueprints): | |
with open("resources/sphere" + str(self.r) + ".form", "r") as f: | |
blueprints[self.r] = pickle.load(f) | |
circle = blueprints[self.r] | |
cz = self.center[0] | |
cy = self.center[1] | |
cx = self.center[2] | |
if relative: | |
for z in xrange(2*(self.r+1) +1): | |
for y in xrange(2*(self.r+1) +1): | |
for x in xrange (2*(self.r+1) +1): | |
blockType = circle.blueprint[z][y][x] | |
if not blockType == 0: | |
blockmap[z][y][x] = self.getBlock(blockType) | |
else: | |
for z in xrange(2*(self.r+1) +1): | |
for y in xrange(2*(self.r+1) +1): | |
for x in xrange (2*(self.r+1) +1): | |
blockType = circle.blueprint[z][y][x] | |
blockmap.map[cz + z - circle.side][cy + y - circle.side][cx + x - circle.side] = self.getBlock(blockType) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math | |
from blockcircle import BlockCircle | |
import sys | |
import pickle | |
if len(sys.argv) < 3: | |
print "Usage:\npython spheregen.py [lower limit, >= 3] [upper limit]" | |
quit() | |
if sys.argv[1] < 3: | |
print "Lower limit must be >= 3" | |
lower = int(sys.argv[1]) | |
upper = int(sys.argv[2]) | |
for r in xrange(lower, upper+1): | |
circle = BlockCircle(r) | |
file = open("resources/sphere" + str(circle.r) + ".form", "w") | |
print "\tWriting..." | |
pickle.dump(circle, file) | |
file.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment