69 lines
2.0 KiB
Python
69 lines
2.0 KiB
Python
#!/usr/bin/env python3
|
|
|
|
DB_PGSQL = 1
|
|
DB_SQLITE = 2
|
|
|
|
class Db:
|
|
def __init__(self, obj, dbtype):
|
|
self.obj = obj
|
|
self.dbtype = dbtype
|
|
|
|
# Init PostgreSQL database
|
|
def init_pgsql(connect: str):
|
|
global psycopg2
|
|
import psycopg2
|
|
return Db(psycopg2.connect(connect), DB_PGSQL)
|
|
|
|
# Init SQLite database
|
|
def init_sqlite(dbname: str):
|
|
global sqlite3
|
|
import sqlite3
|
|
return Db(sqlite3.connect(dbname), DB_SQLITE)
|
|
|
|
def to_signed(x, bits=11):
|
|
return x if x >= 0 else (1<<bits)-x
|
|
|
|
def from_signed(x, bits=11):
|
|
b = 1<<bits
|
|
return x if x < b else (b^x)-b
|
|
|
|
def chunk_to_int(pos: (int, int, int)):
|
|
return to_signed(pos[2])<<24 | to_signed(pos[1])<<12 | to_signed(pos[0])
|
|
|
|
def int_to_chunk(pos: int):
|
|
return (from_signed(pos>>24), from_signed(pos>>12&0xfff), from_signed(pos&0xfff))
|
|
|
|
# Read chunk from db
|
|
def get_chunk(db: Db, pos: (int, int, int)):
|
|
if db.dbtype == DB_PGSQL:
|
|
c = db.obj.cursor()
|
|
c.execute("SELECT data FROM blocks WHERE posx={} AND posy={} AND posz={} LIMIT 1".format(*pos))
|
|
res = c.fetchone()
|
|
if res:
|
|
res = res[0].tobytes()
|
|
return res
|
|
else:
|
|
c = db.obj.cursor()
|
|
c.execute("SELECT data FROM blocks WHERE pos={} LIMIT 1".format(chunk_to_int(pos)))
|
|
res = c.fetchone()
|
|
if res:
|
|
res = res[0]
|
|
return res
|
|
|
|
# Write chunk to db
|
|
def set_chunk(db: Db, pos: (int, int, int), data: bytes):
|
|
if db.dbtype == DB_PGSQL:
|
|
c = db.obj.cursor()
|
|
c.execute("SELECT 1 FROM blocks WHERE posx={} AND posy={} AND posz={} LIMIT 1".format(*pos))
|
|
if c.fetchone():
|
|
c.execute("UPDATE blocks SET data={} WHERE posx={} AND posy={} AND posz={} LIMIT 1".format(data, *pos))
|
|
else:
|
|
c.execute("INSERT INTO blocks (posx, posy, posz, data) VALUES ({}, {}, {}, {})".format(*pos, data))
|
|
else:
|
|
chunk_id = chunk_to_int(pos)
|
|
c.execute("SELECT 1 FROM blocks WHERE pos={} LIMIT 1".format(chunk_id))
|
|
if c.fetchone():
|
|
c.execute("UPDATE blocks SET data={} WHERE pos={} LIMIT 1".format(data, chunk_id))
|
|
else:
|
|
c.execute("INSERT INTO blocks (pos, data) VALUES ({}, {})".format(chunk_id, data))
|