@@ -145,7 +201,6 @@ export const BridgeOutStep2 = () => {
}
});
}
- setSe;
setSelectedDonkeys(newSelected);
updateResourcesFromSelectedDonkeys(newSelected);
}}
diff --git a/landing/src/components/modules/swap-panel.tsx b/landing/src/components/modules/swap-panel.tsx
index a5fb46b7c..62fc18fc0 100644
--- a/landing/src/components/modules/swap-panel.tsx
+++ b/landing/src/components/modules/swap-panel.tsx
@@ -1,10 +1,12 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import { useSyncPlayerRealms } from "@/hooks/helpers/use-sync-entity";
import { BookOpen } from "lucide-react";
import { BridgeIn } from "./bridge-in";
import { BridgeOutStep1 } from "./bridge-out-step-1";
import { BridgeOutStep2 } from "./bridge-out-step-2";
export const SwapPanel = () => {
+ useSyncPlayerRealms();
return (
diff --git a/landing/src/dojo/queries.ts b/landing/src/dojo/queries.ts
new file mode 100644
index 000000000..a805e9763
--- /dev/null
+++ b/landing/src/dojo/queries.ts
@@ -0,0 +1,104 @@
+// onload -> fetch single key entities
+
+import { Component, Metadata, Schema } from "@dojoengine/recs";
+import { setEntities } from "@dojoengine/state";
+import { Clause, EntityKeysClause, PatternMatching, ToriiClient } from "@dojoengine/torii-client";
+
+// on hexception -> fetch below queries based on entityID
+
+// background sync after load ->
+
+export const getEntities = async (
+ client: ToriiClient,
+ clause: Clause | undefined,
+ components: Component[],
+ limit: number = 100,
+ logging: boolean = false,
+) => {
+ if (logging) console.log("Starting getEntities");
+ let offset = 0;
+ let continueFetching = true;
+
+ while (continueFetching) {
+ const entities = await client.getEntities({
+ limit,
+ offset,
+ clause,
+ dont_include_hashed_keys: false,
+ order_by: [],
+ });
+
+ setEntities(entities, components);
+
+ if (Object.keys(entities).length < limit) {
+ continueFetching = false;
+ } else {
+ offset += limit;
+ }
+ }
+};
+
+export const syncEntitiesEternum = async (
+ client: ToriiClient,
+ components: Component[],
+ entityKeyClause: EntityKeysClause[],
+ logging: boolean = false,
+) => {
+ // if (logging) console.log("Starting syncEntities");
+ return await client.onEntityUpdated(entityKeyClause, (fetchedEntities: any, data: any) => {
+ // if (logging) console.log("Entity updated", fetchedEntities);
+
+ setEntities({ [fetchedEntities]: data }, components);
+ });
+};
+
+export const addToSubscription = async (
+ client: ToriiClient,
+ components: Component[],
+ entityID: string,
+ position?: { x: number; y: number },
+) => {
+ const positionClause: EntityKeysClause = {
+ Keys: {
+ keys: [String(position?.x || 0), String(position?.y || 0), undefined, undefined],
+ pattern_matching: "FixedLen" as PatternMatching,
+ models: [],
+ },
+ };
+
+ await getEntities(
+ client,
+ {
+ Composite: {
+ operator: "Or",
+ clauses: [
+ positionClause,
+ {
+ Keys: {
+ keys: [entityID],
+ pattern_matching: "FixedLen",
+ models: [],
+ },
+ },
+ {
+ Keys: {
+ keys: [entityID, undefined],
+ pattern_matching: "FixedLen",
+ models: [],
+ },
+ },
+ {
+ Keys: {
+ keys: [entityID, undefined, undefined],
+ pattern_matching: "FixedLen",
+ models: [],
+ },
+ },
+ ],
+ },
+ },
+ components,
+ 10_000,
+ false,
+ );
+};
diff --git a/landing/src/dojo/setup.ts b/landing/src/dojo/setup.ts
index 0efd65ea0..310caae86 100644
--- a/landing/src/dojo/setup.ts
+++ b/landing/src/dojo/setup.ts
@@ -1,6 +1,6 @@
import { WORLD_CONFIG_ID } from "@bibliothecadao/eternum";
import { DojoConfig } from "@dojoengine/core";
-import { getSyncEntities, getSyncEvents, syncEntities } from "@dojoengine/state";
+import { getEvents, getSyncEntities } from "@dojoengine/state";
import { Clause } from "@dojoengine/torii-client";
import { createClientComponents } from "./createClientComponents";
import { createSystemCalls } from "./createSystemCalls";
@@ -15,16 +15,7 @@ export async function setup({ ...config }: DojoConfig) {
const components = createClientComponents(network);
const systemCalls = createSystemCalls(network);
- // Helper function to filter components or events for syncing
- const getFilteredComponents = (componentKeys: (keyof typeof network.contractComponents)[]) => {
- return componentKeys.map((key) => network.contractComponents[key]);
- };
-
- const getFilteredEvents = (eventKeys: (keyof (typeof network.contractComponents)["events"])[]) => {
- return eventKeys.map((key) => network.contractComponents["events"][key]);
- };
-
- const filteredComponents = getFilteredComponents([
+ const filteredModels = [
"AddressName",
"Realm",
"Owner",
@@ -40,27 +31,17 @@ export async function setup({ ...config }: DojoConfig) {
"GuildMember",
"EntityName",
"Structure",
- // todo: these are needed only for the bridge: how to improve this?
- "Position",
- "WeightConfig",
"CapacityConfig",
- "EntityOwner",
- "ArrivalTime",
- "OwnedResourcesTracker",
- "Weight",
- "Resource",
- "SpeedConfig",
- ]) as any;
+ ];
- const filteredEvents = getFilteredEvents([
+ const filteredEvents = [
"BurnDonkey",
// points
"HyperstructureCoOwnersChange",
"HyperstructureFinished",
"GameEnded",
- // count
- "FragmentMineDiscovered",
- ]) as any;
+ ];
+
const clauses: Clause[] = [
{
Keys: {
@@ -87,17 +68,42 @@ export async function setup({ ...config }: DojoConfig) {
// fetch all existing entities from torii with optional component filtering
await getSyncEntities(
network.toriiClient,
- filteredComponents,
+ network.contractComponents as any,
{ Composite: { operator: "Or", clauses } },
[],
10_000,
);
- const sync = await syncEntities(network.toriiClient, filteredComponents, [], false);
+ const sync = await getSyncEntities(
+ network.toriiClient,
+ network.contractComponents as any,
+ {
+ Keys: {
+ keys: [undefined],
+ pattern_matching: "VariableLen",
+ models: filteredModels.map((model) => `s0_eternum-${model}`),
+ },
+ },
+ [],
+ 10_000,
+ );
- configManager.setDojo(components);
+ const eventSync = getEvents(
+ network.toriiClient,
+ network.contractComponents.events as any,
+ undefined,
+ {
+ Keys: {
+ keys: [undefined],
+ pattern_matching: "VariableLen",
+ models: filteredEvents.map((event) => `s0_eternum-${event}`),
+ },
+ },
+ false,
+ false,
+ );
- const eventSync = getSyncEvents(network.toriiClient, filteredEvents, undefined, [], 20_000, false, false);
+ configManager.setDojo(components);
return {
network,
diff --git a/landing/src/hooks/helpers/use-sync-entity.tsx b/landing/src/hooks/helpers/use-sync-entity.tsx
new file mode 100644
index 000000000..e3511daff
--- /dev/null
+++ b/landing/src/hooks/helpers/use-sync-entity.tsx
@@ -0,0 +1,39 @@
+import { addToSubscription } from "@/dojo/queries";
+import { useEffect, useMemo, useState } from "react";
+import { useDojo } from "../context/DojoContext";
+import { useEntities } from "./useEntities";
+
+export const useSyncEntity = (entityIds: number | number[]) => {
+ const dojo = useDojo();
+ const [isSyncing, setIsSyncing] = useState(false);
+
+ useEffect(() => {
+ setIsSyncing(true);
+ const fetch = async () => {
+ try {
+ const ids = Array.isArray(entityIds) ? entityIds : [entityIds];
+ await Promise.all(
+ ids.map((id) =>
+ addToSubscription(dojo.network.toriiClient, dojo.network.contractComponents as any, id.toString()),
+ ),
+ );
+ } catch (error) {
+ console.error("Fetch failed", error);
+ } finally {
+ setIsSyncing(false);
+ }
+ };
+ fetch();
+ }, [entityIds]);
+
+ return isSyncing;
+};
+
+export const useSyncPlayerRealms = () => {
+ const { playerRealms } = useEntities();
+ const realmEntityIds = useMemo(() => {
+ return playerRealms.map((realm) => realm!.entity_id);
+ }, [playerRealms]);
+
+ return useSyncEntity(realmEntityIds);
+};
diff --git a/landing/src/hooks/helpers/useResources.tsx b/landing/src/hooks/helpers/useResources.tsx
index bbef77688..0c374e284 100644
--- a/landing/src/hooks/helpers/useResources.tsx
+++ b/landing/src/hooks/helpers/useResources.tsx
@@ -32,17 +32,18 @@ export function useDonkeyArrivals() {
const arrivals: any[] = [];
for (const realmEntityId of realmEntityIds) {
- arrivals.push(
- ...runQuery([
- HasValue(Position, { x: bankPosition?.x ?? 0, y: bankPosition?.y ?? 0 }),
- NotValue(OwnedResourcesTracker, { resource_types: 0n }),
- Has(OwnedResourcesTracker),
- Has(Weight),
- Has(ArrivalTime),
- HasValue(EntityOwner, { entity_owner_id: realmEntityId }),
- ]),
- );
+ const res = runQuery([
+ HasValue(Position, { x: bankPosition?.x ?? 0, y: bankPosition?.y ?? 0 }),
+ NotValue(OwnedResourcesTracker, { resource_types: 0n }),
+ Has(OwnedResourcesTracker),
+ Has(Weight),
+ Has(ArrivalTime),
+ HasValue(EntityOwner, { entity_owner_id: realmEntityId }),
+ ]);
+
+ arrivals.push(...res);
}
+
return arrivals;
};
diff --git a/landing/src/hooks/use-structures.tsx b/landing/src/hooks/use-structures.tsx
index 987370ae1..685e0098f 100644
--- a/landing/src/hooks/use-structures.tsx
+++ b/landing/src/hooks/use-structures.tsx
@@ -1,19 +1,19 @@
+import { StructureType } from "@bibliothecadao/eternum";
import { useEntityQuery } from "@dojoengine/react";
-import { Has } from "@dojoengine/recs";
+import { Has, HasValue } from "@dojoengine/recs";
import { useDojo } from "./context/DojoContext";
export const useStructuresNumber = () => {
const {
setup: {
- components: {
- Hyperstructure,
- Realm,
- events: { FragmentMineDiscovered },
- },
+ components: { Hyperstructure, Realm, Structure },
},
} = useDojo();
- const fragmentMinesCount = useEntityQuery([Has(FragmentMineDiscovered)]).length;
+ const fragmentMinesCount = useEntityQuery([
+ HasValue(Structure, { category: StructureType[StructureType.FragmentMine] }),
+ ]).length;
+
const hyperstructuresCount = useEntityQuery([Has(Hyperstructure)]).length;
const realmsCount = useEntityQuery([Has(Realm)]).length;