Set up simple chat server

This commit is contained in:
2023-01-15 16:09:50 +01:00
parent 573fac40cc
commit 28e93b1fa3
4 changed files with 250 additions and 24 deletions
+35 -3
View File
@@ -1,7 +1,39 @@
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
<script lang="ts">
import Game from './components/Game.vue'
/*
Basically just opens the websocket connection to the server,
waits for the 'init' message and passes the initial state to the Game
component. Once the initial state has been received, no more event are processed.
*/
export default {
components: {
Game
},
data() {
return {
ws: new WebSocket('ws://localhost:5000/glebby'),
model: null
}
},
created() {
const messageListener = (ev: MessageEvent) => {
const message = JSON.parse(ev.data)
const payload = message.payload
if (payload.type === 'init') {
console.log('Received initial game state:')
console.log(payload.state)
this.model = payload.state
this.ws.removeEventListener('message', messageListener)
}
}
this.ws.addEventListener('message', messageListener)
}
}
</script>
<template>
<HelloWorld msg="Vite + Vue" />
<Game v-if="model" :ws="ws" :model="model" />
</template>
+102
View File
@@ -0,0 +1,102 @@
<script lang="ts">
import { defineComponent, PropType } from 'vue';
interface Player {
id: number,
name: string
}
interface Model {
yourId: number,
players: Player[]
}
function getPlayer(model: Model, id: number): Player | undefined {
return model.players.find(player => player.id === id)
}
/*
Handles all game business. Sends (local) player input to the server for distribution.
Receives player input from the server and manages state accordingly.
*/
export default defineComponent({
props: {
ws: { type: WebSocket, required: true },
model: { type: Object as PropType<Model>, required: true }
},
data() {
return {
chatMessages: [] as string[],
playerName: '',
chatMessage: ''
}
},
created() {
this.ws.addEventListener('message', (ev) => {
const message = JSON.parse(ev.data)
const payload = message.payload
console.log(`Message from player ${message.from}:`)
console.log(payload)
switch (payload.type) {
case 'join':
this.model.players.push({
id: message.from,
name: ''
})
break
case 'leave':
this.model.players = this.model.players.filter(player => player.id !== message.from)
break
case 'chat':
this.chatMessages.push(payload.message)
break
case 'set-name':
getPlayer(this.model, message.from)!.name = payload.name
break
}
})
},
methods: {
setName() {
this.ws.send(JSON.stringify({
type: 'set-name',
name: this.playerName
}))
},
sendChat() {
if (this.chatMessage === '') {
return
}
this.ws.send(JSON.stringify({
type: 'chat',
message: this.chatMessage
}))
this.chatMessage = ''
}
}
})
</script>
<template>
<pre>{{ JSON.stringify(model, null, 2) }}</pre>
<h1>I am #{{ model.yourId }}</h1>
<form @submit.prevent="setName">
<input v-model="playerName" placeholder="enter your name...">
<button >set name</button>
</form>
<form @submit.prevent="sendChat">
<input v-model="chatMessage">
<button>Post</button>
</form>
<h2>players</h2>
<ul v-if="model">
<li v-for="player in model.players" :key="player.id">{{ player.name }}#{{ player.id }}</li>
</ul>
<h2>chat</h2>
<ul v-if="model">
<li v-for="message in chatMessages">{{ message }}</li>
</ul>
</template>
@@ -1,15 +0,0 @@
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
</div>
</template>