Skip to content

Commit

Permalink
webworker
Browse files Browse the repository at this point in the history
  • Loading branch information
ponderingdemocritus committed Dec 18, 2024
1 parent 6a47469 commit 8d06296
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 85 deletions.
6 changes: 3 additions & 3 deletions client/.env.preview
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ VITE_PUBLIC_MASTER_PRIVATE_KEY=0x075362a844768f31c8058ce31aec3dd7751686440b4f220
VITE_PUBLIC_WORLD_ADDRESS="0x00fd85ef42eaed3b90d02d2cdc7417d6cae189ff4ba876aa5608551afbf1fb47"
VITE_PUBLIC_ACCOUNT_CLASS_HASH="0x07dc7899aa655b0aae51eadff6d801a58e97dd99cf4666ee59e704249e51adf2"
VITE_PUBLIC_FEE_TOKEN_ADDRESS=0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7
VITE_PUBLIC_TORII=https://api.cartridge.gg/x/sepolia-rc-18/torii
VITE_PUBLIC_TORII=https://api.cartridge.gg/x/sepolia-rc-19/torii
VITE_PUBLIC_NODE_URL=https://api.cartridge.gg/x/starknet/sepolia
VITE_PUBLIC_DEV=false
VITE_PUBLIC_GAME_VERSION="v1.0.0-rc7"
VITE_PUBLIC_SHOW_FPS=false
VITE_PUBLIC_GRAPHICS_DEV=false
VITE_PUBLIC_TORII_RELAY=/dns4/api.cartridge.gg/tcp/443/x-parity-wss/%2Fx%2Fsepolia-rc-18%2Ftorii%2Fwss
VITE_PUBLIC_TORII_RELAY=/dns4/api.cartridge.gg/tcp/443/x-parity-wss/%2Fx%2Fsepolia-rc-19%2Ftorii%2Fwss
VITE_SEASON_PASS_ADDRESS=0x23cc88996a5f9c7bcb559fdcffc257c0f75abe60f2a7e5d5cd343f8a95967f7
VITE_REALMS_ADDRESS=0x3205f47bd6f0b5e9cd5c79fcae19e12523a024709776d0a9e8b375adf63468d
VITE_LORDS_ADDRESS=0x0342ad5cc14002c005a5cedcfce2bd3af98d5e7fb79e9bf949b3a91cf145d72e

VITE_PUBLIC_CHAIN=sepolia
VITE_PUBLIC_SLOT=sepolia-rc-17
VITE_PUBLIC_SLOT=sepolia-rc-19

VITE_SOCIAL_LINK=http://bit.ly/3Zz1mpp

Expand Down
31 changes: 31 additions & 0 deletions client/src/dojo/entityWorker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { debounce } from "lodash";

let toriiClient = null;
let entityBatch = {};
let logging = false;
const DEBOUNCE_DELAY = 1000;

let debouncedSendBatch = debounce(() => {
if (Object.keys(entityBatch).length > 0) {
console.log("Worker: Sending batch", entityBatch);
self.postMessage({ updatedEntities: entityBatch });
entityBatch = {};
}
}, DEBOUNCE_DELAY);

self.onmessage = async (e) => {
const { type, entities, logging: logFlag } = e.data;
if (type === "update") {
logging = logFlag;
if (logging) console.log("Worker: Received entities update");
handleUpdate(entities.fetchedEntities, entities.data);
}
};

function handleUpdate(fetchedEntities, data) {
entityBatch[fetchedEntities] = {
...entityBatch[fetchedEntities],
...data,
};
debouncedSendBatch();
}
125 changes: 67 additions & 58 deletions client/src/dojo/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,73 +4,72 @@ import {
WORLD_CONFIG_ID,
} from "@bibliothecadao/eternum";
import { DojoConfig } from "@dojoengine/core";
import { Component, Metadata, Schema } from "@dojoengine/recs";
import { getEntities, getEvents, setEntities } from "@dojoengine/state";
import { Clause, EntityKeysClause, ToriiClient } from "@dojoengine/torii-client";
import { debounce } from "lodash";
import { getEntities, getEvents } from "@dojoengine/state";
import { Clause } from "@dojoengine/torii-client";
import { createClientComponents } from "./createClientComponents";
import { createSystemCalls } from "./createSystemCalls";
import { openDatabase, syncEntitiesFromStorage } from "./indexedDB";
import { ClientConfigManager } from "./modelManager/ConfigManager";
import { setupNetwork } from "./setupNetwork";
import { setupWorker } from "./worker";

export type SetupResult = Awaited<ReturnType<typeof setup>>;

export const configManager = ClientConfigManager.instance();

export const syncEntitiesDebounced = async <S extends Schema>(
client: ToriiClient,
components: Component<S, Metadata, undefined>[],
entityKeyClause: EntityKeysClause[],
logging: boolean = true,
historical: boolean = false,
) => {
if (logging) console.log("Starting syncEntities");

let entityBatch: Record<string, any> = {};

const debouncedSetEntities = debounce(() => {
if (Object.keys(entityBatch).length > 0) {
// console.log("Applying batch update", entityBatch);
setEntities(entityBatch, components, logging);
entityBatch = {}; // Clear the batch after applying
}
}, 1000); // Increased debounce time to 1 second for larger batches

// Handle entity updates
const entitySub = await client.onEntityUpdated(entityKeyClause, (fetchedEntities: any, data: any) => {
if (logging) console.log("Entity updated", fetchedEntities);
// Merge new data with existing data for this entity
entityBatch[fetchedEntities] = {
...entityBatch[fetchedEntities],
...data,
};
debouncedSetEntities();
});

// Handle event message updates
const eventSub = await client.onEventMessageUpdated(
entityKeyClause,
historical,
(fetchedEntities: any, data: any) => {
if (logging) console.log("Event message updated", fetchedEntities);
// Merge new data with existing data for this entity
entityBatch[fetchedEntities] = {
...entityBatch[fetchedEntities],
...data,
};
debouncedSetEntities();
},
);

// Return combined subscription that can cancel both
return {
cancel: () => {
entitySub.cancel();
eventSub.cancel();
},
};
};
// export const syncEntitiesDebounced = async <S extends Schema>(
// client: ToriiClient,
// components: Component<S, Metadata, undefined>[],
// entityKeyClause: EntityKeysClause[],
// logging: boolean = true,
// historical: boolean = false,
// ) => {
// if (logging) console.log("Starting syncEntities");

// let entityBatch: Record<string, any> = {};

// const debouncedSetEntities = debounce(() => {
// if (Object.keys(entityBatch).length > 0) {
// // console.log("Applying batch update", entityBatch);
// setEntities(entityBatch, components, logging);
// entityBatch = {}; // Clear the batch after applying
// }
// }, 1000); // Increased debounce time to 1 second for larger batches

// // Handle entity updates
// const entitySub = await client.onEntityUpdated(entityKeyClause, (fetchedEntities: any, data: any) => {
// if (logging) console.log("Entity updated", fetchedEntities);
// // Merge new data with existing data for this entity
// entityBatch[fetchedEntities] = {
// ...entityBatch[fetchedEntities],
// ...data,
// };
// debouncedSetEntities();
// });

// // Handle event message updates
// const eventSub = await client.onEventMessageUpdated(
// entityKeyClause,
// historical,
// (fetchedEntities: any, data: any) => {
// if (logging) console.log("Event message updated", fetchedEntities);
// // Merge new data with existing data for this entity
// entityBatch[fetchedEntities] = {
// ...entityBatch[fetchedEntities],
// ...data,
// };
// debouncedSetEntities();
// },
// );

// // Return combined subscription that can cancel both
// return {
// cancel: () => {
// entitySub.cancel();
// eventSub.cancel();
// },
// };
// };

export async function setup({ ...config }: DojoConfig) {
const network = await setupNetwork(config);
Expand Down Expand Up @@ -178,7 +177,17 @@ export async function setup({ ...config }: DojoConfig) {
{ dbConnection: indexedDB, timestampCacheKey: "double_keyed_query" },
);

const sync = await syncEntitiesDebounced(network.toriiClient, network.contractComponents as any, [], false);
const sync = await setupWorker(
{
rpcUrl: config.rpcUrl,
toriiUrl: config.toriiUrl,
relayUrl: config.relayUrl,
worldAddress: config.manifest.world.address || "",
},
network.contractComponents as any,
[],
false,
);

configManager.setDojo(components);

Expand Down
56 changes: 56 additions & 0 deletions client/src/dojo/worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Component, Metadata, Schema } from "@dojoengine/recs";
import { setEntities } from "@dojoengine/state";
import { EntityKeysClause, createClient } from "@dojoengine/torii-wasm";

export async function setupWorker(
config: { rpcUrl: string; toriiUrl: string; relayUrl: string; worldAddress: string },
components: Component<Schema, Metadata, undefined>[],
entityKeyClause: EntityKeysClause[],
historical: boolean,
logging = false,
) {
if (logging) console.log("Starting syncEntities");

const worker = new Worker(new URL("./entityWorker.js", import.meta.url), { type: "module" });

// Create the client in the main thread
const toriiClient = await createClient({
rpcUrl: config.rpcUrl,
toriiUrl: config.toriiUrl,
relayUrl: config.relayUrl,
worldAddress: config.worldAddress,
});

// Listen for batches from the Worker
worker.onmessage = (event) => {
const { updatedEntities } = event.data;
setEntities(updatedEntities, components, logging);
};

// Set up subscriptions in the main thread
await toriiClient.onEntityUpdated(entityKeyClause, (fetchedEntities: any, data: any) => {
if (logging) console.log("Main: Entity updated", fetchedEntities);
// Send updates to worker for processing
worker.postMessage({
type: "update",
entities: { fetchedEntities, data },
logging,
});
});

await toriiClient.onEventMessageUpdated(entityKeyClause, historical, (fetchedEntities: any, data: any) => {
if (logging) console.log("Main: Event message updated", fetchedEntities);
// Send updates to worker for processing
worker.postMessage({
type: "update",
entities: { fetchedEntities, data },
logging,
});
});

return {
cancel: () => {
worker.terminate();
},
};
}
67 changes: 51 additions & 16 deletions client/src/ui/layouts/World.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export const World = ({ backgroundImage }: { backgroundImage: string }) => {
[structures, subscriptions],
);

// Handle initial structure and admin bank subscription
useEffect(() => {
if (
!structureEntityId ||
Expand All @@ -141,58 +142,92 @@ export const World = ({ backgroundImage }: { backgroundImage: string }) => {
...prev,
[structureEntityId.toString()]: true,
[ADMIN_BANK_ENTITY_ID.toString()]: true,
...Object.fromEntries(filteredStructures.map((structure) => [structure.entity_id.toString(), true])),
}));

const fetch = async () => {
try {
await Promise.all([
addToSubscriptionOneKeyModelbyRealmEntityId(
addToSubscription(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[...filteredStructures.map((structure) => structure.entity_id.toString())],
[structureEntityId.toString()],
dojo.setup.db,
[{ x: position?.x || 0, y: position?.y || 0 }],
),
addToSubscriptionTwoKeyModelbyRealmEntityId(
addToSubscription(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[...filteredStructures.map((structure) => structure.entity_id.toString())],
[ADMIN_BANK_ENTITY_ID.toString()],
dojo.setup.db,
),
addToSubscription(
]);
} catch (error) {
console.error("Fetch failed", error);
} finally {
setWorldLoading(false);
}
};

fetch();
}, [structureEntityId, subscriptions, setWorldLoading, setSubscriptions]);

// Handle filtered structures subscription
useEffect(() => {
if (filteredStructures.length === 0) return;

setWorldLoading(true);
setSubscriptions((prev) => ({
...prev,
...Object.fromEntries(filteredStructures.map((structure) => [structure.entity_id.toString(), true])),
}));

const fetch = async () => {
try {
await Promise.all([
addToSubscriptionOneKeyModelbyRealmEntityId(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[structureEntityId.toString()],
filteredStructures.map((structure) => structure.entity_id.toString()),
dojo.setup.db,
[{ x: position?.x || 0, y: position?.y || 0 }],
),

addToSubscription(
addToSubscriptionTwoKeyModelbyRealmEntityId(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[ADMIN_BANK_ENTITY_ID.toString()],
filteredStructures.map((structure) => structure.entity_id.toString()),
dojo.setup.db,
),

addToSubscription(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[...filteredStructures.map((structure) => structure.entity_id.toString())],
filteredStructures.map((structure) => structure.entity_id.toString()),
dojo.setup.db,
[...filteredStructures.map((structure) => ({ x: structure.position.x, y: structure.position.y }))],
filteredStructures.map((structure) => ({ x: structure.position.x, y: structure.position.y })),
),
addMarketSubscription(dojo.network.toriiClient, dojo.network.contractComponents as any, dojo.setup.db),
]);
} catch (error) {
console.error("Fetch failed", error);
} finally {
setWorldLoading(false);
}
};

fetch();
}, [filteredStructures, setWorldLoading, setSubscriptions]);

// Handle market subscription
useEffect(() => {
const fetch = async () => {
try {
await addMarketSubscription(dojo.network.toriiClient, dojo.network.contractComponents as any, dojo.setup.db);
} catch (error) {
console.error("Market fetch failed", error);
} finally {
setMarketLoading(false);
}
};

fetch();
}, [structureEntityId, subscriptions, setWorldLoading, setSubscriptions, filteredStructures]);
}, [setMarketLoading]);

return (
<div
Expand Down
Loading

0 comments on commit 8d06296

Please sign in to comment.