Files
healer-man/src/platform/authoritativeDualScreenRuntime.ts
T
2026-09-12 21:14:41 -04:00

68 lines
2.5 KiB
TypeScript

import { useCombatStore } from "../game/combatStore";
import { useGameStore } from "../game/store";
import { usePartyStore } from "../game/partyStore";
import { useShellStore } from "../app/shellStore";
import { emitControllerToken, setExternalControllerMovement } from "../input/controller";
import { currentCompanionSnapshot, executeCompanionCommand, type DualScreenMessage } from "./dualScreenSync";
import { createRateLimitedPublisher } from "./rateLimitedPublisher";
import { useUiLayoutStore } from "../game/uiLayoutStore";
import { useDpsMeterStore } from "../game/dpsMeterStore";
export function connectAuthoritativeDualScreen(
channel: BroadcastChannel,
initialMessage: MessageEvent<DualScreenMessage>,
): () => void {
let companionReady = initialMessage.data.type === "companion-ready";
const publish = () => channel.postMessage({
type: "app-state",
snapshot: currentCompanionSnapshot(),
} satisfies DualScreenMessage);
const gamePublisher = createRateLimitedPublisher(() => {
if (companionReady) publish();
}, 100);
const unsubscribeShell = useShellStore.subscribe(() => {
if (companionReady) publish();
});
const unsubscribeGame = useGameStore.subscribe(() => {
if (companionReady) gamePublisher.request();
});
const unsubscribeCombat = useCombatStore.subscribe(() => {
if (companionReady) gamePublisher.request();
});
const unsubscribeParty = usePartyStore.subscribe(() => {
if (companionReady) gamePublisher.request();
});
const unsubscribeUi = useUiLayoutStore.subscribe(() => {
if (companionReady) gamePublisher.request();
});
const unsubscribeDps = useDpsMeterStore.subscribe(() => {
if (companionReady) gamePublisher.request();
});
channel.onmessage = (event: MessageEvent<DualScreenMessage>) => {
if (event.data.type === "companion-ready") {
companionReady = true;
publish();
} else if (event.data.type === "companion-closing") {
companionReady = false;
gamePublisher.cancel();
} else if (event.data.type === "command") {
executeCompanionCommand(event.data.command);
publish();
} else if (event.data.type === "controller-token") {
emitControllerToken(event.data.event);
} else if (event.data.type === "controller-motion") {
setExternalControllerMovement(event.data.movement);
}
};
if (companionReady) publish();
return () => {
unsubscribeShell();
unsubscribeGame();
unsubscribeCombat();
unsubscribeParty();
unsubscribeUi();
unsubscribeDps();
gamePublisher.dispose();
};
}