It works!

master
Julius 2019-07-07 17:28:00 +02:00
parent 1040f980a0
commit 089e6021f9
9 changed files with 259 additions and 21 deletions

View File

@ -1,7 +1,7 @@
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/">Start</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>

7
src/models/Answer.ts Normal file
View File

@ -0,0 +1,7 @@
export class Answer {
public constructor(public text: string[], public uuid: string = "", public index: number = -1) {
this.text = text;
this.index! = index;
this.uuid! = uuid;
}
}

17
src/models/Message.ts Normal file
View File

@ -0,0 +1,17 @@
export enum MessageType {
JOIN = "JOIN",
START = "START",
ANSWER = "ANSWER",
PICK = "PICK",
ROOM = "ROOM",
}
export class Message {
public msgtype: MessageType;
public data: any;
public constructor(msgtype: MessageType, data: any) {
this.msgtype = msgtype;
this.data = data;
}
}

13
src/models/Room.ts Normal file
View File

@ -0,0 +1,13 @@
import { Player } from "./Player";
export class Room {
public code: string;
public czar: number = 0;
public players: Player[] = [];
public started: boolean = false;
// tslint:disable-next-line:variable-name
public played_cards: number[] = [];
public constructor(code: string) {
this.code = code;
}
}

View File

@ -1,6 +1,7 @@
import Vue from "vue";
import Router from "vue-router";
import JoinRoom from "./views/JoinRoom.vue";
import Game from "./views/Game.vue";
Vue.use(Router);
@ -13,6 +14,11 @@ export default new Router({
name: "home",
component: JoinRoom,
},
{
path: "/game/:code",
name: "game",
component: Game,
},
{
path: "/about",
name: "about",

View File

@ -1,9 +1,12 @@
import axios from "axios";
import { Message, MessageType } from "../models/Message";
import { Answer } from "../models/Answer";
const webProt = "http://";
const baseURL = "localhost:8000";
const axios_api = axios.create({
baseURL,
export const axios_api = axios.create({
baseURL: webProt + baseURL,
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
@ -11,21 +14,62 @@ const axios_api = axios.create({
});
export class Game {
public uuid!: string;
public owner!: boolean;
public you!: number;
private pub: WebSocket;
private sub: WebSocket;
private uuid: string;
constructor(code: string, name: string) {
this.pub = new WebSocket(`://localhost:8000/ws/room/${code}/pub`);
this.sub = new WebSocket(`://localhost:8000/ws/room/${code}/sub`);
constructor(code: string, name: string, message_callback: (message: Message) => void) {
this.pub = new WebSocket(`ws://${baseURL}/ws/room/${code}/pub`);
this.sub = new WebSocket(`ws://${baseURL}/ws/room/${code}/sub`);
this.pub.addEventListener("open", (event) => {
// JOIN
console.info("pub-ws connected");
const join = new Message(MessageType.JOIN, name);
this.pub.send(JSON.stringify(join));
});
this.pub.addEventListener("message", (event) => {
const data: Player = JSON.parse(event.data);
const msg: Message = JSON.parse(event.data);
if (msg.msgtype === MessageType.JOIN) {
this.uuid = msg.data.uuid;
this.owner = msg.data.owner;
this.you = msg.data.you;
} else {
message_callback(msg);
}
});
this.sub.addEventListener("open", (event) => {
console.info("sub-ws connected");
});
this.sub.addEventListener("message", (event) => {
if (event.data === "1") {
console.info("Hyperadvanced one way websocket connection established");
return;
}
console.log(event.data);
const msg: Message = JSON.parse(event.data);
message_callback(msg);
});
}
public start_game() {
const msg = new Message(MessageType.START, this.uuid);
this.pub.send(JSON.stringify(msg));
}
public send_answer(text: string[]) {
const answers = new Answer(text, this.uuid);
const msg = new Message(MessageType.ANSWER, JSON.stringify(answers));
this.pub.send(JSON.stringify(msg));
}
public pick_answer(answer: Answer) {
answer.uuid = this.uuid;
const msg = new Message(MessageType.PICK, JSON.stringify(answer));
this.pub.send(JSON.stringify(msg));
}
}

109
src/views/Game.vue Normal file
View File

@ -0,0 +1,109 @@
<template>
<div id="game">
<h1>
Room:
<a>{{ this.$route.params.code }}</a>
</h1>
<h2>Your name is: {{ this.name }}</h2>
<ul>
<li v-for="player in this.room.players">{{ player.name }}: {{player.points}}</li>
</ul>
<button v-if="this.game.owner && !this.room.started" @click="this.start_game">Stort</button>
<span v-show="this.card" v-html="this.card.text" />
<ul v-show="this.card && !this.czar()">
<li v-for="blank in this.card.pick">
Card {{blank}}:
<input type="text" v-model="inputs[blank - 1]" :disabled="input_blocked" />
</li>
<li>
<button @click="this.send_answers" v-show="!input_blocked && room.started">Submit Answers</button>
</li>
</ul>
<ul>
<li v-for="ans in this.answers">
<span v-for="t in ans.text">{{ t }},&nbsp;</span>
<button @click="pick(ans)" v-show="czar()">Pick</button>
</li>
</ul>
</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { Game, axios_api } from "../util/api";
import { Message, MessageType } from "../models/Message";
import { Room } from "../models/Room";
import { Card } from "../models/Card";
import { Answer } from "../models/Answer";
@Component({
name: "Game",
})
export default class GameVueView extends Vue {
private game: Game = {};
private room: Room = {};
private card: Card = {};
private inputs: string[] = [];
private input_blocked: boolean = false;
private answers: Answer[] = [];
private name: string;
/**
* Lifecycle hooks
*/
private async mounted() {
this.name = this.$route.query.name || prompt("What is your nickname?");
if (name && this.$route.params.code.length > 3) {
this.name = name as string;
const room = await axios_api.get(`/room/${this.$route.params.code}`);
if (room.status === 200 && !room.data.started) {
this.game = new Game(this.$route.params.code, name, this.on_message);
}
}
}
private start_game() {
this.game.start_game();
}
private send_answers() {
this.input_blocked = true;
this.game.send_answer(this.inputs);
}
private czar(): boolean {
return this.game.you === this.room.czar;
}
private pick(ans: Answer) {
this.game.pick_answer(ans);
}
private on_message(message: Message) {
switch (message.msgtype) {
case MessageType.JOIN:
break;
case MessageType.START:
this.answers = [];
this.inputs = [];
this.input_blocked = false;
this.card = message.data.card as Card;
break;
case MessageType.ROOM:
this.room = message.data as Room;
break;
case MessageType.ANSWER:
this.answers = message.data as Answer[];
break;
case MessageType.PICK:
alert(message.data.text);
break;
}
}
}
</script>
<style lang="scss">
</style>

View File

@ -1,15 +1,25 @@
<template>
<div id="joinroom">
<label class="code-label" for="code">Room Code:</label>
<input id="code" type="text" v-model="code" placeholder="Enter code here" minlength="4" />
<label class="name-label" for>Name:</label>
<input id="name" type="text" placeholder="Enter a username" maxlength="25" />
<input
required
id="name"
v-model="name"
type="text"
placeholder="Enter a username"
maxlength="25"
minlength="1"
/>
<label class="code-label" for="code">Room Code:</label>
<input id="code" type="text" v-model="code" placeholder="Optional room code" minlength="4" />
<button id="join">Join!</button>
<button @click="checkRoom" id="join">Join!</button>
</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { axios_api } from "../util/api";
import {Room} from "../models/Room";
@Component({
name: "JoinRoom",
@ -17,6 +27,29 @@ import { Component, Vue } from "vue-property-decorator";
export default class JoinRoom extends Vue {
private code: string = "";
private name: string = "";
private checkRoom() {
if (this.name.length < 1 || this.name.length > 25) {
return;
}
if (this.code.length >= 4) {
this.code = this.code.trim();
axios_api
.get(`/room/${this.code}`)
.then((data) => {
this.$router.push(`/game/${this.code}?name=${this.name}`);
})
.catch((response) => {
console.log("Error?" + response);
alert("Sadly, this room does not exist...");
});
} else if (this.code.length === 0) {
axios_api.post("/room").then((data) => {
const room: Room = data.data;
this.$router.push(`/game/${room.code}?name=${this.name}`);
});
}
}
}
</script>
<style lang="scss">
@ -27,20 +60,20 @@ export default class JoinRoom extends Vue {
}
.code-label {
grid-row: 1;
grid-row: 2;
grid-column: 2;
min-width: 100px;
}
#code {
grid-row: 1;
grid-row: 2;
grid-column: 3;
}
.name-label {
grid-row: 2;
grid-row: 1;
grid-column: 2;
}
#name {
grid-row: 2;
grid-row: 1;
grid-column: 3;
}

View File

@ -9,11 +9,20 @@
]
},
"rules": {
"quotemark": [true, "double"],
"indent": [true, "spaces", 4],
"quotemark": [
true,
"double"
],
"indent": [
true,
"spaces",
4
],
"no-console": false,
"interface-name": false,
"ordered-imports": false,
"object-literal-sort-keys": false,
"no-consecutive-blank-lines": false
"no-consecutive-blank-lines": false,
"variable-name": false
}
}
}