From 4617d6c9fa606f6e4283c7089a9ecc4d105c88eb Mon Sep 17 00:00:00 2001 From: neru Date: Fri, 19 Jun 2026 04:42:59 -0300 Subject: [PATCH] fix: prevent sync spam --- app/page.tsx | 4 +- store/useWebsocketStore.ts | 83 +++++++++++++++++++------------------- store/wsProtocol.ts | 5 --- 3 files changed, 43 insertions(+), 49 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index 5319916..5e54cec 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -50,8 +50,8 @@ export default function Home() { }, []); /* - profile handling - */ + profile handling + */ const handleDownload = () => { const blob = new Blob([importText], { type: 'application/json' }); const url = URL.createObjectURL(blob); diff --git a/store/useWebsocketStore.ts b/store/useWebsocketStore.ts index 416334c..1370c13 100644 --- a/store/useWebsocketStore.ts +++ b/store/useWebsocketStore.ts @@ -40,11 +40,9 @@ export const useWebsocketStore = create((set, get) => ({ try { const payload = JSON.parse(msg.data); - // C++ sends action=0 (INIT_CONFIG) on WebSocket open if (payload.action === 0) { const mapped = await mapSpooferConfigToStore(payload.profile); - // Snapshot current state strings to prevent echo lastInventoryJson = JSON.stringify({ unlockedCharacters: mapped.unlockedCharacters, unlockedCustomizations: mapped.unlockedCustomizations, @@ -71,48 +69,49 @@ export const useWebsocketStore = create((set, get) => ({ } })); -// Subscribe to store changes and sync to C++ client +let syncTimeout: any = null; + useInventoryStore.subscribe((state) => { - const { socket, isConnected } = useWebsocketStore.getState(); - if (!isConnected || !socket || socket.readyState !== WebSocket.OPEN) return; + if (syncTimeout) clearTimeout(syncTimeout); - // --- Check toggles --- - const toggles = { - spoofItems: state.spoofItems, - spoofPerks: state.spoofPerks, - spoofCatalog: state.spoofCatalog, - spoofDLCs: state.spoofDLCs - }; - const togglesJson = JSON.stringify(toggles); - if (togglesJson !== lastTogglesJson) { - lastTogglesJson = togglesJson; - socket.send(JSON.stringify({ action: 2, toggles })); - } + syncTimeout = setTimeout(() => { + const { socket, isConnected } = useWebsocketStore.getState(); + if (!isConnected || !socket || socket.readyState !== WebSocket.OPEN) return; - // --- Check inventory --- - const inventory = { - unlockedCharacters: state.unlockedCharacters, - unlockedCustomizations: state.unlockedCustomizations, - unlockedDLCs: state.unlockedDLCs, - unlockedPerks: state.unlockedPerks, - items: state.items, - offerings: state.offerings, - addons: state.addons - }; - const inventoryJson = JSON.stringify(inventory); - if (inventoryJson !== lastInventoryJson) { - lastInventoryJson = inventoryJson; + const toggles = { + spoofItems: state.spoofItems, + spoofPerks: state.spoofPerks, + spoofCatalog: state.spoofCatalog, + spoofDLCs: state.spoofDLCs + }; + const togglesJson = JSON.stringify(toggles); + if (togglesJson !== lastTogglesJson) { + lastTogglesJson = togglesJson; + socket.send(JSON.stringify({ action: 2, toggles })); + } - mapStoreToSpooferConfig(state).then((profile) => { - // Re-check connection in case it dropped during async mapping - const ws = useWebsocketStore.getState(); - if ( - ws.isConnected && - ws.socket && - ws.socket.readyState === WebSocket.OPEN - ) { - ws.socket.send(JSON.stringify({ action: 1, profile })); - } - }); - } + const inventory = { + unlockedCharacters: state.unlockedCharacters, + unlockedCustomizations: state.unlockedCustomizations, + unlockedDLCs: state.unlockedDLCs, + unlockedPerks: state.unlockedPerks, + items: state.items, + offerings: state.offerings, + addons: state.addons + }; + const inventoryJson = JSON.stringify(inventory); + if (inventoryJson !== lastInventoryJson) { + lastInventoryJson = inventoryJson; + + mapStoreToSpooferConfig(state).then((profile) => { + const ws = useWebsocketStore.getState(); + if ( + ws.isConnected && + ws.socket && + ws.socket.readyState === WebSocket.OPEN + ) + ws.socket.send(JSON.stringify({ action: 1, profile })); + }); + } + }, 250); }); diff --git a/store/wsProtocol.ts b/store/wsProtocol.ts index dbc5588..29030a0 100644 --- a/store/wsProtocol.ts +++ b/store/wsProtocol.ts @@ -59,7 +59,6 @@ export async function mapStoreToSpooferConfig(state: { const perkMap = new Map(); allPerks.forEach((p: { id: string; role: number }) => perkMap.set(p.id, p)); - // --- DLCs --- const dlcListSteam: string[] = []; const dlcListEGS: string[] = []; const dlcListGRDK: string[] = []; @@ -87,13 +86,11 @@ export async function mapStoreToSpooferConfig(state: { dlcListGRDK.push(dlc.dlcIds.grdk); } - // --- Items --- const camperItems: Record = {}; for (const [id, qty] of Object.entries(state.items)) { if (qty > 0 && itemIdSet.has(id)) camperItems[id] = qty; } - // --- Offerings --- const camperOfferings: Record = {}; const slasherOfferings: Record = {}; const globalOfferings: Record = {}; @@ -107,7 +104,6 @@ export async function mapStoreToSpooferConfig(state: { else globalOfferings[id] = qty; } - // --- Addons --- const camperAddons: Record = {}; const slasherAddons: Record = {}; @@ -119,7 +115,6 @@ export async function mapStoreToSpooferConfig(state: { else camperAddons[id] = qty; } - // --- Perks --- const camperPerks: string[] = []; const slasherPerks: string[] = [];