minetest-api-py/mtdb.py

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))