Skip to content

Commit

Permalink
cache
Browse files Browse the repository at this point in the history
  • Loading branch information
ponderingdemocritus committed Dec 17, 2024
1 parent 123b8f0 commit 6a47469
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 84 deletions.
14 changes: 7 additions & 7 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
"@bibliothecadao/eternum": "workspace:^",
"@cartridge/connector": "0.5.6",
"@cartridge/controller": "0.5.6",
"@dojoengine/core": "1.0.4-alpha.3.1.0",
"@dojoengine/create-burner": "1.0.4-alpha.3.1.0",
"@dojoengine/react": "1.0.4-alpha.3.1.0",
"@dojoengine/core": "1.0.4-alpha.3.1.1",
"@dojoengine/create-burner": "1.0.4-alpha.3.1.1",
"@dojoengine/react": "1.0.4-alpha.3.1.1",
"@dojoengine/recs": "^2.0.13",
"@dojoengine/state": "1.0.4-alpha.3.1.0",
"@dojoengine/torii-client": "1.0.4-alpha.3.1.0",
"@dojoengine/torii-wasm": "1.0.4-alpha.3.1.0",
"@dojoengine/utils": "1.0.4-alpha.3.1.0",
"@dojoengine/state": "1.0.4-alpha.3.1.1",
"@dojoengine/torii-client": "1.0.4-alpha.3.1.1",
"@dojoengine/torii-wasm": "1.0.4-alpha.3.1.1",
"@dojoengine/utils": "1.0.4-alpha.3.1.1",
"@headlessui/react": "^1.7.18",
"@latticexyz/utils": "^2.0.0-next.12",
"@radix-ui/react-collapsible": "^1.1.1",
Expand Down
108 changes: 108 additions & 0 deletions client/src/dojo/indexedDB.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Component, Metadata, Schema } from "@dojoengine/recs";
import { setEntities } from "@dojoengine/state";
import { Entities } from "@dojoengine/torii-client";

const DB_NAME = "eternum-db";
const DB_VERSION = 1;

function openDatabase(): Promise<IDBDatabase> {
let db: IDBDatabase;

return new Promise((resolve, reject) => {
const request: IDBOpenDBRequest = indexedDB.open(DB_NAME, DB_VERSION);

request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
const db = (event.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains("entities")) {
db.createObjectStore("entities", { keyPath: "id" });
}
};

request.onsuccess = (event: Event) => {
db = (event.target as IDBOpenDBRequest).result;
resolve(db);
};

request.onerror = (event: Event) => {
console.error("Database error:", (event.target as IDBOpenDBRequest).error);
reject((event.target as IDBOpenDBRequest).error);
};
});
}

async function syncEntitiesFromStorage<S extends Schema>(
dbConnection: IDBDatabase,
components: Component<S, Metadata, undefined>[],
): Promise<void> {
return new Promise((resolve, reject) => {
const transaction = dbConnection.transaction(["entities"], "readonly");
const store = transaction.objectStore("entities");
const request = store.getAll();

request.onsuccess = () => {
const entities = request.result;
const entityMap: Entities = {};

for (const entity of entities) {
const { id, ...data } = entity;
entityMap[id] = data;
}

setEntities(entityMap, components, false);

resolve();
};

request.onerror = () => {
console.log("Error fetching entities from storage:", request.error);
reject(request.error);
};
});
}

async function insertEntitiesInDB(db: IDBDatabase, entities: Entities): Promise<void> {
return new Promise((resolve, reject) => {
const transaction = db.transaction(["entities"], "readwrite");
const store = transaction.objectStore("entities");

let error: Error | null = null;

// Handle transaction completion
transaction.oncomplete = () => {
if (error) {
reject(error);
} else {
resolve();
}
};

transaction.onerror = () => {
reject(transaction.error);
};

// Store each entity
for (const [entityId, data] of Object.entries(entities)) {
const entityData = {
id: entityId,
...data,
};

const request = store.put(entityData);

request.onerror = () => {
error = request.error;
};
}
});
}

async function clearCache() {
Object.keys(localStorage)
.filter((x) => x.endsWith("_query"))
.forEach((x) => localStorage.removeItem(x));

indexedDB.deleteDatabase(DB_NAME);
location.reload();
}

export { clearCache, insertEntitiesInDB, openDatabase, syncEntitiesFromStorage };
36 changes: 11 additions & 25 deletions client/src/dojo/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,11 @@ import { Component, Metadata, Schema } from "@dojoengine/recs";
import { getEntities } from "@dojoengine/state";
import { PatternMatching, ToriiClient } from "@dojoengine/torii-client";

// on hexception -> fetch below queries based on entityID

// background sync after load ->

export const syncPosition = async <S extends Schema>(
client: ToriiClient,
components: Component<S, Metadata, undefined>[],
entityID: string,
) => {
await getEntities(
client,
{
Keys: {
keys: [entityID],
pattern_matching: "FixedLen" as PatternMatching,
models: ["s0_eternum-Position"],
},
},
components,
[],
[],
30_000,
);
};

export const addToSubscriptionTwoKeyModelbyRealmEntityId = async <S extends Schema>(
client: ToriiClient,
components: Component<S, Metadata, undefined>[],
entityID: string[],
db: IDBDatabase,
) => {
await getEntities(
client,
Expand All @@ -54,13 +30,16 @@ export const addToSubscriptionTwoKeyModelbyRealmEntityId = async <S extends Sche
[],
[],
30_000,
false,
{ dbConnection: db, timestampCacheKey: `entity_two_key_${entityID}_query` },
);
};

export const addToSubscriptionOneKeyModelbyRealmEntityId = async <S extends Schema>(
client: ToriiClient,
components: Component<S, Metadata, undefined>[],
entityID: string[],
db: IDBDatabase,
) => {
await getEntities(
client,
Expand All @@ -82,13 +61,16 @@ export const addToSubscriptionOneKeyModelbyRealmEntityId = async <S extends Sche
[],
[],
30_000,
false,
{ dbConnection: db, timestampCacheKey: `entity_one_key_${entityID}_query` },
);
};

export const addToSubscription = async <S extends Schema>(
client: ToriiClient,
components: Component<S, Metadata, undefined>[],
entityID: string[],
db: IDBDatabase,
position?: { x: number; y: number }[],
) => {
const start = performance.now();
Expand Down Expand Up @@ -121,6 +103,8 @@ export const addToSubscription = async <S extends Schema>(
[],
[],
30_000,
false,
{ dbConnection: db, timestampCacheKey: `entity_${entityID}_query` },
);
const end = performance.now();
console.log("AddToSubscriptionEnd", end - start);
Expand All @@ -129,6 +113,7 @@ export const addToSubscription = async <S extends Schema>(
export const addMarketSubscription = async <S extends Schema>(
client: ToriiClient,
components: Component<S, Metadata, undefined>[],
db: IDBDatabase,
) => {
const start = performance.now();
await getEntities(
Expand All @@ -145,6 +130,7 @@ export const addMarketSubscription = async <S extends Schema>(
[],
30_000,
false,
{ dbConnection: db, timestampCacheKey: "market_query" },
);
const end = performance.now();
console.log("MarketEnd", end - start);
Expand Down
12 changes: 12 additions & 0 deletions client/src/dojo/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Clause, EntityKeysClause, ToriiClient } from "@dojoengine/torii-client"
import { debounce } from "lodash";
import { createClientComponents } from "./createClientComponents";
import { createSystemCalls } from "./createSystemCalls";
import { openDatabase, syncEntitiesFromStorage } from "./indexedDB";
import { ClientConfigManager } from "./modelManager/ConfigManager";
import { setupNetwork } from "./setupNetwork";

Expand Down Expand Up @@ -114,10 +115,18 @@ export async function setup({ ...config }: DojoConfig) {
},
];

const indexedDB = await openDatabase();
await syncEntitiesFromStorage(indexedDB, network.contractComponents as any);

await getEntities(
network.toriiClient,
{ Composite: { operator: "Or", clauses: configClauses } },
network.contractComponents as any,
[],
[],
40_000,
false,
{ dbConnection: indexedDB, timestampCacheKey: "config_query" },
);

// fetch all existing entities from torii
Expand Down Expand Up @@ -149,6 +158,7 @@ export async function setup({ ...config }: DojoConfig) {
[],
40_000,
false,
{ dbConnection: indexedDB, timestampCacheKey: "single_keyed_query" },
);

await getEntities(
Expand All @@ -165,6 +175,7 @@ export async function setup({ ...config }: DojoConfig) {
[],
40_000,
false,
{ dbConnection: indexedDB, timestampCacheKey: "double_keyed_query" },
);

const sync = await syncEntitiesDebounced(network.toriiClient, network.contractComponents as any, [], false);
Expand Down Expand Up @@ -206,5 +217,6 @@ export async function setup({ ...config }: DojoConfig) {
systemCalls,
sync,
eventSync,
db: indexedDB,
};
}
9 changes: 6 additions & 3 deletions client/src/ui/components/resources/InventoryResources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,12 @@ export const InventoryResources = ({

setIsSyncing(true);
try {
await addToSubscription(dojo.network.toriiClient, dojo.network.contractComponents as any, [
entityId.toString(),
]);
await addToSubscription(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[entityId.toString()],
dojo.setup.db,
);
localStorage.setItem(cacheKey, now.toString());
} catch (error) {
console.error("Fetch failed", error);
Expand Down
9 changes: 6 additions & 3 deletions client/src/ui/components/trading/ResourceArrivals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ export const AllResourceArrivals = memo(
});

// Move API call outside of state updates
addToSubscription(dojo.network.toriiClient, dojo.network.contractComponents as any, unsubscribedIds).catch(
(error) => console.error("Fetch failed", error),
);
addToSubscription(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
unsubscribedIds,
dojo.setup.db,
).catch((error) => console.error("Fetch failed", error));
}, [arrivals, subscribedIds]);

return (
Expand Down
17 changes: 13 additions & 4 deletions client/src/ui/layouts/World.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,28 +151,37 @@ export const World = ({ backgroundImage }: { backgroundImage: string }) => {
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[...filteredStructures.map((structure) => structure.entity_id.toString())],
dojo.setup.db,
),
addToSubscriptionTwoKeyModelbyRealmEntityId(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[...filteredStructures.map((structure) => structure.entity_id.toString())],
dojo.setup.db,
),
addToSubscription(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[structureEntityId.toString()],
dojo.setup.db,
[{ x: position?.x || 0, y: position?.y || 0 }],
),
addToSubscription(dojo.network.toriiClient, dojo.network.contractComponents as any, [
ADMIN_BANK_ENTITY_ID.toString(),
]),

addToSubscription(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[ADMIN_BANK_ENTITY_ID.toString()],
dojo.setup.db,
),

addToSubscription(
dojo.network.toriiClient,
dojo.network.contractComponents as any,
[...filteredStructures.map((structure) => structure.entity_id.toString())],
dojo.setup.db,
[...filteredStructures.map((structure) => ({ x: structure.position.x, y: structure.position.y }))],
),
addMarketSubscription(dojo.network.toriiClient, dojo.network.contractComponents as any),
addMarketSubscription(dojo.network.toriiClient, dojo.network.contractComponents as any, dojo.setup.db),
]);
} catch (error) {
console.error("Fetch failed", error);
Expand Down
12 changes: 11 additions & 1 deletion client/src/ui/modules/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ReactComponent as Unmuted } from "@/assets/icons/common/unmuted.svg";
import { ReactComponent as Controller } from "@/assets/icons/Controller.svg";
import { ReactComponent as DojoMark } from "@/assets/icons/dojo-mark-full-dark.svg";
import { ReactComponent as RealmsWorld } from "@/assets/icons/rw-logo.svg";
import { clearCache } from "@/dojo/indexedDB";
import { useDojo } from "@/hooks/context/DojoContext";
import { useRealm } from "@/hooks/helpers/useRealm";
import useUIStore from "@/hooks/store/useUIStore";
Expand Down Expand Up @@ -61,7 +62,7 @@ export const SettingsWindow = () => {

const isOpen = useUIStore((state) => state.isPopupOpen(settings));

const GRAPHICS_SETTING = localStorage.getItem("GRAPHICS_SETTING") as GraphicsSettings || GraphicsSettings.HIGH;
const GRAPHICS_SETTING = (localStorage.getItem("GRAPHICS_SETTING") as GraphicsSettings) || GraphicsSettings.HIGH;

return (
<OSWindow onClick={() => togglePopup(settings)} show={isOpen} title={settings}>
Expand Down Expand Up @@ -171,6 +172,15 @@ export const SettingsWindow = () => {
Github
</a>
</div>
<Button
onClick={() => {
clearCache();
setShowSettings(false);
setBlankOverlay(true);
}}
>
clear cache
</Button>

<Button
onClick={() => {
Expand Down
Loading

0 comments on commit 6a47469

Please sign in to comment.