diff --git a/client/src/dojo/setup.ts b/client/src/dojo/setup.ts index 9fc3801b4..25d8fbf31 100644 --- a/client/src/dojo/setup.ts +++ b/client/src/dojo/setup.ts @@ -166,6 +166,7 @@ export async function setup(config: DojoConfig & { state: AppStore }) { "s0_eternum-Trade", "s0_eternum-Structure", "s0_eternum-Battle", + "s0_eternum-Guild", ], }, }, diff --git a/client/src/hooks/helpers/use-resource-arrivals.tsx b/client/src/hooks/helpers/use-resource-arrivals.tsx index dfb205ee5..3a7fe7066 100644 --- a/client/src/hooks/helpers/use-resource-arrivals.tsx +++ b/client/src/hooks/helpers/use-resource-arrivals.tsx @@ -23,6 +23,7 @@ export type ArrivalInfo = { isOwner: boolean; hasResources: boolean; isHome: boolean; + originOwner: string; // resources: Resource[]; }; @@ -95,6 +96,7 @@ const usePlayerArrivals = () => { isOwner: true, position: { x: position.x, y: position.y }, hasResources, + originOwner: owner?.address.toString(), isHome, }; }, diff --git a/client/src/hooks/helpers/useGuilds.tsx b/client/src/hooks/helpers/useGuilds.tsx index 94e1e6ff5..b197add82 100644 --- a/client/src/hooks/helpers/useGuilds.tsx +++ b/client/src/hooks/helpers/useGuilds.tsx @@ -308,5 +308,6 @@ export const useGuilds = () => { usePlayerWhitelist, getGuildFromEntityId, getPlayersInPlayersGuild, + getPlayerListInGuild, }; }; diff --git a/client/src/ui/components/trading/ResourceArrivals.tsx b/client/src/ui/components/trading/ResourceArrivals.tsx index a1a86b841..807a71719 100644 --- a/client/src/ui/components/trading/ResourceArrivals.tsx +++ b/client/src/ui/components/trading/ResourceArrivals.tsx @@ -1,12 +1,13 @@ import { addToSubscription } from "@/dojo/queries"; import { useDojo } from "@/hooks/context/DojoContext"; import { ArrivalInfo } from "@/hooks/helpers/use-resource-arrivals"; +import { useGuilds } from "@/hooks/helpers/useGuilds"; import useNextBlockTimestamp from "@/hooks/useNextBlockTimestamp"; import Button from "@/ui/elements/Button"; import { Checkbox } from "@/ui/elements/Checkbox"; import { Headline } from "@/ui/elements/Headline"; import { HintModalButton } from "@/ui/elements/HintModalButton"; -import { memo, useEffect, useState } from "react"; +import { memo, useEffect, useMemo, useState } from "react"; import { create } from "zustand"; import { EntityArrival } from "../entities/Entity"; import { HintSection } from "../hints/HintModal"; @@ -27,16 +28,39 @@ const useSubscribedIdsStore = create((set) => ({ export const AllResourceArrivals = memo( ({ arrivals, className = "" }: { arrivals: ArrivalInfo[]; className?: string }) => { - const dojo = useDojo(); const [displayCount, setDisplayCount] = useState(DISPLAYED_ARRIVALS); const [showOnlyArrived, setShowOnlyArrived] = useState(true); + const [showOnlyGuildMembers, setShowOnlyGuildMembers] = useState(false); const { nextBlockTimestamp } = useNextBlockTimestamp(); const { subscribedIds, addSubscribedIds } = useSubscribedIdsStore(); + const { getPlayersInPlayersGuild, getPlayerListInGuild } = useGuilds(); + + const { + account: { account }, + network: { toriiClient, contractComponents }, + } = useDojo(); + + const savedGuilds = localStorage.getItem("WHITELIST")?.split(","); + + const whitelistedGuilds = useMemo(() => { + return [ + ...(savedGuilds?.flatMap((guildId) => getPlayerListInGuild(Number(guildId))) || []), + ...getPlayersInPlayersGuild(BigInt(account?.address || 0n)).map((player) => player.address), + ]; + }, [account?.address, savedGuilds]); + useEffect(() => { // Create a single Set from newIds for O(1) lookup - const newIdsSet = new Set(arrivals.map((arrival) => arrival.entityId.toString())); + + const newIdsSet = new Set( + arrivals + .filter( + (arrival) => whitelistedGuilds.includes(arrival.originOwner) || arrival.originOwner === account.address, + ) + .map((arrival) => arrival.entityId.toString()), + ); // Find ids that aren't already subscribed const unsubscribedIds = Array.from(newIdsSet).filter((id) => !subscribedIds.has(id)); @@ -47,15 +71,28 @@ export const AllResourceArrivals = memo( addSubscribedIds(unsubscribedIds); // 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(toriiClient, contractComponents as any, unsubscribedIds).catch((error) => + console.error("Fetch failed", error), ); console.log("AddToSubscriptionStart - 5"); }, [arrivals, subscribedIds, addSubscribedIds]); - const filteredArrivals = showOnlyArrived - ? arrivals.filter((arrival) => arrival.arrivesAt < nextBlockTimestamp) - : arrivals; + const guildPlayers = getPlayersInPlayersGuild(BigInt(account?.address || 0n)).map((player) => player.address); + + const filteredArrivals = useMemo( + () => + arrivals.filter((arrival) => { + const timeCondition = showOnlyArrived ? arrival.arrivesAt < nextBlockTimestamp : true; + // Add a check for empty guildPlayers array + const guildCondition = showOnlyGuildMembers + ? guildPlayers.length === 0 + ? true // If no guild players, show all arrivals + : guildPlayers.includes(arrival.originOwner) + : true; + return timeCondition && guildCondition; + }), + [arrivals, showOnlyArrived, showOnlyGuildMembers, nextBlockTimestamp, guildPlayers], + ); const displayedArrivals = filteredArrivals.slice(0, displayCount); const hasMore = displayCount < filteredArrivals.length; @@ -72,11 +109,15 @@ export const AllResourceArrivals = memo( -
+
+
{displayedArrivals.map((arrival) => ( diff --git a/client/src/ui/modules/settings/Settings.tsx b/client/src/ui/modules/settings/Settings.tsx index 700b8e54d..60b1719d3 100644 --- a/client/src/ui/modules/settings/Settings.tsx +++ b/client/src/ui/modules/settings/Settings.tsx @@ -1,11 +1,12 @@ +import { ReactComponent as Controller } from "@/assets/icons/Controller.svg"; import { ReactComponent as Copy } from "@/assets/icons/common/copy.svg"; import { ReactComponent as Next } from "@/assets/icons/common/fast-forward.svg"; import { ReactComponent as Muted } from "@/assets/icons/common/muted.svg"; 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 { useDojo } from "@/hooks/context/DojoContext"; +import { useGuilds } from "@/hooks/helpers/useGuilds"; import { useRealm } from "@/hooks/helpers/useRealm"; import useUIStore from "@/hooks/store/useUIStore"; import { useMusicPlayer } from "@/hooks/useMusic"; @@ -61,7 +62,29 @@ 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; + + const { useGuildQuery } = useGuilds(); + const { guilds } = useGuildQuery(); + const [selectedGuilds, setSelectedGuilds] = useState(() => { + const savedGuilds = localStorage.getItem("WHITELIST"); + return savedGuilds ? savedGuilds.split(",") : []; + }); + + const handleGuildSelect = (guildId: string) => { + setSelectedGuilds((prev) => { + const newGuilds = prev.includes(guildId) ? prev.filter((id) => id !== guildId) : [...prev, guildId]; + localStorage.setItem("WHITELIST", newGuilds.join(",")); + toast(prev.includes(guildId) ? "Guild removed from whitelist!" : "Guild added to whitelist!"); + return newGuilds; + }); + }; + + const handleClearGuilds = () => { + setSelectedGuilds([]); + localStorage.removeItem("WHITELIST"); + toast("Guild whitelist cleared!"); + }; return ( togglePopup(settings)} show={isOpen} title={settings}> @@ -126,6 +149,27 @@ export const SettingsWindow = () => {
Sound +
+
Whitelist guilds
+
+ {guilds.map((guild) => ( + + ))} +
+ {selectedGuilds.length > 0 && ( + + )} +
+
{isSoundOn ? (