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.1 is the newest →

Manipulating snapshots

All code examples in this section assume using Improbable.Worker; and using Example; (the generated code namespace).

The SDK provides two classes in to manipulate snapshots stored in files:

This lets you write tools to perform offline transformations of the simulation state, or to programmatically create the starting point of a simulation.

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.

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.

SnapshotInputStream

SnapshotInputStream has a constructor and three public methods:

// Creates a SnapshotInputStream to read the snapshot file from the given path.
// Throws a StreamBadStateException if the SnapshotInputStream failed to be initialized and is not
// in a usable state. Further calls to the stream are ignored and this exception is re-thrown.
public SnapshotInputStream(string path)

// Releases the resources of the SnapshotInputStream.
public void Dispose()

// Reads the next EntityId and Entity pair from the Snapshot.
// Throws a StreamBadStateException if a snapshot internal error occurred and the stream is not
// in a usable state. Throws a StreamInvalidDataException if the last entity read operation on
// the snapshot stream failed and the stream is still in a usable state. Throws a
// System.IO.EndOfStreamException if the end of Snapshot was reached while trying to execute the
// last entity read operation.
// Returns a pair containing the read entity id and entity.
public System.Collections.Generic.KeyValuePair<EntityId, Entity> ReadEntity()

// Returns true if the SnapshotInputStream has not reached EOF.
public bool HasNext();

SnapshotOutputStream

SnapshotOutputStream has a constructor and two public methods:

// Creates a SnapshotOutputStream to write to the snapshot file in the given path.
// Throws a StreamBadStateException if the SnapshotOutputStream failed to be initialized and is not
// in a usable state. Further calls to the stream are ignored and this exception is re-thrown.
public SnapshotOutputStream(string path)

// Writes the end of snapshot header and releases the resources of the SnapshotOutputStream.
public void Dispose()

// Writes the EntityId and Entity pair to the output stream.
// Throws a StreamBadStateException if a snapshot internal error occurred and the stream is not in
// a usable state. Throws a StreamInvalidDataException if the last entity write operation on the
// snapshot stream failed and the stream is still in a usable.
public void WriteEntity(EntityId entityId, Entity entity)

Example

The assemblies that contain the generated code for the components present in the snapshots your program manipulates must be loaded (not just referenced); otherwise, the SDK will report “undefined component ID” errors.

These assemblies are loaded automatically whenever your program uses any class defined in them, but if this is not the case, you can manually load them using the Assembly.Load() method.

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. This example highlights the different errors which may arise after different snapshot calls, and you can choose how to handle them at your convenience.

public static void AddLowHealthEffectToEntities(string snapshotFilename, string newSnapshotFilename)
{
  try
  {
    // Open a SnapshotInputStream to read from the snapshot file saved at snapshotFilename.
    SnapshotInputStream inputStream = new SnapshotInputStream(snapshotFilename);
    // Open a SnapshotOutputStream to write to a snapshot file at newSnapshotFilename.
    SnapshotOutputStream outputStream = new SnapshotOutputStream(newSnapshotFilename);

    // Iterate over every entity in the snapshot file.
    while (inputStream.HasNext())    // this check can be done alternatively by catching EndOfStreamException.
    {
      try
      {
        var readEntity = inputStream.ReadEntity();

        if (readEntity.Value.Get(Creature.Metaclass).HasValue)
        {
          var status = readEntity.Value.Get(Creature.Metaclass).Value;
          // Add the "LowHealth" effect to all entities that have a Creature component
          // and less than 10 health points.
          if (status.health < 10)
          {
            status.effects.Add(new StatusEffect("LowHealth", 100));
          }
        }
        // Write the (entityId, entity) pair to the snapshot file.
        outputStream.WriteEntity(readEntity.Key, readEntity.Value);
      }
      catch (StreamInvalidDataException ex)
      {
        // 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.
        Log(ex.Message);
      }
      catch (StreamBadStateException ex)
      {
        // An internal error occurred when reading or writing and the snapshot is not usable.
        Log(ex.Message);
        break;
      }
      catch (System.IO.EndOfStreamException ex)
      {
        // The eof was reached when reading. Not an error if used as alternative to HasNext.
        Log(ex.Message);
        break;
      }
    }
    // Dispose of the inputStream to release the stream's resources.
    inputStream.Dispose();
    // Dispose of the outputStream to write the end of the Snapshot and release the stream's
    // resources.
    outputStream.Dispose();
  }
  catch (StreamBadStateException ex)
  {
    // The snapshot failed to be initialized, and the stream is not usable.
    Log(ex.Message);
  }
}

Search results

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums