Add received handlers, force rename on name conflicts

This commit is contained in:
Hamcha 2019-09-04 17:57:19 +02:00
parent c164a70fc1
commit 005290d057
Signed by: hamcha
GPG key ID: 44AD3571EB09A39E
5 changed files with 116 additions and 37 deletions

View file

@ -1,6 +1,6 @@
import NetworkPeer from "./peer";
import { DataConnection } from "peerjs";
import { PeerMetadata } from "./types";
import { PeerMetadata, NetworkMessage } from "./types";
export default class PeerClient extends NetworkPeer {
private connection: DataConnection;
@ -11,5 +11,11 @@ export default class PeerClient extends NetworkPeer {
metadata,
reliable: true
});
this.connection.on("open", () => {
console.info("Connected to server");
});
this.connection.on("data", this._received);
}
private _received(data: NetworkMessage) {}
}

19
src/network/local.ts Normal file
View file

@ -0,0 +1,19 @@
import NetworkPeer from "./peer";
import { DataConnection } from "peerjs";
import { PeerMetadata, NetworkMessage } from "./types";
export default class LocalClient {
public metadata: PeerMetadata;
public constructor(metadata: PeerMetadata) {
this.metadata = metadata;
}
public receive(data: NetworkMessage) {
//TODO
}
public send(data: NetworkMessage) {
//TODO
}
}

View file

@ -1,4 +1,5 @@
import Peer, { DataConnection } from "peerjs";
import { NetworkMessage } from "./types";
export default class NetworkPeer {
protected peer: Peer;
@ -9,7 +10,7 @@ export default class NetworkPeer {
});
}
protected send<T>(conn: DataConnection, data: T) {
protected send<T extends NetworkMessage>(conn: DataConnection, data: T) {
//TODO Debugging support?
conn.send(data);
}

View file

@ -8,30 +8,53 @@ import {
PasswordResponse,
PeerMetadata,
JoinMessage,
RoomInfoMessage
RoomInfoMessage,
Player,
NetworkMessage,
RenameMessage
} from "./types";
import LocalClient from "./local";
// Increment name, add number at the end if not present
// Examples:
// Guest -> Guest1
// Guest1 -> Guest2
// Guest9 -> Guest10
function nextName(name: string): string {
let i = 1;
for (; i < name.length; i++) {
if (!isNaN(Number(name.slice(i - name.length)))) {
break;
}
}
return name.substr(0, i) + (Number(name.slice(i)) + 1);
}
export default class PeerServer extends NetworkPeer {
private room: Room;
public constructor(roomInfo: RoomInfo) {
public constructor(roomInfo: RoomInfo, local: LocalClient) {
super();
let players: Record<string, Player> = {};
players[local.metadata.name] = {
kind: "local",
name: local.metadata.name,
client: local
};
this.room = {
info: roomInfo,
players: {
//TODO Add local player
}
players
};
this.peer.on("connection", this._connection);
}
private async _connection(conn: DataConnection) {
private _connection(conn: DataConnection) {
const metadata = conn.metadata as PeerMetadata;
console.info("%s (%s) connected!", metadata.name, conn.label);
//
// Check if this connection should be allowed
console.info(
"%s (%s) connected!",
(conn.metadata as PeerMetadata).name,
conn.label
);
//
// Check if room is full
if (this.playerCount >= this.room.info.max_players) {
@ -40,34 +63,48 @@ export default class PeerServer extends NetworkPeer {
return;
}
// Check if there is already a player called that way
if (this.room.players[metadata.name]) {
// Force rename
const newname = nextName(metadata.name);
this.send<RenameMessage>(conn, {
kind: "rename",
oldname: metadata.name,
newname: newname
});
metadata.name = newname;
}
// Check for password
if (this.room.info.password != "") {
const checkPasswordResponse = (data: any) => {
try {
let resp = data as PasswordResponse;
if (resp.password != this.room.info.password) {
this.send<ErrorMessage>(conn, {
kind: "error",
error: "invalid password"
});
return;
}
conn.off("data", checkPasswordResponse);
this.addPlayer(conn);
} catch (e) {
this.send<ErrorMessage>(conn, {
kind: "error",
error: "not a password"
});
}
};
this.send<PasswordRequest>(conn, { kind: "password-req" });
conn.on("data", this.checkPasswordResponse.bind(this, conn));
conn.on("data", checkPasswordResponse);
return;
}
this.addPlayer(conn);
}
private checkPasswordResponse(conn: DataConnection, data: any) {
try {
let resp = data as PasswordResponse;
if (resp.password != this.room.info.password) {
this.send<ErrorMessage>(conn, {
kind: "error",
error: "invalid password"
});
return;
}
this.addPlayer(conn);
} catch (e) {
this.send<ErrorMessage>(conn, {
kind: "error",
error: "not a password"
});
}
}
private addPlayer(conn: DataConnection) {
const playerName = conn.metadata.name;
this.room.players[playerName] = {
@ -76,6 +113,9 @@ export default class PeerServer extends NetworkPeer {
conn: conn
};
// Start listening for new messages
conn.on("data", this._received.bind(this, this.room.players[playerName]));
// Send the player info about the room
this.send<RoomInfoMessage>(conn, {
kind: "room-info",
@ -93,17 +133,19 @@ export default class PeerServer extends NetworkPeer {
});
}
private _received(player: Player, data: NetworkMessage) {}
private get playerCount(): number {
return Object.keys(this.room.players).length;
}
private broadcast<T>(message: T) {
private broadcast<T extends NetworkMessage>(message: T) {
for (const playerName in this.room.players) {
const player = this.room.players[playerName];
if (player.kind == "remote") {
this.send<T>(player.conn, message);
} else {
//TODO Local wrapper
player.client.receive(message);
}
}
}

View file

@ -1,8 +1,10 @@
import { DataConnection } from "peerjs";
import LocalClient from "./local";
export interface LocalPlayer {
kind: "local";
name: string;
client: LocalClient;
}
export interface NetworkPlayer {
@ -11,13 +13,15 @@ export interface NetworkPlayer {
conn: DataConnection;
}
export type Player = NetworkPlayer | LocalPlayer;
export interface PeerMetadata {
name: string;
}
export interface Room {
info: RoomInfo;
players: Record<string, NetworkPlayer | LocalPlayer>;
players: Record<string, Player>;
}
export interface RoomInfo {
@ -61,7 +65,8 @@ export type NetworkMessage =
| PasswordResponse
| ErrorMessage
| RoomInfoMessage
| JoinMessage;
| JoinMessage
| RenameMessage;
export interface PasswordRequest {
kind: "password-req";
@ -83,6 +88,12 @@ export interface JoinMessage {
name: string;
}
export interface RenameMessage {
kind: "rename";
oldname: string;
newname: string;
}
export interface ErrorMessage {
kind: "error";
error: string;