import $ from "jquery"; import { Vec2 } from "./vector"; import { MouseController } from "./mouse_controller"; import { EntityPositionUpdateEvent, EventPublisher, EventQueue, EventType, SetControllableEvent, WebsocketEventPublisher, WebSocketEventQueue, } from "./network"; class KennelClient { private running: boolean; private last_update: number; private controllable_entities: Set = new Set(); private mouse_controller: MouseController; constructor( private readonly client_id: string, private readonly event_queue: EventQueue, private readonly event_publisher: EventPublisher, ) { this.last_update = 0; this.running = false; this.mouse_controller = new MouseController((position: Vec2) => this.on_mouse_move(position), ); } public start() { this.running = true; this.last_update = performance.now(); this.mouse_controller.start(); const loop = (timestamp: number) => { if (!this.running) return; const dt = timestamp - this.last_update; this.propogate_state_after(dt); requestAnimationFrame(loop); // tail call recursion! /s }; requestAnimationFrame(loop); $(document).on("mousemove", (event) => { this.mouse_controller.move(event.clientX, event.clientY); }); } public close() { this.running = false; this.mouse_controller.stop(); this.controllable_entities.clear(); $(document).off("mousemove"); } private propogate_state_after(dt: number) { const events = this.event_queue.peek(); for (const event of events) { switch (event.event_type) { case EventType.SET_CONTROLLABLE: this.process_set_controllable_event(event as SetControllableEvent); break; } } if (events.length > 0) { console.log(events, dt); } this.event_queue.clear(); this.event_publisher.publish(); } private process_set_controllable_event(event: SetControllableEvent) { if (event.data.client_id !== this.client_id) { console.warn("got controllable event for client that is not us"); return; } this.controllable_entities.add(event.data.id); } private on_mouse_move(position: Vec2) { for (const id of this.controllable_entities) { const event: EntityPositionUpdateEvent = { event_type: EventType.ENTITY_POSITION_UPDATE, data: { id, position: { x: position.x, y: position.y } }, }; this.event_publisher.add(event); } } } $(async () => { const client_id = await fetch("/assign", { credentials: "include", }) .then((res) => res.json()) .then(({ session }) => session); const ws = new WebSocket("/ws"); await new Promise((resolve) => { ws.onopen = () => resolve(); }); const queue: EventQueue = new WebSocketEventQueue(ws); const publisher: EventPublisher = new WebsocketEventPublisher(ws); const kennel_client = new KennelClient(client_id, queue, publisher); ws.onclose = () => kennel_client.close(); kennel_client.start(); });