# How It Works

## The Canisters

**There are three types of canisters in the World Engine:**

1. **World canister:** The game server canister
2. **World Hub canister:** The indexing canister
3. **User Node canisters:** The user data canisters

<details>

<summary>World canister</summary>

A World canister is essentially your **game server** written as a canister smart contract. You can deploy your own through our website. Your game client communicates exclusively with this canister. Its main purpose is:

* Act as the game server for your game
* Manage the Configs of your game
* Validate the actions that players are doing in your game
* Ensure players aren’t cheating

</details>

<details>

<summary>World Hub</summary>

The World Hub indexes **World canisters** and **User Node canisters**. It tells the World canisters which User Node canister they need to call.

</details>

<details>

<summary>User Node</summary>

UserNode canisters store the data of all users. User data is stored as pieces of data called **Entities**.

</details>

***

## The Data

**There are four types of data stored across the World, World Hub, and User Nodes:**

1. **Action:** Actions enforce what players can do in your World
2. **Config:** Configs define metadata, usually about Entities
3. **Entity:** Entities are data representing the objects or things in a World
4. **Permissions:** Defines which Worlds have permission to alter Entities in your World

<details>

<summary>Action</summary>

An **Action** is something a player can do in your game that gets saved to the database.

***Example: If a player spends 100 Gold they receive 1 Sword***

### Action

This is what an Action looks like in code:

```motoko
    public type Action = 
    {
        aid : Text;
        callerAction : ?SubAction;
        targetAction : ?SubAction;
        worldAction : ?SubAction;
    };
```

* **aid:** The action id that identifies this specific Action
* **callerAction:** The SubAction to apply to the user calling the Action
* **targetAction:** The SubAction to apply to the user being targeted by the Action
* **worldAction:** The SubAction to apply to the World executing the Action<br>

### SubAction

This is what a SubAction looks like in code:

```motoko
    public type SubAction =
    {
        actionConstraint : ?ActionConstraint;
        actionResult : ActionResult;
    };
```

* **actionConstraint:** The requirements for a player to do this Action
* **actionResult:** The result of this Action

</details>

<details>

<summary>Config</summary>

A **Config** defines static metadata for your game. **Configs** are stored in the **World** canister, and are fetched by the Unity game client when the game starts. They can be changed in the canister without requiring a new game build. They look like this:

```motoko
public type Config = {
    cid : Text;
    fields : Map.Map<Text, Text>;
};
```

* **cid:** The config id for this Config
* **fields:** A hashmap of "fields" and values. This allows for flexibility to define whatever fields you want to store in this Config.

</details>

<details>

<summary>Entity</summary>

In its simplest definition, an **Entity** is a piece of data in the database. They look like this:

```motoko
    public type Entity = {
        wid : TGlobal.worldId;
        eid : TGlobal.entityId;
        fields : Map.Map<Text, Text>;
    };
```

* **wid:** The world id in which this entity exists (aka the canister id of the World canister)
* **eid:** The entity id that uniquely identifies this Entity (eg. awesome\_item\_01)
* **fields:** A hashmap of fields and values contained in the Entity

This standardized data format for Entities can represent almost any data type imaginable.

The most common use cases for **Entities** include **Items**, **Buffs**, and **Stats**. But they can be used for more complex data like **Characters, User Profiles, Purchases, Tech Tree** etc. &#x20;

Entities are the building blocks of your game economy.&#x20;

Here are some example implementations:

**Item Entity:**

```
{
 eid="item_01"                       //entity id
 wid="awcae-maaaa-aaaam-abmyq-cai"   //world id (aka the canister id of your world)
 fields = [
  ("quantity", "420"),             //quantity of item user holds
 ];
};
```

**Buff Entity:**

```
{
 eid="buff_01"
 wid="awcae-maaaa-aaaam-abmyq-cai"
 fields = [
  ("expiration", "1695954265797"),            // expiration timestamp
 ];
};
```

**Stat Entity:**

```
{
 eid="stat_01"
 wid="awcae-maaaa-aaaam-abmyq-cai"
 fields = [
  ("games_played", "420"),            
 ];
};
```

**Character Entity**:

```
{
 eid="warrior_01"
 wid="awcae-maaaa-aaaam-abmyq-cai"
 fields = [
  ("attack", "420"),
  ("defense", "69"),
  ("health", "9000"),            
 ];
};
```

</details>

<details>

<summary>Permissions</summary>

Permissions allow other games to alter your game's database.

There are two types of permissions:

**GlobalPermission** allows another game World to change all the Entities in your World.

```motoko
public type GlobalPermission = {
    wid : Text; // The World Id of the World that you're giving permission to
};
```

**EntityPermission** allows another game World to change a specific Entity in your World.

```motoko
public type EntityPermission = {
    wid : Text; // World Id of the World that you're giving permission to
    gid : Text; // Group Id of the Entity
    eid : Text; // Entity Id of the Entity
};
```

These are the functions in your World canister that allow you to add and remove permissions:

```motoko
public shared ({ caller }) func grantEntityPermission(permission : EntityPermission) : async () {
    assert (isAdmin_(caller));
    await worldHub.grantEntityPermission(permission);
};

public shared ({ caller }) func removeEntityPermission(permission : EntityPermission) : async () {
    assert (isAdmin_(caller));
    await worldHub.removeEntityPermission(permission);
};

public shared ({ caller }) func grantGlobalPermission(permission : GlobalPermission) : async () {
    assert (isAdmin_(caller));
    await worldHub.grantGlobalPermission(permission);
};

public shared ({ caller }) func removeGlobalPermission(permission : GlobalPermission) : async () {
    assert (isAdmin_(caller));
    await worldHub.removeGlobalPermission(permission);
};
```

</details>

***

**Below is a diagram of how game World canisters interact with the World Hub and User Node canisters:**

<img src="https://1999307885-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs83D1dD4EQXtTNdbbsjd%2Fuploads%2F8jBc4ye26kIJfM8iSKxX%2Ffile.excalidraw.svg?alt=media&#x26;token=3d20692d-86fd-463a-a9f9-970c1c6ca3be" alt="" class="gitbook-drawing">

<figure><img src="https://1999307885-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs83D1dD4EQXtTNdbbsjd%2Fuploads%2FnbUDTKGLEqi2isITUP5Z%2FWorld%20Engine_2.png?alt=media&#x26;token=0e6cf64f-287a-48b7-8b07-89da3e3e9157" alt=""><figcaption></figcaption></figure>
