106 lines
2.8 KiB
TypeScript
106 lines
2.8 KiB
TypeScript
import EventEmitter from "eventemitter3";
|
|
import Vue from "vue";
|
|
|
|
import { NetworkMessage, PasswordResponse, PeerMetadata, RoomInfo } from "./types";
|
|
|
|
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;
|
|
this.emit("handshake");
|
|
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;
|
|
}
|
|
|
|
// Only mutate player list if we have one
|
|
// This is because rename messages can be received during the initial
|
|
// handshake, to signal a forced name change before joining.
|
|
if (this.players) {
|
|
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;
|
|
}
|
|
Vue.set(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.emit("player-left", data.name);
|
|
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<PasswordResponse>({
|
|
kind: "password-resp",
|
|
password
|
|
});
|
|
}
|
|
|
|
public get name(): string {
|
|
return this.metadata.name;
|
|
}
|
|
|
|
public abstract send<T extends NetworkMessage>(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;
|