282 lines
5.7 KiB
Vue
282 lines
5.7 KiB
Vue
<template>
|
|
<section class="lobby">
|
|
<TopNav />
|
|
<section v-if="!inRoom" class="body">
|
|
<section id="info">
|
|
<b-field label="Your name">
|
|
<b-input :disabled="busy" v-model="playerName"></b-input>
|
|
</b-field>
|
|
</section>
|
|
<section id="join">
|
|
<header>
|
|
<h1>Join someone's session</h1>
|
|
</header>
|
|
<b-field label="Session ID" class="only-full">
|
|
<b-input :disabled="busy" v-model="joinSessionID"></b-input>
|
|
</b-field>
|
|
<div class="center submit only-full">
|
|
<b-button
|
|
type="is-primary"
|
|
@click="join"
|
|
class="wide"
|
|
:disabled="busy || !canJoin"
|
|
>
|
|
Join
|
|
</b-button>
|
|
</div>
|
|
<div class="only-mobile">
|
|
<b-field class="full">
|
|
<b-input
|
|
:disabled="busy"
|
|
placeholder="Session ID"
|
|
v-model="joinSessionID"
|
|
></b-input>
|
|
<p class="control">
|
|
<b-button
|
|
type="is-primary"
|
|
@click="join"
|
|
:disabled="busy || !canJoin"
|
|
>
|
|
Join
|
|
</b-button>
|
|
</p>
|
|
</b-field>
|
|
</div>
|
|
</section>
|
|
<section id="host">
|
|
<header>
|
|
<h1>Host a new session</h1>
|
|
</header>
|
|
<div class="columns">
|
|
<div class="column">
|
|
<b-field label="Max players">
|
|
<b-numberinput
|
|
:disabled="busy"
|
|
controls-position="compact"
|
|
v-model="hostMaxPlayers"
|
|
min="2"
|
|
max="8"
|
|
></b-numberinput>
|
|
</b-field>
|
|
</div>
|
|
<div class="column">
|
|
<b-field label="Password">
|
|
<b-input :disabled="busy" v-model="hostPassword"></b-input>
|
|
</b-field>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="center">
|
|
<b-button
|
|
:disabled="busy"
|
|
type="is-primary"
|
|
@click="create"
|
|
class="wide"
|
|
>
|
|
Create
|
|
</b-button>
|
|
</div>
|
|
</section>
|
|
</section>
|
|
<section class="room" v-else>
|
|
<section class="info">
|
|
Session ID: <span class="selectable">{{ sessionID }}</span>
|
|
</section>
|
|
<section class="players">
|
|
Players:
|
|
<ul>
|
|
<li class="selectable" v-for="player in players" :key="player">
|
|
{{ player }}
|
|
</li>
|
|
</ul>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
@import "@/assets/scss/_variables.scss";
|
|
|
|
.lobby {
|
|
background: url("../assets/images/backgrounds/menubg.webp") center;
|
|
background-repeat: no-repeat;
|
|
background-size: cover;
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-flow: column;
|
|
}
|
|
|
|
.body {
|
|
flex: 1;
|
|
display: grid;
|
|
padding: 10px;
|
|
padding-top: 0;
|
|
grid-template: 150px 1fr / 1fr 1fr;
|
|
|
|
#info {
|
|
grid-row: 1;
|
|
grid-column: 1 / end;
|
|
}
|
|
|
|
#join,
|
|
#host {
|
|
grid-row: 2;
|
|
}
|
|
|
|
#join {
|
|
grid-column: 2;
|
|
}
|
|
#host {
|
|
grid-column: 1;
|
|
}
|
|
|
|
section {
|
|
margin: 10px;
|
|
border: 1px solid rgba($white, 20%);
|
|
border-radius: 10px;
|
|
padding: 20px;
|
|
header {
|
|
font-family: $fantasy;
|
|
h1 {
|
|
text-align: center;
|
|
font-size: 18pt;
|
|
}
|
|
margin-bottom: 20px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.wide {
|
|
min-width: 30%;
|
|
margin: 10px auto;
|
|
}
|
|
|
|
.full {
|
|
width: 100%;
|
|
margin: 10px;
|
|
}
|
|
|
|
.center {
|
|
width: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
.full-btn {
|
|
flex: 1;
|
|
:global(.button) {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
.room {
|
|
padding: 10px 20px;
|
|
margin: 10px;
|
|
border: 1px solid rgba($white, 20%);
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.only-mobile {
|
|
display: none;
|
|
}
|
|
|
|
.selectable {
|
|
user-select: all;
|
|
}
|
|
|
|
@media (max-width: 500px) {
|
|
.only-full {
|
|
display: none;
|
|
}
|
|
.only-mobile {
|
|
display: inherit;
|
|
}
|
|
.body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
section {
|
|
padding: 10px;
|
|
header h1 {
|
|
font-size: 14pt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue } from "vue-property-decorator";
|
|
import TopNav from "@/components/Navigation/TopNav.vue";
|
|
import { StartServerOptions, ConnectOptions } from "@/store/network/types";
|
|
import { Action, Getter } from "vuex-class";
|
|
import { Client } from "@/network";
|
|
|
|
@Component({
|
|
components: {
|
|
TopNav
|
|
}
|
|
})
|
|
export default class Lobby extends Vue {
|
|
private playerName!: string;
|
|
private hostMaxPlayers!: number;
|
|
private hostPassword!: string;
|
|
private joinSessionID!: string;
|
|
private busy!: boolean;
|
|
|
|
@Action("startServer", { namespace: "network" })
|
|
private startServer!: (options: StartServerOptions) => void;
|
|
|
|
@Action("connect", { namespace: "network" })
|
|
private connect!: (options: ConnectOptions) => void;
|
|
|
|
@Getter("inRoom", { namespace: "network" })
|
|
private inRoom!: boolean;
|
|
|
|
@Getter("sessionID", { namespace: "network" })
|
|
private sessionID!: string | null;
|
|
|
|
@Getter("players", { namespace: "network" })
|
|
private players!: string[];
|
|
|
|
private data() {
|
|
return {
|
|
playerName:
|
|
"Guest-" +
|
|
Math.random()
|
|
.toString()
|
|
.slice(2, 8),
|
|
busy: false,
|
|
hostMaxPlayers: 8,
|
|
hostPassword: "",
|
|
joinSessionID: ""
|
|
};
|
|
}
|
|
|
|
private async create() {
|
|
this.busy = true;
|
|
this.startServer({
|
|
playerInfo: {
|
|
name: this.playerName
|
|
},
|
|
roomInfo: {
|
|
max_players: this.hostMaxPlayers,
|
|
password: this.hostPassword
|
|
}
|
|
});
|
|
}
|
|
|
|
private async join() {
|
|
this.busy = true;
|
|
this.connect({
|
|
serverID: this.joinSessionID,
|
|
playerInfo: {
|
|
name: this.playerName
|
|
}
|
|
});
|
|
}
|
|
|
|
private get canJoin(): boolean {
|
|
return this.joinSessionID != "";
|
|
}
|
|
}
|
|
</script>
|