Lattice Workshop - Step 0

Get familiar with the Lattice Starterkit

Next step

Prerequisites

Intro

Before we get started, let's get familiar with the codebase. The only two relevant files for now are contracts/src/Game.sol and client/src/Game.ts.

The starterkit includes a general scaffold for crypto-native games built with the Lattice SDK (or Lattice Mud). Mappings between contract components and client components are set up for you, as well as a basic Phaser and React renderer.

The starterkit is powered by lattice-solidity-ecs, @latticexyz/mobx-ecs@latticexyz/eth-middleware, and @latticexyz/phaser-middleware, all of which are not part of this workshop. The source files are included in the starterkit, so feel free to dive deeper into the internals if you like.

The diffs you see below are already part of the starterkit, nothing else do do here.

For a sneak peak of the game we'll implement, checkout the demo branch.

Files changed (2) hide show
  1. client/src/Game.ts +64 -0
  2. contracts/src/Game.sol +46 -0
client/src/Game.ts CHANGED
@@ -0,0 +1,64 @@
1
+ import { createWorld } from "@latticexyz/mobx-ecs";
2
+ import { createMapping, loadEvents, setupContracts, setupMappings } from "../packages/lattice-eth-middleware";
3
+ import { setupPhaser } from "@latticexyz/phaser-middleware";
4
+ import { createCoordComponent, decodeCoordComponent } from "./components";
5
+ import { createExampleSystem } from "./systems/ExampleSystem";
6
+
7
+ export async function createGame(contractAddress: string, privateKey: string, chainId: number, personaId: number) {
8
+ const world = createWorld();
9
+
10
+ /*****************************************
11
+ * Contract setup
12
+ *****************************************/
13
+ const { contracts, txExecutor, provider, signer } = await setupContracts(contractAddress, privateKey, chainId);
14
+ const componentAddresses = await contracts.Game.c();
15
+
16
+ /*****************************************
17
+ * Phaser setup
18
+ *****************************************/
19
+ const width = (await contracts.Game.width()).toNumber();
20
+ const height = (await contracts.Game.height()).toNumber();
21
+ const phaser = await setupPhaser(width, height);
22
+
23
+ /*****************************************
24
+ * Component definitions
25
+ *****************************************/
26
+ const Position = createCoordComponent(world, "Position");
27
+
28
+ const components = {
29
+ Position,
30
+ };
31
+
32
+ /*****************************************
33
+ * Mapping contract to client components
34
+ *****************************************/
35
+ setupMappings(world, contracts.World, {
36
+ ...createMapping(componentAddresses.position, Position, decodeCoordComponent),
37
+ });
38
+ await loadEvents(provider, contracts.World);
39
+
40
+ /*****************************************
41
+ * Methods and context for consumers
42
+ *****************************************/
43
+ function ping() {
44
+ return "pong";
45
+ }
46
+
47
+ const context = {
48
+ world,
49
+ phaser,
50
+ contracts,
51
+ components,
52
+ signer,
53
+ txExecutor,
54
+ personaId,
55
+ api: { ping },
56
+ };
57
+
58
+ /*****************************************
59
+ * Systems
60
+ *****************************************/
61
+ createExampleSystem(context);
62
+
63
+ return context;
64
+ }
contracts/src/Game.sol CHANGED
@@ -0,0 +1,46 @@
1
+ // SPDX-License-Identifier: Unlicense
2
+ pragma solidity >=0.8.13;
3
+
4
+ import { console } from 'forge-std/console.sol';
5
+ import { World } from 'lattice-ecs/World.sol';
6
+ import { Component } from 'lattice-ecs/Component.sol';
7
+ import { CoordComponent, Coord } from './components/CoordComponent.sol';
8
+ import { UintComponent } from './components/UintComponent.sol';
9
+
10
+ struct Components {
11
+ CoordComponent position;
12
+ UintComponent num;
13
+ }
14
+
15
+ contract Game {
16
+ address public world;
17
+ address public owner;
18
+ uint256 public width = 32;
19
+ uint256 public height = 32;
20
+ address[] public componentList;
21
+ Components public c;
22
+
23
+ modifier onlyContractOwner() {
24
+ require(msg.sender == owner, 'only contract owner');
25
+ _;
26
+ }
27
+
28
+ constructor(address _world) {
29
+ owner = msg.sender;
30
+ world = _world;
31
+ }
32
+
33
+ function registerComponents(Components memory _components, address[] memory _componentList) public onlyContractOwner {
34
+ c = _components;
35
+ componentList = _componentList;
36
+ }
37
+
38
+ /**
39
+ * Remove all components from the given entity
40
+ */
41
+ function remove(uint256 entity) internal {
42
+ for (uint256 i; i < componentList.length; i++) {
43
+ Component(componentList[i]).remove(entity);
44
+ }
45
+ }
46
+ }