Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
100 lines
3 KiB
TypeScript
100 lines
3 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import {
|
|
GAME_EVENT_EVENT,
|
|
GAME_TICK_EVENT,
|
|
NOTIFICATION_EVENT,
|
|
POKER_STATE_EVENT,
|
|
POKER_TABLES_EVENT,
|
|
POKER_TERMINATED_EVENT,
|
|
PROFILE_UPDATE_EVENT,
|
|
type GameTickDetail,
|
|
type PokerStateDetail,
|
|
type PokerTablesDetail,
|
|
type PokerTerminatedDetail,
|
|
type ProfileUpdateDetail,
|
|
} from "@/hooks/useGameTick";
|
|
|
|
/**
|
|
* Opens a Server-Sent Events connection to the game tick stream.
|
|
* When a game tick completes, refreshes server-rendered data via
|
|
* router.refresh() and dispatches a window event that client-side
|
|
* components (e.g. ShipmentToasts, EventLedger) listen to for refetch.
|
|
*/
|
|
export function GameTickRealtime() {
|
|
const router = useRouter();
|
|
|
|
useEffect(() => {
|
|
const source = new EventSource("/api/realtime");
|
|
let refreshTimer: ReturnType<typeof setTimeout> | null = null;
|
|
const refresh = (delay = 250) => {
|
|
if (refreshTimer) return;
|
|
refreshTimer = setTimeout(() => {
|
|
refreshTimer = null;
|
|
router.refresh();
|
|
}, delay);
|
|
};
|
|
source.addEventListener("game-tick", (event) => {
|
|
let detail: GameTickDetail = {};
|
|
try {
|
|
detail = JSON.parse(event.data ?? "{}");
|
|
} catch {
|
|
// ignore malformed payload
|
|
}
|
|
refresh();
|
|
window.dispatchEvent(new CustomEvent(GAME_TICK_EVENT, { detail }));
|
|
});
|
|
source.addEventListener("profile-update", (event) => {
|
|
let detail: ProfileUpdateDetail = {};
|
|
try {
|
|
detail = JSON.parse(event.data ?? "{}");
|
|
} catch {
|
|
// ignore malformed payload
|
|
}
|
|
refresh(detail.xpGained ? 1700 : 250);
|
|
window.dispatchEvent(new CustomEvent(PROFILE_UPDATE_EVENT, { detail }));
|
|
});
|
|
source.addEventListener("game-event", () => {
|
|
refresh();
|
|
window.dispatchEvent(new CustomEvent(GAME_EVENT_EVENT));
|
|
});
|
|
source.addEventListener("notification", (event) => {
|
|
window.dispatchEvent(new CustomEvent(NOTIFICATION_EVENT, { detail: event.data }));
|
|
});
|
|
source.addEventListener("poker-state", (event) => {
|
|
let detail: PokerStateDetail = {};
|
|
try {
|
|
detail = JSON.parse(event.data ?? "{}");
|
|
} catch {
|
|
// ignore malformed payload
|
|
}
|
|
window.dispatchEvent(new CustomEvent(POKER_STATE_EVENT, { detail }));
|
|
});
|
|
source.addEventListener("poker-tables", (event) => {
|
|
let detail: PokerTablesDetail = {};
|
|
try {
|
|
detail = JSON.parse(event.data ?? "{}");
|
|
} catch {
|
|
// ignore malformed payload
|
|
}
|
|
window.dispatchEvent(new CustomEvent(POKER_TABLES_EVENT, { detail }));
|
|
});
|
|
source.addEventListener("poker-terminated", (event) => {
|
|
let detail: PokerTerminatedDetail = {};
|
|
try {
|
|
detail = JSON.parse(event.data ?? "{}");
|
|
} catch {
|
|
// ignore malformed payload
|
|
}
|
|
window.dispatchEvent(new CustomEvent(POKER_TERMINATED_EVENT, { detail }));
|
|
});
|
|
return () => {
|
|
if (refreshTimer) clearTimeout(refreshTimer);
|
|
source.close();
|
|
};
|
|
}, [router]);
|
|
|
|
return null;
|
|
}
|