@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
231 lines (230 loc) • 7.44 kB
TypeScript
/**
* 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>;
}