forked from eros/curltastic
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
import type {
|
|
ServerGameStateMessage,
|
|
ServerMessageTyped as ServerMessage,
|
|
Team,
|
|
} from './protocol'
|
|
|
|
const WS_URL = import.meta.env.VITE_WS_URL
|
|
|
|
function resolveWsUrl(): string {
|
|
if (WS_URL) return WS_URL
|
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
|
return `${protocol}//${window.location.hostname}:3000/ws`
|
|
}
|
|
|
|
export interface NetCallbacks {
|
|
onJoined: (room: string, team: Team) => void
|
|
onWaiting: (message: string) => void
|
|
onGameState: (msg: ServerGameStateMessage) => void
|
|
onTrajectory: (path: [number, number, number][]) => void
|
|
onEndScored: (end: number, points: number, scoringTeam: Team | null) => void
|
|
onGameOver: (scores: number[], winner: Team | null) => void
|
|
onError: (message: string) => void
|
|
onClose: () => void
|
|
}
|
|
|
|
let socket: WebSocket | null = null
|
|
|
|
export function connect(room: string, team: Team | null, callbacks: NetCallbacks): void {
|
|
if (socket) return
|
|
const teamParam = team ? `&team=${encodeURIComponent(team)}` : ''
|
|
const url = `${resolveWsUrl()}?room=${encodeURIComponent(room)}${teamParam}`
|
|
const ws = new WebSocket(url)
|
|
|
|
ws.onopen = () => {
|
|
socket = ws
|
|
}
|
|
|
|
ws.onmessage = (event) => {
|
|
try {
|
|
const msg = JSON.parse(event.data) as ServerMessage
|
|
if (!msg || typeof msg.type !== 'string') return
|
|
|
|
switch (msg.type) {
|
|
case 'joined':
|
|
callbacks.onJoined(msg.room, msg.team)
|
|
break
|
|
case 'waiting':
|
|
callbacks.onWaiting(msg.message)
|
|
break
|
|
case 'game_state':
|
|
callbacks.onGameState(msg)
|
|
break
|
|
case 'trajectory':
|
|
callbacks.onTrajectory(msg.path)
|
|
break
|
|
case 'end_scored':
|
|
callbacks.onEndScored(msg.end, msg.points, msg.scoring_team ?? null)
|
|
break
|
|
case 'game_over':
|
|
callbacks.onGameOver(msg.scores, msg.winner)
|
|
break
|
|
case 'error':
|
|
callbacks.onError(msg.message)
|
|
break
|
|
}
|
|
} catch (err) {
|
|
console.error('Failed to parse server message', err)
|
|
}
|
|
}
|
|
|
|
ws.onclose = () => {
|
|
socket = null
|
|
callbacks.onClose()
|
|
}
|
|
|
|
ws.onerror = () => {}
|
|
}
|
|
|
|
export function sendThrow(broomX: number, broomY: number, weight: number, curl: number, friction: number): void {
|
|
if (!socket || socket.readyState !== WebSocket.OPEN) return
|
|
socket.send(JSON.stringify({ type: 'throw', broom_x: broomX, broom_y: broomY, weight, curl, friction }))
|
|
}
|