---
title: "Save and restore a 3D physics snapshot in C#"
url: https://recursiveai.org/onegame/cookbook/save-and-restore-3d-physics-snapshot/
description: "Save a OneGame 3D physics snapshot to bytes, advance the simulation and restore its step, hash, origin and events. Includes a file round-trip example."
version: "2.0.0"
---

# Save and restore a 3D physics snapshot in C#

**onegame** is a free, open-source game engine for .NET from Recursive AI. MIT or Apache-2.0, no editor required.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneGame.Physics) · [GitHub](https://github.com/recursive-ai-oss/onegame) · [Docs](https://recursiveai.org/onegame/docs/) · [Download example (.zip)](https://recursiveai.org/onegame/cookbook/save-and-restore-3d-physics-snapshot/save-and-restore-3d-physics-snapshot.zip)

A physics snapshot keeps simulation state so you can return to an earlier step.

```shell
dotnet add package RecursiveAI.OneGame.Physics
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

`Fixed` and `FVec3` are onegame’s deterministic fixed-point number and vector types.

```csharp
using OneGame.Core;
using OneGame.Physics;

var space = new PhysicsSpace3D();
space.AddSphere(Fixed.One,
    new FVec3(0, 5, 0));
byte[] saved = space.Snapshot();
space.Step();
space.Restore(saved);
Console.WriteLine(space.StepCount);
```

Prints the restored step count.

```text
0
```

Unzip [the example](https://recursiveai.org/onegame/cookbook/save-and-restore-3d-physics-snapshot/save-and-restore-3d-physics-snapshot.zip), then `dotnet run`.

## The full program

The download shifts the local origin, takes a snapshot after one step, advances again, then restores. The hash covers saved physics state, including events and origin; the separate event check below compares the event count.

```csharp
using OneGame.Core;
using OneGame.Physics;

var space = new PhysicsSpace3D();
var body = space.AddSphere(
    Fixed.One, new FVec3(100, 5, 0));
space.ShiftOrigin(new FVec3(100, 0, 0));
space.Step();
byte[] saved = space.Snapshot();
ulong savedHash = space.Hash;
var savedOrigin = space.Origin;
int savedEvents = space.Events.Count;
space.Step();
Console.WriteLine(
    $"Advanced steps: {space.StepCount}");
space.Restore(saved);
Console.WriteLine(
    $"Restored steps: {space.StepCount}");
Console.WriteLine(
    $"Hash matches: {space.Hash == savedHash}");
Console.WriteLine(
    "Origin matches: " +
    (space.Origin == savedOrigin));
Console.WriteLine(
    "Events match: " +
    (space.Events.Count == savedEvents));
Console.WriteLine(
    $"Body alive: {space.IsAlive(body)}");
```

`dotnet run` prints:

```text
Advanced steps: 2
Restored steps: 1
Hash matches: True
Origin matches: True
Events match: True
Body alive: True
```

Invalid snapshot input leaves the space unchanged; `Restore` rejects data larger than 64 MiB with `ArgumentOutOfRangeException`.

## Variations

Write the snapshot to a file and load it again. Append this to the full program:

```csharp
File.WriteAllBytes("physics.bin", saved);
space.Step();
space.Restore(File.ReadAllBytes("physics.bin"));
Console.WriteLine($"File round-trip: {space.Hash == savedHash}");
```

```text
File round-trip: True
```

## Related recipes

- [Sphere cast in a 3D physics world in C#](https://recursiveai.org/onegame/cookbook/sphere-cast-3d-physics-world/)
- [Query a 3D sphere overlap in C#](https://recursiveai.org/onegame/cookbook/query-3d-sphere-overlap/)
- [Fork 3D physics for prediction in C#](https://recursiveai.org/onegame/cookbook/fork-3d-physics-for-prediction/)

## The short answer

Call `Snapshot()` to obtain an independent byte array, then pass those bytes to `Restore()` to return the same 3D physics space to that state. The full program advances past the saved step and restores it, checking the hash, origin, event count and body reference. The file variation writes exactly those snapshot bytes and reads them back.

## How do I save and restore physics state?

Save the simulation, not only the visible transforms. A body’s position is not the whole state needed to continue a physics run. The space’s saved state includes velocities, contacts and their warm-start impulses, sleeping bodies, the layer matrix, characters, the step counter and the previous step’s events. The 3D space also saves and hashes its accumulated origin. These are the state contracts described in the [physics guide](https://recursiveai.org/onegame/docs/physics/).

`Snapshot()` returns independent bytes for the space’s `Restore`, not a complete game-world save or a storage-slot record. Your entities, inventory and game rules are outside this standalone example.

The download starts with a body at global X = 100, shifts the local origin by 100, and steps once before saving. It advances once more, so the count becomes two. Restoring brings the count back to one. Comparing the hash checks the saved physics sections as a whole; comparing the event count separately shows only that the number of events matches. In this small scene, there are no colliding pairs to generate contact events.

A `BodyRef` captured before the snapshot can name the same restored body afterward. The sample checks `IsAlive` instead of replacing the reference with a new body. Do not rebuild shapes from their drawn positions after a restore: that would create a different scene rather than continue the saved simulation.

### Save snapshot bytes to a file

The variation uses `File.WriteAllBytes` and `File.ReadAllBytes` because the snapshot is already bytes. After writing, it advances the space, reloads the file and checks the saved hash again. The file contains physics state only. Keep any application-level information you need to choose a save, such as a level identifier or game version, in your own save format.

The wrapper bounds physics snapshots at 64 MiB. `Snapshot` checks the underlying snapshot-size bound before allocating its scratch storage, and `Restore` rejects an input beyond the limit. Invalid snapshot data leaves the space unchanged. Treat a missing file or a failed restore as a load failure rather than continuing as though the requested state was applied.

The raw snapshot bytes carry no onegame version or tick-rate header, so store and check those yourself. Use a compatible simulation configuration. The standalone example restores into the same space with unchanged options. This recipe does not promise raw snapshots are a migration format between arbitrary package versions or game configurations.

After restoring, continue with the space’s fixed stepping API. A registered world already schedules its physics step after entities, whereas the standalone console example must call `Step` itself. If you need to predict an alternative future without rewinding the live space, make a [prediction fork](https://recursiveai.org/onegame/cookbook/fork-3d-physics-for-prediction/) and restore there instead.
