Implement creating and joining rooms

This commit is contained in:
Michael Zhang 2020-11-27 01:16:15 -06:00
parent 50f359c1c3
commit 4ba0f326bd
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
7 changed files with 127 additions and 17 deletions

View file

@ -2,7 +2,7 @@ import { Mongo } from "meteor/mongo";
let Players = new Mongo.Collection("players"); let Players = new Mongo.Collection("players");
// let collection = Players.rawCollection(); let collection = Players.rawCollection();
// collection.ensureIndex({ joinCode: 1 }, { unique: true }); collection.ensureIndex({ name: 1, roomId: 1, }, { unique: true });
export default Players; export default Players;

View file

@ -1 +1,2 @@
import "./newGame"; import "./newGame";
import "./joinGame";

View file

@ -0,0 +1,38 @@
import { Meteor } from "meteor/meteor";
import { Random } from "meteor/random";
import { check } from "meteor/check";
import Rooms from "../collections/Rooms.js";
import Players from "../collections/Players.js";
Meteor.methods({
"joinGame": async ({ code, name }) => {
check(code, String);
check(name, String);
name = name.trim();
let room = Rooms.findOne({ joinCode: code });
if (room === undefined) {
throw new Meteor.Error("room-not-found");
}
if (room.state !== "waitingRoom") {
throw new Meteor.Error("room-already-playing");
}
let roomId = room._id;
try {
let playerId = Players.insert({ roomId, name });
} catch (e) {
if (e.code === 11000) {
throw new Meteor.Error("name-collision");
}
}
let joinCode = room.joinCode;
let players = {};
Players.find({ roomId }).forEach((doc) => {
players[doc._id] = doc.name;
});
return { joinCode, players, roomId };
}
});

View file

@ -7,6 +7,8 @@ import Players from "../collections/Players.js";
Meteor.methods({ Meteor.methods({
"newGame": async ({ name }) => { "newGame": async ({ name }) => {
check(name, String); check(name, String);
name = name.trim();
let roomId = null; let roomId = null;
let state = "waitingRoom"; let state = "waitingRoom";
@ -25,16 +27,21 @@ Meteor.methods({
// BulkWriteError // BulkWriteError
if (e.code === 11000) { if (e.code === 11000) {
remainingAttempts -= 1; remainingAttempts -= 1;
} else {
console.log("UNCAUGHT", e);
} }
} }
} }
let playerId = Players.insert({ roomId, name }); let playerId = Players.insert({ roomId, name });
Rooms.update(roomId, { $set: { owner: playerId } });
if (remainingAttempts == 0 && roomId === null) { if (remainingAttempts == 0 && roomId === null) {
return "failed"; throw new Meteor.Error("no-more-rooms");
} }
return { playerId, roomId, joinCode }; let players = {};
players[playerId] = name;
return { players, roomId, joinCode };
}, },
}); });

View file

@ -1,15 +1,22 @@
<template> <template>
<div> <div>
<component v-bind:is="whatScreen"></component> <component
v-bind:is="whatScreen"
v-bind="currentRoom"
v-on:newGame="newGame"
v-on:joinGame="joinGame"
></component>
</div> </div>
</template> </template>
<script> <script>
import Lobby from './components/Lobby.vue' import Lobby from './components/Lobby.vue'
import WaitingRoom from './components/WaitingRoom.vue'
export default { export default {
components: { components: {
Lobby, Lobby,
WaitingRoom,
}, },
data() { data() {
@ -18,6 +25,18 @@ export default {
whatScreen: Lobby, whatScreen: Lobby,
}; };
}, },
methods: {
newGame: function(args) {
this.currentRoom = args;
this.whatScreen = WaitingRoom;
},
joinGame: function(args) {
this.currentRoom = args;
this.whatScreen = WaitingRoom;
},
}
} }
</script> </script>

View file

@ -2,6 +2,8 @@
<div> <div>
<h1>LOBBY</h1> <h1>LOBBY</h1>
<div id="error">{{ errorMessage }}</div>
<form v-on:submit.prevent="newGame"> <form v-on:submit.prevent="newGame">
<input <input
type="text" type="text"
@ -11,16 +13,30 @@
v-model="newGameName" v-model="newGameName"
:disabled="loading" :disabled="loading"
/> />
<button type="submit">new game</button> <button type="submit" :disabled="loading">new game</button>
</form> </form>
<p>or</p> <p>or</p>
<div> <form v-on:submit.prevent="joinGame">
<input type="text" autocomplete="off" name="name" placeholder="what's your name?" /> <input
<input type="text" autocomplete="off" name="code" placeholder="join code" /> type="text"
<button id="joingame-btn">join game</button> autocomplete="off"
</div> required
placeholder="join code"
v-model="joinGameCode"
:disabled="loading"
/>
<input
type="text"
autocomplete="off"
required
placeholder="what's your name?"
v-model="joinGameName"
:disabled="loading"
/>
<button type="submit" :disabled="loading">join game</button>
</form>
</div> </div>
</template> </template>
@ -32,20 +48,45 @@ export default {
return { return {
loading: false, loading: false,
newGameName: "", newGameName: "",
joinGameName: "",
joinGameCode: "",
errorMessage: "",
}; };
}, },
methods: { methods: {
newGame: function (evt) { newGame: function(evt) {
loading = true; this.loading = true;
let name = this.newGameName; let name = this.newGameName;
Meteor.call("newGame", { name }, (err, res) => { Meteor.call("newGame", { name }, (err, res) => {
console.log(err, res); if (err !== undefined) {
this.errorMessage = err.message;
this.loading = false;
return;
}
this.$emit("newGame", res);
}); });
} },
joinGame: function(evt) {
this.loading = true;
let name = this.joinGameName;
let code = this.joinGameCode;
Meteor.call("joinGame", { code, name }, (err, res) => {
if (err !== undefined) {
this.errorMessage = err.message;
this.loading = false;
return;
}
this.$emit("joinGame", res);
});
},
} }
} }
</script> </script>
<style scoped> <style scoped>
#error {
color: red;
}
</style> </style>

View file

@ -1,10 +1,14 @@
<template> <template>
<div>
<h1>Waiting for players...</h1>
<p>Join code: {{ joinCode.toUpperCase() }}</p>
<p>Players: {{ players }}</p>
</div>
</template> </template>
<script> <script>
export default { export default {
props: ["joinCode", "players"],
} }
</script> </script>