import { PeerMetadata, NetworkMessage, PasswordResponse, RoomInfo } from "./types"; import EventEmitter from "eventemitter3"; export abstract class Client extends EventEmitter { public metadata: PeerMetadata; public players!: string[]; public roomInfo!: RoomInfo; public constructor(metadata: PeerMetadata) { super(); this.metadata = metadata; } protected _received(data: NetworkMessage) { this.emit("data", data); switch (data.kind) { // Server is sending over player list and room info case "room-info": this.roomInfo = data.room; this.players = data.players; break; // Someone changed name (or was forced to) case "rename": if (data.oldname == this.metadata.name) { // We got a name change! this.metadata.name = data.newname; } else { let idx = this.players.indexOf(data.oldname); if (idx < 0) { // Weird console.warn( `Someone (${data.oldname}) changed name but wasn't on the player list` ); this.players.push(data.newname); break; } this.players[idx] = data.newname; } this.emit("rename", data.oldname, data.newname); break; // A new player joined the room (this includes us) case "player-joined": this.players.push(data.name); this.emit("player-joined", data.name); break; case "player-left": { let idx = this.players.indexOf(data.name); if (idx < 0) { // Weird console.warn( `Someone (${data.name}) left but wasn't on the player list` ); break; } this.players.splice(idx, 1); break; } case "password-req": this.emit("password-required"); break; default: // For most cases, we can just use the kind as event type this.emit(data.kind, data); } } public password(password: string) { this.send({ kind: "password-resp", password }); } public get name(): string { return this.metadata.name; } public abstract send(data: T): void; public leave(): void { this.send({ kind: "leave-req" }); } public say(to: string | null, message: string) { this.send({ kind: "chat", from: this.name, to: to ? to : "", message }); } } export default Client;