def _create( self, overwrite: bool, bounds: Union[SelectionGroup, Dict[Dimension, Optional[SelectionGroup]], None] = None, **kwargs, ): if os.path.isdir(self.path): if overwrite: shutil.rmtree(self.path) else: raise ObjectWriteError( f"A world already exists at the path {self.path}") version = self.translation_manager.get_version( self.platform, self.version).version_number self._version = version + (0, ) * (5 - len(version)) self.root_tag = root = nbt.TAG_Compound() root["StorageVersion"] = nbt.TAG_Int(8) root["lastOpenedWithVersion"] = nbt.TAG_List( [nbt.TAG_Int(i) for i in self._version]) root["Generator"] = nbt.TAG_Int(1) root["LastPlayed"] = nbt.TAG_Long(int(time.time())) root["LevelName"] = nbt.TAG_String("World Created By Amulet") os.makedirs(self.path, exist_ok=True) self.root_tag.save(os.path.join(self.path, "level.dat")) db = LevelDB(os.path.join(self.path, "db"), True) db.close() self._reload_world()
def test_put(self): self._clear_db() db = LevelDB(DB_PATH, True) db.putBatch(incr_db) for k, v in num_db.items(): db.put(k, v) self.assertEqual(dict(db.iterate()), full_db) # TODO: Uncomment this when the new db wrapper is fixed # self.assertEqual(dict(db.items()), full_db) self.assertEqual(set(db.keys()), full_db.keys()) self.assertEqual(set(db), full_db.keys()) db.close()
def __init__(self, directory: str): self._directory = directory self._db = LevelDB(os.path.join(self._directory, "db")) # self._levels format Dict[level, Dict[Tuple[cx, cz], List[Tuple[full_key, key_extension]]]] self._levels: Dict[InternalDimension, Set[ChunkCoordinates]] = {} self._dimension_name_map: Dict["Dimension", InternalDimension] = {} self._batch_temp: Dict[bytes, Union[bytes, None]] = {} self.register_dimension(None, "overworld") self.register_dimension(1, "nether") self.register_dimension(2, "end") for key in self._db.keys(): if 9 <= len(key) <= 10 and key[8] == 118: self._add_chunk(key) elif 13 <= len(key) <= 14 and key[12] == 118: self._add_chunk(key, has_level=True)
def __init__(self, directory: str): self._directory = directory self._db = LevelDB(os.path.join(self._directory, "db")) # self._levels format Dict[level, Dict[Tuple[cx, cz], List[Tuple[full_key, key_extension]]]] self._levels: Dict[InternalDimension, Set[ChunkCoordinates]] = {} self._dimension_name_map: Dict["Dimension", InternalDimension] = {} self._batch_temp: Dict[bytes, Union[bytes, None]] = {} self.register_dimension(0, OVERWORLD) self.register_dimension(1, THE_NETHER) self.register_dimension(2, THE_END) for key in self._db.keys(): if 9 <= len(key) <= 10 and key[8] in [44, 118]: # "," "v" self._add_chunk(key) elif 13 <= len(key) <= 14 and key[12] in [44, 118]: # "," "v" self._add_chunk(key, has_level=True)
def test_delete(self): self._clear_db() db = LevelDB(DB_PATH, True) self.assertFalse(b"test_key3" in db) db.put(b"test_key3", b"test") self.assertTrue(b"test_key3" in db) db.delete(b"test_key3") self.assertFalse(b"test_key3" in db) db.close()
def test_contains(self): self._clear_db() db = LevelDB(DB_PATH, True) self.assertFalse(b"test_key2" in db) db.put(b"test_key2", b"test") self.assertTrue(b"test_key2" in db) db.close()
def get_cache_db() -> LevelDB: global _cache_db if _cache_db is None: _cache_db = LevelDB(_path, True) atexit.register(_clear_db) return _cache_db
class LevelDBLevelManager: # tag_ids = {45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 118} def __init__(self, directory: str): self._directory = directory self._db = LevelDB(os.path.join(self._directory, "db")) # self._levels format Dict[level, Dict[Tuple[cx, cz], List[Tuple[full_key, key_extension]]]] self._levels: Dict[InternalDimension, Set[ChunkCoordinates]] = {} self._dimension_name_map: Dict["Dimension", InternalDimension] = {} self._batch_temp: Dict[bytes, Union[bytes, None]] = {} self.register_dimension(None, "overworld") self.register_dimension(1, "nether") self.register_dimension(2, "end") for key in self._db.keys(): if 9 <= len(key) <= 10 and key[8] == 118: self._add_chunk(key) elif 13 <= len(key) <= 14 and key[12] == 118: self._add_chunk(key, has_level=True) def save(self): batch = {} for key, val in self._batch_temp.items(): if val is None: self._db.delete(key) else: batch[key] = val self._db.putBatch(batch) self._batch_temp.clear() def close(self): self._db.close() @property def dimensions(self) -> List["Dimension"]: """A list of all the levels contained in the world""" return list(self._dimension_name_map.keys()) def register_dimension( self, dimension_internal: InternalDimension, dimension_name: Optional["Dimension"] = None, ): """ Register a new dimension. :param dimension_internal: The internal representation of the dimension :param dimension_name: The name of the dimension shown to the user :return: """ if dimension_name is None: dimension_name: "Dimension" = f"DIM{dimension_internal}" if ( dimension_internal not in self._levels and dimension_name not in self._dimension_name_map ): self._levels[dimension_internal] = set() self._dimension_name_map[dimension_name] = dimension_internal def _get_internal_dimension(self, dimension: "Dimension") -> InternalDimension: if dimension in self._dimension_name_map: return self._dimension_name_map[dimension] else: raise LevelDoesNotExist(dimension) def all_chunk_coords(self, dimension: "Dimension") -> Set[ChunkCoordinates]: internal_dimension = self._get_internal_dimension(dimension) if internal_dimension in self._levels: return self._levels[internal_dimension] else: return set() def _add_chunk(self, key_: bytes, has_level: bool = False): if has_level: cx, cz, level = struct.unpack("<iii", key_[:12]) else: cx, cz = struct.unpack("<ii", key_[:8]) level = None if level not in self._levels: self.register_dimension(level) self._levels[level].add((cx, cz)) def get_chunk_data( self, cx: int, cz: int, dimension: "Dimension" ) -> Dict[bytes, bytes]: """Get a dictionary of chunk key extension in bytes to the raw data in the key. chunk key extension are the character(s) after <cx><cz>[level] in the key Will raise ChunkDoesNotExist if the chunk does not exist """ iter_start = struct.pack("<ii", cx, cz) iter_end = iter_start + b"\xff" internal_dimension = self._get_internal_dimension(dimension) if ( internal_dimension in self._levels and (cx, cz) in self._levels[internal_dimension] ): chunk_data = {} for key, val in self._db.iterate(iter_start, iter_end): if internal_dimension is None: if 9 <= len(key) <= 10: key_extension = key[8:] else: continue else: if ( 13 <= len(key) <= 14 and struct.unpack("<i", key[8:12])[0] == internal_dimension ): key_extension = key[12:] else: continue chunk_data[key_extension] = val return chunk_data else: raise ChunkDoesNotExist def put_chunk_data( self, cx: int, cz: int, data: Dict[bytes, bytes], dimension: "Dimension" ): """pass data to the region file class""" # get the region key internal_dimension = self._get_internal_dimension(dimension) self._levels[internal_dimension].add((cx, cz)) if internal_dimension is None: key_prefix = struct.pack("<ii", cx, cz) else: key_prefix = struct.pack("<iii", cx, cz, internal_dimension) for key, val in data.items(): self._batch_temp[key_prefix + key] = val def delete_chunk(self, cx: int, cz: int, dimension: "Dimension"): if dimension in self._dimension_name_map: internal_dimension = self._dimension_name_map[dimension] if ( internal_dimension in self._levels and (cx, cz) in self._levels[internal_dimension] ): chunk_data = self.get_chunk_data(cx, cz, dimension) self._levels[internal_dimension].remove((cx, cz)) for key in chunk_data.keys(): if internal_dimension is None: key_prefix = struct.pack("<ii", cx, cz) else: key_prefix = struct.pack("<iii", cx, cz, internal_dimension) self._batch_temp[key_prefix + key] = None
# A cache for objects implemented using leveldb for speed. import os import shutil import atexit from amulet.libs.leveldb import LevelDB from amulet.api.paths import get_temp_dir from amulet import log _path = os.path.join(get_temp_dir("cache"), "db") CacheDB = LevelDB(_path, True) def clear_db(): log.info("Removing cache.") CacheDB.close(compact=False) shutil.rmtree(_path) atexit.register(clear_db)
def test_read_write(self): self._clear_db() db = LevelDB(DB_PATH, True) with self.assertRaises(KeyError): db.get(b"random_key") key1 = b"key" value1 = b"value" db.put(key1, value1) self.assertEqual(db.get(key1), value1) key2 = key1 * 1000 value2 = value1 * 1000 db.put(key2, value2) self.assertEqual(db.get(key2), value2) db.close()
def test_create_fail(self): self._clear_db() with self.assertRaises(LevelDBException): db = LevelDB(DB_PATH)
def test_create_ldb(self): self._clear_db() db = LevelDB(DB_PATH, True) db.close()