Add Lobby #43

Merged
hamcha merged 18 commits from feature/lobby into master 2019-10-16 08:31:04 +00:00
7 changed files with 106 additions and 67 deletions
Showing only changes of commit 3a5989ea0d - Show all commits

View file

@ -1,10 +1,7 @@
import {
PeerMetadata,
NetworkMessage,
PasswordResponse,
RoomInfo
} from "./types";
import EventEmitter from "eventemitter3"; import EventEmitter from "eventemitter3";
import Vue from "vue";
import { NetworkMessage, PasswordResponse, PeerMetadata, RoomInfo } from "./types";
export abstract class Client extends EventEmitter { export abstract class Client extends EventEmitter {
public metadata: PeerMetadata; public metadata: PeerMetadata;
@ -30,7 +27,8 @@ export abstract class Client extends EventEmitter {
if (data.oldname == this.metadata.name) { if (data.oldname == this.metadata.name) {
// We got a name change! // We got a name change!
this.metadata.name = data.newname; this.metadata.name = data.newname;
} else { }
let idx = this.players.indexOf(data.oldname); let idx = this.players.indexOf(data.oldname);
if (idx < 0) { if (idx < 0) {
// Weird // Weird
@ -40,8 +38,7 @@ export abstract class Client extends EventEmitter {
this.players.push(data.newname); this.players.push(data.newname);
break; break;
} }
this.players[idx] = data.newname; Vue.set(this.players, idx, data.newname);
}
this.emit("rename", data.oldname, data.newname); this.emit("rename", data.oldname, data.newname);
break; break;
// A new player joined the room (this includes us) // A new player joined the room (this includes us)

View file

@ -1,23 +1,24 @@
import EventEmitter from "eventemitter3";
import Peer, { DataConnection } from "peerjs"; import Peer, { DataConnection } from "peerjs";
import { LocalClient } from ".";
import { import {
RoomInfo, AckMessage,
PasswordRequest, ChatMessage,
Room,
ErrorMessage, ErrorMessage,
JoinMessage,
LeaveMessage,
NetworkMessage,
NetworkPlayer,
PasswordRequest,
PasswordResponse, PasswordResponse,
PeerMetadata, PeerMetadata,
JoinMessage,
RoomInfoMessage,
Player, Player,
NetworkMessage,
RenameMessage, RenameMessage,
LeaveMessage, Room,
NetworkPlayer, RoomInfo,
AckMessage, RoomInfoMessage,
ChatMessage
} from "./types"; } from "./types";
import { LocalClient } from ".";
import EventEmitter from "eventemitter3";
// Increment name, add number at the end if not present // Increment name, add number at the end if not present
// Examples: // Examples:
@ -212,16 +213,30 @@ export class PeerServer extends EventEmitter {
this.broadcast(data); this.broadcast(data);
} else { } else {
// Player is telling someone specifically // Player is telling someone specifically
if (data.to in this.players) { if (!(data.to in this.players)) {
this.send<ChatMessage>(this.players[data.to], data);
} else {
this.send<ErrorMessage>(player, { this.send<ErrorMessage>(player, {
kind: "error", kind: "error",
error: `player not found: ${data.to}` error: `player not found: ${data.to}`
}); });
return;
} }
this.send<ChatMessage>(this.players[data.to], data);
} }
break; break;
// Player wants to change name
case "rename":
// Make sure new name is valid
data.oldname = player.name;
if (data.newname in this.players) {
this.send<ErrorMessage>(player, {
kind: "error",
error: "name not available"
});
return;
}
player.name = data.newname;
this.broadcast<RenameMessage>(data);
break;
// Player is leaving! // Player is leaving!
case "leave-req": case "leave-req":
// If we're leaving, end the server // If we're leaving, end the server

View file

@ -1,14 +1,8 @@
import { ChatMessage, Client, LocalClient, NetworkMessage, PeerClient, PeerServer } from "@/network";
import { ActionTree, Commit } from "vuex"; import { ActionTree, Commit } from "vuex";
import { AppState } from "../types"; import { AppState } from "../types";
import { NetworkState, StartServerOptions, ConnectOptions } from "./types"; import { ConnectOptions, NetworkState, StartServerOptions } from "./types";
import {
PeerServer,
LocalClient,
PeerClient,
NetworkMessage,
Client,
ChatMessage
} from "@/network";
function bindClientEvents(commit: Commit, client: Client) { function bindClientEvents(commit: Commit, client: Client) {
client.on("handshake", () => { client.on("handshake", () => {

View file

@ -1,7 +1,8 @@
import { Client } from "@/network";
import { GetterTree } from "vuex"; import { GetterTree } from "vuex";
import { AppState } from "../types"; import { AppState } from "../types";
import { NetworkState } from "./types"; import { NetworkState } from "./types";
import { Client } from "@/network";
const getters: GetterTree<NetworkState, AppState> = { const getters: GetterTree<NetworkState, AppState> = {
peerID(state): string | null { peerID(state): string | null {
@ -32,6 +33,15 @@ const getters: GetterTree<NetworkState, AppState> = {
return state.peerType; return state.peerType;
}, },
busy(state): boolean {
if (state.peerType == "client") {
if (state.connectionStatus == "connecting") {
return true;
}
}
return false;
},
inRoom(state): boolean { inRoom(state): boolean {
if (state.peerType == "client") { if (state.peerType == "client") {
return state.connectionStatus == "connected"; return state.connectionStatus == "connected";

View file

@ -1,4 +1,5 @@
import { ChatMessage, LocalClient, PeerClient, PeerServer } from "@/network"; import { ChatMessage, LocalClient, PeerClient, PeerServer } from "@/network";
import Vue from "vue";
import { MutationTree } from "vuex"; import { MutationTree } from "vuex";
import { ClientNetworkState, ConnectionStatus, NetworkState, ServerNetworkState } from "./types"; import { ClientNetworkState, ConnectionStatus, NetworkState, ServerNetworkState } from "./types";
@ -36,7 +37,7 @@ const mutations: MutationTree<NetworkState> = {
}, },
playerListChanged(state, players: string[]) { playerListChanged(state, players: string[]) {
state.players = players; Vue.set(state, "players", players);
} }
}; };

View file

@ -1,11 +1,4 @@
import { import { ChatMessage, LocalClient, PeerClient, PeerMetadata, PeerServer, RoomInfo } from "@/network";
PeerClient,
PeerServer,
LocalClient,
RoomInfo,
PeerMetadata,
ChatMessage
} from "@/network";
import Peer from "peerjs"; import Peer from "peerjs";
export type ConnectionStatus = export type ConnectionStatus =

View file

@ -93,6 +93,14 @@
</li> </li>
</ul> </ul>
</section> </section>
<section class="player-options">
<b-field label="Change name">
<b-input :disabled="busy" v-model="wantedName"></b-input>
</b-field>
<b-button @click="changeName" :disabled="!nameAvailable"
>Change name</b-button
>
</section>
</section> </section>
</section> </section>
</template> </template>
@ -211,7 +219,9 @@ import { Component, Vue } from "vue-property-decorator";
import TopNav from "@/components/Navigation/TopNav.vue"; import TopNav from "@/components/Navigation/TopNav.vue";
import { StartServerOptions, ConnectOptions } from "@/store/network/types"; import { StartServerOptions, ConnectOptions } from "@/store/network/types";
import { Action, Getter } from "vuex-class"; import { Action, Getter } from "vuex-class";
import { Client } from "@/network"; import { Client, NetworkMessage } from "@/network";
const networkNS = { namespace: "network" };
@Component({ @Component({
components: { components: {
@ -223,34 +233,41 @@ export default class Lobby extends Vue {
private hostMaxPlayers!: number; private hostMaxPlayers!: number;
private hostPassword!: string; private hostPassword!: string;
private joinSessionID!: string; private joinSessionID!: string;
private busy!: boolean; private wantedName!: string;
@Action("startServer", { namespace: "network" }) @Action("startServer", networkNS)
private startServer!: (options: StartServerOptions) => void; private startServer!: (options: StartServerOptions) => void;
@Action("connect", { namespace: "network" }) @Action("sendMessage", networkNS)
private sendMessage!: (message: NetworkMessage) => void;
@Action("connect", networkNS)
private connect!: (options: ConnectOptions) => void; private connect!: (options: ConnectOptions) => void;
@Getter("inRoom", { namespace: "network" }) @Getter("inRoom", networkNS)
private inRoom!: boolean; private inRoom!: boolean;
@Getter("sessionID", { namespace: "network" }) @Getter("busy", networkNS)
private busy!: boolean;
@Getter("sessionID", networkNS)
private sessionID!: string | null; private sessionID!: string | null;
@Getter("players", { namespace: "network" }) @Getter("players", networkNS)
private players!: string[]; private players!: string[];
private data() { private data() {
return { const playerName =
playerName:
"Guest-" + "Guest-" +
Math.random() Math.random()
.toString() .toString()
.slice(2, 8), .slice(2, 8);
busy: false, return {
playerName,
hostMaxPlayers: 8, hostMaxPlayers: 8,
hostPassword: "", hostPassword: "",
joinSessionID: "" joinSessionID: "",
wantedName: playerName
}; };
} }
@ -262,7 +279,7 @@ export default class Lobby extends Vue {
} }
private async create() { private async create() {
this.busy = true; this.wantedName = this.playerName;
this.startServer({ this.startServer({
playerInfo: { playerInfo: {
name: this.playerName name: this.playerName
@ -275,7 +292,7 @@ export default class Lobby extends Vue {
} }
private async join() { private async join() {
this.busy = true; this.wantedName = this.playerName;
this.connect({ this.connect({
serverID: this.joinSessionID, serverID: this.joinSessionID,
playerInfo: { playerInfo: {
@ -284,6 +301,14 @@ export default class Lobby extends Vue {
}); });
} }
private async changeName() {
this.sendMessage({
kind: "rename",
oldname: this.playerName,
newname: this.wantedName
});
}
private get canJoin(): boolean { private get canJoin(): boolean {
return this.joinSessionID != ""; return this.joinSessionID != "";
} }
@ -300,5 +325,9 @@ export default class Lobby extends Vue {
} }
return `${location.origin}${subpath}/join/${this.sessionID}`; return `${location.origin}${subpath}/join/${this.sessionID}`;
} }
private get nameAvailable(): boolean {
return this.wantedName != "" && !this.players.includes(this.wantedName);
}
} }
</script> </script>