From 626849f6ab74563bb4a98b6ed35c048174f1a8d2 Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Thu, 5 Dec 2024 12:03:32 +1100 Subject: [PATCH] building opt --- client/package.json | 3 +- client/src/App.tsx | 7 ++-- client/src/dojo/createSystemCalls.ts | 21 +++--------- client/src/dojo/modelManager/TileManager.ts | 14 ++++++-- client/src/hooks/helpers/useRealm.tsx | 7 ++-- client/src/ui/components/Toaster.tsx | 27 ++++++++++++++++ client/src/ui/components/TxEmit.tsx | 32 +++++++++++++++++++ .../construction/SelectPreviewBuilding.tsx | 15 ++++----- .../entity-details/BuildingEntityDetails.tsx | 28 +++++++++++++++- client/src/ui/modules/settings/Settings.tsx | 2 +- client/vite.config.ts | 2 ++ pnpm-lock.yaml | 6 ++++ sdk/packages/eternum/src/provider/index.ts | 6 +--- 13 files changed, 127 insertions(+), 43 deletions(-) create mode 100644 client/src/ui/components/Toaster.tsx create mode 100644 client/src/ui/components/TxEmit.tsx diff --git a/client/package.json b/client/package.json index cc4704eb7..ddfb82216 100644 --- a/client/package.json +++ b/client/package.json @@ -47,12 +47,13 @@ "lil-gui": "^0.19.2", "lodash": "^4.17.21", "lucide-react": "^0.365.0", + "next-themes": "^0.4.3", "postprocessing": "^6.36.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-draggable": "^4.4.6", - "react-toastify": "^10.0.5", "rxjs": "^7.8.1", + "sonner": "^1.7.0", "tailwind-merge": "^2.2.2", "three": "^0.166.0", "three-csg": "^1.0.0", diff --git a/client/src/App.tsx b/client/src/App.tsx index 5f7d73332..3dd68dcd9 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,12 +1,13 @@ -import { ToastContainer } from "react-toastify"; -import "react-toastify/dist/ReactToastify.css"; import "./index.css"; +import { Toaster } from "./ui/components/Toaster"; +import { TransactionNotification } from "./ui/components/TxEmit"; import { World } from "./ui/layouts/World"; function App({ backgroundImage }: { backgroundImage: string }) { return ( <> - + + ); diff --git a/client/src/dojo/createSystemCalls.ts b/client/src/dojo/createSystemCalls.ts index d3248ee02..937c6cf2c 100644 --- a/client/src/dojo/createSystemCalls.ts +++ b/client/src/dojo/createSystemCalls.ts @@ -1,5 +1,5 @@ import type * as SystemProps from "@bibliothecadao/eternum"; -import { toast } from "react-toastify"; +import { toast } from "sonner"; import { type SetupNetworkResult } from "./setupNetwork"; class PromiseQueue { @@ -39,26 +39,15 @@ class PromiseQueue { } } -type SystemCallFunctions = ReturnType; -type SystemCallFunction = (...args: any[]) => any; -type WrappedSystemCalls = Record; - -const withErrorHandling = - (fn: any) => - async (...args: any[]) => { - try { - return await fn(...args); - } catch (error: any) { - toast(error.message); - } - }; - export function createSystemCalls({ provider }: SetupNetworkResult) { const promiseQueue = new PromiseQueue(); const withQueueing = Promise>(fn: T) => { return async (...args: Parameters): Promise> => { - return await promiseQueue.enqueue(async () => await fn(...args)); + return await promiseQueue.enqueue(async () => { + const result = await fn(...args); + return result; + }); }; }; diff --git a/client/src/dojo/modelManager/TileManager.ts b/client/src/dojo/modelManager/TileManager.ts index 03c48c352..796f96d8a 100644 --- a/client/src/dojo/modelManager/TileManager.ts +++ b/client/src/dojo/modelManager/TileManager.ts @@ -252,12 +252,15 @@ export class TileManager { }; private _optimisticDestroy = (entityId: ID, col: number, row: number) => { - const currentBuilding = getComponentValue(this.setup.components.Building, getEntityIdFromKeys([BigInt(entityId)])); - const overrideId = uuid(); const realmPosition = getComponentValue(this.setup.components.Position, getEntityIdFromKeys([BigInt(entityId)])); const { x: outercol, y: outerrow } = realmPosition || { x: 0, y: 0 }; const entity = getEntityIdFromKeys([outercol, outerrow, col, row].map((v) => BigInt(v))); + + const currentBuilding = getComponentValue(this.setup.components.Building, entity); + + console.log(currentBuilding); + this.setup.components.Building.addOverride(overrideId, { entity, value: { @@ -277,12 +280,17 @@ export class TileManager { const realmEntityId = getEntityIdFromKeys([BigInt(entityId)]); + const type = BuildingType[currentBuilding?.category as keyof typeof BuildingType]; + this.setup.components.Population.addOverride(populationOverrideId, { entity: realmEntityId, value: { population: (getComponentValue(this.setup.components.Population, realmEntityId)?.population || 0) - - configManager.getBuildingPopConfig(currentBuilding?.category as unknown as BuildingType).population, + configManager.getBuildingPopConfig(type).population, + capacity: + (getComponentValue(this.setup.components.Population, realmEntityId)?.capacity || 0) - + configManager.getBuildingPopConfig(type).capacity, }, }); diff --git a/client/src/hooks/helpers/useRealm.tsx b/client/src/hooks/helpers/useRealm.tsx index f019eb29b..12d08a29d 100644 --- a/client/src/hooks/helpers/useRealm.tsx +++ b/client/src/hooks/helpers/useRealm.tsx @@ -8,7 +8,6 @@ import { } from "@bibliothecadao/eternum"; import { useEntityQuery } from "@dojoengine/react"; import { type ComponentValue, type Entity, Has, HasValue, getComponentValue, runQuery } from "@dojoengine/recs"; -import { useMemo } from "react"; import { shortString } from "starknet"; import realmIdsByOrder from "../../data/realmids_by_order.json"; import { unpackResources } from "../../ui/utils/packedData"; @@ -210,7 +209,7 @@ export function useGetRealm(realmEntityId: ID | undefined) { const query = useEntityQuery([HasValue(Realm, { entity_id: realmEntityId })]); - const realm = useMemo((): any => { + const realm = (): any => { if (realmEntityId !== undefined) { const entityId = getEntityIdFromKeys([BigInt(realmEntityId)]); const realm = getComponentValue(Realm, entityId); @@ -240,10 +239,10 @@ export function useGetRealm(realmEntityId: ID | undefined) { }; } } - }, [realmEntityId, query]); + }; return { - realm, + realm: realm(), }; } diff --git a/client/src/ui/components/Toaster.tsx b/client/src/ui/components/Toaster.tsx new file mode 100644 index 000000000..5add2ce9d --- /dev/null +++ b/client/src/ui/components/Toaster.tsx @@ -0,0 +1,27 @@ +import { useTheme } from "next-themes"; +import { Toaster as Sonner } from "sonner"; + +type ToasterProps = React.ComponentProps; + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = "system" } = useTheme(); + + return ( + + ); +}; + +export { Toaster }; diff --git a/client/src/ui/components/TxEmit.tsx b/client/src/ui/components/TxEmit.tsx new file mode 100644 index 000000000..d7846ba3d --- /dev/null +++ b/client/src/ui/components/TxEmit.tsx @@ -0,0 +1,32 @@ +import { useDojo } from "@/hooks/context/DojoContext"; +import { useEffect } from "react"; +import { toast } from "sonner"; + +export function TransactionNotification() { + const { + setup: { + network: { provider }, + }, + } = useDojo(); + useEffect(() => { + const handleTransactionComplete = (receipt: any) => { + console.log("Transaction completed:", receipt); + toast("Transaction completed"); + }; + + const handleTransactionFailed = (error: string) => { + console.error("Transaction failed:", error); + toast("Transaction failed"); + }; + + provider.on("transactionComplete", handleTransactionComplete); + provider.on("transactionFailed", handleTransactionFailed); + + return () => { + provider.off("transactionComplete", handleTransactionComplete); + provider.off("transactionFailed", handleTransactionFailed); + }; + }, [provider]); + + return null; +} diff --git a/client/src/ui/components/construction/SelectPreviewBuilding.tsx b/client/src/ui/components/construction/SelectPreviewBuilding.tsx index 6f8f09566..ea2a4c2d5 100644 --- a/client/src/ui/components/construction/SelectPreviewBuilding.tsx +++ b/client/src/ui/components/construction/SelectPreviewBuilding.tsx @@ -40,8 +40,6 @@ import clsx from "clsx"; import React, { useMemo, useState } from "react"; import { HintSection } from "../hints/HintModal"; -// TODO: THIS IS TERRIBLE CODE, PLEASE REFACTOR - export const SelectPreviewBuildingMenu = ({ className, entityId }: { className?: string; entityId: number }) => { const dojo = useDojo(); @@ -174,17 +172,16 @@ export const SelectPreviewBuildingMenu = ({ className, entityId }: { className?: if (!buildingCosts) return; const hasBalance = checkBalance(buildingCosts); - const hasEnoughPopulation = hasEnoughPopulationForBuilding(realm, building); const canBuild = - BuildingType.WorkersHut == building + building === BuildingType.WorkersHut ? hasBalance : hasBalance && realm?.hasCapacity && hasEnoughPopulation; - const isFarm = building === BuildingType["Farm"]; - const isFishingVillage = building === BuildingType["FishingVillage"]; - const isWorkersHut = building === BuildingType["WorkersHut"]; - const isMarket = building === BuildingType["Market"]; + const isFarm = building === BuildingType.Farm; + const isFishingVillage = building === BuildingType.FishingVillage; + const isWorkersHut = building === BuildingType.WorkersHut; + const isMarket = building === BuildingType.Market; return ( { } setLeftNavigationView(LeftView.None); }, [selectedBuildingHex, buildingState]); + + const canDestroyBuilding = useMemo(() => { + if (buildingState.buildingType !== BuildingType.WorkersHut) return true; + + const realmId = getComponentValue( + dojo.setup.components.EntityOwner, + getEntityIdFromKeys([BigInt(structureEntityId)]), + ); + + const populationImpact = configManager.getBuildingPopConfig(buildingState.buildingType).capacity; + + const population = getComponentValue( + dojo.setup.components.Population, + getEntityIdFromKeys([BigInt(realmId?.entity_owner_id || 0)]), + ); + return (population?.capacity || 0) - (population?.population || 0) >= populationImpact; + }, [buildingState.buildingType, buildingState.ownerEntityId]); + return (
{isCastleSelected ? ( @@ -141,7 +161,13 @@ export const BuildingEntityDetails = () => { > {isPaused ? "Resume" : "Pause"} -
diff --git a/client/src/ui/modules/settings/Settings.tsx b/client/src/ui/modules/settings/Settings.tsx index ebb899857..6abbe64f0 100644 --- a/client/src/ui/modules/settings/Settings.tsx +++ b/client/src/ui/modules/settings/Settings.tsx @@ -21,7 +21,7 @@ import { RangeInput } from "@/ui/elements/RangeInput"; import { addressToNumber, displayAddress } from "@/ui/utils/utils"; import { ContractAddress } from "@bibliothecadao/eternum"; import { useEffect, useRef, useState } from "react"; -import { toast } from "react-toastify"; +import { toast } from "sonner"; export const SettingsWindow = () => { const { diff --git a/client/vite.config.ts b/client/vite.config.ts index 21016ef10..1af31c477 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -21,6 +21,8 @@ export default defineConfig({ }, workbox: { maximumFileSizeToCacheInBytes: 4000000, + clientsClaim: true, + skipWaiting: false, }, manifest: { name: "Eternum", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c85c3aae6..8e72b8cfc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -185,6 +185,9 @@ importers: lucide-react: specifier: ^0.365.0 version: 0.365.0(react@18.3.1) + next-themes: + specifier: ^0.4.3 + version: 0.4.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) postprocessing: specifier: ^6.36.2 version: 6.36.3(three@0.166.1) @@ -203,6 +206,9 @@ importers: rxjs: specifier: ^7.8.1 version: 7.8.1 + sonner: + specifier: ^1.7.0 + version: 1.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) starknet: specifier: 6.11.0 version: 6.11.0(encoding@0.1.13) diff --git a/sdk/packages/eternum/src/provider/index.ts b/sdk/packages/eternum/src/provider/index.ts index 298876c9f..2a5a39766 100644 --- a/sdk/packages/eternum/src/provider/index.ts +++ b/sdk/packages/eternum/src/provider/index.ts @@ -840,11 +840,7 @@ export class EternumProvider extends EnhancedDojoProvider { public async create_building(props: SystemProps.CreateBuildingProps) { const { entity_id, directions, building_category, produce_resource_type, signer } = props; ["62", "1", "0", "4", "1"]; - console.log("Create Building Call Data:", { - contractAddress: getContractByName(this.manifest, `${NAMESPACE}-building_systems`), - entrypoint: "create", - calldata: CallData.compile([entity_id, directions, building_category, produce_resource_type]), - }); + return this.executeAndCheckTransaction(signer, { contractAddress: getContractByName(this.manifest, `${NAMESPACE}-building_systems`), entrypoint: "create",