private SaveTransaction createSaveTransaction() { SaveTransactionBuilder saveTransactionBuilder = new SaveTransactionBuilder(privateEntityManager, entitySetDeltaRecorder, isStoreChunksInZips(), getStoragePathProvider(), worldDirectoryWriteLock, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus); ChunkProvider chunkProvider = CoreRegistry.get(ChunkProvider.class); NetworkSystem networkSystem = CoreRegistry.get(NetworkSystem.class); addChunksToSaveTransaction(saveTransactionBuilder, chunkProvider); addPlayersToSaveTransaction(saveTransactionBuilder, networkSystem); addGlobalStoreBuilderToSaveTransaction(saveTransactionBuilder); addGameManifestToSaveTransaction(saveTransactionBuilder); return saveTransactionBuilder.build(); }
@Override public void update() { if (!isRunModeAllowSaving()) { return; } if (isSaving()) { return; } checkSaveTransactionAndClearUpIfItIsDone(); if (saveRequested) { startSaving(); } else if (isSavingNecessary()) { startAutoSaving(); } }
@Override public void deactivatePlayer(Client client) { EntityRef character = client.getEntity().getComponent(ClientComponent.class).character; PlayerStoreBuilder playerStoreBuilder = createPlayerStore(client, character); EntityData.PlayerStore playerStore = playerStoreBuilder.build(getEntityManager()); deactivateOrDestroyEntityRecursive(character); unloadedAndUnsavedPlayerMap.put(client.getId(), playerStore); }
@Test public void testGlobalEntitiesStoredAndRestored() throws Exception { EntityRef entity = entityManager.create(new StringComponent("Test")); long entityId = entity.getId(); esm.waitForCompletionOfPreviousSaveAndStartSaving(); esm.finishSavingAndShutdown(); EntitySystemSetupUtil.addReflectionBasedLibraries(context); EntitySystemSetupUtil.addEntityManagementRelatedClasses(context); EngineEntityManager newEntityManager = context.get(EngineEntityManager.class); StorageManager newSM = new ReadWriteStorageManager(savePath, moduleEnvironment, newEntityManager, blockManager, biomeManager, extraDataManager, false, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus); newSM.loadGlobalStore(); List<EntityRef> entities = Lists.newArrayList(newEntityManager.getEntitiesWith(StringComponent.class)); assertEquals(1, entities.size()); assertEquals(entityId, entities.get(0).getId()); }
@Test public void testChunkSurvivesStorageSaveAndRestore() throws Exception { Chunk chunk = new ChunkImpl(CHUNK_POS, blockManager, biomeManager, extraDataManager); chunk.setBlock(0, 0, 0, testBlock); chunk.setBlock(0, 4, 2, testBlock2); chunk.markReady(); ChunkProvider chunkProvider = mock(ChunkProvider.class); when(chunkProvider.getAllChunks()).thenReturn(Arrays.asList(chunk)); when(chunkProvider.getChunk(Matchers.any(Vector3i.class))).thenReturn(chunk); CoreRegistry.put(ChunkProvider.class, chunkProvider); boolean storeChunkInZips = true; esm.setStoreChunksInZips(storeChunkInZips); esm.waitForCompletionOfPreviousSaveAndStartSaving(); esm.finishSavingAndShutdown(); EntitySystemSetupUtil.addReflectionBasedLibraries(context); EntitySystemSetupUtil.addEntityManagementRelatedClasses(context); EngineEntityManager newEntityManager = context.get(EngineEntityManager.class); StorageManager newSM = new ReadWriteStorageManager(savePath, moduleEnvironment, newEntityManager, blockManager, biomeManager, extraDataManager, storeChunkInZips, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus); newSM.loadGlobalStore(); ChunkStore restored = newSM.loadChunkStore(CHUNK_POS); assertNotNull(restored); assertEquals(CHUNK_POS, restored.getChunkPosition()); assertNotNull(restored.getChunk()); assertEquals(testBlock, restored.getChunk().getBlock(0, 0, 0)); assertEquals(testBlock2, restored.getChunk().getBlock(0, 4, 2)); }
@Override protected void setupStorageManager() throws IOException { ModuleManager moduleManager = context.get(ModuleManager.class); EngineEntityManager engineEntityManager = context.get(EngineEntityManager.class); BlockManager blockManager = context.get(BlockManager.class); BiomeManager biomeManager = context.get(BiomeManager.class); RecordAndReplaySerializer recordAndReplaySerializer = context.get(RecordAndReplaySerializer.class); Path savePath = PathManager.getInstance().getSavePath("world1"); RecordAndReplayUtils recordAndReplayUtils = new RecordAndReplayUtils(); RecordAndReplayCurrentStatus recordAndReplayCurrentStatus = context.get(RecordAndReplayCurrentStatus.class); ModuleEnvironment environment = context.get(ModuleManager.class).getEnvironment(); context.put(BlockFamilyLibrary.class, new BlockFamilyLibrary(environment,context)); ExtraBlockDataManager extraDataManager = context.get(ExtraBlockDataManager.class); context.put(StorageManager.class, new ReadWriteStorageManager(savePath, moduleManager.getEnvironment(), engineEntityManager, blockManager, biomeManager, extraDataManager, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus)); }
private void startAutoSaving() { logger.info("Auto Saving - Creating game snapshot"); PerformanceMonitor.startActivity("Auto Saving"); ComponentSystemManager componentSystemManager = CoreRegistry.get(ComponentSystemManager.class); for (ComponentSystem sys : componentSystemManager.iterateAll()) { sys.preAutoSave(); } saveTransaction = createSaveTransaction(); saveThreadManager.offer(saveTransaction); for (ComponentSystem sys : componentSystemManager.iterateAll()) { sys.postAutoSave(); } scheduleNextAutoSave(); PerformanceMonitor.endActivity(); entitySetDeltaRecorder = new EntitySetDeltaRecorder(this.entityRefReplacingComponentLibrary); logger.info("Auto Saving - Snapshot created: Writing phase starts"); }
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; }
private void startSaving() { logger.info("Saving - Creating game snapshot"); PerformanceMonitor.startActivity("Saving"); ComponentSystemManager componentSystemManager = CoreRegistry.get(ComponentSystemManager.class); for (ComponentSystem sys : componentSystemManager.iterateAll()) { sys.preSave(); } saveRequested = false; saveTransaction = createSaveTransaction(); saveThreadManager.offer(saveTransaction); if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.NOT_ACTIVATED) { saveGamePreviewImage(); } for (ComponentSystem sys : componentSystemManager.iterateAll()) { sys.postSave(); } PerformanceMonitor.endActivity(); entitySetDeltaRecorder = new EntitySetDeltaRecorder(this.entityRefReplacingComponentLibrary); logger.info("Saving - Snapshot created: Writing phase starts"); }
@Override public void finishSavingAndShutdown() { if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.RECORDING) { recordAndReplayUtils.setShutdownRequested(true); } saveThreadManager.shutdown(new ShutdownTask(), true); checkSaveTransactionAndClearUpIfItIsDone(); }
private void addPlayersToSaveTransaction(SaveTransactionBuilder saveTransactionBuilder, NetworkSystem networkSystem) { unloadedAndSavingPlayerMap.clear(); /* * New entries might be added concurrently. By using putAll + clear to transfer entries we might loose new * ones added in between putAll and clear. By iterating we can make sure that all entities removed * from unloadedAndUnsavedPlayerMap get added to unloadedAndSavingPlayerMap. */ Iterator<Map.Entry<String, EntityData.PlayerStore>> unsavedEntryIterator = unloadedAndUnsavedPlayerMap.entrySet().iterator(); while (unsavedEntryIterator.hasNext()) { Map.Entry<String, EntityData.PlayerStore> entry = unsavedEntryIterator.next(); unloadedAndSavingPlayerMap.put(entry.getKey(), entry.getValue()); unsavedEntryIterator.remove(); } for (Client client : networkSystem.getPlayers()) { // If there is a newer undisposed version of the player,we don't need to save the disposed version: unloadedAndSavingPlayerMap.remove(client.getId()); EntityRef character = client.getEntity().getComponent(ClientComponent.class).character; saveTransactionBuilder.addLoadedPlayer(client.getId(), createPlayerStore(client, character)); } for (Map.Entry<String, EntityData.PlayerStore> entry : unloadedAndSavingPlayerMap.entrySet()) { saveTransactionBuilder.addUnloadedPlayer(entry.getKey(), entry.getValue()); } }
@Test public void testReferenceRemainsValidOverStorageRestoral() throws Exception { EntityRef someEntity = entityManager.create(); character.addComponent(new EntityRefComponent(someEntity)); esm.waitForCompletionOfPreviousSaveAndStartSaving(); esm.finishSavingAndShutdown(); EntitySystemSetupUtil.addReflectionBasedLibraries(context); EntitySystemSetupUtil.addEntityManagementRelatedClasses(context); EngineEntityManager newEntityManager = context.get(EngineEntityManager.class); StorageManager newSM = new ReadWriteStorageManager(savePath, moduleEnvironment, newEntityManager, blockManager, biomeManager, extraDataManager, false, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus); newSM.loadGlobalStore(); PlayerStore restored = newSM.loadPlayerStore(PLAYER_ID); restored.restoreEntities(); assertTrue(restored.getCharacter().getComponent(EntityRefComponent.class).entityRef.exists()); }
esm = new ReadWriteStorageManager(savePath, moduleEnvironment, entityManager, blockManager, biomeManager, extraDataManager, false, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus); context.put(StorageManager.class, esm);
private void waitForCompletionOfPreviousSave() { if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.REPLAY_FINISHED) { recordAndReplayUtils.setShutdownRequested(true); //Important to trigger complete serialization in a recording } if (saveTransaction != null && saveTransaction.getResult() == null) { saveThreadManager.shutdown(new ShutdownTask(), true); saveThreadManager.restart(); } checkSaveTransactionAndClearUpIfItIsDone(); }
locationComponent.setWorldPosition(positionInChunk); entity.addComponent(locationComponent); esm.waitForCompletionOfPreviousSaveAndStartSaving(); esm.finishSavingAndShutdown(); StorageManager newSM = new ReadWriteStorageManager(savePath, moduleEnvironment, newEntityManager, blockManager, biomeManager, extraDataManager, false, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus); newSM.loadGlobalStore();
context.put(StorageManager.class, new ReadWriteStorageManager(savePath, moduleManager.getEnvironment(), engineEntityManager, mockBlockManager, biomeManager, extraDataManager, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus));
try { storageManager = writeSaveGamesEnabled ? new ReadWriteStorageManager(saveOrRecordingPath, environment, entityManager, blockManager, biomeManager, extraDataManager, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus) : new ReadOnlyStorageManager(saveOrRecordingPath, environment, entityManager, blockManager, biomeManager, extraDataManager); } catch (IOException e) {