This commit is contained in:
Dylan Pizzo
2026-06-11 13:41:52 -04:00
parent e51df30a08
commit 6ad0ffe1c5
2 changed files with 111 additions and 71 deletions
+71 -37
View File
@@ -1,10 +1,15 @@
import { Link, useParams, useSearchParams } from "react-router-dom"; import { Link, useParams, useSearchParams } from "react-router-dom";
import { useEffect, useRef, useState } from "react"; import { MutableRefObject, useEffect, useRef, useState } from "react";
import { css } from "@emotion/css"; import { css } from "@emotion/css";
import { useWebsocket } from "./hooks/useWebsocket"; import { useWebsocket } from "./hooks/useWebsocket";
import { Pico8Player } from "@athingperday/react-pico-player"; import { Pico8Player } from "@athingperday/react-pico-player";
// type ConsoleRef = Parameters<typeof Pico8Player>["0"]["consoleRef"]; type PicoPlayerHandle =
NonNullable<
Parameters<typeof Pico8Player>["0"]["consoleRef"]
> extends MutableRefObject<infer T>
? NonNullable<T>
: never;
type Game = { type Game = {
carts: Parameters<typeof Pico8Player>["0"]["carts"]; carts: Parameters<typeof Pico8Player>["0"]["carts"];
@@ -12,30 +17,37 @@ type Game = {
export const GamePage = () => { export const GamePage = () => {
const { author, slug } = useParams(); const { author, slug } = useParams();
// const [searchParams, setSearchParams] = useSearchParams(); const [text, setText] = useState("");
// const room = searchParams.get('room'); const [prevGpio, setPrevGpio] = useState<number[] | null>(null);
// const picoRef = useRef<ConsoleRef>(null); const [searchParams, setSearchParams] = useSearchParams();
// const socket = useWebsocket({ const room = searchParams.get("room");
// url: `/api/ws/room?room=${room}`, const picoRef = useRef<PicoPlayerHandle>(null);
// // url: "wss://echo.websocket.org", const socket = useWebsocket({
// onMessage({message}) { url: `/api/ws/room?room=${room}`,
// // const msg = message as any; onMessage({ message }) {
// // if (msg.type === "gpio") { // console.log("message", message);
// // if (picoRef.current) { const msg = message as any;
// // const handle = picoRef.current.getPicoConsoleHandle(); if (msg.getGpio) {
// // if (handle) { if (picoRef.current) {
// // console.log("updating pico gpio"); const handle = picoRef.current;
// // (handle.gpio as any).dontSend = true; if (handle) {
// // handle.gpio.length = 0; socket.sendMessage({ gpio: handle.gpio });
// // handle.gpio.push(...msg.gpio); }
// // (handle.gpio as any).dontSend = false; }
// // } }
// // } if (msg.gpio) {
// // } if (picoRef.current) {
// console.log('message', message); const handle = picoRef.current;
// } if (handle) {
// }) // console.log("updating pico gpio");
// const version = searchParams.get('v'); handle.gpio.length = 0;
handle.gpio.push(...msg.gpio);
setPrevGpio([...handle.gpio]);
}
}
}
},
});
const [game, setGame] = useState<Game | null>(null); const [game, setGame] = useState<Game | null>(null);
useEffect(() => { useEffect(() => {
@@ -49,6 +61,28 @@ export const GamePage = () => {
fetchInfo(); fetchInfo();
}, [setGame, slug]); }, [setGame, slug]);
useEffect(() => {
const interval = setInterval(() => {
const handle = picoRef.current;
if (!handle) {
return;
}
if (JSON.stringify(handle.gpio) !== JSON.stringify(prevGpio)) {
if (prevGpio) {
setPrevGpio([...handle.gpio]);
socket.sendMessage({ gpio: handle.gpio });
} else {
socket.sendMessage({ getGpio: true });
setPrevGpio([...handle.gpio]);
}
}
}, 1000 / 60);
return () => {
clearInterval(interval);
};
});
if (!game) { if (!game) {
return <div>LOADING...</div>; return <div>LOADING...</div>;
} }
@@ -90,19 +124,19 @@ export const GamePage = () => {
} }
`} `}
> >
<Pico8Player <Pico8Player consoleRef={picoRef} carts={game.carts} />
// consoleRef={picoRef}
carts={game.carts}
// onGpioChange={(gpio: number[]) => {
// console.log("sending gpio");
// socket.sendMessage({
// type: "gpio",
// gpio,
// });
// }}
/>
</div> </div>
</div> </div>
<div>
<input onChange={(x) => setText(x.target.value)} />
<button
onClick={() => {
socket.sendMessage({ text });
}}
>
Send
</button>
</div>
{/* <div> {/* <div>
<p>This is a paragraph about this game. It is a cool game. And a cool website to play it on. It automagically connects from GitHub.</p> <p>This is a paragraph about this game. It is a cool game. And a cool website to play it on. It automagically connects from GitHub.</p>
</div> */} </div> */}
+40 -34
View File
@@ -1,46 +1,52 @@
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
export const useWebsocket = (props: {url: string; onMessage: (stuff: {socket: WebSocket; message: unknown}) => void}) => { export const useWebsocket = (props: {
const {url, onMessage} = props; url: string;
const onMessageRef = useRef(onMessage); onMessage: (stuff: { socket: WebSocket; message: unknown }) => void;
const ws = useRef<WebSocket | null>(null); }) => {
onMessageRef.current = onMessage; const { url, onMessage } = props;
const onMessageRef = useRef(onMessage);
const ws = useRef<WebSocket | null>(null);
onMessageRef.current = onMessage;
useEffect(() => { useEffect(() => {
const webSocket = new WebSocket(url); const webSocket = new WebSocket(url);
webSocket.addEventListener("open", () => { webSocket.addEventListener("open", () => {
console.log("WebSocket is open now."); console.log("WebSocket is open now.");
}); });
webSocket.addEventListener("message", (event: any) => { webSocket.addEventListener("message", (event: any) => {
onMessageRef.current({socket: webSocket, message: JSON.parse(event.data)}); onMessageRef.current({
}); socket: webSocket,
message: JSON.parse(event.data),
});
});
webSocket.addEventListener("error", (event) => { webSocket.addEventListener("error", (event) => {
console.log("WebSocket error: ", event); console.log("WebSocket error: ", event);
}); });
webSocket.addEventListener("close", () => { webSocket.addEventListener("close", () => {
console.log("WebSocket is closed now."); console.log("WebSocket is closed now.");
ws.current = null; ws.current = null;
}); });
ws.current = webSocket; ws.current = webSocket;
return () => { return () => {
webSocket.close(); webSocket.close();
}; };
}, [url]);
}, [url]); const sendMessage = useCallback((message: unknown) => {
if (ws.current && ws.current.readyState === WebSocket.OPEN) {
ws.current.send(JSON.stringify(message));
// console.log("sending", message);
} else {
console.error("WebSocket is not open. Message not sent.");
}
}, []);
const sendMessage = useCallback((message: unknown) => { return { sendMessage };
if (ws.current && ws.current.readyState === WebSocket.OPEN) { };
ws.current.send(JSON.stringify(message));
} else {
console.error("WebSocket is not open. Message not sent.");
}
}, []);
return {sendMessage};
};