> For the complete documentation index, see [llms.txt](https://morningheartgames.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://morningheartgames.gitbook.io/docs/gameplay-ability-toolkit-ecs/build-with-it/netcode-for-entities.md).

# Netcode for Entities

This page shows how to run ECS actors in a server-authoritative game with Unity's Netcode for Entities package. The server runs the rules and owns the result. The player's client predicts its own abilities, so a button press has an effect at once, and corrects itself when the server disagrees. By the end you will have a player actor that replicates, a client that activates abilities on it, and a way to check the setup.

Netcode for Entities is optional. Without it, nothing here applies and the ECS runtime works as before.

**Before you start**

* Your actors work in a single-player scene. See [Getting started](/docs/gameplay-ability-toolkit-ecs/start/getting-started.md).
* You know the basics of Netcode for Entities: client and server worlds, ghosts, ghost owners and connections. This page covers what the add-on adds, not Netcode itself.
* You use Unity 6000.6 or newer, with Netcode for Entities (`com.unity.netcode`) 6.6.0 or newer.

## Limits to know first

* **Delivery runs on the server and is not predicted on clients.** A client predicts that an ability activates, pays, cools down, grants tags and plays its montage. It does not predict who the ability hits. Hits, and the damage they do, arrive from the server. See [Abilities that reach other actors](#abilities-that-reach-other-actors).
* **Visible network projectiles need ghost prefabs.** A projectile the server fires is seen on clients only if its prefab is a ghost.
* **Use Netcode for Entities or the toolkit's Netcode for GameObjects integration in a project, not both.** See [Netcode for Entities or Netcode for GameObjects](#netcode-for-entities-or-netcode-for-gameobjects).
* **The server does not check the level a client asks for.** See [Activating from a client](#activating-from-a-client).
* **Only the runtime's own state is rolled back.** State your own systems keep elsewhere is not. See [What is replicated](#what-is-replicated).
* **The ECS Swarm demo is not a networked game.** In a project with Netcode for Entities it runs in the server world only. See [ECS Swarm demo](/docs/gameplay-ability-toolkit-ecs/start/swarm-demo.md).

## Netcode for Entities or Netcode for GameObjects

The toolkit has two networking integrations. The GameObject runtime uses Netcode for GameObjects, described in the toolkit's [Unity Netcode for GameObjects](https://morningheartgames.gitbook.io/docs/gameplay-ability-toolkit/integrations/unity-netcode) page. The ECS runtime uses Netcode for Entities, described here. They are different packages with similar names:

| Package                         | Name                                                     |
| ------------------------------- | -------------------------------------------------------- |
| `com.unity.netcode`             | Netcode for Entities. Used by this page.                 |
| `com.unity.netcode.gameobjects` | Netcode for GameObjects. Used by the GameObject runtime. |

You cannot install both in one project. Each declares an editor assembly, `Unity.Netcode.Editor` for one and `Unity.NetCode.Editor` for the other. Unity compares assembly names without regard to case and rejects the duplicate, so scripts stop compiling. If you see an error such as `Assembly with name 'Unity.Netcode.Editor' already exists`, remove one of the two packages. **Tools > Gameplay Ability Toolkit > Dashboard > ECS Runtime** has a **Networking packages** section that reports which are installed.

## Set up a player actor

1. **Install Netcode for Entities.** Open **Tools > Gameplay Ability Toolkit > Dashboard** and go to the **Dependencies** page. In the **Netcode for Entities** row, click **Package Manager** and install the package. Wait for Unity to recompile. Nothing else enables the integration: it switches on when the package is present.
2. **Make the catalog a prefab.** A ghost is a prefab asset, and a prefab asset cannot refer to an object in a scene. So the catalog its actors use has to be on a prefab too.
   1. Create an empty GameObject and add **Gas Catalog Authoring** (see [Authoring](/docs/gameplay-ability-toolkit-ecs/build-with-it/authoring.md)).
   2. Drag it into the Project window to make a prefab, and delete it from the scene.
   3. Put one instance of the catalog prefab in your SubScene. That instance bakes the world's catalog.
3. **Make the actor a ghost prefab.**
   1. Create a GameObject with **Gas Entity Authoring**, with its attribute set and abilities.
   2. Add `GhostAuthoringComponent` (from Netcode for Entities) to the same GameObject, and save it as a prefab. The ghost component must be on the prefab's root.
   3. Tick **Has Owner** if a player controls the actor.
   4. Leave **Catalog** empty if the project has exactly one catalog prefab: the editor fills it in. Otherwise assign the catalog prefab.
4. **Let the automatic setup run.** You do not need to press anything. Baking and the editor's automatic setup do the following. The setup runs when the hierarchy or a component changes, and when the editor loads. It does not run in Play mode. To run it by hand, choose **Tools > Gameplay Ability Toolkit > ECS > Re-run automatic setup**.

   | What                                                             | How                                                                                             |
   | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
   | The replicated copies of the actor's state (`GasGhost…` buffers) | Added to every ghost that has **Gas Entity Authoring**.                                         |
   | `GasAbilityInput`, the predicted input                           | Added to a ghost that has an owner.                                                             |
   | `AutoCommandTarget`, which sends that input to the server        | Added by Netcode's own ghost baker, because the setup turns **Support Auto Command Target** on. |
   | **Supported Ghost Modes**                                        | Changed from All to Predicted.                                                                  |
   | **Default Ghost Mode**                                           | Changed from Interpolated to Owner Predicted, on a ghost that has an owner.                     |
   | **Optimization Mode**                                            | Set to Dynamic.                                                                                 |
   | **Importance**                                                   | Raised to 1 if it was lower.                                                                    |
   | **Rollback Prediction On Structural Changes**                    | Turned on. The runtime adds and removes buffer elements all the time, so leave it on.           |
   | **Catalog**                                                      | Filled in with the project's only catalog prefab.                                               |

   The setup visits each ghost once in each editor session and then leaves it alone, so a value you change by hand lasts until you restart Unity.

   With **Supported Ghost Modes** on Predicted only, Netcode makes one version of the ghost, and every client predicts it, not just its owner. To have only the owner predict and other clients interpolate, set **Supported Ghost Modes** to All and **Default Ghost Mode** to Owner Predicted. The setup changes an All back to Predicted the first time it visits the ghost in a new editor session, so set it again after you restart Unity.
5. **Check the setup.** Open **Tools > Gameplay Ability Toolkit > Dashboard > ECS Networking**. It counts the ghost prefabs in the project, and lists what it could not decide on its own for each GAS ghost. See [Checking the setup](#checking-the-setup).
6. **Spawn the actor on the server.** This is Netcode's own pattern, not the add-on's. When a connection is in game, instantiate the ghost prefab in the server world and make the connection its owner:

   ```csharp
   // networkId is the NetworkId.Value of the connection that should own the actor.
   var actor = state.EntityManager.Instantiate(actorPrefab);
   state.EntityManager.SetComponentData(actor, new GhostOwner { NetworkId = networkId });
   ```

   Both ends of the connection need `NetworkStreamInGame`. The client then receives its actor as a ghost and predicts it.

Two more things about the prefab:

* **The ghost must be a saved prefab asset.** A ghost type is the prefab's asset ID, so baking a scene object as a ghost fails.
* **A transform is opt-in.** `GhostAuthoringComponent` asks for no transform, and neither does **Gas Entity Authoring**. If your actor moves, request one from a baker of your own with `GetEntity(TransformUsageFlags.Dynamic)`.

### Automatic world creation

Installing `com.unity.netcode` turns on automatic client and server world creation in Play mode. That changes how every scene in the project plays, including scenes with no networking. To control it, create a `NetCodeConfig` asset and set its `EnableClientServerBootstrap` to disable automatic bootstrap, or add `OverrideAutomaticNetcodeBootstrap` to a root object of the active scene. The toolkit does not make this choice for you. The **World bootstrap** section of the ECS Networking page shows whether a `NetCodeConfig` asset turns it off.

## Where your code goes

With Netcode for Entities installed, `GasPredictedBootstrapSystem` moves `GasRequestSystemGroup`, `GasSimulationSystemGroup` and `GasResultSystemGroup` into Netcode's `PredictedSimulationSystemGroup`, in every client and server world. There is one set of rules. Prediction only decides when it runs. A world without Netcode keeps the groups where they were.

Your systems follow from that:

* **Put systems that ask in `GasRequestSystemGroup` and systems that read results in `GasResultSystemGroup`**, with `[UpdateInGroup]`, as on [Writing gameplay code](/docs/gameplay-ability-toolkit-ecs/build-with-it/gameplay-code.md). Both then run once for every tick that is simulated. A tick that is simulated again after a rollback asks again, starting from the state the rollback restored.
* **Do not order a system in `SimulationSystemGroup` against `GasSimulationSystemGroup`.** Entities ignores the order once the group has moved, with an "Ignoring invalid \[UpdateBefore] attribute" warning, and your system runs after the whole prediction loop instead.
* **The same system runs on the client and the server.** That is how prediction works. If something must happen on the server only, such as dealing damage, add `[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]` to the system.
* **Read time from `GasTime`, not `UnityEngine.Time`.** In a netcode world the runtime sets `GasTime` from the network tick, so the client and the server compute the same time for the same tick, and a rollback replays a past tick with its own time. `GasTime.Elapsed` is the tick number divided by the tick rate (60 when the project sets no tick rate). The runtime switches `GasTimeSystem` off in these worlds. A clock marked `Manual` is left alone.
* **On a client, change the runtime's state only through requests in `GasRequestSystemGroup`, or through predicted input.** The runtime of a predicted ghost is rebuilt from its ghost components at the start of every predicted tick, and anything you write outside the loop is overwritten.
* **On the server, you can change the state from any system.** It reaches clients in a later snapshot.
* **Guard one-off results with `NetworkTime.IsFirstTimeFullyPredictingTick`.** A system in `GasResultSystemGroup` sees a result each time a tick is simulated. To spawn a prefab or play a sound from there, act only on the first full prediction of a tick. Cue events are handled for you; see [Cues on a predicting client](#cues-on-a-predicting-client).
* **Keep prediction-loop code repeatable.** Simulating a tick again must give the same answer. Do not use the wall clock or unseeded random numbers there.

When an effect or activation targets an actor that this client is not simulating, it does nothing. A direct effect call reports `TargetNotSimulated`, and an activation fails with `InvalidRequest`. That actor's state comes from the server's snapshots.

## Activating from a client

There are two ways to ask the server for an ability. Use predicted input for anything the player triggers: the owning client sees the result at once. Use the RPC for a request that does not need to be predicted.

|                            | Predicted input                              | RPC                                                       |
| -------------------------- | -------------------------------------------- | --------------------------------------------------------- |
| How                        | The player's client writes `GasAbilityInput` | The client calls `GasNetcodeRequests.SendActivateAbility` |
| The client sees the result | At once, as a prediction                     | After the server's snapshot arrives                       |
| After a rollback           | The press is replayed with its tick          | Nothing to replay: the server decides                     |

For both, the actor is the source of the activation and the ability has no ability target. The server checks the same things as for any activation: the ability was granted, and its cooldown, cost and tag requirements. It does **not** compare the level in the message with the level the actor was granted. The level a client sends is the level the ability runs at. If levels change damage or cost in your game, a modified client can ask for any level, so keep that in mind before you rely on levels in a competitive game.

### Predicted input

`GasAbilityInput` is on every owned ghost. It is in the `GameplayAbilityToolkit.Entities.Netcode` namespace, which compiles only when `com.unity.netcode` is installed. Add `using GameplayAbilityToolkit.Entities.Netcode;` and `using Unity.NetCode;` to the scripts below. Write the input in `GhostInputSystemGroup`, which exists in client worlds only, and build the value from scratch every frame, from what the player is doing now:

```csharp
// Runs on the client only, once a frame, for the ghost the player owns.
[UpdateInGroup(typeof(GhostInputSystemGroup))]
public partial struct PlayerAbilityInputSystem : ISystem
{
    int _fireball;

    public void OnCreate(ref SystemState state)
    {
        _fireball = -1;
        state.RequireForUpdate<GasCatalog>();
    }

    public void OnUpdate(ref SystemState state)
    {
        if (_fireball < 0)
        {
            var catalog = SystemAPI.GetSingleton<GasCatalog>().Value;
            _fireball = catalog.Value.FindAbilityIndex("GA_Fireball");
            if (_fireball < 0)
            {
                return;
            }
        }

        bool pressed = UnityEngine.Input.GetKeyDown(UnityEngine.KeyCode.Q); // or your input package
        bool held = UnityEngine.Input.GetKey(UnityEngine.KeyCode.Q);

        foreach (var input in SystemAPI.Query<RefRW<GasAbilityInput>>().WithAll<GhostOwnerIsLocal>())
        {
            var value = new GasAbilityInput { AbilityIndex = _fireball, Level = 1, Held = held };
            if (pressed)
            {
                value.Trigger.Set();
            }

            input.ValueRW = value;
        }
    }
}
```

| Field          | Meaning                                                                                                                                                      |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `AbilityIndex` | The ability's catalog index, or -1 for no request.                                                                                                           |
| `Level`        | The level to activate at. 0 or less means 1.                                                                                                                 |
| `Trigger`      | An `InputEvent`. Set it on the frame of the press. Netcode reports it as set on exactly one tick, so a held button does not activate the ability every tick. |
| `Held`         | Whether the button is down now. A level, not an event. The runtime copies it into `GasInputState` every tick, which is what input waits read.                |

What happens next:

1. Netcode sends the input to the server and records it for each tick.
2. `GasPredictedInputSystem` runs first in `GasRequestSystemGroup`, on the client and on the server. For each tick it turns a set `Trigger` into an activation request, with the input Netcode recorded for that tick.
3. The request goes through the ordinary activation path. Every gate still applies on both sides. The client predicts the ability at once, and the server activates it on the same tick from the same input.
4. A tick simulated again after a rollback sees the press again, and activates again. The rollback took the first activation away with the rest of the state, so the ability is not paid for twice.

The system only reads the input. It never clears it.

### RPC

```csharp
var connection = SystemAPI.GetSingletonEntity<NetworkId>();   // the client's connection
GasNetcodeRequests.SendActivateAbility(state.EntityManager, connection, _fireball, level: 1);
```

The message carries only the ability index and the level. On the server, `GasNetcodeActivationRpcReceiveSystem` runs in `GasRequestSystemGroup`. It finds the ghost whose `GhostOwner.NetworkId` matches the sender's `NetworkId`, queues an activation for it, and deletes the message. A message from a connection that owns no ghost is dropped, once any ghost with an owner exists in the server world. A message that names an ability the actor does not have fails like any other activation, with `InvalidRequest`. The sender does not get the result back: the RPC is fire-and-forget, and the client learns the outcome from the replicated state.

## How prediction works

A client does not wait for the server. It runs the same rules on its own copy of the actor and shows the result. When the server's snapshot arrives and disagrees, the client rewinds to the server's state and plays the ticks since then again.

For this to work, the runtime's state has to move between two places. The runtime keeps an actor's attributes, tags, ability slots and effects in its own buffers. Netcode can only roll back and compare *ghost components*. So the add-on keeps a copy of the runtime's state in ghost components (the `GasGhost…` buffers), and copies between the two around every predicted tick.

| When                             | System                                                 | World          | What it does                                                                                                                                                              |
| -------------------------------- | ------------------------------------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Start of the tick                | `GasPredictedClockSystem`                              | Client, server | Sets `GasTime` from the network tick.                                                                                                                                     |
| Start of the tick                | `GasPredictedStateRestoreSystem`                       | Client         | Copies the ghost components into the runtime's buffers, wherever they differ. After a snapshot, Netcode has already put the ghost components back to the server's values. |
| Start of the tick                | `GasPredictedCueMarkSystem`                            | Client         | Records how many cue events each actor holds, for the cue drop below.                                                                                                     |
| First in `GasRequestSystemGroup` | `GasPredictedInputSystem`                              | Client, server | Turns this tick's `GasAbilityInput` into an activation request.                                                                                                           |
| The tick                         | Your request systems, the runtime, your result systems | Client, server | The rules, as in a single-player game.                                                                                                                                    |
| End of the tick                  | `GasPredictedStatePublishSystem`                       | Client, server | Copies the runtime's buffers into the ghost components. Netcode snapshots them on the server, and compares and rolls them back on the client.                             |
| End of the tick                  | `GasPredictedCueDropSystem`                            | Client         | Takes back the cue events of every pass but a tick's first full prediction.                                                                                               |
| After the tick                   | `GasNetcodeStateMirrorSystem`                          | Server         | Copies state written outside the prediction loop into the ghost components, so it is sent.                                                                                |

`Simulate` is honoured everywhere. It is an Entities flag that Netcode switches on each ghost to say whether the ghost is simulated on this tick. The runtime skips an actor that has it switched off: its cooldowns do not age, its effects do not expire, its attributes are not recalculated, and it cannot activate an ability or take an effect. A world without Netcode has no disabled flag, so every actor is simulated.

### Server correction

Suppose the client predicts a Fireball, and the server refuses it because the mana was already spent on something else.

1. The client activates the ability on its own tick: mana drops, the cooldown starts, the tags appear. The cue plays.
2. The server's snapshot for that tick arrives. In it the server did not activate the ability, so mana is as it was, and there is no cooldown and no tag.
3. Netcode puts the ghost components back to the server's values for that tick. At the start of the next predicted tick, the restore copies them into the runtime.
4. The client plays the ticks after the snapshot's tick again, from the corrected state, with the inputs it recorded for them. The refused activation is not among them: it belongs to a tick the snapshot already covers.
5. The client now shows what the server has. The player sees the mana jump back and the cooldown disappear.

Two things in that list are not undone. The cue has already played, and anything your own code did on the first prediction, such as spawning a prefab, stays. See [Cues on a predicting client](#cues-on-a-predicting-client).

### What is replicated

You do not write any of this. The ghost copies are added for you.

| Ghost component             | Copy of                                                                                           | Sent to                        |
| --------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------ |
| `GasGhostAttribute`         | `GasAttributeValue`. Element `i` is attribute `i`: `AttributeIndex`, `BaseValue`, `CurrentValue`. | All clients                    |
| `GasGhostOwnedTag`          | The owned entries of `GasTagCount`                                                                | All clients                    |
| `GasGhostAbilitySlot`       | `GasAbilitySlot`                                                                                  | All clients                    |
| `GasGhostActiveEffect`      | `GasActiveEffect`: the live effect instances                                                      | All clients                    |
| `GasGhostAttributeModifier` | `GasAttributeModifier`                                                                            | All clients                    |
| `GasGhostMontage`           | `GasMontagePlayback`. Only on actors whose abilities play montages.                               | All clients                    |
| `GasGhostBlockedTag`        | The blocked-ability entries of `GasTagCount`                                                      | Clients that predict the actor |
| `GasGhostCapturedValue`     | What each effect instance kept from its application, such as set-by-caller values                 | Clients that predict the actor |
| `GasGhostGrantedAbility`    | Which abilities each effect instance granted                                                      | Clients that predict the actor |
| `GasGhostActiveWait`        | What each running ability waits on, with its deadline                                             | Clients that predict the actor |
| `GasGhostInputSnapshot`     | Whether the input was held on the tick before                                                     | Clients that predict the actor |

The reason for the last five: a client that only interpolates an actor does not simulate it, so it never reads them.

Things worth knowing:

* Attribute values, cooldowns, effect times and modifier magnitudes are sent as full floats. A client restores from them and then answers the same questions the server did, such as whether a period has come. A rounded value would answer some of them differently.
* A client that does not predict an actor does not run the runtime on it. Read the `GasGhost…` copies there. For example, `GasGhostAttribute` holds the server's latest attribute values.
* **State your own systems keep is not rolled back.** If a combo counter, a custom resource or a timer in your game changes what an ability does, make it a ghost component of your own with `[GhostField]` on each field. Otherwise a rollback leaves it ahead of the restored state.

## Cues on a predicting client

A client simulates some ticks more than once, and the runtime raises cues on every pass. `GasPredictedCueMarkSystem` and `GasPredictedCueDropSystem` run in client worlds and take back all but the cues of a tick's first full prediction. Presentation code that reads cues in `PresentationSystemGroup` then sees each cue once. A server world needs a system of your own to clear them. See [Cues and presentation](/docs/gameplay-ability-toolkit-ecs/build-with-it/presentation.md#with-netcode-for-entities).

## Abilities that reach other actors

[Abilities that reach other actors](/docs/gameplay-ability-toolkit-ecs/build-with-it/delivery.md) find their targets and apply their hit effects from data. With Netcode for Entities:

* **Delivery runs on the server only.** `GasDeliveryClientOffSystem` switches the delivery systems off in client worlds. A client simulates some ticks more than once, and a delivery is not rolled back, so it would fire a projectile or ask for an effect again on each.
* **Clients see a delivery through what it causes.** The replicated attributes, tags and effects arrive with the server's snapshots. The activation itself is predicted, so the cost, the cooldown, the montage and the tags show at once.
* **A player's abilities are asked for through `GasAbilityInput`, or the RPC.** A caster set to **Code**, **Automatic** or **Interval** asks on the server, which suits enemies and turrets. The **Input Action** mode is for single-player.
* **A projectile is seen on clients only if its prefab is a ghost.** The server spawns it, so on a client it exists only if Netcode replicates it. Put `GhostAuthoringComponent` on the root of the **Projectile Prefab** and save it as a prefab asset, as in step 3 of [Set up a player actor](#set-up-a-player-actor). The projectile needs no **Gas Entity Authoring** and no owner. The projectile on a client is for show. The server still decides what it hits. If the ability's **Projectile Prefab** is empty, the projectile is an entity nothing draws.
* **Your own target search or projectile system should run in single-player and server worlds only.** The example on the delivery page does this with `[WorldSystemFilter(WorldSystemFilterFlags.LocalSimulation | WorldSystemFilterFlags.ServerSimulation)]`.

## Checking the setup

**Tools > Gameplay Ability Toolkit > Dashboard > ECS Networking** checks the things that are silent when wrong. A ghost with the wrong settings still replicates and plays. Abilities just resolve late, or misbehave after a rollback. It lists these:

| Message                                            | Means                                                                        | Fix                                      |
| -------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------- |
| This ghost cannot be predicted                     | **Supported Ghost Modes** is Interpolated only, so no client simulates it.   | Add Predicted.                           |
| DefaultGhostMode is not in SupportedGhostModes     | The default mode is excluded by the supported modes.                         | Make the two agree.                      |
| OwnerPredicted without an owner                    | **Default Ghost Mode** is Owner Predicted but **Has Owner** is off.          | Tick **Has Owner**, or change the mode.  |
| Predicted input will not reach the server          | The ghost has `GasAbilityInput`, but **Support Auto Command Target** is off. | Turn it on.                              |
| Structural-change rollback is disabled             | **Rollback Prediction On Structural Changes** is off.                        | Turn it on.                              |
| Static optimization on a frequently changing ghost | **Optimization Mode** is Static.                                             | Use Dynamic.                             |
| Importance is zero                                 | The ghost is the first dropped when bandwidth is short.                      | Raise it for anything a player controls. |

It also reports a GAS ghost with no catalog, and one that grants no abilities, and its **Re-run automatic setup** button does the same as the menu item. Two entries are notes, not problems. **Runtime prediction switching is unavailable** appears whenever **Supported Ghost Modes** is not All, which includes the Predicted setting the automatic setup chooses. **Owner-predicted** describes **Default Ghost Mode**. With **Supported Ghost Modes** on Predicted, every client predicts the ghost, as in step 4 above. The page's **Prediction** section shows how the groups are placed, and its **Documentation** section has a button that opens this page.

## Next steps

* [Writing gameplay code](/docs/gameplay-ability-toolkit-ecs/build-with-it/gameplay-code.md): the requests and results your systems use, in the groups above.
* [Cues and presentation](/docs/gameplay-ability-toolkit-ecs/build-with-it/presentation.md): draw and play sounds from a predicting client.
* [Abilities that reach other actors](/docs/gameplay-ability-toolkit-ecs/build-with-it/delivery.md): the data-driven way to hit other actors, which runs on the server.
* [Troubleshooting](/docs/gameplay-ability-toolkit-ecs/reference/troubleshooting.md): why a request does nothing.
* [Minimal ECS example](/docs/gameplay-ability-toolkit-ecs/reference/minimal-example.md): a catalog and a world built in code.
