private void addChunksToSaveTransaction(
      SaveTransactionBuilder saveTransactionBuilder, ChunkProvider chunkProvider) {
    unloadedAndSavingChunkMap.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. Bz iterating we can make sure that all
     * entires removed from unloadedAndUnsavedChunkMap get added to unloadedAndSavingChunkMap.
     */
    Iterator<Map.Entry<Vector3i, CompressedChunkBuilder>> unsavedEntryIterator =
        unloadedAndUnsavedChunkMap.entrySet().iterator();
    while (unsavedEntryIterator.hasNext()) {
      Map.Entry<Vector3i, CompressedChunkBuilder> entry = unsavedEntryIterator.next();
      unloadedAndSavingChunkMap.put(entry.getKey(), entry.getValue());
      unsavedEntryIterator.remove();
    }

    chunkProvider
        .getAllChunks()
        .stream()
        .filter(ManagedChunk::isReady)
        .forEach(
            chunk -> {
              // If there is a newer undisposed version of the chunk,we don't need to save the
              // disposed version:
              unloadedAndSavingChunkMap.remove(chunk.getPosition());
              ChunkImpl chunkImpl =
                  (ChunkImpl) chunk; // this storage manager can only work with ChunkImpls
              saveTransactionBuilder.addLoadedChunk(chunk.getPosition(), chunkImpl);
            });

    for (Map.Entry<Vector3i, CompressedChunkBuilder> entry : unloadedAndSavingChunkMap.entrySet()) {
      saveTransactionBuilder.addUnloadedChunk(entry.getKey(), entry.getValue());
    }
  }
  private boolean isSavingNecessary() {
    ChunkProvider chunkProvider = CoreRegistry.get(ChunkProvider.class);
    int unloadedChunkCount = unloadedAndUnsavedChunkMap.size();
    int loadedChunkCount = chunkProvider.getAllChunks().size();
    double totalChunkCount = unloadedChunkCount + loadedChunkCount;
    double percentageUnloaded = 100.0 * unloadedChunkCount / totalChunkCount;
    if (percentageUnloaded >= config.getSystem().getMaxUnloadedChunksPercentageTillSave()) {
      return true;
    }

    long currentTime = System.currentTimeMillis();
    if (nextAutoSave == null) {
      scheduleNextAutoSave();
      return false;
    }
    return currentTime >= nextAutoSave;
  }