249 lines
7.9 KiB
Python
249 lines
7.9 KiB
Python
# This file allows you to programmatically create blocks in Craft.
|
|
# Please use this wisely. Test on your own server first. Do not abuse it.
|
|
|
|
import requests
|
|
import socket
|
|
import sqlite3
|
|
import sys
|
|
|
|
DEFAULT_HOST = '127.0.0.1'
|
|
DEFAULT_PORT = 4080
|
|
|
|
EMPTY = 0
|
|
GRASS = 1
|
|
SAND = 2
|
|
STONE = 3
|
|
BRICK = 4
|
|
WOOD = 5
|
|
CEMENT = 6
|
|
DIRT = 7
|
|
PLANK = 8
|
|
SNOW = 9
|
|
GLASS = 10
|
|
COBBLE = 11
|
|
LIGHT_STONE = 12
|
|
DARK_STONE = 13
|
|
CHEST = 14
|
|
LEAVES = 15
|
|
CLOUD = 16
|
|
TALL_GRASS = 17
|
|
YELLOW_FLOWER = 18
|
|
RED_FLOWER = 19
|
|
PURPLE_FLOWER = 20
|
|
SUN_FLOWER = 21
|
|
WHITE_FLOWER = 22
|
|
BLUE_FLOWER = 23
|
|
|
|
OFFSETS = [
|
|
(-0.5, -0.5, -0.5),
|
|
(-0.5, -0.5, 0.5),
|
|
(-0.5, 0.5, -0.5),
|
|
(-0.5, 0.5, 0.5),
|
|
(0.5, -0.5, -0.5),
|
|
(0.5, -0.5, 0.5),
|
|
(0.5, 0.5, -0.5),
|
|
(0.5, 0.5, 0.5),
|
|
]
|
|
|
|
def sphere(cx, cy, cz, r, fill=False, fx=False, fy=False, fz=False):
|
|
result = set()
|
|
for x in range(cx - r, cx + r + 1):
|
|
if fx and x != cx:
|
|
continue
|
|
for y in range(cy - r, cy + r + 1):
|
|
# if y < cy:
|
|
# continue # top hemisphere only
|
|
if fy and y != cy:
|
|
continue
|
|
for z in range(cz - r, cz + r + 1):
|
|
if fz and z != cz:
|
|
continue
|
|
inside = False
|
|
outside = fill
|
|
for dx, dy, dz in OFFSETS:
|
|
ox, oy, oz = x + dx, y + dy, z + dz
|
|
d2 = (ox - cx) ** 2 + (oy - cy) ** 2 + (oz - cz) ** 2
|
|
d = d2 ** 0.5
|
|
if d < r:
|
|
inside = True
|
|
else:
|
|
outside = True
|
|
if inside and outside:
|
|
result.add((x, y, z))
|
|
return result
|
|
|
|
def circle_x(x, y, z, r, fill=False):
|
|
return sphere(x, y, z, r, fill, fx=True)
|
|
|
|
def circle_y(x, y, z, r, fill=False):
|
|
return sphere(x, y, z, r, fill, fy=True)
|
|
|
|
def circle_z(x, y, z, r, fill=False):
|
|
return sphere(x, y, z, r, fill, fz=True)
|
|
|
|
def cylinder_x(x1, x2, y, z, r, fill=False):
|
|
x1, x2 = sorted((x1, x2))
|
|
result = set()
|
|
for x in range(x1, x2 + 1):
|
|
result |= circle_x(x, y, z, r, fill)
|
|
return result
|
|
|
|
def cylinder_y(x, y1, y2, z, r, fill=False):
|
|
y1, y2 = sorted((y1, y2))
|
|
result = set()
|
|
for y in range(y1, y2 + 1):
|
|
result |= circle_y(x, y, z, r, fill)
|
|
return result
|
|
|
|
def cylinder_z(x, y, z1, z2, r, fill=False):
|
|
z1, z2 = sorted((z1, z2))
|
|
result = set()
|
|
for z in range(z1, z2 + 1):
|
|
result |= circle_z(x, y, z, r, fill)
|
|
return result
|
|
|
|
def cuboid(x1, x2, y1, y2, z1, z2, fill=True):
|
|
x1, x2 = sorted((x1, x2))
|
|
y1, y2 = sorted((y1, y2))
|
|
z1, z2 = sorted((z1, z2))
|
|
result = set()
|
|
a = (x1 == x2) + (y1 == y2) + (z1 == z2)
|
|
for x in range(x1, x2 + 1):
|
|
for y in range(y1, y2 + 1):
|
|
for z in range(z1, z2 + 1):
|
|
n = 0
|
|
n += x in (x1, x2)
|
|
n += y in (y1, y2)
|
|
n += z in (z1, z2)
|
|
if not fill and n <= a:
|
|
continue
|
|
result.add((x, y, z))
|
|
return result
|
|
|
|
def pyramid(x1, x2, y, z1, z2, fill=False):
|
|
x1, x2 = sorted((x1, x2))
|
|
z1, z2 = sorted((z1, z2))
|
|
result = set()
|
|
while x2 >= x1 and z2 >= z2:
|
|
result |= cuboid(x1, x2, y, y, z1, z2, fill)
|
|
y, x1, x2, z1, z2 = y + 1, x1 + 1, x2 - 1, z1 + 1, z2 - 1
|
|
return result
|
|
|
|
def get_identity():
|
|
query = (
|
|
'select username, token from identity_token where selected = 1;'
|
|
)
|
|
conn = sqlite3.connect('auth.db')
|
|
rows = conn.execute(query)
|
|
for row in rows:
|
|
return row
|
|
raise Exception('No identities found.')
|
|
|
|
class Client(object):
|
|
def __init__(self, host, port):
|
|
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
self.conn.connect((host, port))
|
|
self.authenticate()
|
|
def authenticate(self):
|
|
username, identity_token = get_identity()
|
|
url = 'https://craft.michaelfogleman.com/api/1/identity'
|
|
payload = {
|
|
'username': username,
|
|
'identity_token': identity_token,
|
|
}
|
|
response = requests.post(url, data=payload)
|
|
if response.status_code == 200 and response.text.isalnum():
|
|
access_token = response.text
|
|
self.conn.sendall('A,%s,%s\n' % (username, access_token))
|
|
else:
|
|
raise Exception('Failed to authenticate.')
|
|
def set_block(self, x, y, z, w):
|
|
self.conn.sendall('B,%d,%d,%d,%d\n' % (x, y, z, w))
|
|
def set_blocks(self, blocks, w):
|
|
key = lambda block: (block[1], block[0], block[2])
|
|
for x, y, z in sorted(blocks, key=key):
|
|
self.set_block(x, y, z, w)
|
|
def bitmap(self, sx, sy, sz, d1, d2, data, lookup):
|
|
x, y, z = sx, sy, sz
|
|
dx1, dy1, dz1 = d1
|
|
dx2, dy2, dz2 = d2
|
|
for row in data:
|
|
x = sx if dx1 else x
|
|
y = sy if dy1 else y
|
|
z = sz if dz1 else z
|
|
for c in row:
|
|
w = lookup.get(c)
|
|
if w is not None:
|
|
self.set_block(x, y, z, w)
|
|
x, y, z = x + dx1, y + dy1, z + dz1
|
|
x, y, z = x + dx2, y + dy2, z + dz2
|
|
|
|
def get_client():
|
|
default_args = [DEFAULT_HOST, DEFAULT_PORT]
|
|
args = sys.argv[1:] + [None] * len(default_args)
|
|
host, port = [a or b for a, b in zip(args, default_args)]
|
|
client = Client(host, int(port))
|
|
return client
|
|
|
|
def main():
|
|
client = get_client()
|
|
set_block = client.set_block
|
|
set_blocks = client.set_blocks
|
|
# set_blocks(circle_y(0, 32, 0, 16, True), STONE)
|
|
# set_blocks(circle_y(0, 33, 0, 16), BRICK)
|
|
# set_blocks(cuboid(-1, 1, 1, 31, -1, 1), CEMENT)
|
|
# set_blocks(cuboid(-1024, 1024, 32, 32, -3, 3), STONE)
|
|
# set_blocks(cuboid(-3, 3, 32, 32, -1024, 1024), STONE)
|
|
# set_blocks(cuboid(-1024, 1024, 33, 33, -3, -3), BRICK)
|
|
# set_blocks(cuboid(-1024, 1024, 33, 33, 3, 3), BRICK)
|
|
# set_blocks(cuboid(-3, -3, 33, 33, -1024, 1024), BRICK)
|
|
# set_blocks(cuboid(3, 3, 33, 33, -1024, 1024), BRICK)
|
|
# set_blocks(sphere(0, 32, 0, 16), GLASS)
|
|
# for y in range(1, 32):
|
|
# set_blocks(circle_y(0, y, 0, 4, True), CEMENT)
|
|
# set_blocks(circle_x(16, 33, 0, 3), BRICK)
|
|
# set_blocks(circle_x(-16, 33, 0, 3), BRICK)
|
|
# set_blocks(circle_z(0, 33, 16, 3), BRICK)
|
|
# set_blocks(circle_z(0, 33, -16, 3), BRICK)
|
|
# for x in range(0, 1024, 32):
|
|
# set_blocks(cuboid(x - 1, x + 1, 31, 32, -1, 1), CEMENT)
|
|
# set_blocks(cuboid(-x - 1, -x + 1, 31, 32, -1, 1), CEMENT)
|
|
# set_blocks(cuboid(x, x, 1, 32, -1, 1), CEMENT)
|
|
# set_blocks(cuboid(-x, -x, 1, 32, -1, 1), CEMENT)
|
|
# for z in range(0, 1024, 32):
|
|
# set_blocks(cuboid(-1, 1, 31, 32, z - 1, z + 1), CEMENT)
|
|
# set_blocks(cuboid(-1, 1, 31, 32, -z - 1, -z + 1), CEMENT)
|
|
# set_blocks(cuboid(-1, 1, 1, 32, z, z), CEMENT)
|
|
# set_blocks(cuboid(-1, 1, 1, 32, -z, -z), CEMENT)
|
|
# for x in range(0, 1024, 8):
|
|
# set_block(x, 32, 0, CEMENT)
|
|
# set_block(-x, 32, 0, CEMENT)
|
|
# for z in range(0, 1024, 8):
|
|
# set_block(0, 32, z, CEMENT)
|
|
# set_block(0, 32, -z, CEMENT)
|
|
# set_blocks(pyramid(32, 32+64-1, 12, 32, 32+64-1), COBBLE)
|
|
# outer = circle_y(0, 11, 0, 176 + 3, True)
|
|
# inner = circle_y(0, 11, 0, 176 - 3, True)
|
|
# set_blocks(outer - inner, STONE)
|
|
# a = sphere(-32, 48, -32, 24, True)
|
|
# b = sphere(-24, 40, -24, 24, True)
|
|
# set_blocks(a - b, PLANK)
|
|
# set_blocks(cylinder_x(-64, 64, 32, 0, 8), STONE)
|
|
# data = [
|
|
# '...............................',
|
|
# '..xxx..xxxx...xxx..xxxxx.xxxxx.',
|
|
# '.x...x.x...x.x...x.x.......x...',
|
|
# '.x.....xxxx..xxxxx.xxx.....x...',
|
|
# '.x...x.x..x..x...x.x.......x...',
|
|
# '..xxx..x...x.x...x.x.......x...',
|
|
# '...............................',
|
|
# ]
|
|
# lookup = {
|
|
# 'x': STONE,
|
|
# '.': PLANK,
|
|
# }
|
|
# client.bitmap(0, 32, 32, (1, 0, 0), (0, -1, 0), data, lookup)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|