# Serializing and deserializing an ECS in JavaScript/TypeScript

I've been playing around more and more with some prototypes for my online persistent-universe single/coop player space game. In the last iteration, I wanted to use an ECS for getting a feel of how it might look like whether I am to implement an ECS in the production server code.

## Reasons for the ECS research

Using an ECS occurred to me thinking of how might I show the "reasons" behind some resource change. In my case, the "Lifeforce" resource, which can either be increased by lifeforce generation or decreased by mining or population. By creating several `LifeforceConsumption` components and attaching them to a planet entity for example, I can both calculate and control or show what affects that planet's Lifeforce.

Here's an example from the current prototype I'm working on (ignore graphics, released game will be totally different).

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1644679826536/lLPtDJMbg.png)

I didn't want to implement my own ECS because that's boring. I chose [This guy's](https://github.com/Trixt0r/ecsts) ECS, implemented in TypeScript (https://github.com/Trixt0r/ecsts).

## Hello, let's persist the galaxy

The prototypes I'm working on are eventually React or Svelte Apps (see [other prototype post][1]) or whatever that just simulate things to test game design ideas and balance them.

Running on the browser, these prototypes wouldn't be very helpful if they are reset and cleared on a browser refresh, or worse, on a development hot-reload event.

[1]: https://blog.cesspool.games/testing-my-game-design-with-svelte-or-is-it-fun

The ECS-based prototype proved to be an interesting challenge for persistence. Taking all entities in my engine, I should somehow serialize each entity's components and deserialize them properly on reload. Properly means that the actual component class instance must be recovered.

## This is the interesting part

I came up with something like this. The basic idea is to "prepare" the components for JSON.stringify'ing. The name of the class must be kept as a string and the data is a simple stringify.

```typescript
export function prepareEntityForSerialization(entity: AbstractEntity): {
  id: ObjectId;
  components: Array<{ name: string; data: Component }>;
} {
  const components = entity.components.reduce<
    Array<{ name: string; data: Component }>
  >((acc, component) => {
    acc.push({ name: component.constructor.name, data: component });
    return acc;
  }, []);
  return { id: entity.id, components };
}
```

The components' data I write are easily serialized with `JSON.stringify`, I try to keep them as simple as possible. It's just the `component.constructor.name` that I need to add.

When recalling the entity, I use the magical `Object.setPrototypeOf` on a newly created object and set its prototype to the real class component mapped by the name we saved before. I'll show the mapping in a moment. Nice.

```typescript
export function recallEntityFromSerialization(serializedEntity: {
  id: ObjectId;
  components: Array<{ name: string; data: Component }>;
}): GenericEntity {
  const components = serializedEntity.components?.map(({ name, data }) => {
    const component = data;
    const prototype = nameToComponent[name]?.prototype;
    if (prototype) {
      Object.setPrototypeOf(component, prototype);
    }
    return component;
  });
  const entity = new GenericEntity(components, serializedEntity.id);
  return entity;
}
```

The mapping I used is a bit of a bummer, because at its current implementation I have to remember to add each component class I create to it. There are smarter ways to do that but I didn't want to invest time on this in prototyping time. I'd be happy to hear suggestions though!

```typescript
// TODO: create this list by filenames from "components/*" folder?
const supportedComponents = [
  ConsumesLifeforce,
  HasLifeforce,
  HasPosition,
  IsPlanet,
  IsPlanetSlot,
  Colonized,
  Builder,
  HasStockpile,
  IsShip,
  HasDestination,
];

const nameToComponent = supportedComponents.reduce<Record<string, Component>>(
  (acc, componentClass) => {
    acc[componentClass.name] = componentClass;
    return acc;
  },
  {}
);
```

This is basically it. A last small bit is using this in the serialization method of the Game class:

```typescript
  serialize(): string {
    return JSON.stringify({
      tickCount: this.tickCount,
      entities: this.engine.entities.map(prepareEntityForSerialization),
    });
  }
```

---

Phew.
Learning javaScript's prototypal inheritance paid off at the end. What a fruitful day.





