UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

231 lines (230 loc) 7.44 kB
/** * ARCHITECTURE DOCUMENTATION: WorldBackupManager - Central Backup Service * ======================================================================== * * WorldBackupManager is the central service for managing world backups. * It coordinates between ManagedWorld instances, handles file deduplication, * and maintains the global manifest. * * ## Responsibilities * * 1. **World Management**: Create, list, update, delete ManagedWorlds * 2. **Backup Operations**: Create, restore, export, delete backups * 3. **File Deduplication**: Track file hashes across all backups * 4. **Manifest Management**: Maintain the global worlds manifest * * ## Storage Structure * * ``` * Documents/mctools/worlds/ * ├─ manifest.json (global index of all worlds) * ├─ a3k9m2p1/ (world folder) * │ ├─ world.json (world metadata) * │ └─ world20260101.../ (backup folders) * └─ b7n4x8q2/ (another world) * ``` * * ## File Deduplication Strategy * * The manager maintains a global `FileListings` map: * - Key: `{filename}|{size}|{md5hash}` * - Value: Path to the first occurrence of this file * * When backing up: * 1. Compute MD5 hash of each file * 2. Check if it exists in FileListings * 3. If yes: Store reference in backup.json, skip copying * 4. If no: Copy file and add to FileListings * * This is especially effective for LevelDB's immutable .ldb files. * * ## Usage * * ```typescript * const manager = new WorldBackupManager(worldContainerStorage); * await manager.load(); * * // Create a world * const world = await manager.createWorld("My World"); * * // Create a backup * const backup = await manager.createBackup(world.id, sourceWorldPath); * * // Restore a backup * await manager.restoreBackup(world.id, backup.id, targetPath); * * // Export as .mcworld * await manager.exportMcWorld(world.id, backup.id, outputPath); * ``` * * ## Related Files * * - IWorldBackupData.ts: Data interfaces * - ManagedWorld.ts: World entity class * - WorldBackup.ts: Backup entity class * - NodeFolder.ts: File operations with deduplication */ import IFolder from "../storage/IFolder"; import NodeStorage from "./NodeStorage"; import { FileListings } from "./NodeFolder"; import ManagedWorld from "./ManagedWorld"; import WorldBackup from "./WorldBackup"; import { IBackupOptions, IBackupResult, IRestoreResult, IExportResult } from "./IWorldBackupData"; export default class WorldBackupManager { private _containerStorage; private _containerFolder; private _manifest; private _worlds; private _fileListings; private _isLoaded; /** * Get the container folder for all worlds. */ get containerFolder(): IFolder; /** * Get the global file listings for deduplication. */ get fileListings(): FileListings; /** * Check if the manager has been loaded. */ get isLoaded(): boolean; /** * Get all loaded worlds. */ get worlds(): ManagedWorld[]; /** * Alias for worlds (for consistency with ServerManager API). */ get managedWorlds(): ManagedWorld[]; /** * Get the total number of backups across all worlds. */ get totalBackupCount(): number; /** * Create a new WorldBackupManager. * * @param containerStorage NodeStorage pointing to the worlds container folder * @param initialFileListings Optional initial file listings for deduplication */ constructor(containerStorage: NodeStorage, initialFileListings?: FileListings); /** * Create an empty manifest. */ private createEmptyManifest; /** * Load the manager: read manifest and discover worlds. */ load(): Promise<void>; /** * Load the global manifest. */ private loadManifest; /** * Save the global manifest. */ saveManifest(): Promise<void>; /** * Discover all worlds in the container folder. * Worlds are identified by their 8-character ID folder names. */ private discoverWorlds; /** * Build file listings from all existing backups for deduplication. */ private buildFileListings; /** * Create a new managed world. * * @param friendlyName User-visible name * @param configurationHash Optional initial configuration hash * @returns The newly created ManagedWorld */ createWorld(friendlyName: string, configurationHash?: string): Promise<ManagedWorld>; /** * Get a world by ID (synchronous lookup). */ getWorld(worldId: string): ManagedWorld | undefined; /** * Get a world by ID (async version, ensures loaded). */ getWorldAsync(worldId: string): Promise<ManagedWorld | undefined>; /** * Get a world by friendly name (first match). */ getWorldByName(friendlyName: string): Promise<ManagedWorld | undefined>; /** * Get or create a world for a server slot. * This provides a consistent way to manage backups for server slots. * * @param slotNumber The slot number (0, 1, 2, etc.) * @returns The ManagedWorld for this slot */ getOrCreateWorldForSlot(slotNumber: number): Promise<ManagedWorld>; /** * List all worlds. */ listWorlds(): Promise<ManagedWorld[]>; /** * Update a world's metadata. */ updateWorld(worldId: string, updates: { friendlyName?: string; notes?: string; tags?: string[]; }): Promise<boolean>; /** * Delete a world and all its backups. */ deleteWorld(worldId: string): Promise<boolean>; /** * Create a backup of a world from a source path. * * @param worldId The world ID to backup to * @param sourceWorldPath Path to the world folder to backup (e.g., slot0/worlds/defaultWorld/) * @param options Backup options * @returns Backup result */ createBackup(worldId: string, sourceWorldPath: string, options?: IBackupOptions): Promise<IBackupResult>; /** * List backups for a world. */ listBackups(worldId: string): Promise<WorldBackup[]>; /** * Get a specific backup. */ getBackup(worldId: string, backupId: string): Promise<WorldBackup | undefined>; /** * Restore a backup to a target path. */ restoreBackup(worldId: string, backupId: string, targetPath: string, clearTarget?: boolean): Promise<IRestoreResult>; /** * Delete a backup. */ deleteBackup(worldId: string, backupId: string): Promise<boolean>; /** * Export a backup as .mcworld file. */ exportMcWorld(worldId: string, backupId: string, outputPath: string, worldName?: string): Promise<IExportResult>; /** * Prune old backups for a world. */ pruneBackups(worldId: string, keepCount: number): Promise<number>; /** * Get or create a world for a given friendly name. * If a world with this name exists, returns it. Otherwise creates a new one. */ getOrCreateWorld(friendlyName: string, configurationHash?: string): Promise<ManagedWorld>; /** * Get the latest backup for a world. */ getLatestBackup(worldId: string): Promise<WorldBackup | undefined>; /** * Ensure the manager is loaded. */ private ensureLoaded; /** * Reload the manager (refresh from disk). */ reload(): Promise<void>; }