create-mud 2.2.17-ce0e08e6fdf17a061e41a062a2684a592ec15f2f → 2.2.17-d5f4e1e44bbc260ff21dacdfab0e0f8389e9f304
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/react/packages/client/src/mud/Synced.tsx +1 -1
- package/templates/react/packages/contracts/.env +1 -1
- package/templates/react/packages/contracts/mud.config.ts +7 -0
- package/templates/react/packages/contracts/test/MoveTest.t.sol +2 -0
- package/templates/react/packages/contracts/test/WorldTest.t.sol +5 -0
- package/templates/react-ecs/mprocs.yaml +1 -9
- package/templates/react-ecs/package.json +2 -1
- package/templates/react-ecs/packages/client/index.html +2 -2
- package/templates/react-ecs/packages/client/package.json +9 -16
- package/templates/react-ecs/packages/client/src/App.tsx +21 -66
- package/templates/react-ecs/packages/client/src/MUDContext.tsx +21 -0
- package/templates/react-ecs/packages/client/src/index.tsx +32 -17
- package/templates/react-ecs/packages/client/src/mud/createClientComponents.ts +21 -0
- package/templates/react-ecs/packages/client/src/mud/createSystemCalls.ts +51 -0
- package/templates/react-ecs/packages/client/src/mud/getNetworkConfig.ts +77 -0
- package/templates/react-ecs/packages/client/src/mud/setup.ts +21 -0
- package/templates/react-ecs/packages/client/src/mud/setupNetwork.ts +106 -0
- package/templates/react-ecs/packages/client/src/mud/supportedChains.ts +20 -0
- package/templates/react-ecs/packages/client/src/mud/world.ts +3 -0
- package/templates/react-ecs/packages/client/tsconfig.json +1 -1
- package/templates/react-ecs/packages/client/vite.config.ts +7 -2
- package/templates/react-ecs/packages/contracts/.env +1 -1
- package/templates/react-ecs/packages/contracts/mud.config.ts +6 -11
- package/templates/react-ecs/packages/contracts/package.json +0 -1
- package/templates/react-ecs/packages/contracts/script/PostDeploy.s.sol +5 -1
- package/templates/react-ecs/packages/contracts/src/codegen/index.sol +1 -3
- package/templates/react-ecs/packages/contracts/src/codegen/tables/{EntityCount.sol → Counter.sol} +35 -35
- package/templates/react-ecs/packages/contracts/src/codegen/world/{ISpawnSystem.sol → IIncrementSystem.sol} +3 -5
- package/templates/react-ecs/packages/contracts/src/codegen/world/IWorld.sol +2 -3
- package/templates/react-ecs/packages/contracts/src/systems/IncrementSystem.sol +14 -0
- package/templates/react-ecs/packages/contracts/test/CounterTest.t.sol +31 -0
- package/templates/react-ecs/packages/contracts/worlds.json +1 -1
- package/templates/phaser/.gitignore_ +0 -7
- package/templates/phaser/packages/art/.gitignore_ +0 -0
- package/templates/phaser/packages/client/.gitignore_ +0 -3
- package/templates/phaser/packages/contracts/.gitignore_ +0 -9
- package/templates/react/.gitignore_ +0 -16
- package/templates/react/packages/client/.gitignore_ +0 -1
- package/templates/react/packages/contracts/.gitignore_ +0 -13
- package/templates/react-ecs/.gitignore_ +0 -16
- package/templates/react-ecs/packages/client/.gitignore_ +0 -1
- package/templates/react-ecs/packages/client/postcss.config.cjs +0 -6
- package/templates/react-ecs/packages/client/src/Providers.tsx +0 -29
- package/templates/react-ecs/packages/client/src/common.ts +0 -27
- package/templates/react-ecs/packages/client/src/game/GameMap.tsx +0 -112
- package/templates/react-ecs/packages/client/src/game/useKeyboardMovement.ts +0 -26
- package/templates/react-ecs/packages/client/src/mud/Explorer.tsx +0 -32
- package/templates/react-ecs/packages/client/src/mud/Synced.tsx +0 -14
- package/templates/react-ecs/packages/client/src/mud/recs.ts +0 -6
- package/templates/react-ecs/packages/client/src/mud/useSyncStatus.ts +0 -17
- package/templates/react-ecs/packages/client/src/mud/useWorldContract.ts +0 -44
- package/templates/react-ecs/packages/client/src/ui/AsyncButton.tsx +0 -41
- package/templates/react-ecs/packages/client/src/ui/ErrorFallback.tsx +0 -58
- package/templates/react-ecs/packages/client/src/ui/icons/ArrowDownIcon.tsx +0 -22
- package/templates/react-ecs/packages/client/src/ui/icons/MUDIcon.tsx +0 -25
- package/templates/react-ecs/packages/client/src/wagmiConfig.ts +0 -49
- package/templates/react-ecs/packages/client/tailwind.config.ts +0 -10
- package/templates/react-ecs/packages/contracts/.gitignore_ +0 -13
- package/templates/react-ecs/packages/contracts/out/IWorld.sol/IWorld.abi.json +0 -2039
- package/templates/react-ecs/packages/contracts/src/Entity.sol +0 -20
- package/templates/react-ecs/packages/contracts/src/MoveSystem.sol +0 -30
- package/templates/react-ecs/packages/contracts/src/SpawnSystem.sol +0 -18
- package/templates/react-ecs/packages/contracts/src/codegen/common.sol +0 -11
- package/templates/react-ecs/packages/contracts/src/codegen/tables/Owner.sol +0 -202
- package/templates/react-ecs/packages/contracts/src/codegen/tables/Position.sol +0 -321
- package/templates/react-ecs/packages/contracts/src/codegen/world/IMoveSystem.sol +0 -16
- package/templates/react-ecs/packages/contracts/src/createEntity.sol +0 -11
- package/templates/react-ecs/packages/contracts/test/MoveTest.t.sol +0 -39
- package/templates/react-ecs/packages/contracts/test/WorldTest.t.sol +0 -16
- package/templates/threejs/.gitignore_ +0 -7
- package/templates/threejs/packages/client/.gitignore_ +0 -3
- package/templates/threejs/packages/contracts/.gitignore_ +0 -9
- package/templates/vanilla/.gitignore_ +0 -7
- package/templates/vanilla/packages/client/.gitignore_ +0 -3
- package/templates/vanilla/packages/contracts/.gitignore_ +0 -9
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import r from"node:fs/promises";import t from"node:path";import{fileURLToPath as j}from"node:url";import h from"yargs-interactive";import y from"fast-glob";var c={name:"create-mud",version:"2.2.17-d5f4e1e44bbc260ff21dacdfab0e0f8389e9f304",description:"Create a new MUD project",license:"MIT",author:"Lattice <mud@lattice.xyz>",type:"module",bin:"bin/cli.js",files:["bin","dist","templates"],scripts:{build:"pnpm run build:js","build:js":"tsup && pnpm run copy-templates",clean:"pnpm run clean:js","clean:js":"shx rm -rf dist","copy-templates":"tsx ./scripts/copy-templates.ts",dev:"tsup --watch",prepublishOnly:"npm run clean && npm run build",test:"pnpm run copy-templates && pnpm vitest --run && pnpm run test:vanilla && pnpm run test:react && pnpm run test:react-ecs && pnpm run test:phaser && pnpm run test:threejs","test:ci":"pnpm run test","test:phaser":"bin/cli.js --name test-project --template phaser && pnpm --dir test-project install && shx rm -rf test-project","test:react":"bin/cli.js --name test-project --template react && pnpm --dir test-project install && shx rm -rf test-project","test:react-ecs":"bin/cli.js --name test-project --template react-ecs && pnpm --dir test-project install && shx rm -rf test-project","test:threejs":"bin/cli.js --name test-project --template threejs && pnpm --dir test-project install && shx rm -rf test-project","test:vanilla":"bin/cli.js --name test-project --template vanilla && pnpm --dir test-project install && shx rm -rf test-project"},dependencies:{"fast-glob":"^3.3.3","yargs-interactive":"^3.0.1"},devDependencies:{"@types/yargs-interactive":"^2.1.6",execa:"^7.0.0"},publishConfig:{access:"public",registry:"https://registry.npmjs.org"}};var o=["react","react-ecs","phaser","threejs","vanilla"];import f from"node:fs/promises";async function m(e){try{return await f.access(e),!0}catch{return!1}}var b=j(import.meta.url),v=t.dirname(b);async function w(){h().usage("$0 [args]").interactive({interactive:{default:!0},name:{describe:"Name your project",type:"input"},template:{describe:"Pick a template",type:"list",choices:o},"mud-version":{type:"input",describe:"The version of MUD packages to use, defaults to latest",default:c.version}}).then(async e=>{if(!e.name)throw new Error("No project name provided.");let s=t.join(process.cwd(),e.name);if(await m(s))throw new Error(`Target directory "${s}" already exists.`);let a=t.join(v,"..","templates",e.template),l=await y("**/*",{cwd:a,dot:!0});for(let p of l){let i=t.join(a,p),n=t.join(s,p);if(await r.mkdir(t.dirname(n),{recursive:!0}),/package\.json$/.test(i)){let u=await r.readFile(i,"utf-8");await r.writeFile(n,u.replaceAll(/{{mud-version}}/g,e.mudVersion),"utf-8")}else await r.copyFile(i,n)}console.log(`
|
|
2
2
|
New project created! Run it with:
|
|
3
3
|
|
|
4
4
|
cd ${e.name}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bin/cli.ts","../package.json","../src/common.ts","../src/exists.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport yargsInteractive from \"yargs-interactive\";\nimport glob from \"fast-glob\";\nimport packageJson from \"../../package.json\";\nimport { templates } from \"../common\";\nimport { exists } from \"../exists\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nasync function run() {\n yargsInteractive()\n .usage(\"$0 [args]\")\n .interactive({\n interactive: { default: true },\n name: {\n describe: \"Name your project\",\n type: \"input\",\n },\n template: {\n describe: \"Pick a template\",\n type: \"list\",\n choices: templates,\n },\n \"mud-version\": {\n type: \"input\",\n describe: \"The version of MUD packages to use, defaults to latest\",\n default: packageJson.version,\n },\n })\n .then(async (args) => {\n if (!args.name) throw new Error(\"No project name provided.\");\n\n const destDir = path.join(process.cwd(), args.name);\n if (await exists(destDir)) {\n throw new Error(`Target directory \"${destDir}\" already exists.`);\n }\n\n const sourceDir = path.join(__dirname, \"..\", \"templates\", args.template);\n const files = await glob(\"**/*\", { cwd: sourceDir, dot: true });\n\n for (const filename of files) {\n const sourceFile = path.join(sourceDir, filename);\n const destFile = path.join(destDir, filename);\n\n await fs.mkdir(path.dirname(destFile), { recursive: true });\n\n if (/package\\.json$/.test(sourceFile)) {\n const source = await fs.readFile(sourceFile, \"utf-8\");\n await fs.writeFile(destFile, source.replaceAll(/{{mud-version}}/g, args.mudVersion), \"utf-8\");\n } else
|
|
1
|
+
{"version":3,"sources":["../src/bin/cli.ts","../package.json","../src/common.ts","../src/exists.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport yargsInteractive from \"yargs-interactive\";\nimport glob from \"fast-glob\";\nimport packageJson from \"../../package.json\";\nimport { templates } from \"../common\";\nimport { exists } from \"../exists\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nasync function run() {\n yargsInteractive()\n .usage(\"$0 [args]\")\n .interactive({\n interactive: { default: true },\n name: {\n describe: \"Name your project\",\n type: \"input\",\n },\n template: {\n describe: \"Pick a template\",\n type: \"list\",\n choices: templates,\n },\n \"mud-version\": {\n type: \"input\",\n describe: \"The version of MUD packages to use, defaults to latest\",\n default: packageJson.version,\n },\n })\n .then(async (args) => {\n if (!args.name) throw new Error(\"No project name provided.\");\n\n const destDir = path.join(process.cwd(), args.name);\n if (await exists(destDir)) {\n throw new Error(`Target directory \"${destDir}\" already exists.`);\n }\n\n const sourceDir = path.join(__dirname, \"..\", \"templates\", args.template);\n const files = await glob(\"**/*\", { cwd: sourceDir, dot: true });\n\n for (const filename of files) {\n const sourceFile = path.join(sourceDir, filename);\n const destFile = path.join(destDir, filename);\n\n await fs.mkdir(path.dirname(destFile), { recursive: true });\n\n if (/package\\.json$/.test(sourceFile)) {\n const source = await fs.readFile(sourceFile, \"utf-8\");\n await fs.writeFile(destFile, source.replaceAll(/{{mud-version}}/g, args.mudVersion), \"utf-8\");\n } else {\n await fs.copyFile(sourceFile, destFile);\n }\n }\n\n console.log(`\nNew project created! Run it with:\n\n cd ${args.name}\n pnpm install\n pnpm dev\n\nHave fun! For more info, check the docs at https://mud.dev/\n`);\n });\n}\n\nrun();\n","{\n \"name\": \"create-mud\",\n \"version\": \"2.2.17-d5f4e1e44bbc260ff21dacdfab0e0f8389e9f304\",\n \"description\": \"Create a new MUD project\",\n \"license\": \"MIT\",\n \"author\": \"Lattice <mud@lattice.xyz>\",\n \"type\": \"module\",\n \"bin\": \"bin/cli.js\",\n \"files\": [\n \"bin\",\n \"dist\",\n \"templates\"\n ],\n \"scripts\": {\n \"build\": \"pnpm run build:js\",\n \"build:js\": \"tsup && pnpm run copy-templates\",\n \"clean\": \"pnpm run clean:js\",\n \"clean:js\": \"shx rm -rf dist\",\n \"copy-templates\": \"tsx ./scripts/copy-templates.ts\",\n \"dev\": \"tsup --watch\",\n \"prepublishOnly\": \"npm run clean && npm run build\",\n \"test\": \"pnpm run copy-templates && pnpm vitest --run && pnpm run test:vanilla && pnpm run test:react && pnpm run test:react-ecs && pnpm run test:phaser && pnpm run test:threejs\",\n \"test:ci\": \"pnpm run test\",\n \"test:phaser\": \"bin/cli.js --name test-project --template phaser && pnpm --dir test-project install && shx rm -rf test-project\",\n \"test:react\": \"bin/cli.js --name test-project --template react && pnpm --dir test-project install && shx rm -rf test-project\",\n \"test:react-ecs\": \"bin/cli.js --name test-project --template react-ecs && pnpm --dir test-project install && shx rm -rf test-project\",\n \"test:threejs\": \"bin/cli.js --name test-project --template threejs && pnpm --dir test-project install && shx rm -rf test-project\",\n \"test:vanilla\": \"bin/cli.js --name test-project --template vanilla && pnpm --dir test-project install && shx rm -rf test-project\"\n },\n \"dependencies\": {\n \"fast-glob\": \"^3.3.3\",\n \"yargs-interactive\": \"^3.0.1\"\n },\n \"devDependencies\": {\n \"@types/yargs-interactive\": \"^2.1.6\",\n \"execa\": \"^7.0.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"registry\": \"https://registry.npmjs.org\"\n }\n}\n","// We define these here to keep them in the order we want to present in the CLI.\n// Tests will ensure this list stays up to date.\nexport const templates = [\"react\", \"react-ecs\", \"phaser\", \"threejs\", \"vanilla\"];\n","import fs from \"node:fs/promises\";\n\nexport async function exists(path: string) {\n try {\n await fs.access(path);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"AAAA,OAAOA,MAAQ,mBACf,OAAOC,MAAU,YACjB,OAAS,iBAAAC,MAAqB,WAC9B,OAAOC,MAAsB,oBAC7B,OAAOC,MAAU,YCJjB,IAAAC,EAAA,CACE,KAAQ,aACR,QAAW,kDACX,YAAe,2BACf,QAAW,MACX,OAAU,4BACV,KAAQ,SACR,IAAO,aACP,MAAS,CACP,MACA,OACA,WACF,EACA,QAAW,CACT,MAAS,oBACT,WAAY,kCACZ,MAAS,oBACT,WAAY,kBACZ,iBAAkB,kCAClB,IAAO,eACP,eAAkB,iCAClB,KAAQ,2KACR,UAAW,gBACX,cAAe,iHACf,aAAc,gHACd,iBAAkB,oHAClB,eAAgB,kHAChB,eAAgB,iHAClB,EACA,aAAgB,CACd,YAAa,SACb,oBAAqB,QACvB,EACA,gBAAmB,CACjB,2BAA4B,SAC5B,MAAS,QACX,EACA,cAAiB,CACf,OAAU,SACV,SAAY,4BACd,CACF,ECvCO,IAAMC,EAAY,CAAC,QAAS,YAAa,SAAU,UAAW,SAAS,ECF9E,OAAOC,MAAQ,mBAEf,eAAsBC,EAAOC,EAAc,CACzC,GAAI,CACF,aAAMF,EAAG,OAAOE,CAAI,EACb,EACT,MAAQ,CACN,MAAO,EACT,CACF,CHAA,IAAMC,EAAaC,EAAc,YAAY,GAAG,EAC1CC,EAAYC,EAAK,QAAQH,CAAU,EAEzC,eAAeI,GAAM,CACnBC,EAAiB,EACd,MAAM,WAAW,EACjB,YAAY,CACX,YAAa,CAAE,QAAS,EAAK,EAC7B,KAAM,CACJ,SAAU,oBACV,KAAM,OACR,EACA,SAAU,CACR,SAAU,kBACV,KAAM,OACN,QAASC,CACX,EACA,cAAe,CACb,KAAM,QACN,SAAU,yDACV,QAASC,EAAY,OACvB,CACF,CAAC,EACA,KAAK,MAAOC,GAAS,CACpB,GAAI,CAACA,EAAK,KAAM,MAAM,IAAI,MAAM,2BAA2B,EAE3D,IAAMC,EAAUN,EAAK,KAAK,QAAQ,IAAI,EAAGK,EAAK,IAAI,EAClD,GAAI,MAAME,EAAOD,CAAO,EACtB,MAAM,IAAI,MAAM,qBAAqBA,CAAO,mBAAmB,EAGjE,IAAME,EAAYR,EAAK,KAAKD,EAAW,KAAM,YAAaM,EAAK,QAAQ,EACjEI,EAAQ,MAAMC,EAAK,OAAQ,CAAE,IAAKF,EAAW,IAAK,EAAK,CAAC,EAE9D,QAAWG,KAAYF,EAAO,CAC5B,IAAMG,EAAaZ,EAAK,KAAKQ,EAAWG,CAAQ,EAC1CE,EAAWb,EAAK,KAAKM,EAASK,CAAQ,EAI5C,GAFA,MAAMG,EAAG,MAAMd,EAAK,QAAQa,CAAQ,EAAG,CAAE,UAAW,EAAK,CAAC,EAEtD,iBAAiB,KAAKD,CAAU,EAAG,CACrC,IAAMG,EAAS,MAAMD,EAAG,SAASF,EAAY,OAAO,EACpD,MAAME,EAAG,UAAUD,EAAUE,EAAO,WAAW,mBAAoBV,EAAK,UAAU,EAAG,OAAO,CAC9F,MACE,MAAMS,EAAG,SAASF,EAAYC,CAAQ,CAE1C,CAEA,QAAQ,IAAI;AAAA;AAAA;AAAA,OAGXR,EAAK,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,CAKf,CACG,CAAC,CACL,CAEAJ,EAAI","names":["fs","path","fileURLToPath","yargsInteractive","glob","package_default","templates","fs","exists","path","__filename","fileURLToPath","__dirname","path","run","yargsInteractive","templates","package_default","args","destDir","exists","sourceDir","files","glob","filename","sourceFile","destFile","fs","source"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { useSyncStatus } from "./useSyncStatus";
|
|
3
3
|
import { TableRecord } from "@latticexyz/stash/internal";
|
|
4
|
-
import { SyncProgress } from "@latticexyz/store-sync/
|
|
4
|
+
import { SyncProgress } from "@latticexyz/store-sync/stash/common";
|
|
5
5
|
|
|
6
6
|
export type Props = {
|
|
7
7
|
children: ReactNode;
|
|
@@ -3,6 +3,7 @@ pragma solidity >=0.8.24;
|
|
|
3
3
|
|
|
4
4
|
import "forge-std/Test.sol";
|
|
5
5
|
import { MudTest } from "@latticexyz/world/test/MudTest.t.sol";
|
|
6
|
+
import { getKeysWithValue } from "@latticexyz/world-modules/src/modules/keyswithvalue/getKeysWithValue.sol";
|
|
6
7
|
|
|
7
8
|
import { IWorld } from "../src/codegen/world/IWorld.sol";
|
|
8
9
|
import { Position, PositionData } from "../src/codegen/tables/Position.sol";
|
|
@@ -19,6 +20,7 @@ contract MoveTest is MudTest {
|
|
|
19
20
|
|
|
20
21
|
IWorld(worldAddress).app__move(Direction.North);
|
|
21
22
|
position = Position.get(alice);
|
|
23
|
+
|
|
22
24
|
assertEq(position.x, 0);
|
|
23
25
|
assertEq(position.y, 1);
|
|
24
26
|
}
|
|
@@ -3,6 +3,11 @@ pragma solidity >=0.8.24;
|
|
|
3
3
|
|
|
4
4
|
import "forge-std/Test.sol";
|
|
5
5
|
import { MudTest } from "@latticexyz/world/test/MudTest.t.sol";
|
|
6
|
+
import { getKeysWithValue } from "@latticexyz/world-modules/src/modules/keyswithvalue/getKeysWithValue.sol";
|
|
7
|
+
|
|
8
|
+
import { IWorld } from "../src/codegen/world/IWorld.sol";
|
|
9
|
+
import { Position, PositionData } from "../src/codegen/tables/Position.sol";
|
|
10
|
+
import { Direction } from "../src/codegen/common.sol";
|
|
6
11
|
|
|
7
12
|
contract WorldTest is MudTest {
|
|
8
13
|
function testWorldDeployed() public {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
scrollback: 10000
|
|
2
1
|
procs:
|
|
3
2
|
client:
|
|
4
3
|
cwd: packages/client
|
|
@@ -6,16 +5,9 @@ procs:
|
|
|
6
5
|
contracts:
|
|
7
6
|
cwd: packages/contracts
|
|
8
7
|
shell: pnpm mud dev-contracts --rpc http://127.0.0.1:8545
|
|
9
|
-
deploy-prereqs:
|
|
10
|
-
cwd: packages/contracts
|
|
11
|
-
shell: pnpm deploy-local-prereqs
|
|
12
|
-
env:
|
|
13
|
-
DEBUG: "mud:*"
|
|
14
|
-
# Anvil default account (0x70997970C51812dc3A010C7d01b50e0d17dc79C8)
|
|
15
|
-
PRIVATE_KEY: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
|
|
16
8
|
anvil:
|
|
17
9
|
cwd: packages/contracts
|
|
18
|
-
shell: anvil --block-time 2
|
|
10
|
+
shell: anvil --base-fee 0 --block-time 2
|
|
19
11
|
explorer:
|
|
20
12
|
cwd: packages/contracts
|
|
21
13
|
shell: pnpm explorer
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "mud-template-react",
|
|
2
|
+
"name": "mud-template-react-ecs",
|
|
3
3
|
"private": true,
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "pnpm recursive run build",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"@latticexyz/explorer": "{{mud-version}}",
|
|
18
18
|
"@latticexyz/store-indexer": "{{mud-version}}",
|
|
19
19
|
"@types/debug": "4.1.7",
|
|
20
|
+
"@types/node": "^18",
|
|
20
21
|
"@typescript-eslint/eslint-plugin": "7.1.1",
|
|
21
22
|
"@typescript-eslint/parser": "7.1.1",
|
|
22
23
|
"eslint": "8.57.0",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>a MUD
|
|
6
|
+
<title>a minimal MUD client</title>
|
|
7
7
|
</head>
|
|
8
8
|
<body>
|
|
9
9
|
<div id="react-root"></div>
|
|
@@ -6,39 +6,32 @@
|
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "vite build",
|
|
9
|
-
"dev": "vite",
|
|
9
|
+
"dev": "wait-port localhost:8545 && vite",
|
|
10
10
|
"preview": "vite preview",
|
|
11
11
|
"test": "tsc --noEmit"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@latticexyz/common": "{{mud-version}}",
|
|
15
|
-
"@latticexyz/
|
|
16
|
-
"@latticexyz/explorer": "{{mud-version}}",
|
|
15
|
+
"@latticexyz/dev-tools": "{{mud-version}}",
|
|
17
16
|
"@latticexyz/react": "{{mud-version}}",
|
|
18
17
|
"@latticexyz/recs": "{{mud-version}}",
|
|
19
18
|
"@latticexyz/schema-type": "{{mud-version}}",
|
|
20
19
|
"@latticexyz/store-sync": "{{mud-version}}",
|
|
21
20
|
"@latticexyz/utils": "{{mud-version}}",
|
|
22
21
|
"@latticexyz/world": "{{mud-version}}",
|
|
23
|
-
"@tanstack/react-query": "^5.63.0",
|
|
24
22
|
"contracts": "workspace:*",
|
|
25
|
-
"react": "18.2.0",
|
|
26
|
-
"react-dom": "18.2.0",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"viem": "2.21.19",
|
|
30
|
-
"wagmi": "2.12.11"
|
|
23
|
+
"react": "^18.2.0",
|
|
24
|
+
"react-dom": "^18.2.0",
|
|
25
|
+
"rxjs": "7.5.5",
|
|
26
|
+
"viem": "2.21.19"
|
|
31
27
|
},
|
|
32
28
|
"devDependencies": {
|
|
33
29
|
"@types/react": "18.2.22",
|
|
34
30
|
"@types/react-dom": "18.2.7",
|
|
35
|
-
"@vitejs/plugin-react": "^
|
|
36
|
-
"autoprefixer": "^10.4.20",
|
|
31
|
+
"@vitejs/plugin-react": "^3.1.0",
|
|
37
32
|
"eslint-plugin-react": "7.31.11",
|
|
38
33
|
"eslint-plugin-react-hooks": "4.6.0",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"vite": "^6.0.7",
|
|
42
|
-
"vite-plugin-mud": "{{mud-version}}"
|
|
34
|
+
"vite": "^4.2.1",
|
|
35
|
+
"wait-port": "^1.0.4"
|
|
43
36
|
}
|
|
44
37
|
}
|
|
@@ -1,74 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { useMemo } from "react";
|
|
5
|
-
import { GameMap } from "./game/GameMap";
|
|
6
|
-
import { useWorldContract } from "./mud/useWorldContract";
|
|
7
|
-
import { Synced } from "./mud/Synced";
|
|
8
|
-
import { useSync } from "@latticexyz/store-sync/react";
|
|
9
|
-
import { components } from "./mud/recs";
|
|
10
|
-
import { useEntityQuery } from "@latticexyz/react";
|
|
11
|
-
import { Has, getComponentValueStrict } from "@latticexyz/recs";
|
|
12
|
-
import { Address } from "viem";
|
|
1
|
+
import { useComponentValue } from "@latticexyz/react";
|
|
2
|
+
import { useMUD } from "./MUDContext";
|
|
3
|
+
import { singletonEntity } from "@latticexyz/store-sync/recs";
|
|
13
4
|
|
|
14
|
-
export
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const owner = getComponentValueStrict(components.Owner, entity);
|
|
20
|
-
const position = getComponentValueStrict(components.Position, entity);
|
|
21
|
-
return {
|
|
22
|
-
entity: entity as Entity,
|
|
23
|
-
owner: owner.owner as Address,
|
|
24
|
-
x: position.x,
|
|
25
|
-
y: position.y,
|
|
26
|
-
};
|
|
27
|
-
}),
|
|
28
|
-
[playerEntities],
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const sync = useSync();
|
|
32
|
-
const worldContract = useWorldContract();
|
|
33
|
-
|
|
34
|
-
const onMove = useMemo(
|
|
35
|
-
() =>
|
|
36
|
-
sync.data && worldContract
|
|
37
|
-
? async (entity: Entity, direction: Direction) => {
|
|
38
|
-
const tx = await worldContract.write.app__move([entity, mudConfig.enums.Direction.indexOf(direction)]);
|
|
39
|
-
await sync.data.waitForTransaction(tx);
|
|
40
|
-
}
|
|
41
|
-
: undefined,
|
|
42
|
-
[sync.data, worldContract],
|
|
43
|
-
);
|
|
5
|
+
export const App = () => {
|
|
6
|
+
const {
|
|
7
|
+
components: { Counter },
|
|
8
|
+
systemCalls: { increment },
|
|
9
|
+
} = useMUD();
|
|
44
10
|
|
|
45
|
-
const
|
|
46
|
-
() =>
|
|
47
|
-
sync.data && worldContract
|
|
48
|
-
? async () => {
|
|
49
|
-
const tx = await worldContract.write.app__spawn();
|
|
50
|
-
await sync.data.waitForTransaction(tx);
|
|
51
|
-
}
|
|
52
|
-
: undefined,
|
|
53
|
-
[sync.data, worldContract],
|
|
54
|
-
);
|
|
11
|
+
const counter = useComponentValue(Counter, singletonEntity);
|
|
55
12
|
|
|
56
13
|
return (
|
|
57
14
|
<>
|
|
58
|
-
<div
|
|
59
|
-
<
|
|
60
|
-
fallback={({ message, percentage }) => (
|
|
61
|
-
<div className="tabular-nums">
|
|
62
|
-
{message} ({percentage.toFixed(1)}%)…
|
|
63
|
-
</div>
|
|
64
|
-
)}
|
|
65
|
-
>
|
|
66
|
-
<GameMap players={players} onMove={onMove} onSpawn={onSpawn} />
|
|
67
|
-
</Synced>
|
|
68
|
-
</div>
|
|
69
|
-
<div className="fixed top-2 right-2">
|
|
70
|
-
<AccountButton />
|
|
15
|
+
<div>
|
|
16
|
+
Counter: <span>{counter?.value ?? "??"}</span>
|
|
71
17
|
</div>
|
|
18
|
+
<button
|
|
19
|
+
type="button"
|
|
20
|
+
onClick={async (event) => {
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
console.log("new counter value:", await increment());
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
Increment
|
|
26
|
+
</button>
|
|
72
27
|
</>
|
|
73
28
|
);
|
|
74
|
-
}
|
|
29
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createContext, ReactNode, useContext } from "react";
|
|
2
|
+
import { SetupResult } from "./mud/setup";
|
|
3
|
+
|
|
4
|
+
const MUDContext = createContext<SetupResult | null>(null);
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
value: SetupResult;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const MUDProvider = ({ children, value }: Props) => {
|
|
12
|
+
const currentValue = useContext(MUDContext);
|
|
13
|
+
if (currentValue) throw new Error("MUDProvider can only be used once");
|
|
14
|
+
return <MUDContext.Provider value={value}>{children}</MUDContext.Provider>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const useMUD = () => {
|
|
18
|
+
const value = useContext(MUDContext);
|
|
19
|
+
if (!value) throw new Error("Must be used within a MUDProvider");
|
|
20
|
+
return value;
|
|
21
|
+
};
|
|
@@ -1,19 +1,34 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import { StrictMode } from "react";
|
|
3
|
-
import { createRoot } from "react-dom/client";
|
|
4
|
-
import { Providers } from "./Providers";
|
|
1
|
+
import ReactDOM from "react-dom/client";
|
|
5
2
|
import { App } from "./App";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
3
|
+
import { setup } from "./mud/setup";
|
|
4
|
+
import { MUDProvider } from "./MUDContext";
|
|
5
|
+
import mudConfig from "contracts/mud.config";
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
const rootElement = document.getElementById("react-root");
|
|
8
|
+
if (!rootElement) throw new Error("React root not found");
|
|
9
|
+
const root = ReactDOM.createRoot(rootElement);
|
|
10
|
+
|
|
11
|
+
// TODO: figure out if we actually want this to be async or if we should render something else in the meantime
|
|
12
|
+
setup().then(async (result) => {
|
|
13
|
+
root.render(
|
|
14
|
+
<MUDProvider value={result}>
|
|
15
|
+
<App />
|
|
16
|
+
</MUDProvider>,
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
// https://vitejs.dev/guide/env-and-mode.html
|
|
20
|
+
if (import.meta.env.DEV) {
|
|
21
|
+
const { mount: mountDevTools } = await import("@latticexyz/dev-tools");
|
|
22
|
+
mountDevTools({
|
|
23
|
+
config: mudConfig,
|
|
24
|
+
publicClient: result.network.publicClient,
|
|
25
|
+
walletClient: result.network.walletClient,
|
|
26
|
+
latestBlock$: result.network.latestBlock$,
|
|
27
|
+
storedBlockLogs$: result.network.storedBlockLogs$,
|
|
28
|
+
worldAddress: result.network.worldContract.address,
|
|
29
|
+
worldAbi: result.network.worldContract.abi,
|
|
30
|
+
write$: result.network.write$,
|
|
31
|
+
recsWorld: result.network.world,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Creates components for use by the client.
|
|
3
|
+
*
|
|
4
|
+
* By default it returns the components from setupNetwork.ts, those which are
|
|
5
|
+
* automatically inferred from the mud.config.ts table definitions.
|
|
6
|
+
*
|
|
7
|
+
* However, you can add or override components here as needed. This
|
|
8
|
+
* lets you add user defined components, which may or may not have
|
|
9
|
+
* an onchain component.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { SetupNetworkResult } from "./setupNetwork";
|
|
13
|
+
|
|
14
|
+
export type ClientComponents = ReturnType<typeof createClientComponents>;
|
|
15
|
+
|
|
16
|
+
export function createClientComponents({ components }: SetupNetworkResult) {
|
|
17
|
+
return {
|
|
18
|
+
...components,
|
|
19
|
+
// add your client components or overrides here
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Create the system calls that the client can use to ask
|
|
3
|
+
* for changes in the World state (using the System contracts).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getComponentValue } from "@latticexyz/recs";
|
|
7
|
+
import { ClientComponents } from "./createClientComponents";
|
|
8
|
+
import { SetupNetworkResult } from "./setupNetwork";
|
|
9
|
+
import { singletonEntity } from "@latticexyz/store-sync/recs";
|
|
10
|
+
|
|
11
|
+
export type SystemCalls = ReturnType<typeof createSystemCalls>;
|
|
12
|
+
|
|
13
|
+
export function createSystemCalls(
|
|
14
|
+
/*
|
|
15
|
+
* The parameter list informs TypeScript that:
|
|
16
|
+
*
|
|
17
|
+
* - The first parameter is expected to be a
|
|
18
|
+
* SetupNetworkResult, as defined in setupNetwork.ts
|
|
19
|
+
*
|
|
20
|
+
* Out of this parameter, we only care about two fields:
|
|
21
|
+
* - worldContract (which comes from getContract, see
|
|
22
|
+
* https://github.com/latticexyz/mud/blob/main/templates/react/packages/client/src/mud/setupNetwork.ts#L63-L69).
|
|
23
|
+
*
|
|
24
|
+
* - waitForTransaction (which comes from syncToRecs, see
|
|
25
|
+
* https://github.com/latticexyz/mud/blob/main/templates/react/packages/client/src/mud/setupNetwork.ts#L77-L83).
|
|
26
|
+
*
|
|
27
|
+
* - From the second parameter, which is a ClientComponent,
|
|
28
|
+
* we only care about Counter. This parameter comes to use
|
|
29
|
+
* through createClientComponents.ts, but it originates in
|
|
30
|
+
* syncToRecs
|
|
31
|
+
* (https://github.com/latticexyz/mud/blob/main/templates/react/packages/client/src/mud/setupNetwork.ts#L77-L83).
|
|
32
|
+
*/
|
|
33
|
+
{ worldContract, waitForTransaction }: SetupNetworkResult,
|
|
34
|
+
{ Counter }: ClientComponents,
|
|
35
|
+
) {
|
|
36
|
+
const increment = async () => {
|
|
37
|
+
/*
|
|
38
|
+
* Because IncrementSystem
|
|
39
|
+
* (https://mud.dev/templates/typescript/contracts#incrementsystemsol)
|
|
40
|
+
* is in the root namespace, `.increment` can be called directly
|
|
41
|
+
* on the World contract.
|
|
42
|
+
*/
|
|
43
|
+
const tx = await worldContract.write.app__increment();
|
|
44
|
+
await waitForTransaction(tx);
|
|
45
|
+
return getComponentValue(Counter, singletonEntity);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
increment,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Network specific configuration for the client.
|
|
3
|
+
* By default connect to the anvil test network.
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* By default the template just creates a temporary wallet
|
|
9
|
+
* (called a burner wallet).
|
|
10
|
+
*/
|
|
11
|
+
import { getBurnerPrivateKey } from "@latticexyz/common";
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* Import the addresses of the World, possibly on multiple chains,
|
|
15
|
+
* from packages/contracts/worlds.json. When the contracts package
|
|
16
|
+
* deploys a new `World`, it updates this file.
|
|
17
|
+
*/
|
|
18
|
+
import worlds from "contracts/worlds.json";
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* The supported chains.
|
|
22
|
+
* By default, there are only two chains here:
|
|
23
|
+
*/
|
|
24
|
+
import { supportedChains } from "./supportedChains";
|
|
25
|
+
|
|
26
|
+
export async function getNetworkConfig() {
|
|
27
|
+
const params = new URLSearchParams(window.location.search);
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* The chain ID is the first item available from this list:
|
|
31
|
+
* 1. chainId query parameter
|
|
32
|
+
* 2. chainid query parameter
|
|
33
|
+
* 3. The VITE_CHAIN_ID environment variable set when the
|
|
34
|
+
* vite dev server was started or client was built
|
|
35
|
+
* 4. The default, 31337 (anvil)
|
|
36
|
+
*/
|
|
37
|
+
const chainId = Number(params.get("chainId") || params.get("chainid") || import.meta.env.VITE_CHAIN_ID || 31337);
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
* Find the chain (unless it isn't in the list of supported chains).
|
|
41
|
+
*/
|
|
42
|
+
const chainIndex = supportedChains.findIndex((c) => c.id === chainId);
|
|
43
|
+
const chain = supportedChains[chainIndex];
|
|
44
|
+
if (!chain) {
|
|
45
|
+
throw new Error(`Chain ${chainId} not found`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
* Get the address of the World. If you want to use a
|
|
50
|
+
* different address than the one in worlds.json,
|
|
51
|
+
* provide it as worldAddress in the query string.
|
|
52
|
+
*/
|
|
53
|
+
const world = worlds[chain.id.toString()];
|
|
54
|
+
const worldAddress = params.get("worldAddress") || world?.address;
|
|
55
|
+
if (!worldAddress) {
|
|
56
|
+
throw new Error(`No world address found for chain ${chainId}. Did you run \`mud deploy\`?`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
* MUD clients use events to synchronize the database, meaning
|
|
61
|
+
* they need to look as far back as when the World was started.
|
|
62
|
+
* The block number for the World start can be specified either
|
|
63
|
+
* on the URL (as initialBlockNumber) or in the worlds.json
|
|
64
|
+
* file. If neither has it, it starts at the first block, zero.
|
|
65
|
+
*/
|
|
66
|
+
const initialBlockNumber = params.has("initialBlockNumber")
|
|
67
|
+
? Number(params.get("initialBlockNumber"))
|
|
68
|
+
: world?.blockNumber ?? 0n;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
privateKey: getBurnerPrivateKey(),
|
|
72
|
+
chainId,
|
|
73
|
+
chain,
|
|
74
|
+
worldAddress,
|
|
75
|
+
initialBlockNumber,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file sets up all the definitions required for a MUD client.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createClientComponents } from "./createClientComponents";
|
|
6
|
+
import { createSystemCalls } from "./createSystemCalls";
|
|
7
|
+
import { setupNetwork } from "./setupNetwork";
|
|
8
|
+
|
|
9
|
+
export type SetupResult = Awaited<ReturnType<typeof setup>>;
|
|
10
|
+
|
|
11
|
+
export async function setup() {
|
|
12
|
+
const network = await setupNetwork();
|
|
13
|
+
const components = createClientComponents(network);
|
|
14
|
+
const systemCalls = createSystemCalls(network, components);
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
network,
|
|
18
|
+
components,
|
|
19
|
+
systemCalls,
|
|
20
|
+
};
|
|
21
|
+
}
|