diff --git a/bun.lockb b/bun.lockb index a7795a37..8cae6050 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/examples/react-phaser-example/.env b/examples/react-phaser-example/.env.development similarity index 73% rename from examples/react-phaser-example/.env rename to examples/react-phaser-example/.env.development index 49b085e6..7c66c62b 100644 --- a/examples/react-phaser-example/.env +++ b/examples/react-phaser-example/.env.development @@ -2,6 +2,7 @@ VITE_PUBLIC_ETH_CONTRACT_ADDRESS=0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c74 VITE_PUBLIC_ACCOUNT_CLASS_HASH=0x04d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f VITE_PUBLIC_MASTER_ADDRESS=0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973 VITE_PUBLIC_MASTER_PRIVATE_KEY=0x1800000000300000180000000000030000000000003006001800006600 -VITE_PUBLIC_WORLD_ADDRESS=0x534692277764b04cfc469858891b825c799d1da550d2509fdd5be2f32abdaa0 +VITE_PUBLIC_WORLD_ADDRESS=0x33ac2f528bb97cc7b79148fd1756dc368be0e95d391d8c6d6473ecb60b4560e VITE_PUBLIC_NODE_URL=http://localhost:5050 -VITE_PUBLIC_TORII=http://localhost:8080 \ No newline at end of file +VITE_PUBLIC_TORII=http://localhost:8080 +VITE_PUBLIC_DEV=true diff --git a/examples/react-phaser-example/.prettierrc b/examples/react-phaser-example/.prettierrc new file mode 100644 index 00000000..36ff1651 --- /dev/null +++ b/examples/react-phaser-example/.prettierrc @@ -0,0 +1,8 @@ +{ + "trailingComma": "es5", + "tabWidth": 4, + "semi": true, + "singleQuote": false, + "bracketSpacing": true, + "printWidth": 80 +} diff --git a/examples/react-phaser-example/bun.lockb b/examples/react-phaser-example/bun.lockb new file mode 100755 index 00000000..37712492 Binary files /dev/null and b/examples/react-phaser-example/bun.lockb differ diff --git a/examples/react-phaser-example/codegen.ts b/examples/react-phaser-example/codegen.ts deleted file mode 100644 index fb3280cc..00000000 --- a/examples/react-phaser-example/codegen.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { CodegenConfig } from "@graphql-codegen/cli"; - -const config: CodegenConfig = { - schema: "http://localhost:8080", - documents: "src/**/*.graphql", - generates: { - "src/generated/graphql.ts": { - plugins: [ - "typescript", - "typescript-operations", - "typescript-graphql-request", - ], - config: { - rawRequest: true, - }, - }, - }, -}; -export default config; diff --git a/examples/react-phaser-example/components.json b/examples/react-phaser-example/components.json new file mode 100644 index 00000000..2a12988a --- /dev/null +++ b/examples/react-phaser-example/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "stone", + "cssVariables": true + }, + "aliases": { + "components": "src/components", + "utils": "src/lib/utils" + } +} diff --git a/examples/react-phaser-example/index.html b/examples/react-phaser-example/index.html index e0ef3be8..5b6420e9 100644 --- a/examples/react-phaser-example/index.html +++ b/examples/react-phaser-example/index.html @@ -4,7 +4,7 @@ - Vite + React + TS + 🪨 v 📄 x ✂️
diff --git a/examples/react-phaser-example/package.json b/examples/react-phaser-example/package.json index 63f513e0..8b4d6733 100644 --- a/examples/react-phaser-example/package.json +++ b/examples/react-phaser-example/package.json @@ -9,21 +9,27 @@ "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", "codegen": "graphql-codegen", - "components": "npx @dojoengine/core ../dojo-starter/target/dev/manifest.json src/dojo/contractComponents.ts http://localhost:5050 0x534692277764b04cfc469858891b825c799d1da550d2509fdd5be2f32abdaa0" + "components": "npx @dojoengine/core ../dojo-starter/target/dev/manifest.json src/dojo/contractComponents.ts http://localhost:5050 0x33ac2f528bb97cc7b79148fd1756dc368be0e95d391d8c6d6473ecb60b4560e" }, "dependencies": { "@dojoengine/core": "link:dojo-packages/packages/core", "@dojoengine/create-burner": "link:dojo-packages/packages/create-burner", "@dojoengine/torii-client": "link:dojo-packages/packages/torii-client", + "@dojoengine/torii-wasm": "link:dojo-packages/packages/torii-wasm", "@dojoengine/utils": "link:dojo-packages/packages/utils", "@dojoengine/react": "link:dojo-packages/packages/react", "@dojoengine/recs": "0.1.35", - "@latticexyz/utils": "^2.0.0-next.11", - "@latticexyz/phaserx": "^2.0.0-next.11", + "@latticexyz/phaserx": "^2.0.0-next.14", + "@latticexyz/utils": "^2.0.0-next.14", + "@radix-ui/react-slot": "^1.0.2", + "alea": "^1.0.1", + "class-variance-authority": "^0.7.0", + "clsx": "^2.0.0", "ethers": "^5.7.2", "events": "^3.3.0", "graphql": "^16.7.1", "graphql-request": "^6.1.0", + "lucide-react": "^0.292.0", "mobx": "^6.9.0", "phaser": "3.60.0-beta.14", "proxy-deep": "^3.1.1", @@ -33,16 +39,18 @@ "simplex-noise": "^4.0.1", "starknet": "5.19.5", "styled-components": "^6.0.7", - "zustand": "^4.4.1", + "tailwind-merge": "^2.0.0", + "tailwindcss-animate": "^1.0.7", "vite-plugin-top-level-await": "^1.3.1", - "vite-plugin-wasm": "^3.2.2" + "vite-plugin-wasm": "^3.2.2", + "zustand": "^4.4.1" }, "devDependencies": { "@graphql-codegen/cli": "^5.0.0", "@graphql-codegen/typescript": "^4.0.1", "@graphql-codegen/typescript-graphql-request": "^5.0.0", "@graphql-codegen/typescript-operations": "^4.0.1", - "@types/node": "^20.4.8", + "@types/node": "^20.9.0", "@types/react": "^18.0.37", "@types/react-dom": "^18.0.11", "@typescript-eslint/eslint-plugin": "^5.59.0", @@ -54,7 +62,7 @@ "eslint-plugin-react-refresh": "^0.3.4", "postcss": "^8.4.31", "tailwindcss": "^3.3.5", - "typescript": "^5.0.2", + "typescript": "^5.2.2", "vite": "^4.3.9" } } diff --git a/examples/react-phaser-example/src/assets/atlases/atlas.json b/examples/react-phaser-example/public/assets/atlases/atlas.json similarity index 68% rename from examples/react-phaser-example/src/assets/atlases/atlas.json rename to examples/react-phaser-example/public/assets/atlases/atlas.json index d4529f25..d47553c1 100644 --- a/examples/react-phaser-example/src/assets/atlases/atlas.json +++ b/examples/react-phaser-example/public/assets/atlases/atlas.json @@ -5,7 +5,7 @@ }, "textures": [ { - "image": "atlas.png?timestamp=1678825051140", + "image": "../texture.png?timestamp=1678825051140", "format": "RGBA8888", "size": { "w": 2048, @@ -14,7 +14,7 @@ "scale": 1, "frames": [ { - "filename": "sprites/soldier/idle/0.png", + "filename": "sprites/paper/0.png", "rotated": false, "trimmed": false, "sourceSize": { @@ -35,7 +35,7 @@ } }, { - "filename": "sprites/soldier/idle/1.png", + "filename": "sprites/rock/0.png", "rotated": false, "trimmed": false, "sourceSize": { @@ -56,7 +56,7 @@ } }, { - "filename": "sprites/soldier/idle/2.png", + "filename": "sprites/scissors/0.png", "rotated": false, "trimmed": false, "sourceSize": { @@ -70,31 +70,10 @@ "h": 32 }, "frame": { - "x": 0, - "y": 32, - "w": 32, - "h": 32 - } - }, - { - "filename": "sprites/soldier/idle/3.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 0, + "x": 64, "y": 0, "w": 32, "h": 32 - }, - "frame": { - "x": 32, - "y": 32, - "w": 32, - "h": 32 } } ] diff --git a/examples/react-phaser-example/src/assets/atlases/atlas.png b/examples/react-phaser-example/public/assets/atlases/atlas.png similarity index 100% rename from examples/react-phaser-example/src/assets/atlases/atlas.png rename to examples/react-phaser-example/public/assets/atlases/atlas.png diff --git a/examples/react-phaser-example/public/assets/paper.png b/examples/react-phaser-example/public/assets/paper.png new file mode 100644 index 00000000..864042a2 Binary files /dev/null and b/examples/react-phaser-example/public/assets/paper.png differ diff --git a/examples/react-phaser-example/public/assets/rock.png b/examples/react-phaser-example/public/assets/rock.png new file mode 100644 index 00000000..93303300 Binary files /dev/null and b/examples/react-phaser-example/public/assets/rock.png differ diff --git a/examples/react-phaser-example/public/assets/scissors.png b/examples/react-phaser-example/public/assets/scissors.png new file mode 100644 index 00000000..284c1c01 Binary files /dev/null and b/examples/react-phaser-example/public/assets/scissors.png differ diff --git a/examples/react-phaser-example/public/assets/texture.json b/examples/react-phaser-example/public/assets/texture.json new file mode 100644 index 00000000..a49a21ef --- /dev/null +++ b/examples/react-phaser-example/public/assets/texture.json @@ -0,0 +1,83 @@ +{ + "textures": [ + { + "image": "texture.png", + "format": "RGBA8888", + "size": { + "w": 96, + "h": 32 + }, + "scale": 1, + "frames": [ + { + "filename": "paper.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + } + }, + { + "filename": "rock.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + } + }, + { + "filename": "scissors.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:7dd38248733509cfafbacea47809c895:4ba9ad81aa06f2955894ea13212a26b7:88db1022cd6b660616541d2788fcd4f7$" + } +} diff --git a/examples/react-phaser-example/public/assets/texture.png b/examples/react-phaser-example/public/assets/texture.png new file mode 100644 index 00000000..9e519a9b Binary files /dev/null and b/examples/react-phaser-example/public/assets/texture.png differ diff --git a/examples/react-phaser-example/public/assets/tilesets/land.png b/examples/react-phaser-example/public/assets/tilesets/land.png new file mode 100644 index 00000000..4e3af1c1 Binary files /dev/null and b/examples/react-phaser-example/public/assets/tilesets/land.png differ diff --git a/examples/react-phaser-example/src/assets/tilesets/world.png b/examples/react-phaser-example/public/assets/tilesets/world.png similarity index 100% rename from examples/react-phaser-example/src/assets/tilesets/world.png rename to examples/react-phaser-example/public/assets/tilesets/world.png diff --git a/examples/react-phaser-example/public/paper.png b/examples/react-phaser-example/public/paper.png new file mode 100644 index 00000000..864042a2 Binary files /dev/null and b/examples/react-phaser-example/public/paper.png differ diff --git a/examples/react-phaser-example/public/rock.png b/examples/react-phaser-example/public/rock.png new file mode 100644 index 00000000..93303300 Binary files /dev/null and b/examples/react-phaser-example/public/rock.png differ diff --git a/examples/react-phaser-example/public/scissors.png b/examples/react-phaser-example/public/scissors.png new file mode 100644 index 00000000..284c1c01 Binary files /dev/null and b/examples/react-phaser-example/public/scissors.png differ diff --git a/examples/react-phaser-example/public/texture.png b/examples/react-phaser-example/public/texture.png new file mode 100644 index 00000000..9e519a9b Binary files /dev/null and b/examples/react-phaser-example/public/texture.png differ diff --git a/examples/react-phaser-example/readme.md b/examples/react-phaser-example/readme.md index 8012680b..e69de29b 100644 --- a/examples/react-phaser-example/readme.md +++ b/examples/react-phaser-example/readme.md @@ -1 +0,0 @@ -## Integrate Phaser with Dojo: A Quick Start Guide diff --git a/examples/react-phaser-example/src/App.tsx b/examples/react-phaser-example/src/App.tsx index 40982626..8f27c7ce 100644 --- a/examples/react-phaser-example/src/App.tsx +++ b/examples/react-phaser-example/src/App.tsx @@ -1,14 +1,14 @@ import { useEffect } from "react"; -import { useNetworkLayer } from "./hooks/useNetworkLayer"; +import { useNetworkLayer } from "./ui/hooks/useNetworkLayer"; import { PhaserLayer } from "./phaser/phaserLayer"; -import { store } from "./store/store"; +import { store } from "./store"; import { UI } from "./ui"; function App() { const networkLayer = useNetworkLayer(); useEffect(() => { - if (!networkLayer) return; + if (!networkLayer || !networkLayer.account) return; console.log("Setting network layer"); @@ -17,8 +17,12 @@ function App() { return (
+
+
+ {!networkLayer && "loading..."} +
+
-
); diff --git a/examples/react-phaser-example/src/assets/paper.png b/examples/react-phaser-example/src/assets/paper.png new file mode 100644 index 00000000..864042a2 Binary files /dev/null and b/examples/react-phaser-example/src/assets/paper.png differ diff --git a/examples/react-phaser-example/src/assets/react.svg b/examples/react-phaser-example/src/assets/react.svg deleted file mode 100644 index 6c87de9b..00000000 --- a/examples/react-phaser-example/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/react-phaser-example/src/assets/rock.png b/examples/react-phaser-example/src/assets/rock.png new file mode 100644 index 00000000..93303300 Binary files /dev/null and b/examples/react-phaser-example/src/assets/rock.png differ diff --git a/examples/react-phaser-example/src/assets/scissors.png b/examples/react-phaser-example/src/assets/scissors.png new file mode 100644 index 00000000..284c1c01 Binary files /dev/null and b/examples/react-phaser-example/src/assets/scissors.png differ diff --git a/examples/react-phaser-example/src/assets/texture.json b/examples/react-phaser-example/src/assets/texture.json new file mode 100644 index 00000000..a49a21ef --- /dev/null +++ b/examples/react-phaser-example/src/assets/texture.json @@ -0,0 +1,83 @@ +{ + "textures": [ + { + "image": "texture.png", + "format": "RGBA8888", + "size": { + "w": 96, + "h": 32 + }, + "scale": 1, + "frames": [ + { + "filename": "paper.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + } + }, + { + "filename": "rock.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "frame": { + "x": 32, + "y": 0, + "w": 32, + "h": 32 + } + }, + { + "filename": "scissors.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 32 + }, + "frame": { + "x": 64, + "y": 0, + "w": 32, + "h": 32 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:7dd38248733509cfafbacea47809c895:4ba9ad81aa06f2955894ea13212a26b7:88db1022cd6b660616541d2788fcd4f7$" + } +} diff --git a/examples/react-phaser-example/src/assets/texture.png b/examples/react-phaser-example/src/assets/texture.png new file mode 100644 index 00000000..9e519a9b Binary files /dev/null and b/examples/react-phaser-example/src/assets/texture.png differ diff --git a/examples/react-phaser-example/src/assets/tilesets/land.png b/examples/react-phaser-example/src/assets/tilesets/land.png new file mode 100644 index 00000000..4e3af1c1 Binary files /dev/null and b/examples/react-phaser-example/src/assets/tilesets/land.png differ diff --git a/examples/react-phaser-example/src/artTypes/world.ts b/examples/react-phaser-example/src/assets/world.ts similarity index 58% rename from examples/react-phaser-example/src/artTypes/world.ts rename to examples/react-phaser-example/src/assets/world.ts index ba704d3c..67a4155c 100644 --- a/examples/react-phaser-example/src/artTypes/world.ts +++ b/examples/react-phaser-example/src/assets/world.ts @@ -1,9 +1,8 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - export enum Tileset { - Grass = 0, - Mountains = 1, - Forest = 2, + Land = 0, + Forest = 1, + Sea = 2, + Desert = 3, } export enum TileAnimationKey {} export const TileAnimations: { [key in TileAnimationKey]: number[] } = {}; diff --git a/examples/react-phaser-example/src/dojo/createBurner.ts b/examples/react-phaser-example/src/dojo/createBurner.ts new file mode 100644 index 00000000..30b05244 --- /dev/null +++ b/examples/react-phaser-example/src/dojo/createBurner.ts @@ -0,0 +1,33 @@ +import { BurnerManager } from "@dojoengine/create-burner"; +import { Account, RpcProvider } from "starknet"; + +export const createBurner = async () => { + const rpcProvider = new RpcProvider({ + nodeUrl: import.meta.env.VITE_PUBLIC_NODE_URL!, + }); + + const masterAccount = new Account( + rpcProvider, + import.meta.env.VITE_PUBLIC_MASTER_ADDRESS!, + import.meta.env.VITE_PUBLIC_MASTER_PRIVATE_KEY! + ); + + const burnerManager = new BurnerManager({ + masterAccount, + accountClassHash: import.meta.env.VITE_PUBLIC_ACCOUNT_CLASS_HASH!, + rpcProvider, + }); + + try { + await burnerManager.create(); + } catch (e) { + console.log(e); + } + + burnerManager.init(); + + return { + account: burnerManager.account as Account, + burnerManager, + }; +}; diff --git a/examples/react-phaser-example/src/dojo/createClientComponents.ts b/examples/react-phaser-example/src/dojo/createClientComponents.ts index 79ee4e15..12ef0456 100644 --- a/examples/react-phaser-example/src/dojo/createClientComponents.ts +++ b/examples/react-phaser-example/src/dojo/createClientComponents.ts @@ -9,6 +9,5 @@ export function createClientComponents({ return { ...contractComponents, Position: overridableComponent(contractComponents.Position), - Moves: overridableComponent(contractComponents.Moves), }; } diff --git a/examples/react-phaser-example/src/dojo/createNetworkLayer.ts b/examples/react-phaser-example/src/dojo/createNetworkLayer.ts index 5d6a3f34..e71c1825 100644 --- a/examples/react-phaser-example/src/dojo/createNetworkLayer.ts +++ b/examples/react-phaser-example/src/dojo/createNetworkLayer.ts @@ -1,53 +1,19 @@ import { world } from "./world"; import { setup } from "./setup"; -import { Account, RpcProvider } from "starknet"; -import { BurnerManager } from "@dojoengine/create-burner"; -import { SyncManager } from "@dojoengine/react"; export type NetworkLayer = Awaited>; export const createNetworkLayer = async () => { const { components, systemCalls, network } = await setup(); - const rpcProvider = new RpcProvider({ - nodeUrl: import.meta.env.VITE_PUBLIC_NODE_URL!, - }); - - const masterAccount = new Account( - rpcProvider, - import.meta.env.VITE_PUBLIC_MASTER_ADDRESS!, - import.meta.env.VITE_PUBLIC_MASTER_PRIVATE_KEY! - ); - - const burnerManager = new BurnerManager({ - masterAccount, - accountClassHash: import.meta.env.VITE_PUBLIC_ACCOUNT_CLASS_HASH!, - rpcProvider, - }); - - // TODO: Currently if you change wallets in the UI, phaser will not update. - burnerManager.init(); - - if (burnerManager.account) { - // sync manager to active address - new SyncManager(network.torii_client, [ - { - model: network.contractComponents.Position, - keys: [burnerManager.account?.address], - }, - { - model: network.contractComponents.Moves as any, - keys: [burnerManager.account?.address], - }, - ]); - } + const { burnerManager, account } = network; return { world, components, systemCalls, network, - account: burnerManager.account as Account, + account, burnerManager, }; }; diff --git a/examples/react-phaser-example/src/dojo/createSystemCalls.ts b/examples/react-phaser-example/src/dojo/createSystemCalls.ts index 5ad180cd..c83ae366 100644 --- a/examples/react-phaser-example/src/dojo/createSystemCalls.ts +++ b/examples/react-phaser-example/src/dojo/createSystemCalls.ts @@ -1,124 +1,33 @@ import { SetupNetworkResult } from "./setupNetwork"; -import { Account, AccountInterface } from "starknet"; -import { Entity, getComponentValue } from "@dojoengine/recs"; -import { uuid } from "@latticexyz/utils"; import { ClientComponents } from "./createClientComponents"; -import { Direction, updatePositionWithDirection } from "../utils"; -import { getEvents, setComponentsFromEvents } from "@dojoengine/utils"; +import { MoveSystemProps, SystemSigner } from "./types"; +import { uuid } from "@latticexyz/utils"; +import { Entity, getComponentValue } from "@dojoengine/recs"; +import { getEntityIdFromKeys } from "@dojoengine/utils"; +import { updatePositionWithDirection } from "./utils"; export type SystemCalls = ReturnType; -export interface SystemSigner { - signer: Account; -} - -export interface MoveSystemProps extends SystemSigner { - direction: Direction; -} - export function createSystemCalls( - { execute, contractComponents }: SetupNetworkResult, - { Position, Moves }: ClientComponents + { execute }: SetupNetworkResult, + { Position }: ClientComponents ) { const spawn = async (props: SystemSigner) => { - const signer = props.signer; - - console.log("spawn", signer.address); - const entityId = signer.address.toString() as Entity; - - const positionId = uuid(); - Position.addOverride(positionId, { - entity: entityId, - value: { player: BigInt(entityId), vec: { x: 10, y: 10 } }, - }); - - const movesId = uuid(); - Moves.addOverride(movesId, { - entity: entityId, - value: { - player: BigInt(entityId), - remaining: 100, - last_direction: 0, - }, - }); - + console.log(props.signer); try { - const { transaction_hash } = await execute( - signer, - "actions", - "spawn", - [] - ); - - setComponentsFromEvents( - contractComponents, - getEvents( - await signer.waitForTransaction(transaction_hash, { - retryInterval: 100, - }) - ) - ); + await execute(props.signer, "actions", "spawn", []); } catch (e) { - console.log(e); - Position.removeOverride(positionId); - Moves.removeOverride(movesId); - } finally { - Position.removeOverride(positionId); - Moves.removeOverride(movesId); + console.error(e); } }; const move = async (props: MoveSystemProps) => { const { signer, direction } = props; - const entityId = signer.address.toString() as Entity; - - const positionId = uuid(); - Position.addOverride(positionId, { - entity: entityId, - value: { - player: BigInt(entityId), - vec: updatePositionWithDirection( - direction, - // currently recs does not support nested values so we use any here - getComponentValue(Position, entityId) as any - ).vec, - }, - }); - - const movesId = uuid(); - Moves.addOverride(movesId, { - entity: entityId, - value: { - player: BigInt(entityId), - remaining: - (getComponentValue(Moves, entityId)?.remaining || 0) - 1, - }, - }); - try { - const { transaction_hash } = await execute( - signer, - "actions", - "move", - [direction] - ); - - setComponentsFromEvents( - contractComponents, - getEvents( - await signer.waitForTransaction(transaction_hash, { - retryInterval: 100, - }) - ) - ); + await execute(signer, "actions", "move", [direction]); } catch (e) { console.log(e); - Position.removeOverride(positionId); - Moves.removeOverride(movesId); - } finally { - Position.removeOverride(positionId); - Moves.removeOverride(movesId); } }; diff --git a/examples/react-phaser-example/src/dojo/setupNetwork.ts b/examples/react-phaser-example/src/dojo/setupNetwork.ts index d466fc66..08527492 100644 --- a/examples/react-phaser-example/src/dojo/setupNetwork.ts +++ b/examples/react-phaser-example/src/dojo/setupNetwork.ts @@ -2,37 +2,43 @@ import { defineContractComponents } from "./contractComponents"; import { world } from "./world"; import { RPCProvider } from "@dojoengine/core"; import { Account, num } from "starknet"; -import manifest from "../../../dojo-starter/target/dev/manifest.json"; +import dev_manifest from "../../../dojo-starter/target/dev/manifest.json"; import * as torii from "@dojoengine/torii-client"; +import { createBurner } from "./createBurner"; export type SetupNetworkResult = Awaited>; export async function setupNetwork() { - // Extract environment variables for better readability. const { VITE_PUBLIC_WORLD_ADDRESS, VITE_PUBLIC_NODE_URL, VITE_PUBLIC_TORII, } = import.meta.env; - // Create a new RPCProvider instance. const provider = new RPCProvider( VITE_PUBLIC_WORLD_ADDRESS, - manifest, + dev_manifest, VITE_PUBLIC_NODE_URL ); - const torii_client = await torii.createClient([], { + const toriiClient = await torii.createClient([], { rpcUrl: VITE_PUBLIC_NODE_URL, - toriiUrl: VITE_PUBLIC_TORII + "/grpc", + toriiUrl: VITE_PUBLIC_TORII, worldAddress: VITE_PUBLIC_WORLD_ADDRESS, }); - // Return the setup object. + const { account, burnerManager } = await createBurner(); + return { + // dojo provider from core provider, + + // recs world world, - torii_client, + + toriiClient, + account, + burnerManager, // Define contract components for the world. contractComponents: defineContractComponents(world), diff --git a/examples/react-phaser-example/src/dojo/types.ts b/examples/react-phaser-example/src/dojo/types.ts new file mode 100644 index 00000000..3696655b --- /dev/null +++ b/examples/react-phaser-example/src/dojo/types.ts @@ -0,0 +1,10 @@ +import { Account } from "starknet"; +import { Direction } from "./utils"; + +export interface SystemSigner { + signer: Account; +} + +export interface MoveSystemProps extends SystemSigner { + direction: Direction; +} diff --git a/examples/react-phaser-example/src/utils/index.ts b/examples/react-phaser-example/src/dojo/utils/index.ts similarity index 75% rename from examples/react-phaser-example/src/utils/index.ts rename to examples/react-phaser-example/src/dojo/utils/index.ts index 1ec8b000..20888569 100644 --- a/examples/react-phaser-example/src/utils/index.ts +++ b/examples/react-phaser-example/src/dojo/utils/index.ts @@ -7,20 +7,20 @@ export enum Direction { export function updatePositionWithDirection( direction: Direction, - value: { vec: { x: number; y: number } } + value: { x: number; y: number } ) { switch (direction) { case Direction.Left: - value.vec.x--; + value.x--; break; case Direction.Right: - value.vec.x++; + value.x++; break; case Direction.Up: - value.vec.y--; + value.y--; break; case Direction.Down: - value.vec.y++; + value.y++; break; default: throw new Error("Invalid direction provided"); diff --git a/examples/react-phaser-example/src/hooks/useDojo.tsx b/examples/react-phaser-example/src/hooks/useDojo.tsx deleted file mode 100644 index 9528d619..00000000 --- a/examples/react-phaser-example/src/hooks/useDojo.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Account } from "starknet"; -import { NetworkLayer } from "../dojo/createNetworkLayer"; -import { PhaserLayer } from "../phaser"; -import { store } from "../store/store"; -import { useBurnerManager } from "@dojoengine/create-burner"; - -export type UIStore = ReturnType; - -export const useDojo = () => { - const { networkLayer, phaserLayer } = store(); - - if (phaserLayer === null || networkLayer === null) { - throw new Error("Store not initialized"); - } - - const { account, get, create, select, list, isDeploying, clear } = - useBurnerManager({ - burnerManager: networkLayer.burnerManager, - }); - - return { - networkLayer: networkLayer as NetworkLayer, - phaserLayer: phaserLayer as PhaserLayer, - account: { - account: account as Account, - get, - create, - select, - list, - clear, - isDeploying, - }, - systemCalls: networkLayer.systemCalls, - toriiClient: networkLayer.network.torii_client, - contractComponents: networkLayer.network.contractComponents, - }; -}; diff --git a/examples/react-phaser-example/src/index.css b/examples/react-phaser-example/src/index.css index b5c61c95..16605217 100644 --- a/examples/react-phaser-example/src/index.css +++ b/examples/react-phaser-example/src/index.css @@ -1,3 +1,76 @@ @tailwind base; @tailwind components; @tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 20 14.3% 4.1%; + + --card: 0 0% 100%; + --card-foreground: 20 14.3% 4.1%; + + --popover: 0 0% 100%; + --popover-foreground: 20 14.3% 4.1%; + + --primary: 24 9.8% 10%; + --primary-foreground: 60 9.1% 97.8%; + + --secondary: 60 4.8% 95.9%; + --secondary-foreground: 24 9.8% 10%; + + --muted: 60 4.8% 95.9%; + --muted-foreground: 25 5.3% 44.7%; + + --accent: 60 4.8% 95.9%; + --accent-foreground: 24 9.8% 10%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 60 9.1% 97.8%; + + --border: 20 5.9% 90%; + --input: 20 5.9% 90%; + --ring: 20 14.3% 4.1%; + + --radius: 0.5rem; + } + + .dark { + --background: 20 14.3% 4.1%; + --foreground: 60 9.1% 97.8%; + + --card: 20 14.3% 4.1%; + --card-foreground: 60 9.1% 97.8%; + + --popover: 20 14.3% 4.1%; + --popover-foreground: 60 9.1% 97.8%; + + --primary: 60 9.1% 97.8%; + --primary-foreground: 24 9.8% 10%; + + --secondary: 12 6.5% 15.1%; + --secondary-foreground: 60 9.1% 97.8%; + + --muted: 12 6.5% 15.1%; + --muted-foreground: 24 5.4% 63.9%; + + --accent: 12 6.5% 15.1%; + --accent-foreground: 60 9.1% 97.8%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 60 9.1% 97.8%; + + --border: 12 6.5% 15.1%; + --input: 12 6.5% 15.1%; + --ring: 24 5.7% 82.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/examples/react-phaser-example/src/main.tsx b/examples/react-phaser-example/src/main.tsx index 4807751a..cc6e4ad5 100644 --- a/examples/react-phaser-example/src/main.tsx +++ b/examples/react-phaser-example/src/main.tsx @@ -1,5 +1,5 @@ import ReactDOM from "react-dom/client"; -import App from "./App.tsx"; +import App from "./App"; import "./index.css"; const rootElement = document.getElementById("root"); diff --git a/examples/react-phaser-example/src/phaser/configurePhaser.ts b/examples/react-phaser-example/src/phaser/config/configurePhaser.ts similarity index 67% rename from examples/react-phaser-example/src/phaser/configurePhaser.ts rename to examples/react-phaser-example/src/phaser/config/configurePhaser.ts index 7c46f9ab..259f5c64 100644 --- a/examples/react-phaser-example/src/phaser/configurePhaser.ts +++ b/examples/react-phaser-example/src/phaser/config/configurePhaser.ts @@ -5,8 +5,7 @@ import { defineMapConfig, defineCameraConfig, } from "@latticexyz/phaserx"; -import worldTileset from "../assets/tilesets/world.png"; -import { TileAnimations, Tileset } from "../artTypes/world"; +import { TileAnimations, Tileset } from "../../assets/world"; import { Sprites, Assets, @@ -23,7 +22,7 @@ const mainMap = defineMapConfig({ chunkSize: TILE_WIDTH * 64, // tile size * tile amount tileWidth: TILE_WIDTH, tileHeight: TILE_HEIGHT, - backgroundTile: [Tileset.Grass], + backgroundTile: [Tileset.Land], animationInterval: ANIMATION_INTERVAL, tileAnimations: TileAnimations, layers: { @@ -42,15 +41,15 @@ export const phaserConfig = { [Assets.Tileset]: { type: AssetType.Image, key: Assets.Tileset, - path: worldTileset, + path: "assets/tilesets/land.png", }, [Assets.MainAtlas]: { type: AssetType.MultiAtlas, key: Assets.MainAtlas, // Add a timestamp to the end of the path to prevent caching - path: `src/assets/atlases/atlas.json?timestamp=${Date.now()}`, + path: `assets/atlases/atlas.json?timestamp=${Date.now()}`, options: { - imagePath: "src/assets/atlases/", + imagePath: "assets/atlases/", }, }, }, @@ -65,13 +64,33 @@ export const phaserConfig = { }, animations: [ { - key: Animations.SwordsmanIdle, + key: Animations.RockIdle, assetKey: Assets.MainAtlas, startFrame: 0, - endFrame: 3, + endFrame: 0, frameRate: 6, repeat: -1, - prefix: "sprites/soldier/idle/", + prefix: "sprites/rock/", + suffix: ".png", + }, + { + key: Animations.ScissorsIdle, + assetKey: Assets.MainAtlas, + startFrame: 0, + endFrame: 0, + frameRate: 6, + repeat: -1, + prefix: "sprites/scissors/", + suffix: ".png", + }, + { + key: Animations.PaperIdle, + assetKey: Assets.MainAtlas, + startFrame: 0, + endFrame: 0, + frameRate: 6, + repeat: -1, + prefix: "sprites/paper/", suffix: ".png", }, ], diff --git a/examples/react-phaser-example/src/phaser/config/constants.ts b/examples/react-phaser-example/src/phaser/config/constants.ts new file mode 100644 index 00000000..18d3c87c --- /dev/null +++ b/examples/react-phaser-example/src/phaser/config/constants.ts @@ -0,0 +1,52 @@ +export enum Scenes { + Main = "Main", +} + +export enum Maps { + Main = "Main", +} + +export enum Animations { + RockIdle = "RockIdle", + PaperIdle = "PaperIdle", + ScissorsIdle = "ScissorsIdle", +} + +// image addresses + +export enum Sprites { + Soldier, +} + +export enum RPSSprites { + Rock = "r", + Paper = "p", + Scissors = "s", +} + +export const ImagePaths: { [key in RPSSprites]: string } = { + [RPSSprites.Rock]: "rock.png", + [RPSSprites.Paper]: "paper.png", + [RPSSprites.Scissors]: "scissors.png", +}; + +export enum Assets { + MainAtlas = "MainAtlas", + Tileset = "Tileset", +} + +export enum Direction { + Unknown, + Up, + Down, + Left, + Right, +} + +export const TILE_HEIGHT = 32; +export const TILE_WIDTH = 32; + +// contract offset so we don't overflow +export const ORIGIN_OFFSET = 100; + +export const MAP_AMPLITUDE = 16; diff --git a/examples/react-phaser-example/src/phaser/constants.ts b/examples/react-phaser-example/src/phaser/constants.ts deleted file mode 100644 index 149cb9e1..00000000 --- a/examples/react-phaser-example/src/phaser/constants.ts +++ /dev/null @@ -1,33 +0,0 @@ -export enum Scenes { - Main = "Main", -} - -export enum Maps { - Main = "Main", -} - -export enum Animations { - SwordsmanIdle = "SwordsmanIdle", -} -export enum Sprites { - Soldier, -} - -export enum Assets { - MainAtlas = "MainAtlas", - Tileset = "Tileset", -} - -export enum Direction { - Unknown, - Up, - Down, - Left, - Right, -} - -export const TILE_HEIGHT = 32; -export const TILE_WIDTH = 32; - -// contract offset so we don't overflow -export const POSITION_OFFSET = 1000; diff --git a/examples/react-phaser-example/src/phaser/index.ts b/examples/react-phaser-example/src/phaser/index.ts index 9637c8c7..94bbe9f5 100644 --- a/examples/react-phaser-example/src/phaser/index.ts +++ b/examples/react-phaser-example/src/phaser/index.ts @@ -2,6 +2,7 @@ import { createPhaserEngine } from "@latticexyz/phaserx"; import { NetworkLayer } from "../dojo/createNetworkLayer"; import { registerSystems } from "./systems/registerSystems"; import { namespaceWorld } from "@dojoengine/recs"; +import { TILE_HEIGHT, TILE_WIDTH } from "./config/constants"; export type PhaserLayer = Awaited>; type PhaserEngineConfig = Parameters[0]; @@ -20,8 +21,8 @@ export const createPhaserLayer = async ( const { camera } = scenes.Main; - camera.phaserCamera.setBounds(-1000, -1000, 2000, 2000); - camera.phaserCamera.centerOn(0, 0); + camera.phaserCamera.setBounds(0, 0, TILE_WIDTH * 50, TILE_HEIGHT * 50); + camera.phaserCamera.centerOn(1500, 1500); const components = {}; diff --git a/examples/react-phaser-example/src/phaser/phaserLayer.tsx b/examples/react-phaser-example/src/phaser/phaserLayer.tsx index 1e5a8360..2cabf3e7 100644 --- a/examples/react-phaser-example/src/phaser/phaserLayer.tsx +++ b/examples/react-phaser-example/src/phaser/phaserLayer.tsx @@ -1,14 +1,14 @@ import { useEffect } from "react"; import { NetworkLayer } from "../dojo/createNetworkLayer"; -import { store } from "../store/store"; -import { usePhaserLayer } from "../hooks/usePhaserLayer"; +import { store, useUIStore } from "../store"; +import { usePhaserLayer } from "../ui/hooks/usePhaserLayer"; type Props = { networkLayer: NetworkLayer | null; }; -// TODO: this is where we need to set the burner account from local storage. export const PhaserLayer = ({ networkLayer }: Props) => { + const loggedIn = useUIStore((state: any) => state.loggedIn); const { phaserLayer, ref } = usePhaserLayer({ networkLayer }); useEffect(() => { @@ -17,7 +17,7 @@ export const PhaserLayer = ({ networkLayer }: Props) => { console.log("Setting phaser layer"); } - }, [phaserLayer]); + }, [phaserLayer, loggedIn]); return (
{ + const { + scenes: { + Main: { + camera: { phaserCamera }, + }, + }, + } = layer; + + phaserCamera.centerOn(0, 0); +}; diff --git a/examples/react-phaser-example/src/phaser/systems/controls.ts b/examples/react-phaser-example/src/phaser/systems/controls.ts index 7f0cf57b..d9d6d0e4 100644 --- a/examples/react-phaser-example/src/phaser/systems/controls.ts +++ b/examples/react-phaser-example/src/phaser/systems/controls.ts @@ -1,5 +1,5 @@ import { PhaserLayer } from ".."; -import { Direction } from "../../utils"; +import { Direction } from "../../dojo/utils"; export const controls = (layer: PhaserLayer) => { const { @@ -8,35 +8,63 @@ export const controls = (layer: PhaserLayer) => { }, networkLayer: { systemCalls: { move }, - account, + account: signer, }, } = layer; input.onKeyPress( (keys) => keys.has("W"), () => { - move({ signer: account, direction: Direction.Up }); + move({ signer, direction: Direction.Up }); } ); input.onKeyPress( (keys) => keys.has("A"), () => { - move({ signer: account, direction: Direction.Left }); + move({ signer, direction: Direction.Left }); } ); input.onKeyPress( (keys) => keys.has("S"), () => { - move({ signer: account, direction: Direction.Down }); + move({ signer, direction: Direction.Down }); } ); input.onKeyPress( (keys) => keys.has("D"), () => { - move({ signer: account, direction: Direction.Right }); + move({ signer, direction: Direction.Right }); + } + ); + + input.onKeyPress( + (keys) => keys.has("UP"), + () => { + move({ signer, direction: Direction.Up }); + } + ); + + input.onKeyPress( + (keys) => keys.has("LEFT"), + () => { + move({ signer, direction: Direction.Left }); + } + ); + + input.onKeyPress( + (keys) => keys.has("DOWN"), + () => { + move({ signer, direction: Direction.Down }); + } + ); + + input.onKeyPress( + (keys) => keys.has("RIGHT"), + () => { + move({ signer, direction: Direction.Right }); } ); }; diff --git a/examples/react-phaser-example/src/phaser/systems/mapSystem.ts b/examples/react-phaser-example/src/phaser/systems/mapSystem.ts index 551f0a1c..b09ad553 100644 --- a/examples/react-phaser-example/src/phaser/systems/mapSystem.ts +++ b/examples/react-phaser-example/src/phaser/systems/mapSystem.ts @@ -1,6 +1,7 @@ -import { Tileset } from "../../artTypes/world"; +import { Tileset } from "../../assets/world"; import { PhaserLayer } from ".."; -import { createNoise2D } from "simplex-noise"; +import { snoise } from "@dojoengine/utils"; +import { MAP_AMPLITUDE } from "../config/constants"; export function mapSystem(layer: PhaserLayer) { const { @@ -13,19 +14,24 @@ export function mapSystem(layer: PhaserLayer) { }, } = layer; - const noise = createNoise2D(); - - for (let x = -500; x < 500; x++) { - for (let y = -500; y < 500; y++) { + for (let x = 0; x < 50; x++) { + for (let y = 0; y < 50; y++) { const coord = { x, y }; - const seed = noise(x, y); - - putTileAt(coord, Tileset.Grass, "Background"); + // Get a noise value between 0 and 100 + const seed = Math.floor(((snoise([x / MAP_AMPLITUDE, 0, y / MAP_AMPLITUDE]) + 1) / 2) * 100); - if (seed >= 0.45) { - putTileAt(coord, Tileset.Mountains, "Foreground"); - } else if (seed < -0.45) { + if (seed > 70) { + // This would be the highest 'elevation' + putTileAt(coord, Tileset.Sea, "Foreground"); + } else if (seed > 60) { + // Even lower, could be fields or plains + putTileAt(coord, Tileset.Desert, "Foreground"); + } else if (seed > 53) { + // Close to water level, might be beach putTileAt(coord, Tileset.Forest, "Foreground"); + } else { + // Below a certain threshold, it is sea + putTileAt(coord, Tileset.Land, "Foreground"); } } } diff --git a/examples/react-phaser-example/src/phaser/systems/move.ts b/examples/react-phaser-example/src/phaser/systems/move.ts index 377c1194..b645f609 100644 --- a/examples/react-phaser-example/src/phaser/systems/move.ts +++ b/examples/react-phaser-example/src/phaser/systems/move.ts @@ -1,13 +1,17 @@ import { Entity, Has, - defineEnterSystem, defineSystem, getComponentValueStrict, } from "@dojoengine/recs"; import { PhaserLayer } from ".."; import { tileCoordToPixelCoord } from "@latticexyz/phaserx"; -import { Animations, TILE_HEIGHT, TILE_WIDTH } from "../constants"; +import { + Animations, + ORIGIN_OFFSET, + TILE_HEIGHT, + TILE_WIDTH, +} from "../config/constants"; export const move = (layer: PhaserLayer) => { const { @@ -20,29 +24,34 @@ export const move = (layer: PhaserLayer) => { }, } = layer; - defineEnterSystem(world, [Has(Position)], ({ entity }: any) => { - const playerObj = objectPool.get(entity.toString(), "Sprite"); - - console.log(playerObj); - - playerObj.setComponent({ - id: "animation", - once: (sprite: any) => { - console.log(sprite); - sprite.play(Animations.SwordsmanIdle); - }, - }); - }); - defineSystem(world, [Has(Position)], ({ entity }: any) => { - console.log(entity); - const position = getComponentValueStrict( Position, entity.toString() as Entity ); - const offsetPosition = { x: position?.vec.x, y: position?.vec.y }; + const entity_uniform = (+entity).toString(); + + console.log( + entity, + entity_uniform, + "\n------- pos/type triggered -------\n", + position + ); + + const player = objectPool.get(entity_uniform, "Sprite"); + + player.setComponent({ + id: "animation", + once: (sprite) => { + sprite.play(Animations.RockIdle); + }, + }); + + const offsetPosition = { + x: position?.vec.x - ORIGIN_OFFSET || 0, + y: position?.vec.y - ORIGIN_OFFSET || 0, + }; const pixelPosition = tileCoordToPixelCoord( offsetPosition, @@ -50,12 +59,11 @@ export const move = (layer: PhaserLayer) => { TILE_HEIGHT ); - const player = objectPool.get(entity, "Sprite"); - player.setComponent({ id: "position", - once: (sprite: any) => { + once: (sprite) => { sprite.setPosition(pixelPosition?.x, pixelPosition?.y); + camera.centerOn(pixelPosition?.x, pixelPosition?.y); }, }); diff --git a/examples/react-phaser-example/src/phaser/systems/registerSystems.ts b/examples/react-phaser-example/src/phaser/systems/registerSystems.ts index 9796736f..95df0c48 100644 --- a/examples/react-phaser-example/src/phaser/systems/registerSystems.ts +++ b/examples/react-phaser-example/src/phaser/systems/registerSystems.ts @@ -1,12 +1,12 @@ import { PhaserLayer } from ".."; import { move } from "./move"; -import { spawn } from "./spawn"; import { controls } from "./controls"; import { mapSystem } from "./mapSystem"; +import { camera } from "./camera"; export const registerSystems = (layer: PhaserLayer) => { move(layer); - spawn(layer); controls(layer); mapSystem(layer); + camera(layer); }; diff --git a/examples/react-phaser-example/src/phaser/systems/spawn.ts b/examples/react-phaser-example/src/phaser/systems/spawn.ts deleted file mode 100644 index 88f77fa3..00000000 --- a/examples/react-phaser-example/src/phaser/systems/spawn.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { PhaserLayer } from ".."; - -export const spawn = (layer: PhaserLayer) => { - const { - scenes: { - Main: { input }, - }, - networkLayer: { - systemCalls: { spawn }, - account, - }, - } = layer; - - input.onKeyPress( - (keys) => keys.has("SPACE"), - () => { - spawn({ signer: account }); - } - ); -}; diff --git a/examples/react-phaser-example/src/store/store.ts b/examples/react-phaser-example/src/store.ts similarity index 50% rename from examples/react-phaser-example/src/store/store.ts rename to examples/react-phaser-example/src/store.ts index 11510912..5a148834 100644 --- a/examples/react-phaser-example/src/store/store.ts +++ b/examples/react-phaser-example/src/store.ts @@ -1,6 +1,6 @@ import { create } from "zustand"; -import { NetworkLayer } from "../dojo/createNetworkLayer"; -import { PhaserLayer } from "../phaser"; +import { NetworkLayer } from "./dojo/createNetworkLayer"; +import { PhaserLayer } from "./phaser"; export type Store = { networkLayer: NetworkLayer | null; @@ -11,3 +11,8 @@ export const store = create(() => ({ networkLayer: null, phaserLayer: null, })); + +export const useUIStore = create((set) => ({ + loggedIn: false, + setLoggedIn: () => set(() => ({ loggedIn: true })), +})); diff --git a/examples/react-phaser-example/src/ui/CreateAccount.tsx b/examples/react-phaser-example/src/ui/CreateAccount.tsx new file mode 100644 index 00000000..bddf82f3 --- /dev/null +++ b/examples/react-phaser-example/src/ui/CreateAccount.tsx @@ -0,0 +1,26 @@ +import { useUIStore } from "../store"; +import { ClickWrapper } from "./ClickWrapper"; +import { Spawn } from "./Spawn"; + +export const CreateAccount = () => { + const loggedIn = useUIStore((state: any) => state.loggedIn); + return ( +
+
+

RPS

+
Eat to survive
+
+ +
+ +
+
+
+
+
+ ); +}; diff --git a/examples/react-phaser-example/src/ui/Spawn.tsx b/examples/react-phaser-example/src/ui/Spawn.tsx new file mode 100644 index 00000000..6ef9396e --- /dev/null +++ b/examples/react-phaser-example/src/ui/Spawn.tsx @@ -0,0 +1,43 @@ +import { useDojo } from "./hooks/useDojo"; +import { Button } from "./button"; +import { useUIStore } from "../store"; +import { useEffect } from "react"; + +export const Spawn = () => { + const setLoggedIn = useUIStore((state: any) => state.setLoggedIn); + const { + account: { account, isDeploying }, + systemCalls: { spawn }, + } = useDojo(); + + useEffect(() => { + if (isDeploying) { + return; + } + + if (account) { + return; + } + }, [account]); + + if (!account) { + return
Deploying...
; + } + + return ( +
+ +
+ ); +}; diff --git a/examples/react-phaser-example/src/ui/button.tsx b/examples/react-phaser-example/src/ui/button.tsx new file mode 100644 index 00000000..ffcc068b --- /dev/null +++ b/examples/react-phaser-example/src/ui/button.tsx @@ -0,0 +1,57 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "./lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + } +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/examples/react-phaser-example/src/ui/hooks/useDojo.tsx b/examples/react-phaser-example/src/ui/hooks/useDojo.tsx new file mode 100644 index 00000000..73360d09 --- /dev/null +++ b/examples/react-phaser-example/src/ui/hooks/useDojo.tsx @@ -0,0 +1,38 @@ +import { Account } from "starknet"; +import { store } from "../../store"; +import { useBurnerManager } from "@dojoengine/create-burner"; + +export const useDojo = () => { + const layers = store((state) => { + return { + networkLayer: state.networkLayer, + phaserLayer: state.phaserLayer, + }; + }); + + if (!layers.phaserLayer || !layers.networkLayer) { + throw new Error("Store not initialized"); + } + + const { networkLayer, phaserLayer } = layers; + + const { get, create, select, list, isDeploying, clear } = useBurnerManager({ + burnerManager: layers.networkLayer.burnerManager, + }); + + return { + networkLayer, + phaserLayer, + account: { + account: networkLayer.burnerManager.account as Account, + get, + create, + select, + list, + clear, + isDeploying, + }, + systemCalls: networkLayer.systemCalls, + contractComponents: networkLayer.network.contractComponents, + }; +}; diff --git a/examples/react-phaser-example/src/hooks/useNetworkLayer.tsx b/examples/react-phaser-example/src/ui/hooks/useNetworkLayer.tsx similarity index 87% rename from examples/react-phaser-example/src/hooks/useNetworkLayer.tsx rename to examples/react-phaser-example/src/ui/hooks/useNetworkLayer.tsx index 78728f68..fa4a7219 100644 --- a/examples/react-phaser-example/src/hooks/useNetworkLayer.tsx +++ b/examples/react-phaser-example/src/ui/hooks/useNetworkLayer.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo } from "react"; -import { createNetworkLayer } from "../dojo/createNetworkLayer"; +import { createNetworkLayer } from "../../dojo/createNetworkLayer"; import { usePromiseValue } from "./usePromiseValue"; export const useNetworkLayer = () => { diff --git a/examples/react-phaser-example/src/hooks/usePhaserLayer.tsx b/examples/react-phaser-example/src/ui/hooks/usePhaserLayer.tsx similarity index 86% rename from examples/react-phaser-example/src/hooks/usePhaserLayer.tsx rename to examples/react-phaser-example/src/ui/hooks/usePhaserLayer.tsx index 0a1bbf3d..98bd2123 100644 --- a/examples/react-phaser-example/src/hooks/usePhaserLayer.tsx +++ b/examples/react-phaser-example/src/ui/hooks/usePhaserLayer.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { createPhaserLayer } from "../phaser"; -import { NetworkLayer } from "../dojo/createNetworkLayer"; -import { phaserConfig } from "../phaser/configurePhaser"; +import { createPhaserLayer } from "../../phaser"; +import { NetworkLayer } from "../../dojo/createNetworkLayer"; +import { phaserConfig } from "../../phaser/config/configurePhaser"; import { usePromiseValue } from "./usePromiseValue"; type Props = { @@ -19,7 +19,7 @@ const createContainer = () => { export const usePhaserLayer = ({ networkLayer }: Props) => { const parentRef = useRef(null); - const [{ width, height }, setSize] = useState({ width: 0, height: 0 }); + const [{ width, height }] = useState({ width: 0, height: 0 }); const { phaserLayerPromise, container } = useMemo(() => { if (!networkLayer) return { container: null, phaserLayerPromise: null }; @@ -42,8 +42,6 @@ export const usePhaserLayer = ({ networkLayer }: Props) => { }, }), }; - - // We don't want width/height to recreate phaser layer, so we ignore linter }, [networkLayer]); useEffect(() => { diff --git a/examples/react-phaser-example/src/hooks/usePromiseValue.ts b/examples/react-phaser-example/src/ui/hooks/usePromiseValue.ts similarity index 100% rename from examples/react-phaser-example/src/hooks/usePromiseValue.ts rename to examples/react-phaser-example/src/ui/hooks/usePromiseValue.ts diff --git a/examples/react-phaser-example/src/ui/index.tsx b/examples/react-phaser-example/src/ui/index.tsx index 438b6022..872b2562 100644 --- a/examples/react-phaser-example/src/ui/index.tsx +++ b/examples/react-phaser-example/src/ui/index.tsx @@ -1,7 +1,5 @@ -import styled from "styled-components"; -import { store } from "../store/store"; -import { Wrapper } from "./wrapper"; -import { SpawnBtn } from "./spawnbtn"; +import { store } from "../store"; +import { CreateAccount } from "./CreateAccount"; export const UI = () => { const layers = store((state) => { @@ -14,10 +12,8 @@ export const UI = () => { if (!layers.networkLayer || !layers.phaserLayer) return <>; return ( - -
- -
-
+
+ +
); }; diff --git a/examples/react-phaser-example/src/ui/lib/utils.ts b/examples/react-phaser-example/src/ui/lib/utils.ts new file mode 100644 index 00000000..e6447944 --- /dev/null +++ b/examples/react-phaser-example/src/ui/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/examples/react-phaser-example/src/ui/spawnbtn.tsx b/examples/react-phaser-example/src/ui/spawnbtn.tsx deleted file mode 100644 index 9befcaf9..00000000 --- a/examples/react-phaser-example/src/ui/spawnbtn.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { useDojo } from "../hooks/useDojo"; -import { ClickWrapper } from "./clickWrapper"; - -export const SpawnBtn = () => { - const { - account: { account, create, isDeploying, select, list, clear }, - systemCalls: { spawn }, - } = useDojo(); - - return ( - -
-
- - -
- -
-
signer:
- - -
-
- -
-
-
- ); -}; diff --git a/examples/react-phaser-example/src/ui/wrapper.tsx b/examples/react-phaser-example/src/ui/wrapper.tsx deleted file mode 100644 index b52789d3..00000000 --- a/examples/react-phaser-example/src/ui/wrapper.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import styled from "styled-components"; - -export const Wrapper = styled.div` - position: absolute; - inset: 0; - pointer-events: none; -`; diff --git a/examples/react-phaser-example/tailwind.config.js b/examples/react-phaser-example/tailwind.config.js index 40eda665..6d3e2407 100644 --- a/examples/react-phaser-example/tailwind.config.js +++ b/examples/react-phaser-example/tailwind.config.js @@ -1,8 +1,76 @@ /** @type {import('tailwindcss').Config} */ -export default { - content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], +module.exports = { + darkMode: ["class"], + content: [ + "./pages/**/*.{ts,tsx}", + "./components/**/*.{ts,tsx}", + "./app/**/*.{ts,tsx}", + "./src/**/*.{ts,tsx}", + ], theme: { - extend: {}, + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: { height: 0 }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: 0 }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, }, - plugins: [], + plugins: [require("tailwindcss-animate")], }; diff --git a/examples/react-phaser-example/tsconfig.json b/examples/react-phaser-example/tsconfig.json index 5e3a04ec..db13e438 100644 --- a/examples/react-phaser-example/tsconfig.json +++ b/examples/react-phaser-example/tsconfig.json @@ -14,12 +14,16 @@ "jsx": "react-jsx", /* Linting */ "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "allowSyntheticDefaultImports": true }, "include": ["src"], + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, "references": [ { "path": "./tsconfig.node.json" diff --git a/examples/react-phaser-example/vite.config.ts b/examples/react-phaser-example/vite.config.ts index a77004fe..36a2dcd8 100644 --- a/examples/react-phaser-example/vite.config.ts +++ b/examples/react-phaser-example/vite.config.ts @@ -1,3 +1,4 @@ +import path from "path"; import { defineConfig } from "vite"; import wasm from "vite-plugin-wasm"; import react from "@vitejs/plugin-react"; @@ -6,4 +7,9 @@ import topLevelAwait from "vite-plugin-top-level-await"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react(), wasm(), topLevelAwait()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, });