Skip to content

Data Model

DUST is built using MUD, and so the mud.config.ts defines all the different entities and components. Here we look at 2 specific kinds of data and how to read them.

Object at Position

The entire world is a 3D grid where each [x, y, z] coordinate has a certain object (ie player, block, or air). This is what you see in the client as you look around.

For example, we can see the player is standing at [1380, 79, -2434], and there is a grass block below at [1380, 78, -2434].

dust terrian third person

dust terrian first person

Tables

The latest object type at a coordinate can be read from the EntityObjectType table.

EntityObjectType: {
  schema: {
    entityId: "EntityId",
    objectType: "ObjectType",
  },
  key: ["entityId"],
},
EntityPosition: {
  schema: {
    entityId: "EntityId",
    x: "int32",
    y: "int32",
    z: "int32",
  },
  key: ["entityId"],
}

To save on gas, this table is not prefilled with the entire map. Instead the intitial terrain is defined in the bytecode of a smart contract (each chunk has its own contract).

Reading Via Explorer

Which object is at this position?

  1. Get the entity id corresponding to the coordinate using the encodeBlock util:
world.utils.encodeBlock([1380, 78, -2434]);

This returns 0x03000005640000004efffff67e00000000000000000000000000000000000000

  1. Filter the EntityObjectType table using this entity id:
SELECT "entityId", "objectType" FROM "EntityObjectType" WHERE "entityId" = '0x03000005640000004efffff67e00000000000000000000000000000000000000';

explorer entity object type

This shows the object type is 21.

  1. Check which object this id is from ObjectType.sol

We can see this coordinate has grass!

ObjectType constant Grass = ObjectType.wrap(21);

Which coordinate is this player at?

  1. Get the player entity id using the encodePlayer util:
world.utils.encodePlayer("0xcD0DD7a799b8281dddA11c5AA54FE8A2D05aAcF4");

This returns 0x01cd0dd7a799b8281ddda11c5aa54fe8a2d05aacf40000000000000000000000

  1. Filter the EntityPosition table using this entity id:
SELECT "entityId", "x", "y", "z" FROM "EntityPosition" WHERE "entityId" = '0x01cd0dd7a799b8281ddda11c5aa54fe8a2d05aacf40000000000000000000000';

explorer entity position

This shows the player is at [1380, 79, -2434].

Reading In A Program

import { EntityId, EntityTypeLib } from "@dust/world/src/types/EntityId.sol";
import { ObjectType } from "@dust/world/src/types/ObjectType.sol";
import { Vec3 } from "@dust/world/src/types/Vec3.sol";
import { EntityObjectType } from "@dust/world/src/codegen/tables/EntityObjectType.sol";
 
function getObjectTypeAt(Vec3 coord) internal view returns (ObjectType) {
  EntityId entityId = EntityTypeLib.encodeBlock(coord);
  ObjectType objectType = EntityObjectType.get(entityId);
 
  return objectType.isNull() ? TerrainLib.getBlockType(coord) : objectType;
}

Reading In An App

import { encodeBlock, getTerrainBlockType, Vec3 } from "@dust/world/internal";
 
async function getObjectTypeAt(pos: Vec3): Promise<number> {
  const objectTypeRecord = stash.getRecord({
    table: tables.EntityObjectType,
    key: { entityId: encodeBlock(pos) },
  });
  let objectTypeId = objectTypeRecord?.objectType;
  if (!objectTypeId) {
    objectTypeId = await getTerrainBlockType(publicClient, worldAddress, pos);
  }
  return objectTypeId;
}

Inventory

Players, chests, and all pass through blocks (ie, air, water, flower, etc) can have an inventory.

Players have 36 slots

player inventory labelled

Chests have 27 slots

chest inventory labelled

Tables

InventorySlot: {
  schema: {
    owner: "EntityId",
    slot: "uint16",
    entityId: "EntityId",
    objectType: "ObjectType",
    amount: "uint16",
  },
  key: ["owner", "slot"],
},
InventoryBitmap: {
  schema: {
    owner: "EntityId",
    bitmap: "uint256[]", // Each uint256 holds 256 slots
  },
  key: ["owner"],
},

Reading Via Explorer

player inventory

  1. Get the player entity id using the encodePlayer util:
world.utils.encodePlayer("0xcD0DD7a799b8281dddA11c5AA54FE8A2D05aAcF4");

This returns 0x01cd0dd7a799b8281ddda11c5aa54fe8a2d05aacf40000000000000000000000

  1. Filter the InventorySlot table using this entity id and slot:
SELECT "owner", "slot", "entityId", "objectType", "amount" FROM "InventorySlot" WHERE "owner" = '0x01cd0dd7a799b8281ddda11c5aa54fe8a2d05aacf40000000000000000000000';

explorer entity inventory slot

This shows all the items the player has. eg, the player has 4 WheatSeeds (id 134) in slot 2.

Reading In A Program

import { InventorySlot, InventorySlotData } from "@dust/world/src/codegen/tables/InventorySlot.sol";
 
InventorySlotData slotData = InventorySlot.get(EntityId.encodePlayer(0xcD0DD7a799b8281dddA11c5AA54FE8A2D05aAcF4), 1);

Reading In An App

import { getRecord } from "@latticexyz/store/internal";
import { encodePlayer } from "@dust/world/internal";
import mudConfig from "@dust/world/mud.config";
 
const slotData = await getRecord(publicClient, {
  address: worldAddress,
  table: mudConfig.tables.InventorySlot,
  key: {
    owner: encodePlayer("0xcD0DD7a799b8281dddA11c5AA54FE8A2D05aAcF4"),
    slot: 1,
  },
});