create-mud 2.2.17-ce0e08e6fdf17a061e41a062a2684a592ec15f2f → 2.2.17-d252fd65ce1e5a2085d1a43ba02df7e985d90aa5

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.
Files changed (119) hide show
  1. package/dist/cli.js +2 -8
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +6 -6
  4. package/templates/react/mprocs.yaml +1 -9
  5. package/templates/react/packages/client/index.html +2 -2
  6. package/templates/react/packages/client/package.json +9 -17
  7. package/templates/react/packages/client/src/App.tsx +100 -41
  8. package/templates/react/packages/client/src/MUDContext.tsx +21 -0
  9. package/templates/react/packages/client/src/index.tsx +32 -17
  10. package/templates/react/packages/client/src/mud/createSystemCalls.ts +56 -0
  11. package/templates/react/packages/client/src/mud/getNetworkConfig.ts +76 -0
  12. package/templates/react/packages/client/src/mud/setup.ts +18 -0
  13. package/templates/react/packages/client/src/mud/setupNetwork.ts +101 -0
  14. package/templates/react/packages/client/src/mud/supportedChains.ts +20 -0
  15. package/templates/react/packages/client/tsconfig.json +1 -1
  16. package/templates/react/packages/client/vite.config.ts +7 -2
  17. package/templates/react/packages/contracts/.env +1 -1
  18. package/templates/react/packages/contracts/mud.config.ts +8 -6
  19. package/templates/react/packages/contracts/package.json +0 -1
  20. package/templates/react/packages/contracts/script/PostDeploy.s.sol +9 -1
  21. package/templates/react/packages/contracts/src/codegen/index.sol +1 -1
  22. package/templates/react/packages/contracts/src/codegen/tables/Tasks.sol +522 -0
  23. package/templates/{react-ecs/packages/contracts/src/codegen/world/IMoveSystem.sol → react/packages/contracts/src/codegen/world/ITasksSystem.sol} +9 -6
  24. package/templates/react/packages/contracts/src/codegen/world/IWorld.sol +2 -2
  25. package/templates/react/packages/contracts/src/systems/TasksSystem.sol +24 -0
  26. package/templates/react/packages/contracts/test/TasksTest.t.sol +30 -0
  27. package/templates/react/packages/contracts/worlds.json +1 -1
  28. package/templates/react-ecs/mprocs.yaml +1 -9
  29. package/templates/react-ecs/package.json +2 -1
  30. package/templates/react-ecs/packages/client/index.html +2 -2
  31. package/templates/react-ecs/packages/client/package.json +9 -16
  32. package/templates/react-ecs/packages/client/src/App.tsx +21 -66
  33. package/templates/react-ecs/packages/client/src/MUDContext.tsx +21 -0
  34. package/templates/react-ecs/packages/client/src/index.tsx +32 -17
  35. package/templates/react-ecs/packages/client/src/mud/createClientComponents.ts +21 -0
  36. package/templates/react-ecs/packages/client/src/mud/createSystemCalls.ts +51 -0
  37. package/templates/react-ecs/packages/client/src/mud/getNetworkConfig.ts +77 -0
  38. package/templates/react-ecs/packages/client/src/mud/setup.ts +21 -0
  39. package/templates/react-ecs/packages/client/src/mud/setupNetwork.ts +106 -0
  40. package/templates/react-ecs/packages/client/src/mud/supportedChains.ts +20 -0
  41. package/templates/react-ecs/packages/client/src/mud/world.ts +3 -0
  42. package/templates/react-ecs/packages/client/tsconfig.json +1 -1
  43. package/templates/react-ecs/packages/client/vite.config.ts +7 -2
  44. package/templates/react-ecs/packages/contracts/.env +1 -1
  45. package/templates/react-ecs/packages/contracts/mud.config.ts +6 -11
  46. package/templates/react-ecs/packages/contracts/package.json +0 -1
  47. package/templates/react-ecs/packages/contracts/script/PostDeploy.s.sol +5 -1
  48. package/templates/react-ecs/packages/contracts/src/codegen/index.sol +1 -3
  49. package/templates/react-ecs/packages/contracts/src/codegen/tables/{EntityCount.sol → Counter.sol} +35 -35
  50. package/templates/{react/packages/contracts/src/codegen/world/IMoveSystem.sol → react-ecs/packages/contracts/src/codegen/world/IIncrementSystem.sol} +3 -5
  51. package/templates/react-ecs/packages/contracts/src/codegen/world/IWorld.sol +2 -3
  52. package/templates/react-ecs/packages/contracts/src/systems/IncrementSystem.sol +14 -0
  53. package/templates/react-ecs/packages/contracts/test/CounterTest.t.sol +31 -0
  54. package/templates/react-ecs/packages/contracts/worlds.json +1 -1
  55. package/templates/phaser/.gitignore_ +0 -7
  56. package/templates/phaser/packages/art/.gitignore_ +0 -0
  57. package/templates/phaser/packages/client/.gitignore_ +0 -3
  58. package/templates/phaser/packages/contracts/.gitignore_ +0 -9
  59. package/templates/react/.gitignore_ +0 -16
  60. package/templates/react/packages/client/.gitignore_ +0 -1
  61. package/templates/react/packages/client/postcss.config.cjs +0 -6
  62. package/templates/react/packages/client/src/Providers.tsx +0 -35
  63. package/templates/react/packages/client/src/common.ts +0 -26
  64. package/templates/react/packages/client/src/game/GameMap.tsx +0 -102
  65. package/templates/react/packages/client/src/game/useKeyboardMovement.ts +0 -26
  66. package/templates/react/packages/client/src/mud/Explorer.tsx +0 -32
  67. package/templates/react/packages/client/src/mud/Synced.tsx +0 -14
  68. package/templates/react/packages/client/src/mud/stash.ts +0 -4
  69. package/templates/react/packages/client/src/mud/useSyncStatus.ts +0 -21
  70. package/templates/react/packages/client/src/mud/useWorldContract.ts +0 -44
  71. package/templates/react/packages/client/src/ui/AsyncButton.tsx +0 -41
  72. package/templates/react/packages/client/src/ui/ErrorFallback.tsx +0 -58
  73. package/templates/react/packages/client/src/ui/icons/ArrowDownIcon.tsx +0 -22
  74. package/templates/react/packages/client/src/ui/icons/MUDIcon.tsx +0 -25
  75. package/templates/react/packages/client/src/wagmiConfig.ts +0 -49
  76. package/templates/react/packages/client/tailwind.config.ts +0 -10
  77. package/templates/react/packages/contracts/.gitignore_ +0 -13
  78. package/templates/react/packages/contracts/out/IWorld.sol/IWorld.abi.json +0 -2021
  79. package/templates/react/packages/contracts/src/MoveSystem.sol +0 -26
  80. package/templates/react/packages/contracts/src/codegen/common.sol +0 -11
  81. package/templates/react/packages/contracts/src/codegen/tables/Position.sol +0 -318
  82. package/templates/react/packages/contracts/test/MoveTest.t.sol +0 -25
  83. package/templates/react/packages/contracts/test/WorldTest.t.sol +0 -16
  84. package/templates/react-ecs/.gitignore_ +0 -16
  85. package/templates/react-ecs/packages/client/.gitignore_ +0 -1
  86. package/templates/react-ecs/packages/client/postcss.config.cjs +0 -6
  87. package/templates/react-ecs/packages/client/src/Providers.tsx +0 -29
  88. package/templates/react-ecs/packages/client/src/common.ts +0 -27
  89. package/templates/react-ecs/packages/client/src/game/GameMap.tsx +0 -112
  90. package/templates/react-ecs/packages/client/src/game/useKeyboardMovement.ts +0 -26
  91. package/templates/react-ecs/packages/client/src/mud/Explorer.tsx +0 -32
  92. package/templates/react-ecs/packages/client/src/mud/Synced.tsx +0 -14
  93. package/templates/react-ecs/packages/client/src/mud/recs.ts +0 -6
  94. package/templates/react-ecs/packages/client/src/mud/useSyncStatus.ts +0 -17
  95. package/templates/react-ecs/packages/client/src/mud/useWorldContract.ts +0 -44
  96. package/templates/react-ecs/packages/client/src/ui/AsyncButton.tsx +0 -41
  97. package/templates/react-ecs/packages/client/src/ui/ErrorFallback.tsx +0 -58
  98. package/templates/react-ecs/packages/client/src/ui/icons/ArrowDownIcon.tsx +0 -22
  99. package/templates/react-ecs/packages/client/src/ui/icons/MUDIcon.tsx +0 -25
  100. package/templates/react-ecs/packages/client/src/wagmiConfig.ts +0 -49
  101. package/templates/react-ecs/packages/client/tailwind.config.ts +0 -10
  102. package/templates/react-ecs/packages/contracts/.gitignore_ +0 -13
  103. package/templates/react-ecs/packages/contracts/out/IWorld.sol/IWorld.abi.json +0 -2039
  104. package/templates/react-ecs/packages/contracts/src/Entity.sol +0 -20
  105. package/templates/react-ecs/packages/contracts/src/MoveSystem.sol +0 -30
  106. package/templates/react-ecs/packages/contracts/src/SpawnSystem.sol +0 -18
  107. package/templates/react-ecs/packages/contracts/src/codegen/common.sol +0 -11
  108. package/templates/react-ecs/packages/contracts/src/codegen/tables/Owner.sol +0 -202
  109. package/templates/react-ecs/packages/contracts/src/codegen/tables/Position.sol +0 -321
  110. package/templates/react-ecs/packages/contracts/src/codegen/world/ISpawnSystem.sol +0 -15
  111. package/templates/react-ecs/packages/contracts/src/createEntity.sol +0 -11
  112. package/templates/react-ecs/packages/contracts/test/MoveTest.t.sol +0 -39
  113. package/templates/react-ecs/packages/contracts/test/WorldTest.t.sol +0 -16
  114. package/templates/threejs/.gitignore_ +0 -7
  115. package/templates/threejs/packages/client/.gitignore_ +0 -3
  116. package/templates/threejs/packages/contracts/.gitignore_ +0 -9
  117. package/templates/vanilla/.gitignore_ +0 -7
  118. package/templates/vanilla/packages/client/.gitignore_ +0 -3
  119. package/templates/vanilla/packages/contracts/.gitignore_ +0 -9
package/dist/cli.js CHANGED
@@ -1,10 +1,4 @@
1
- import s 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-ce0e08e6fdf17a061e41a062a2684a592ec15f2f",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 v=j(import.meta.url),b=t.dirname(v);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 n=t.join(process.cwd(),e.name);if(await m(n))throw new Error(`Target directory "${n}" already exists.`);let a=t.join(b,"..","templates",e.template),l=await y("**/*",{cwd:a,dot:!0});for(let p of l){let r=t.join(a,p),i=t.join(n,p);if(await s.mkdir(t.dirname(i),{recursive:!0}),/package\.json$/.test(r)){let u=await s.readFile(r,"utf-8");await s.writeFile(i,u.replaceAll(/{{mud-version}}/g,e.mudVersion),"utf-8")}else/\.gitignore_$/.test(r)?await s.copyFile(r,i.replace(/_$/,"")):await s.copyFile(r,i)}console.log(`
2
- New project created! Run it with:
3
-
4
- cd ${e.name}
5
- pnpm install
6
- pnpm dev
7
-
8
- Have fun! For more info, check the docs at https://mud.dev/
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-d252fd65ce1e5a2085d1a43ba02df7e985d90aa5",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 && shx rm -rf test-project","test:react":"bin/cli.js --name test-project --template react && shx rm -rf test-project","test:react-ecs":"bin/cli.js --name test-project --template react-ecs && shx rm -rf test-project","test:threejs":"bin/cli.js --name test-project --template threejs && shx rm -rf test-project","test:vanilla":"bin/cli.js --name test-project --template vanilla && 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 i=t.join(v,"..","templates",e.template),l=await y("**/*",{cwd:i,dot:!0});for(let p of l){let a=t.join(i,p),n=t.join(s,p);if(await r.mkdir(t.dirname(n),{recursive:!0}),/package\.json$/.test(a)){let u=await r.readFile(a,"utf-8");await r.writeFile(n,u.replaceAll(/{{mud-version}}/g,e.mudVersion),"utf-8")}else await r.copyFile(a,n)}console.log(`
2
+ Done! Play in the MUD with \`cd ${e.name}\` and \`pnpm run dev\`
9
3
  `)})}w();
10
4
  //# sourceMappingURL=cli.js.map
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 if (/\\.gitignore_$/.test(sourceFile)) {\n await fs.copyFile(sourceFile, destFile.replace(/_$/, \"\"));\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-ce0e08e6fdf17a061e41a062a2684a592ec15f2f\",\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,KAAW,gBAAgB,KAAKO,CAAU,EACxC,MAAME,EAAG,SAASF,EAAYC,EAAS,QAAQ,KAAM,EAAE,CAAC,EAExD,MAAMC,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"]}
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(`\\nDone! Play in the MUD with \\`cd ${args.name}\\` and \\`pnpm run dev\\`\\n`);\n });\n}\n\nrun();\n","{\n \"name\": \"create-mud\",\n \"version\": \"2.2.17-d252fd65ce1e5a2085d1a43ba02df7e985d90aa5\",\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 && shx rm -rf test-project\",\n \"test:react\": \"bin/cli.js --name test-project --template react && shx rm -rf test-project\",\n \"test:react-ecs\": \"bin/cli.js --name test-project --template react-ecs && shx rm -rf test-project\",\n \"test:threejs\": \"bin/cli.js --name test-project --template threejs && shx rm -rf test-project\",\n \"test:vanilla\": \"bin/cli.js --name test-project --template vanilla && 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,8EACf,aAAc,6EACd,iBAAkB,iFAClB,eAAgB,+EAChB,eAAgB,8EAClB,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,kCAAqCR,EAAK,IAAI;AAAA,CAA2B,CACvF,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,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mud",
3
- "version": "2.2.17-ce0e08e6fdf17a061e41a062a2684a592ec15f2f",
3
+ "version": "2.2.17-d252fd65ce1e5a2085d1a43ba02df7e985d90aa5",
4
4
  "description": "Create a new MUD project",
5
5
  "license": "MIT",
6
6
  "author": "Lattice <mud@lattice.xyz>",
@@ -32,10 +32,10 @@
32
32
  "dev": "tsup --watch",
33
33
  "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",
34
34
  "test:ci": "pnpm run test",
35
- "test:phaser": "bin/cli.js --name test-project --template phaser && pnpm --dir test-project install && shx rm -rf test-project",
36
- "test:react": "bin/cli.js --name test-project --template react && pnpm --dir test-project install && shx rm -rf test-project",
37
- "test:react-ecs": "bin/cli.js --name test-project --template react-ecs && pnpm --dir test-project install && shx rm -rf test-project",
38
- "test:threejs": "bin/cli.js --name test-project --template threejs && pnpm --dir test-project install && shx rm -rf test-project",
39
- "test:vanilla": "bin/cli.js --name test-project --template vanilla && pnpm --dir test-project install && shx rm -rf test-project"
35
+ "test:phaser": "bin/cli.js --name test-project --template phaser && shx rm -rf test-project",
36
+ "test:react": "bin/cli.js --name test-project --template react && shx rm -rf test-project",
37
+ "test:react-ecs": "bin/cli.js --name test-project --template react-ecs && shx rm -rf test-project",
38
+ "test:threejs": "bin/cli.js --name test-project --template threejs && shx rm -rf test-project",
39
+ "test:vanilla": "bin/cli.js --name test-project --template vanilla && shx rm -rf test-project"
40
40
  }
41
41
  }
@@ -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,9 +1,9 @@
1
- <!doctype html>
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 app</title>
6
+ <title>a minimal MUD client</title>
7
7
  </head>
8
8
  <body>
9
9
  <div id="react-root"></div>
@@ -6,39 +6,31 @@
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/entrykit": "{{mud-version}}",
16
- "@latticexyz/explorer": "{{mud-version}}",
15
+ "@latticexyz/dev-tools": "{{mud-version}}",
17
16
  "@latticexyz/react": "{{mud-version}}",
18
17
  "@latticexyz/schema-type": "{{mud-version}}",
19
- "@latticexyz/stash": "{{mud-version}}",
20
18
  "@latticexyz/store-sync": "{{mud-version}}",
21
19
  "@latticexyz/utils": "{{mud-version}}",
22
20
  "@latticexyz/world": "{{mud-version}}",
23
- "@tanstack/react-query": "^5.63.0",
24
21
  "contracts": "workspace:*",
25
- "react": "18.2.0",
26
- "react-dom": "18.2.0",
27
- "react-error-boundary": "5.0.0",
28
- "tailwind-merge": "^2.6.0",
29
- "viem": "2.21.19",
30
- "wagmi": "2.12.11"
22
+ "react": "^18.2.0",
23
+ "react-dom": "^18.2.0",
24
+ "rxjs": "7.5.5",
25
+ "viem": "2.21.19"
31
26
  },
32
27
  "devDependencies": {
33
28
  "@types/react": "18.2.22",
34
29
  "@types/react-dom": "18.2.7",
35
- "@vitejs/plugin-react": "^4.3.4",
36
- "autoprefixer": "^10.4.20",
30
+ "@vitejs/plugin-react": "^3.1.0",
37
31
  "eslint-plugin-react": "7.31.11",
38
32
  "eslint-plugin-react-hooks": "4.6.0",
39
- "postcss": "^8.4.49",
40
- "tailwindcss": "^3.4.17",
41
- "vite": "^6.0.7",
42
- "vite-plugin-mud": "{{mud-version}}"
33
+ "vite": "^4.2.1",
34
+ "wait-port": "^1.0.4"
43
35
  }
44
36
  }
@@ -1,46 +1,105 @@
1
- import { stash } from "./mud/stash";
2
- import { useRecords } from "@latticexyz/stash/react";
3
- import { AccountButton } from "@latticexyz/entrykit/internal";
4
- import { Direction } from "./common";
5
- import mudConfig from "contracts/mud.config";
6
- import { useMemo } from "react";
7
- import { GameMap } from "./game/GameMap";
8
- import { useWorldContract } from "./mud/useWorldContract";
9
- import { Synced } from "./mud/Synced";
10
- import { useSync } from "@latticexyz/store-sync/react";
11
-
12
- export function App() {
13
- const players = useRecords({ stash, table: mudConfig.tables.app__Position });
14
-
15
- const sync = useSync();
16
- const worldContract = useWorldContract();
17
- const onMove = useMemo(
18
- () =>
19
- sync.data && worldContract
20
- ? async (direction: Direction) => {
21
- const tx = await worldContract.write.app__move([mudConfig.enums.Direction.indexOf(direction)]);
22
- await sync.data.waitForTransaction(tx);
23
- }
24
- : undefined,
25
- [sync.data, worldContract],
26
- );
1
+ import { useMUD } from "./MUDContext";
2
+
3
+ const styleUnset = { all: "unset" } as const;
4
+
5
+ export const App = () => {
6
+ const {
7
+ network: { tables, useStore },
8
+ systemCalls: { addTask, toggleTask, deleteTask },
9
+ } = useMUD();
10
+
11
+ const tasks = useStore((state) => {
12
+ const records = Object.values(state.getRecords(tables.Tasks));
13
+ records.sort((a, b) => Number(a.value.createdAt - b.value.createdAt));
14
+ return records;
15
+ });
27
16
 
28
17
  return (
29
18
  <>
30
- <div className="fixed inset-0 grid place-items-center p-4">
31
- <Synced
32
- fallback={({ message, percentage }) => (
33
- <div className="tabular-nums">
34
- {message} ({percentage.toFixed(1)}%)…
35
- </div>
36
- )}
37
- >
38
- <GameMap players={players} onMove={onMove} />
39
- </Synced>
40
- </div>
41
- <div className="fixed top-2 right-2">
42
- <AccountButton />
43
- </div>
19
+ <table>
20
+ <tbody>
21
+ {tasks.map((task) => (
22
+ <tr key={task.id}>
23
+ <td align="right">
24
+ <input
25
+ type="checkbox"
26
+ checked={task.value.completedAt > 0n}
27
+ title={task.value.completedAt === 0n ? "Mark task as completed" : "Mark task as incomplete"}
28
+ onChange={async (event) => {
29
+ event.preventDefault();
30
+ const checkbox = event.currentTarget;
31
+
32
+ checkbox.disabled = true;
33
+ try {
34
+ await toggleTask(task.key.id);
35
+ } finally {
36
+ checkbox.disabled = false;
37
+ }
38
+ }}
39
+ />
40
+ </td>
41
+ <td>{task.value.completedAt > 0n ? <s>{task.value.description}</s> : <>{task.value.description}</>}</td>
42
+ <td align="right">
43
+ <button
44
+ type="button"
45
+ title="Delete task"
46
+ style={styleUnset}
47
+ onClick={async (event) => {
48
+ event.preventDefault();
49
+ if (!window.confirm("Are you sure you want to delete this task?")) return;
50
+
51
+ const button = event.currentTarget;
52
+ button.disabled = true;
53
+ try {
54
+ await deleteTask(task.key.id);
55
+ } finally {
56
+ button.disabled = false;
57
+ }
58
+ }}
59
+ >
60
+ &times;
61
+ </button>
62
+ </td>
63
+ </tr>
64
+ ))}
65
+ </tbody>
66
+ <tfoot>
67
+ <tr>
68
+ <td>
69
+ <input type="checkbox" disabled />
70
+ </td>
71
+ <td colSpan={2}>
72
+ <form
73
+ onSubmit={async (event) => {
74
+ event.preventDefault();
75
+ const form = event.currentTarget;
76
+ const fieldset = form.querySelector("fieldset");
77
+ if (!(fieldset instanceof HTMLFieldSetElement)) return;
78
+
79
+ const formData = new FormData(form);
80
+ const desc = formData.get("description");
81
+ if (typeof desc !== "string") return;
82
+
83
+ fieldset.disabled = true;
84
+ try {
85
+ await addTask(desc);
86
+ form.reset();
87
+ } finally {
88
+ fieldset.disabled = false;
89
+ }
90
+ }}
91
+ >
92
+ <fieldset style={styleUnset}>
93
+ <input type="text" name="description" />{" "}
94
+ <button type="submit" title="Add task">
95
+ Add
96
+ </button>
97
+ </fieldset>
98
+ </form>
99
+ </td>
100
+ </tr>
101
+ </tfoot>
102
+ </table>
44
103
  </>
45
104
  );
46
- }
105
+ };
@@ -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 "tailwindcss/tailwind.css";
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 { Explorer } from "./mud/Explorer";
7
- import { ErrorBoundary } from "react-error-boundary";
8
- import { ErrorFallback } from "./ui/ErrorFallback";
3
+ import { setup } from "./mud/setup";
4
+ import { MUDProvider } from "./MUDContext";
5
+ import mudConfig from "contracts/mud.config";
9
6
 
10
- createRoot(document.getElementById("react-root")!).render(
11
- <StrictMode>
12
- <ErrorBoundary FallbackComponent={ErrorFallback}>
13
- <Providers>
14
- <App />
15
- <Explorer />
16
- </Providers>
17
- </ErrorBoundary>
18
- </StrictMode>,
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
+ useStore: result.network.useStore,
32
+ });
33
+ }
34
+ });
@@ -0,0 +1,56 @@
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 { Hex } from "viem";
7
+ import { SetupNetworkResult } from "./setupNetwork";
8
+
9
+ export type SystemCalls = ReturnType<typeof createSystemCalls>;
10
+
11
+ export function createSystemCalls(
12
+ /*
13
+ * The parameter list informs TypeScript that:
14
+ *
15
+ * - The first parameter is expected to be a
16
+ * SetupNetworkResult, as defined in setupNetwork.ts
17
+ *
18
+ * Out of this parameter, we only care about two fields:
19
+ * - worldContract (which comes from getContract, see
20
+ * https://github.com/latticexyz/mud/blob/main/templates/react/packages/client/src/mud/setupNetwork.ts#L63-L69).
21
+ *
22
+ * - waitForTransaction (which comes from syncToRecs, see
23
+ * https://github.com/latticexyz/mud/blob/main/templates/react/packages/client/src/mud/setupNetwork.ts#L77-L83).
24
+ *
25
+ * - From the second parameter, which is a ClientComponent,
26
+ * we only care about Counter. This parameter comes to use
27
+ * through createClientComponents.ts, but it originates in
28
+ * syncToRecs
29
+ * (https://github.com/latticexyz/mud/blob/main/templates/react/packages/client/src/mud/setupNetwork.ts#L77-L83).
30
+ */
31
+ { tables, useStore, worldContract, waitForTransaction }: SetupNetworkResult,
32
+ ) {
33
+ const addTask = async (label: string) => {
34
+ const tx = await worldContract.write.app__addTask([label]);
35
+ await waitForTransaction(tx);
36
+ };
37
+
38
+ const toggleTask = async (id: Hex) => {
39
+ const isComplete = (useStore.getState().getValue(tables.Tasks, { id })?.completedAt ?? 0n) > 0n;
40
+ const tx = isComplete
41
+ ? await worldContract.write.app__resetTask([id])
42
+ : await worldContract.write.app__completeTask([id]);
43
+ await waitForTransaction(tx);
44
+ };
45
+
46
+ const deleteTask = async (id: Hex) => {
47
+ const tx = await worldContract.write.app__deleteTask([id]);
48
+ await waitForTransaction(tx);
49
+ };
50
+
51
+ return {
52
+ addTask,
53
+ toggleTask,
54
+ deleteTask,
55
+ };
56
+ }
@@ -0,0 +1,76 @@
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
+ */
23
+ import { supportedChains } from "./supportedChains";
24
+
25
+ export async function getNetworkConfig() {
26
+ const params = new URLSearchParams(window.location.search);
27
+
28
+ /*
29
+ * The chain ID is the first item available from this list:
30
+ * 1. chainId query parameter
31
+ * 2. chainid query parameter
32
+ * 3. The VITE_CHAIN_ID environment variable set when the
33
+ * vite dev server was started or client was built
34
+ * 4. The default, 31337 (anvil)
35
+ */
36
+ const chainId = Number(params.get("chainId") || params.get("chainid") || import.meta.env.VITE_CHAIN_ID || 31337);
37
+
38
+ /*
39
+ * Find the chain (unless it isn't in the list of supported chains).
40
+ */
41
+ const chainIndex = supportedChains.findIndex((c) => c.id === chainId);
42
+ const chain = supportedChains[chainIndex];
43
+ if (!chain) {
44
+ throw new Error(`Chain ${chainId} not found`);
45
+ }
46
+
47
+ /*
48
+ * Get the address of the World. If you want to use a
49
+ * different address than the one in worlds.json,
50
+ * provide it as worldAddress in the query string.
51
+ */
52
+ const world = worlds[chain.id.toString()];
53
+ const worldAddress = params.get("worldAddress") || world?.address;
54
+ if (!worldAddress) {
55
+ throw new Error(`No world address found for chain ${chainId}. Did you run \`mud deploy\`?`);
56
+ }
57
+
58
+ /*
59
+ * MUD clients use events to synchronize the database, meaning
60
+ * they need to look as far back as when the World was started.
61
+ * The block number for the World start can be specified either
62
+ * on the URL (as initialBlockNumber) or in the worlds.json
63
+ * file. If neither has it, it starts at the first block, zero.
64
+ */
65
+ const initialBlockNumber = params.has("initialBlockNumber")
66
+ ? Number(params.get("initialBlockNumber"))
67
+ : world?.blockNumber ?? 0n;
68
+
69
+ return {
70
+ privateKey: getBurnerPrivateKey(),
71
+ chainId,
72
+ chain,
73
+ worldAddress,
74
+ initialBlockNumber,
75
+ };
76
+ }
@@ -0,0 +1,18 @@
1
+ /*
2
+ * This file sets up all the definitions required for a MUD client.
3
+ */
4
+
5
+ import { createSystemCalls } from "./createSystemCalls";
6
+ import { setupNetwork } from "./setupNetwork";
7
+
8
+ export type SetupResult = Awaited<ReturnType<typeof setup>>;
9
+
10
+ export async function setup() {
11
+ const network = await setupNetwork();
12
+ const systemCalls = createSystemCalls(network);
13
+
14
+ return {
15
+ network,
16
+ systemCalls,
17
+ };
18
+ }
@@ -0,0 +1,101 @@
1
+ /*
2
+ * The MUD client code is built on top of viem
3
+ * (https://viem.sh/docs/getting-started.html).
4
+ * This line imports the functions we need from it.
5
+ */
6
+ import {
7
+ createPublicClient,
8
+ fallback,
9
+ webSocket,
10
+ http,
11
+ createWalletClient,
12
+ Hex,
13
+ ClientConfig,
14
+ getContract,
15
+ } from "viem";
16
+ import { syncToZustand } from "@latticexyz/store-sync/zustand";
17
+ import { getNetworkConfig } from "./getNetworkConfig";
18
+ import IWorldAbi from "contracts/out/IWorld.sol/IWorld.abi.json";
19
+ import { createBurnerAccount, transportObserver, ContractWrite } from "@latticexyz/common";
20
+ import { transactionQueue, writeObserver } from "@latticexyz/common/actions";
21
+ import { Subject, share } from "rxjs";
22
+
23
+ /*
24
+ * Import our MUD config, which includes strong types for
25
+ * our tables and other config options. We use this to generate
26
+ * things like RECS components and get back strong types for them.
27
+ *
28
+ * See https://mud.dev/templates/typescript/contracts#mudconfigts
29
+ * for the source of this information.
30
+ */
31
+ import mudConfig from "contracts/mud.config";
32
+
33
+ export type SetupNetworkResult = Awaited<ReturnType<typeof setupNetwork>>;
34
+
35
+ export async function setupNetwork() {
36
+ const networkConfig = await getNetworkConfig();
37
+
38
+ /*
39
+ * Create a viem public (read only) client
40
+ * (https://viem.sh/docs/clients/public.html)
41
+ */
42
+ const clientOptions = {
43
+ chain: networkConfig.chain,
44
+ transport: transportObserver(fallback([webSocket(), http()])),
45
+ pollingInterval: 1000,
46
+ } as const satisfies ClientConfig;
47
+
48
+ const publicClient = createPublicClient(clientOptions);
49
+
50
+ /*
51
+ * Create an observable for contract writes that we can
52
+ * pass into MUD dev tools for transaction observability.
53
+ */
54
+ const write$ = new Subject<ContractWrite>();
55
+
56
+ /*
57
+ * Create a temporary wallet and a viem client for it
58
+ * (see https://viem.sh/docs/clients/wallet.html).
59
+ */
60
+ const burnerAccount = createBurnerAccount(networkConfig.privateKey as Hex);
61
+ const burnerWalletClient = createWalletClient({
62
+ ...clientOptions,
63
+ account: burnerAccount,
64
+ })
65
+ .extend(transactionQueue())
66
+ .extend(writeObserver({ onWrite: (write) => write$.next(write) }));
67
+
68
+ /*
69
+ * Create an object for communicating with the deployed World.
70
+ */
71
+ const worldContract = getContract({
72
+ address: networkConfig.worldAddress as Hex,
73
+ abi: IWorldAbi,
74
+ client: { public: publicClient, wallet: burnerWalletClient },
75
+ });
76
+
77
+ /*
78
+ * Sync on-chain state into RECS and keeps our client in sync.
79
+ * Uses the MUD indexer if available, otherwise falls back
80
+ * to the viem publicClient to make RPC calls to fetch MUD
81
+ * events from the chain.
82
+ */
83
+ const { tables, useStore, latestBlock$, storedBlockLogs$, waitForTransaction } = await syncToZustand({
84
+ config: mudConfig,
85
+ address: networkConfig.worldAddress as Hex,
86
+ publicClient,
87
+ startBlock: BigInt(networkConfig.initialBlockNumber),
88
+ });
89
+
90
+ return {
91
+ tables,
92
+ useStore,
93
+ publicClient,
94
+ walletClient: burnerWalletClient,
95
+ latestBlock$,
96
+ storedBlockLogs$,
97
+ waitForTransaction,
98
+ worldContract,
99
+ write$: write$.asObservable().pipe(share()),
100
+ };
101
+ }