Sites

Menu
These are the docs for 14.0, an old version of SpatialOS. The docs for this version are frozen: we do not correct, update or republish them. 14.2 is the newest →

Snapshots

All code examples on this page assume import improbable.worker.*; and import example.*; (the generated code namespace).

The SDK provides two classes to manipulate snapshots stored in files; Improbable.worker.SnapshotInputStream to read snapshot files from disk, one entity at a time, and Improbable.worker.SnapshotOutputStream to write snapshot files to disk, one entity at a time. These stream classes are the recommended methods of manipulating snapshots as they do not require the entire snapshot to be stored in memory when reading or writing a snapshot.

Improbable.worker.SnapshotInputStream has a constructor and three public methods:

/**
 * Open a SnapshotInputStream to load a snapshot from a file.
 *
 * @param path The path to the snapshot file.
 * @throws StreamBadStateException if the SnapshotInputStream failed to be initialized.
 *         The SnapshotInputStream is not in a usable state and it is closed.
 */
public SnapshotInputStream(String path) throws StreamBadStateException;

/**
 * Returns true if the SnapshotInputStream has not reached the end of the snapshot file.
 *
 * @return A boolean which is true if the SnapshotInputStream has not reached the end of the snapshot and false otherwise.
 */
public boolean hasNext();

/**
 * Load the next (EntityId, Entity) pair from the snapshot file.
 *
 * @return A Map.Entry<EntityId, Entity> containing the (EntityId, Entity) pair read from the
 *         snapshot file.
 * @throws StreamBadStateException if a snapshot internal error occurred.
 *         The SnapshotInputStream is not in a usable state.
 * @throws StreamInvalidDataException if the last entity read operation failed.
 *         The SnapshotInputStream is in a usable state.
 * @throws EOFException is the end of the snapshot was reached while trying to execute the last entity read operation.
 */
public Map.Entry<EntityId, Entity> readEntity() throws StreamBadStateException,
    StreamInvalidDataException, EOFException;

/**
 * Close the SnapshotInputStream and release its resources.
 */
public void close();

Improbable.worker.SnapshotOutputStream has a constructor and two public methods:

/**
 * Open a SnapshotOutputStream to write a snapshot to a file saved at the String path.
 *
 * @param path The path to write the snapshot file to.
 * @throws StreamBadStateException if the SnapshotOutputStream failed to be initialized.
 *         The SnapshotOutputStream is not in a usable state and it is closed.
 */
public SnapshotOutputStream(String path) throws StreamBadStateException;

/**
 * Write the (EntityId, Entity) pair to the snapshot.
 *
 * @param entityId The EntityId of the Entity to be written to the Snapshot.
 * @param entity The Entity to be written to the Snapshot.
 *
 * @throws StreamBadStateException if a snapshot internal error occurred.
 *         The SnapshotInputStream is not in a usable state.
 * @throws StreamInvalidDataException if the last entity write operation failed.
 *         The SnapshotInputStream is in a usable state.
 */
public void writeEntity(EntityId entityId, Entity entity) throws StreamBadStateException, StreamInvalidDataException;

/**
 * Close the SnapshotOutputStream.
 */
public void close();

Note that, unlike the rest of the API described in this document, snapshot manipulation does not require a Connection, making it possible to develop standalone, offline snapshot manipulation tools. However, we recommend using the build infrastructure provided by SpatialOS for workers to build your standalone tools.

Here is an example of loading a snapshot, performing some manipulation on it, and saving it back. It uses the types and components defined in the example from Generated code.

private static void addLowHealthEffectToEntities(String snapshotFilename, String newSnapshotFilename) {
  try {
    // Create a SnapshotInputStream to read from the snapshot file.
    SnapshotInputStream inputStream = new SnapshotInputStream(snapshotFilename);
    // Create a SnapshotOutputStream to write to a snapshot file.
    SnapshotOutputStream outputStream = new SnapshotOutputStream(newSnapshotFilename);
    java.util.Map.Entry<EntityId, Entity> entry;

    // Iterate over each entity in the snapshot.
    while (inputStream.hasNext()) {
      try {
        // Read the next Map.Entry<Entity, Entity> from the stream.
        entry = inputStream.readEntity();
        EntityId entityId = entry.getKey();
        Entity entity = entry.getValue();
        // Add the "LowHealth" effect to all entities that have a Creature component and less
        // than 10 health points.
        if (entity.get(Creature.COMPONENT).isPresent()) {
          CreatureData status = entity.get(Creature.COMPONENT).get();
          if (status.getHealth() < 10) {
            status.getEffects().add(new StatusEffect("LowHealth", 100));
          }
        }
        // Write the (entityId, entity) pair to the snapshot file.
        outputStream.writeEntity(entityId, entity);
      } catch (StreamInvalidDataException e) {
        // The last read or write operation failed, but the snapshot is still usable.
        // Log or handle the operation failure. Possible errors include unregistered component,
        // failed serialization, missing Persistence component and writing entities with the same id.
        logException(e.getMessage());
      } catch (StreamBadStateException e) {
        // An internal error occurred when reading or writing and the snapshot is not usable.
        logException(e.getMessage());
        break;
      } catch (EOFException e) {
        // The eof was reached when reading. Not an error if used as alternative to HasNext.
        logException(e.getMessage());
        break;
      }
    }
    // Write the end of the snapshot and release the SnapshotOutputStream's resources.
    outputStream.close();
    inputStream.close();
  } catch (StreamBadStateException e) {
    // The snapshot failed to be initialized, and the stream is not usable.
    logException(e.getMessage());
  }
}

Search results

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums