{
}}
/>
);
-};
\ No newline at end of file
+};
diff --git a/examples/react-phaser-example/src/phaser/systems/camera.ts b/examples/react-phaser-example/src/phaser/systems/camera.ts
new file mode 100644
index 00000000..597326c9
--- /dev/null
+++ b/examples/react-phaser-example/src/phaser/systems/camera.ts
@@ -0,0 +1,13 @@
+import { PhaserLayer } from "..";
+
+export const camera = (layer: PhaserLayer) => {
+ 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..d7518530 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 {
diff --git a/examples/react-phaser-example/src/phaser/systems/mapSystem.ts b/examples/react-phaser-example/src/phaser/systems/mapSystem.ts
index 551f0a1c..eb979d97 100644
--- a/examples/react-phaser-example/src/phaser/systems/mapSystem.ts
+++ b/examples/react-phaser-example/src/phaser/systems/mapSystem.ts
@@ -1,4 +1,4 @@
-import { Tileset } from "../../artTypes/world";
+import { Tileset } from "../../assets/world";
import { PhaserLayer } from "..";
import { createNoise2D } from "simplex-noise";
@@ -20,12 +20,18 @@ export function mapSystem(layer: PhaserLayer) {
const coord = { x, y };
const seed = noise(x, y);
- putTileAt(coord, Tileset.Grass, "Background");
-
- if (seed >= 0.45) {
- putTileAt(coord, Tileset.Mountains, "Foreground");
- } else if (seed < -0.45) {
+ if (seed > 0.9) {
+ // This would be the highest 'elevation'
+ putTileAt(coord, Tileset.Desert, "Foreground");
+ } else if (seed > 0.3) {
+ // Even lower, could be fields or plains
+ putTileAt(coord, Tileset.Sea, "Foreground");
+ } else if (seed > 0.1) {
+ // 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 e1ea335d..4fd4e62c 100644
--- a/examples/react-phaser-example/src/phaser/systems/move.ts
+++ b/examples/react-phaser-example/src/phaser/systems/move.ts
@@ -1,54 +1,89 @@
-import { Entity, Has, defineEnterSystem, defineSystem, getComponentValueStrict } from "@dojoengine/recs";
+import {
+ Entity,
+ Has,
+ defineEnterSystem,
+ defineSystem,
+ getComponentValueStrict,
+ getComponentValue,
+} from "@dojoengine/recs";
import { PhaserLayer } from "..";
import { tileCoordToPixelCoord } from "@latticexyz/phaserx";
-import { Animations, TILE_HEIGHT, TILE_WIDTH } from "../constants";
+import {
+ Animations,
+ RPSSprites,
+ TILE_HEIGHT,
+ TILE_WIDTH,
+} from "../config/constants";
export const move = (layer: PhaserLayer) => {
-
const {
world,
scenes: {
Main: { objectPool, camera },
},
networkLayer: {
- components: { Position }
+ components: { Position, RPSType, PlayerID },
},
} = layer;
- defineEnterSystem(world, [Has(Position)], ({ entity }: any) => {
- const playerObj = objectPool.get(entity.toString(), "Sprite");
+ defineEnterSystem(
+ world,
+ [Has(Position), Has(RPSType)],
+ ({ entity }: any) => {
+ const playerObj = objectPool.get(entity.toString(), "Sprite");
- console.log(playerObj)
+ const type = getComponentValue(
+ RPSType,
+ entity.toString() as Entity
+ );
- playerObj.setComponent({
- id: 'animation',
- once: (sprite: any) => {
+ console.log("defineEnterSystem", type);
- console.log(sprite)
- sprite.play(Animations.SwordsmanIdle);
- }
- });
- });
+ let animation = Animations.RockIdle;
- defineSystem(world, [Has(Position)], ({ entity }: any) => {
+ switch (type?.rps) {
+ case RPSSprites.Rock:
+ animation = Animations.RockIdle;
+ break;
+ case RPSSprites.Paper:
+ animation = Animations.PaperIdle;
+ break;
+ case RPSSprites.Scissors:
+ animation = Animations.ScissorsIdle;
+ break;
+ }
- console.log(entity)
+ playerObj.setComponent({
+ id: "animation",
+ once: (sprite: any) => {
+ sprite.play(animation);
+ },
+ });
+ }
+ );
- const position = getComponentValueStrict(Position, entity.toString() as Entity);
+ defineSystem(world, [Has(Position)], ({ entity }: any) => {
+ const position = getComponentValueStrict(
+ Position,
+ entity.toString() as Entity
+ );
- const offsetPosition = { x: position?.vec.x, y: position?.vec.y };
+ const offsetPosition = { x: position?.x, y: position?.y };
- const pixelPosition = tileCoordToPixelCoord(offsetPosition, TILE_WIDTH, TILE_HEIGHT);
+ const pixelPosition = tileCoordToPixelCoord(
+ offsetPosition,
+ TILE_WIDTH,
+ TILE_HEIGHT
+ );
- const player = objectPool.get(entity, "Sprite")
+ const player = objectPool.get(entity, "Sprite");
player.setComponent({
- id: 'position',
+ id: "position",
once: (sprite: any) => {
sprite.setPosition(pixelPosition?.x, pixelPosition?.y);
camera.centerOn(pixelPosition?.x, pixelPosition?.y);
- }
- })
-
+ },
+ });
});
-};
\ No newline at end of file
+};
diff --git a/examples/react-phaser-example/src/phaser/systems/registerSystems.ts b/examples/react-phaser-example/src/phaser/systems/registerSystems.ts
index 7e9a95da..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)
-};
\ No newline at end of file
+ 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/store.ts
index 05794064..c677b9de 100644
--- a/examples/react-phaser-example/src/store/store.ts
+++ b/examples/react-phaser-example/src/store/store.ts
@@ -9,6 +9,10 @@ export type Store = {
export const store = create
(() => ({
networkLayer: null,
- phaserLayer: 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..d07fc24b
--- /dev/null
+++ b/examples/react-phaser-example/src/ui/CreateAccount.tsx
@@ -0,0 +1,21 @@
+import { useUIStore } from "../store/store";
+import { WalletConnect } from "./WalletConnect";
+
+export const CreateAccount = () => {
+ const loggedIn = useUIStore((state: any) => state.loggedIn);
+ return (
+
+
+
RPS
+
Eat to survive
+
+
+
+
+
+ );
+};
diff --git a/examples/react-phaser-example/src/ui/GameState.tsx b/examples/react-phaser-example/src/ui/GameState.tsx
new file mode 100644
index 00000000..e69de29b
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..8a19e6ec
--- /dev/null
+++ b/examples/react-phaser-example/src/ui/Spawn.tsx
@@ -0,0 +1,66 @@
+import { useDojo } from "../hooks/useDojo";
+import { RPSSprites } from "../phaser/config/constants";
+import { ClickWrapper } from "./ClickWrapper";
+import { Button } from "../components/ui/button";
+import { useUIStore } from "../store/store";
+import { useEffect } from "react";
+
+export const Spawn = () => {
+ const setLoggedIn = useUIStore((state: any) => state.setLoggedIn);
+ const {
+ account: { account },
+ systemCalls: { spawn },
+ } = useDojo();
+
+ // useEffect(() => {
+ // if (isDeploying) {
+ // return;
+ // }
+
+ // if (account) {
+ // return;
+ // }
+
+ // (async () => {
+ // const accounts = await list();
+
+ // if (accounts.length === 0) {
+ // await create();
+ // } else {
+ // await select(accounts[0].address);
+ // }
+ // })();
+ // }, [account]);
+
+ if (!account) {
+ return Deploying...
;
+ }
+
+ return (
+
+
+ {Object.keys(RPSSprites)
+ .filter((key) => isNaN(Number(key)))
+ .map((key) => (
+
+
+
+ ))}
+
+
+ );
+};
diff --git a/examples/react-phaser-example/src/ui/WalletConnect.tsx b/examples/react-phaser-example/src/ui/WalletConnect.tsx
new file mode 100644
index 00000000..a4b3ed7b
--- /dev/null
+++ b/examples/react-phaser-example/src/ui/WalletConnect.tsx
@@ -0,0 +1,14 @@
+import { ClickWrapper } from "./ClickWrapper";
+import { Spawn } from "./Spawn";
+
+export const WalletConnect = () => {
+ return (
+
+
+
+ );
+};
diff --git a/examples/react-phaser-example/src/ui/index.tsx b/examples/react-phaser-example/src/ui/index.tsx
index 438b6022..8702ba96 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 { 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/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 8f145635..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;
-`;
\ No newline at end of file
diff --git a/examples/react-phaser-example/tailwind.config.js b/examples/react-phaser-example/tailwind.config.js
index 40eda665..0377ea1d 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}"],
- theme: {
- extend: {},
+module.exports = {
+ darkMode: ["class"],
+ content: [
+ './pages/**/*.{ts,tsx}',
+ './components/**/*.{ts,tsx}',
+ './app/**/*.{ts,tsx}',
+ './src/**/*.{ts,tsx}',
+ ],
+ theme: {
+ container: {
+ center: true,
+ padding: "2rem",
+ screens: {
+ "2xl": "1400px",
+ },
},
- plugins: [],
-};
+ 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: [require("tailwindcss-animate")],
+}
\ No newline at end of file
diff --git a/examples/react-phaser-example/tsconfig.json b/examples/react-phaser-example/tsconfig.json
index 22a01748..a056980a 100644
--- a/examples/react-phaser-example/tsconfig.json
+++ b/examples/react-phaser-example/tsconfig.json
@@ -26,6 +26,12 @@
"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"),
+ },
+ },
});
diff --git a/package.json b/package.json
index 7487fbbb..1329e5a3 100644
--- a/package.json
+++ b/package.json
@@ -1,28 +1,28 @@
{
- "name": "dojo-packages",
- "version": "1.0.0",
- "workspaces": [
- "examples/react-app",
- "examples/react-phaser-example",
- "packages/create-burner",
- "packages/core",
- "packages/utils",
- "packages/torii-client",
- "packages/torii-wasm",
- "packages/react"
- ],
- "devDependencies": {
- "prettier": "^3.0.3"
- },
- "scripts": {
- "build-core": "bun run --cwd packages/core build",
- "build-create-burner": "bun run --cwd packages/create-burner build",
- "build-utils": "bun run --cwd packages/utils build",
- "build-torii-client": "bun run --cwd packages/torii-client build",
- "build-torii-wasm": "bun run --cwd packages/torii-wasm build",
- "build-react": "bun run --cwd packages/react build",
- "build-phaser": "bun run --cwd examples/react-phaser-example build",
- "build": "bun run build-core && bun run build-create-burner && bun run build-utils && bun run build-torii-client && bun run build-torii-wasm",
- "clean": "rm -rf node_modules packages/create-burner/node_modules packages/core/node_modules packages/utils/node_modules packages/torii-client/node_modules packages/torii-wasm/node_modules packages/react/node_modules bun.lockb packages/create-burner/bun.lockb packages/core/bun.lockb packages/utils/bun.lockb packages/torii-client/bun.lockb packages/torii-wasm/bun.lockb packages/react/bun.lockb && rm -rf examples/react-app/node_modules examples/react-app/bun.lockb examples/react-phaser-example/node_modules examples/react-phaser-example/bun.lockb"
- }
+ "name": "dojo-packages",
+ "version": "1.0.0",
+ "workspaces": [
+ "examples/react-app",
+ "examples/react-phaser-example",
+ "packages/create-burner",
+ "packages/core",
+ "packages/utils",
+ "packages/torii-client",
+ "packages/torii-wasm",
+ "packages/react"
+ ],
+ "devDependencies": {
+ "prettier": "^3.0.3"
+ },
+ "scripts": {
+ "build-core": "bun run --cwd packages/core build",
+ "build-create-burner": "bun run --cwd packages/create-burner build",
+ "build-utils": "bun run --cwd packages/utils build",
+ "build-torii-client": "bun run --cwd packages/torii-client build",
+ "build-torii-wasm": "bun run --cwd packages/torii-wasm build",
+ "build-react": "bun run --cwd packages/react build",
+ "build-phaser": "bun run --cwd examples/react-phaser-example build",
+ "build": "bun run build-core && bun run build-create-burner && bun run build-utils && bun run build react && bun run build-torii-wasm && bun run build-torii-client",
+ "clean": "rm -rf node_modules packages/create-burner/node_modules packages/core/node_modules packages/utils/node_modules packages/torii-client/node_modules packages/torii-wasm/node_modules packages/react/node_modules bun.lockb packages/create-burner/bun.lockb packages/core/bun.lockb packages/utils/bun.lockb packages/torii-client/bun.lockb packages/torii-wasm/bun.lockb packages/react/bun.lockb && rm -rf examples/react-app/node_modules examples/react-app/bun.lockb examples/react-phaser-example/node_modules examples/react-phaser-example/bun.lockb"
+ }
}
diff --git a/packages/react/src/syncManager/index.ts b/packages/react/src/syncManager/index.ts
index c019356a..13653309 100644
--- a/packages/react/src/syncManager/index.ts
+++ b/packages/react/src/syncManager/index.ts
@@ -1 +1,3 @@
export { SyncManager } from "./syncManager";
+export { SubscribeManager } from "./subscribeManager";
+export { createSyncManager } from "./syncFunction";
diff --git a/packages/react/src/syncManager/subscribeManager.ts b/packages/react/src/syncManager/subscribeManager.ts
new file mode 100644
index 00000000..cd73c983
--- /dev/null
+++ b/packages/react/src/syncManager/subscribeManager.ts
@@ -0,0 +1,59 @@
+import { Client } from "@dojoengine/torii-client";
+import {
+ Component,
+ Schema,
+ Metadata,
+ Entity,
+ setComponent,
+ ComponentValue,
+} from "@dojoengine/recs";
+import { getEntityIdFromKeys } from "@dojoengine/utils";
+import { convertValues } from "../utils";
+
+type ModelEntry = {
+ model: Component;
+ keys: any[];
+};
+
+export class SubscribeManager {
+ private client: Client;
+ private modelEntries: ModelEntry[];
+
+ constructor(client: Client, modelEntries: ModelEntry[]) {
+ this.client = client;
+ this.modelEntries = modelEntries;
+ this.modelEntries.forEach((entry) => this.subscribeToModel(entry));
+ }
+
+ private async setModelValue(modelEntry: ModelEntry): Promise {
+ const { model, keys } = modelEntry;
+ const componentName = model.metadata?.name;
+ const keysToStrings = keys.map((key) => key.toString());
+ const entityIndex: Entity | string =
+ keys.length === 1 ? keys[0].toString() : getEntityIdFromKeys(keys);
+
+ try {
+ const modelValue = await this.client.getModelValue(
+ componentName! as string,
+ keysToStrings
+ );
+ setComponent(
+ model,
+ entityIndex as Entity,
+ convertValues(model.schema, modelValue) as ComponentValue
+ );
+ } catch (error) {
+ console.error("Failed to fetch or set model value:", error);
+ }
+ }
+
+ private subscribeToModel(modelEntry: ModelEntry): void {
+ this.client.onSyncEntityChange(
+ {
+ model: modelEntry.model.metadata?.name! as string,
+ keys: modelEntry.keys.map((k) => k.toString()),
+ },
+ () => this.setModelValue(modelEntry)
+ );
+ }
+}
diff --git a/packages/react/src/syncManager/syncFunction.ts b/packages/react/src/syncManager/syncFunction.ts
new file mode 100644
index 00000000..e508d9b4
--- /dev/null
+++ b/packages/react/src/syncManager/syncFunction.ts
@@ -0,0 +1,109 @@
+import { Client } from "@dojoengine/torii-client";
+import {
+ Component,
+ Schema,
+ Metadata,
+ Entity,
+ setComponent,
+} from "@dojoengine/recs";
+import { getEntityIdFromKeys } from "@dojoengine/utils";
+import { convertValues } from "../utils";
+
+type ModelEntry = {
+ model: Component;
+ keys: any[];
+};
+
+export function createSyncManager(
+ client: Client,
+ modelEntries: ModelEntry[]
+) {
+ async function fetchAndSetModelValue(
+ modelEntry: ModelEntry
+ ): Promise {
+ const { model, keys } = modelEntry;
+ const componentName = model.metadata?.name as string;
+ const keysToStrings = keys.map((key) => key.toString());
+ const entityIndex: Entity =
+ keys.length === 1 ? keys[0].toString() : getEntityIdFromKeys(keys);
+
+ try {
+ const modelValue = await client.getModelValue(
+ componentName,
+ keysToStrings
+ );
+ console.log("sync modelValue", modelValue);
+
+ const convertedValue = convertValues(model.schema, modelValue);
+
+ console.log(convertedValue);
+ setComponent(model, entityIndex, convertedValue as any);
+ } catch (error) {
+ console.error("Failed to fetch or set model value:", error);
+ }
+ }
+
+ function sync() {
+ modelEntries.forEach((modelEntry) => {
+ fetchAndSetModelValue(modelEntry);
+ client.addEntitiesToSync([
+ {
+ model: modelEntry.model.metadata?.name as string,
+ keys: modelEntry.keys.map((k) => k.toString()),
+ },
+ ]);
+ client.onSyncEntityChange(
+ {
+ model: modelEntry.model.metadata?.name! as string,
+ keys: modelEntry.keys.map((k) => k.toString()),
+ },
+ () => {
+ client
+ .getModelValue(
+ modelEntry.model.metadata?.name! as string,
+ modelEntry.keys.map((k) => k.toString())
+ )
+ .then((modelValue) => {
+ console.log("ohayo", modelValue);
+
+ const convertedValue = convertValues(
+ modelEntry.model.schema,
+ modelValue
+ );
+
+ const entityIndex: Entity =
+ modelEntry.keys.length === 1
+ ? modelEntry.keys[0].toString()
+ : getEntityIdFromKeys(modelEntry.keys);
+
+ setComponent(
+ modelEntry.model,
+ entityIndex,
+ convertedValue as any
+ );
+ });
+ }
+ );
+ });
+ }
+
+ function cleanup() {
+ modelEntries.forEach((modelEntry) => {
+ client
+ .removeEntitiesToSync([
+ {
+ model: modelEntry.model.metadata?.name as string,
+ keys: modelEntry.keys.map((k) => k.toString()),
+ },
+ ])
+ .catch((error) => {
+ console.error(
+ "Failed to remove entities on cleanup",
+ error
+ );
+ });
+ });
+ }
+
+ return { cleanup, sync };
+}
diff --git a/packages/react/src/syncManager/syncManager.ts b/packages/react/src/syncManager/syncManager.ts
index 4940a03b..9b5ac23b 100644
--- a/packages/react/src/syncManager/syncManager.ts
+++ b/packages/react/src/syncManager/syncManager.ts
@@ -9,7 +9,6 @@ import {
import { getEntityIdFromKeys } from "@dojoengine/utils";
import { convertValues } from "../utils";
-// type KeyType = any; // Replace 'any' with your actual key type
type ModelEntry = {
model: Component;
keys: any[];
@@ -44,6 +43,10 @@ export class SyncManager {
componentName,
keysToStrings
);
+ // TODO:
+
+ console.log("modelValue", modelValue);
+
const convertedValue = convertValues(model.schema, modelValue);
setComponent(model, entityIndex, convertedValue as any);
}
diff --git a/packages/react/src/utils.ts b/packages/react/src/utils.ts
index 01a53fed..ca586229 100644
--- a/packages/react/src/utils.ts
+++ b/packages/react/src/utils.ts
@@ -14,9 +14,26 @@ export function convertValues(schema: Schema, values: any) {
acc[key] = convertValues(schemaType, value);
} else {
// Otherwise, convert the value based on the schema type
- // @ts-ignore
- acc[key] =
- schemaType === RecsType.BigInt ? BigInt(value) : Number(value);
+
+ if (value == "Rock") {
+ // @ts-ignore
+ acc[key] =
+ schemaType === RecsType.BigInt ? BigInt(0) : Number(0);
+ } else if (value == "Paper") {
+ // @ts-ignore
+ acc[key] =
+ schemaType === RecsType.BigInt ? BigInt(1) : Number(1);
+ } else if (value == "Scissors") {
+ // @ts-ignore
+ acc[key] =
+ schemaType === RecsType.BigInt ? BigInt(2) : Number(2);
+ } else {
+ // @ts-ignore
+ acc[key] =
+ schemaType === RecsType.BigInt
+ ? BigInt(value)
+ : Number(value);
+ }
}
return acc;
}, {});
diff --git a/packages/torii-wasm/crate/Cargo.lock b/packages/torii-wasm/crate/Cargo.lock
index 89c883fc..ed05c3ff 100644
--- a/packages/torii-wasm/crate/Cargo.lock
+++ b/packages/torii-wasm/crate/Cargo.lock
@@ -1183,8 +1183,8 @@ dependencies = [
[[package]]
name = "dojo-types"
-version = "0.3.3"
-source = "git+https://github.com/dojoengine/dojo?branch=main#29846bd8048dfc63ce170fc8ea86717b9a81738f"
+version = "0.3.9"
+source = "git+https://github.com/dojoengine/dojo?tag=v0.3.9#015e1d2027cef343aca6655f95cd6668305ca272"
dependencies = [
"crypto-bigint",
"hex",
@@ -1199,8 +1199,8 @@ dependencies = [
[[package]]
name = "dojo-world"
-version = "0.3.3"
-source = "git+https://github.com/dojoengine/dojo?branch=main#29846bd8048dfc63ce170fc8ea86717b9a81738f"
+version = "0.3.9"
+source = "git+https://github.com/dojoengine/dojo?tag=v0.3.9#015e1d2027cef343aca6655f95cd6668305ca272"
dependencies = [
"anyhow",
"async-trait",
@@ -1693,6 +1693,12 @@ dependencies = [
"pin-project-lite",
]
+[[package]]
+name = "http-range-header"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f"
+
[[package]]
name = "httparse"
version = "1.8.0"
@@ -4026,6 +4032,39 @@ dependencies = [
"syn 2.0.38",
]
+[[package]]
+name = "tonic-reflection"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fa37c513df1339d197f4ba21d28c918b9ef1ac1768265f11ecb6b7f1cba1b76"
+dependencies = [
+ "prost 0.12.1",
+ "prost-types 0.12.1",
+ "tokio",
+ "tokio-stream",
+ "tonic 0.10.2",
+]
+
+[[package]]
+name = "tonic-web"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fddb2a37b247e6adcb9f239f4e5cefdcc5ed526141a416b943929f13aea2cce"
+dependencies = [
+ "base64 0.21.5",
+ "bytes",
+ "http",
+ "http-body",
+ "hyper",
+ "pin-project",
+ "tokio-stream",
+ "tonic 0.10.2",
+ "tower-http",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
[[package]]
name = "tonic-web-wasm-client"
version = "0.4.0"
@@ -4052,8 +4091,8 @@ dependencies = [
[[package]]
name = "torii-client"
-version = "0.3.3"
-source = "git+https://github.com/dojoengine/dojo?branch=main#29846bd8048dfc63ce170fc8ea86717b9a81738f"
+version = "0.3.9"
+source = "git+https://github.com/dojoengine/dojo?tag=v0.3.9#015e1d2027cef343aca6655f95cd6668305ca272"
dependencies = [
"async-trait",
"crypto-bigint",
@@ -4104,8 +4143,8 @@ dependencies = [
[[package]]
name = "torii-grpc"
-version = "0.3.3"
-source = "git+https://github.com/dojoengine/dojo?branch=main#29846bd8048dfc63ce170fc8ea86717b9a81738f"
+version = "0.3.9"
+source = "git+https://github.com/dojoengine/dojo?tag=v0.3.9#015e1d2027cef343aca6655f95cd6668305ca272"
dependencies = [
"bytes",
"dojo-types",
@@ -4131,6 +4170,8 @@ dependencies = [
"tonic 0.9.2",
"tonic-build 0.10.2",
"tonic-build 0.9.2",
+ "tonic-reflection",
+ "tonic-web",
"tonic-web-wasm-client",
"tower",
"tracing",
@@ -4157,6 +4198,24 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "tower-http"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
+dependencies = [
+ "bitflags 2.4.1",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-range-header",
+ "pin-project-lite",
+ "tower-layer",
+ "tower-service",
+]
+
[[package]]
name = "tower-layer"
version = "0.3.2"
@@ -4470,9 +4529,9 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.65"
+version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
diff --git a/packages/torii-wasm/crate/Cargo.toml b/packages/torii-wasm/crate/Cargo.toml
index fe03cb06..486b119f 100644
--- a/packages/torii-wasm/crate/Cargo.toml
+++ b/packages/torii-wasm/crate/Cargo.toml
@@ -23,13 +23,13 @@ tokio = { version = "1.32.0", default-features = false, features = [ "rt" ] }
url = "2.4.0"
# Dojo
-dojo-types = { git = "https://github.com/dojoengine/dojo", branch = "main" }
-torii-client = { git = "https://github.com/dojoengine/dojo", branch = "main" }
+dojo-types = { git = "https://github.com/dojoengine/dojo", tag = "v0.3.9" }
+torii-client = { git = "https://github.com/dojoengine/dojo", tag = "v0.3.9" }
# WASM
js-sys = "0.3.64"
serde-wasm-bindgen = "0.6.0"
-wasm-bindgen = "0.2.87"
+wasm-bindgen = "=0.2.88"
wasm-bindgen-futures = "0.4.37"
web-sys = { version = "0.3.4", features = [ 'MessageEvent', 'Window', 'Worker', 'WorkerGlobalScope', 'console' ] }
@@ -47,7 +47,7 @@ incremental = true
opt-level = 1
[dev-dependencies]
-wasm-bindgen-test = "0.3.0"
+wasm-bindgen-test = "=0.3.38"
[features]
console-error-panic = [ "dep:console_error_panic_hook" ]
diff --git a/packages/torii-wasm/crate/src/lib.rs b/packages/torii-wasm/crate/src/lib.rs
index 7857c8ef..62b19e17 100644
--- a/packages/torii-wasm/crate/src/lib.rs
+++ b/packages/torii-wasm/crate/src/lib.rs
@@ -2,16 +2,16 @@
use std::str::FromStr;
-use dojo_types::schema::EntityModel;
+use dojo_types::schema::{Clause, EntityQuery, KeysClause};
use futures::StreamExt;
use starknet::core::types::FieldElement;
use starknet::core::utils::cairo_short_string_to_felt;
-use types::{ClientConfig, IEntityModel};
use wasm_bindgen::prelude::*;
mod types;
mod utils;
+use types::{ClientConfig, EntityModel, IEntityModel};
use utils::parse_ty_as_json_str;
type JsFieldElement = JsValue;
@@ -50,9 +50,9 @@ impl Client {
match self
.inner
- .entity(&EntityModel {
- keys,
+ .entity(&EntityQuery {
model: model.to_string(),
+ clause: Clause::Keys(KeysClause { keys }),
})
.await
{
@@ -73,7 +73,7 @@ impl Client {
let entities = entities
.into_iter()
- .map(|e| serde_wasm_bindgen::from_value(e.into()))
+ .map(|e| TryInto::::try_into(e))
.collect::, _>>()?;
self.inner
@@ -95,7 +95,7 @@ impl Client {
let entities = entities
.into_iter()
- .map(|e| serde_wasm_bindgen::from_value(e.into()))
+ .map(|e| TryInto::::try_into(e))
.collect::, _>>()?;
self.inner
@@ -114,8 +114,7 @@ impl Client {
#[cfg(feature = "console-error-panic")]
console_error_panic_hook::set_once();
- let entity =
- serde_wasm_bindgen::from_value::(entity.into())?;
+ let entity = serde_wasm_bindgen::from_value::(entity.into())?;
let model = cairo_short_string_to_felt(&entity.model).expect("invalid model name");
let mut rcv = self
.inner
@@ -151,7 +150,7 @@ pub async fn create_client(
let entities = initialEntitiesToSync
.into_iter()
- .map(|e| serde_wasm_bindgen::from_value(e.into()))
+ .map(|e| TryInto::::try_into(e))
.collect::, _>>()?;
let world_address = FieldElement::from_str(&world_address)
diff --git a/packages/torii-wasm/crate/src/types.rs b/packages/torii-wasm/crate/src/types.rs
index 4871113f..27cd7359 100644
--- a/packages/torii-wasm/crate/src/types.rs
+++ b/packages/torii-wasm/crate/src/types.rs
@@ -1,7 +1,27 @@
+use dojo_types::schema::EntityQuery;
use serde::{Deserialize, Serialize};
+use starknet::core::types::FieldElement;
use tsify::Tsify;
use wasm_bindgen::prelude::wasm_bindgen;
+// TODO: remove this in favour of the new EntityQuery
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
+pub struct EntityModel {
+ pub model: String,
+ pub keys: Vec,
+}
+
+impl From for dojo_types::schema::EntityQuery {
+ fn from(value: EntityModel) -> Self {
+ Self {
+ model: value.model,
+ clause: dojo_types::schema::Clause::Keys(dojo_types::schema::KeysClause {
+ keys: value.keys,
+ }),
+ }
+ }
+}
+
#[wasm_bindgen(typescript_custom_section)]
pub const ENTITY_MODEL_STR: &'static str = r#"
export interface EntityModel {
@@ -16,6 +36,13 @@ extern "C" {
pub type IEntityModel;
}
+impl TryFrom for EntityQuery {
+ type Error = serde_wasm_bindgen::Error;
+ fn try_from(value: IEntityModel) -> Result {
+ serde_wasm_bindgen::from_value::(value.into()).map(|e| e.into())
+ }
+}
+
#[derive(Tsify, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct ClientConfig {
@@ -26,3 +53,29 @@ pub struct ClientConfig {
#[serde(rename = "worldAddress")]
pub world_address: String,
}
+
+#[cfg(test)]
+mod test {
+
+ use starknet::macros::felt;
+
+ use super::*;
+
+ #[test]
+ fn convert_entity_model_to_query() {
+ let entity_model = EntityModel {
+ model: "Position".into(),
+ keys: vec![felt!("0x1"), felt!("0x2")],
+ };
+
+ let entity_query: EntityQuery = entity_model.try_into().unwrap();
+
+ assert_eq!(entity_query.model, "Position");
+ assert_eq!(
+ entity_query.clause,
+ dojo_types::schema::Clause::Keys(dojo_types::schema::KeysClause {
+ keys: vec![felt!("0x1"), felt!("0x2")],
+ })
+ );
+ }
+}
diff --git a/packages/utils/src/utils/index.ts b/packages/utils/src/utils/index.ts
index d389c5dd..e0756070 100644
--- a/packages/utils/src/utils/index.ts
+++ b/packages/utils/src/utils/index.ts
@@ -258,3 +258,14 @@ export function parseComponentValueFromGraphQLEntity(
return value;
}
}
+
+export function shortenHex(hexString: string, numDigits = 6) {
+ if (hexString?.length <= numDigits) {
+ return hexString;
+ }
+
+ const halfDigits = Math.floor(numDigits / 2);
+ const firstHalf = hexString.slice(0, halfDigits);
+ const secondHalf = hexString.slice(-halfDigits);
+ return `${firstHalf}...${secondHalf}`;
+}