public SaveTransaction(EngineEntityManager privateEntityManager, EntitySetDeltaRecorder deltaToSave, Map<String, EntityData.PlayerStore> unloadedPlayers, Map<String, PlayerStoreBuilder> loadedPlayers, GlobalStoreBuilder globalStoreBuilder, Map<Vector3i, CompressedChunkBuilder> unloadedChunks, Map<Vector3i, ChunkImpl> loadedChunks, GameManifest gameManifest, boolean storeChunksInZips, StoragePathProvider storagePathProvider, Lock worldDirectoryWriteLock, RecordAndReplaySerializer recordAndReplaySerializer, RecordAndReplayUtils recordAndReplayUtils, RecordAndReplayCurrentStatus recordAndReplayCurrentStatus) { this.privateEntityManager = privateEntityManager; this.deltaToSave = deltaToSave; this.unloadedPlayers = unloadedPlayers; this.loadedPlayers = loadedPlayers; this.unloadedChunks = unloadedChunks; this.loadedChunks = loadedChunks; this.globalStoreBuilder = globalStoreBuilder; this.gameManifest = gameManifest; this.storeChunksInZips = storeChunksInZips; this.storagePathProvider = storagePathProvider; this.saveTransactionHelper = new SaveTransactionHelper(storagePathProvider); this.worldDirectoryWriteLock = worldDirectoryWriteLock; this.recordAndReplaySerializer = recordAndReplaySerializer; this.recordAndReplayUtils = recordAndReplayUtils; this.recordAndReplayCurrentStatus = recordAndReplayCurrentStatus; }
@Override public void checkAndRepairSaveIfNecessary() throws IOException { saveTransactionHelper.cleanupSaveTransactionDirectory(); if (Files.exists(getStoragePathProvider().getUnmergedChangesPath())) { saveTransactionHelper.mergeChanges(); } }
private void mergeChanges() throws IOException { worldDirectoryWriteLock.lock(); try { saveTransactionHelper.mergeChanges(); } finally { worldDirectoryWriteLock.unlock(); } }
@Override public void run() { if (isReplay()) { return; } try { if (Files.exists(storagePathProvider.getUnmergedChangesPath())) { // should not happen, as initialization should clean it up throw new IOException("Save rand while there were unmerged changes"); } saveTransactionHelper.cleanupSaveTransactionDirectory(); applyDeltaToPrivateEntityManager(); prepareChunksPlayersAndGlobalStore(); createPreviewImagesFolder(); createSaveTransactionDirectory(); writePlayerStores(); writeGlobalStore(); writeChunkStores(); saveGameManifest(); perpareChangesForMerge(); mergeChanges(); result = SaveTransactionResult.createSuccessResult(); logger.info("Save game finished"); saveRecordingData(); } catch (IOException | RuntimeException t) { logger.error("Save game creation failed", t); result = SaveTransactionResult.createFailureResult(t); } }
ReadWriteStorageManager(Path savePath, ModuleEnvironment environment, EngineEntityManager entityManager, BlockManager blockManager, BiomeManager biomeManager, ExtraBlockDataManager extraDataManager, boolean storeChunksInZips, RecordAndReplaySerializer recordAndReplaySerializer, RecordAndReplayUtils recordAndReplayUtils, RecordAndReplayCurrentStatus recordAndReplayCurrentStatus) throws IOException { super(savePath, environment, entityManager, blockManager, biomeManager, extraDataManager, storeChunksInZips); entityManager.subscribeForDestruction(this); entityManager.subscribeForChanges(this); // TODO Ensure that the component library and the type serializer library are thread save (e.g. immutable) this.privateEntityManager = createPrivateEntityManager(entityManager.getComponentLibrary()); Files.createDirectories(getStoragePathProvider().getStoragePathDirectory()); this.saveTransactionHelper = new SaveTransactionHelper(getStoragePathProvider()); this.saveThreadManager = TaskMaster.createFIFOTaskMaster("Saving", 1); this.config = CoreRegistry.get(Config.class); this.entityRefReplacingComponentLibrary = privateEntityManager.getComponentLibrary() .createCopyUsingCopyStrategy(EntityRef.class, new DelayedEntityRefCopyStrategy(this)); this.entitySetDeltaRecorder = new EntitySetDeltaRecorder(this.entityRefReplacingComponentLibrary); this.recordAndReplaySerializer = recordAndReplaySerializer; this.recordAndReplayUtils = recordAndReplayUtils; this.recordAndReplayCurrentStatus = recordAndReplayCurrentStatus; }