Skip to content

Commit b19eefa

Browse files
Merge pull request #19 from yuru-baku/feature/fusion-2
Feature/fusion 2
2 parents c6058db + 663f1e5 commit b19eefa

File tree

263 files changed

+17055
-13702
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

263 files changed

+17055
-13702
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ build/Release
191191
*/.yarn-integrity
192192

193193
# dotenv environment variable files
194-
*/.env
194+
# */.env
195195
*/.env.development.local
196196
*/.env.test.local
197197
*/.env.production.local

backend/src/app.ts

+45-19
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,61 @@ async function main() {
1616
const wss = new WebSocketServer({ port: 8080 });
1717
wss.on('connection', function connection(ws: WebSocket, req) {
1818
// on connection create new room or join an open room
19-
const room_id = req.url?.match(/(?<=room=)\w*/);
20-
let room: Room;
21-
if (room_id) { // get open room
22-
room = rooms.get(room_id);
23-
if (!room) {
24-
ws.send(JSON.stringify({ error: `Room with id ${room_id} could not be found...`}));
25-
ws.close();
26-
}
27-
console.log('User joined', room_id);
28-
} else { // create new room
29-
room = new Room(db);
19+
const room_id = req.url?.match(/(?<=roomId=)\w*/)?.at(0);
20+
const name = req.url?.match(/(?<=name=)\w*/)?.at(0);
21+
const user_id = req.url?.match(/(?<=userId=)\w*/)?.at(0);
22+
let room: Room|undefined = rooms.get(room_id);
23+
24+
// if (room_id && room_id !== '' && room_id !== 'undefined') { // get open room
25+
// room = rooms.get(room_id);
26+
// if (!room) {
27+
// ws.send(JSON.stringify({ error: `Room with id ${room_id} could not be found...`}));
28+
// ws.close();
29+
// return;
30+
// }
31+
// console.log('User joined', room.id);
32+
if (!room) { // create new room
33+
room = new Room(db, room_id);
3034
while (rooms.get(room.id)) {
3135
console.log('Room was already taken!');
3236
room = new Room(db);
3337
}
3438
rooms.set(room.id, room);
35-
console.log('User created', room_id);
39+
console.log('User created', room.id);
3640
}
3741
// find user and join
38-
let user = new User(ws, '', 'Random')
39-
room.join(user);
40-
ws.send(JSON.stringify({ action: 'joined', data: { roomId: room.id }}));
42+
let user: User;
43+
// check if user tries to reconnect
44+
const _user = room.users.find((user) => user.id === user_id && user.name === name && user.timeout);
45+
if (_user) {
46+
user = _user;
47+
user.ws = ws;
48+
room.reconnect(user);
49+
} else {
50+
user = new User(ws, undefined, name);
51+
room.join(user);
52+
}
53+
ws.send(JSON.stringify({
54+
action: 'connected',
55+
data: {
56+
roomId: room.id,
57+
users: room.getUserInformations(),
58+
you: {
59+
name: name,
60+
id: user.id,
61+
isOwner: user.isOwner
62+
},
63+
state: room.state,
64+
selectedGame: room.selectedGame
65+
}
66+
}));
4167

4268
ws.on('error', console.error);
4369
ws.on('close', data => {
44-
let userCount = room.leave(user); // is he actually leaving?
45-
if (userCount <= 0) {
46-
rooms.delete(room.id);
47-
}
70+
let userCount = room!.leave(user); // is he actually leaving?
71+
// if (userCount <= 0) {
72+
// rooms.delete(room.id);
73+
// }
4874
});
4975
});
5076

backend/src/models/room.ts

+80-26
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ export class Room {
1111
game: MauMau;
1212
db: Db;
1313

14-
constructor(db: Db) {
15-
this.id = 'room_' + (Math.random() + 1).toString(36).substring(7);
14+
constructor(db: Db, id?: string) {
15+
this.id = id || 'room_' + (Math.random() + 1).toString(36).substring(7);
1616
this.users = []; // Users taking part in this game
1717
this.state = 'initialising';
1818
this.selectedGame = 'MauMau';
@@ -21,41 +21,64 @@ export class Room {
2121
}
2222

2323
join(user: User) {
24-
// notify users
25-
this.users.forEach(u => {
26-
u.ws.send(JSON.stringify({
27-
action: 'join',
28-
user: {
29-
id: user.id,
30-
name: user.name
31-
}
32-
}));
33-
});
24+
this.setUpUserConnection(user, 'joined');
25+
3426
// add user to game
3527
this.users.push(user);
3628

3729
// make admin if first
3830
if (this.users.length === 1) {
3931
this.makeUserAdmin(user);
4032
}
33+
}
34+
35+
reconnect(user: User) {
36+
clearTimeout(user.timeout);
37+
user.timeout = undefined;
38+
this.setUpUserConnection(user, 'reconnected');
39+
}
40+
41+
private setUpUserConnection(user: User, connectionAction: 'joined'|'reconnected') {
42+
console.log(user.id, connectionAction, this.id);
43+
44+
// notify users
45+
this.users
46+
.filter(u => u.id != user.id)
47+
.forEach(u => {
48+
u.ws.send(JSON.stringify({
49+
action: connectionAction,
50+
data: {
51+
user: {
52+
id: user.id,
53+
name: user.name
54+
}
55+
}
56+
}));
57+
});
4158

4259
// listen for actions of normal players
4360
const availableActions = [
4461
'drawCard',
4562
'playCard',
4663
'endTurn'
4764
];
65+
const availableRoomActions = [
66+
'getRoomInfo',
67+
];
4868
user.ws.on('message', (msg: string) => {
4969
const data: any = JSON.parse(msg);
5070
if (availableActions.includes(data.action)) {
5171
// @ts-ignore
5272
this.game[data.action](user, data);
73+
} else if (availableRoomActions.includes(data.action)){
74+
// @ts-ignore
75+
this[data.action](user, data);
5376
}
5477
});
5578
}
5679

5780
makeUserAdmin(user: User) {
58-
user.isAdmin = true;
81+
user.isOwner = true;
5982
// listen for actions of admin
6083
const availableGameActions = [
6184
'start',
@@ -78,22 +101,53 @@ export class Room {
78101
}
79102

80103
leave(user: User) {
81-
console.log('leaving room');
82-
this.users = this.users.filter(u => u != user); // remove this user
83-
// notify remaining
84-
this.users.forEach(u => {
85-
u.ws.send(JSON.stringify({
86-
action: 'left',
87-
data: {
88-
id: user.id,
89-
name: user.name
90-
}
91-
}));
92-
});
93-
return this.users.length;
104+
console.log(user.id, 'left', this.id);
105+
this.users
106+
.filter(u => u != user)
107+
.forEach(u => {
108+
u.ws.send(JSON.stringify({
109+
action: 'disconnected',
110+
data: {
111+
id: user.id,
112+
name: user.name
113+
}
114+
}));
115+
});
116+
user.timeout = setTimeout(() => {
117+
console.log('triggered timeout')
118+
this.users = this.users.filter(u => u != user); // remove this user
119+
// notify remaining
120+
this.users.forEach(u => {
121+
u.ws.send(JSON.stringify({
122+
action: 'left',
123+
data: {
124+
id: user.id,
125+
name: user.name
126+
}
127+
}));
128+
});
129+
// return this.users.length;
130+
}, 5 * 60 * 1000);
131+
}
132+
133+
getRoomInfo(user: User) {
134+
user.ws.send(JSON.stringify({
135+
action: 'gotRoomInfo',
136+
data: {
137+
you: { name: user.name, isOwner: user.isOwner, id: user.id },
138+
isLocal: false,
139+
selectedGame: this.selectedGame,
140+
state: this.state,
141+
users: this.getUserInformations()
142+
}
143+
}))
94144
}
95145

96146
selectGame() {
97147
// ToDo add multiple games
98148
}
149+
150+
getUserInformations(): { name: string, isOwner: boolean, id: string, disconnected: boolean }[] {
151+
return this.users.map(user => { return { name: user.name, isOwner: user.isOwner, id: user.id, disconnected: user.timeout !== undefined }})
152+
}
99153
}

backend/src/models/user.ts

+14-5
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,23 @@ export class User {
77
name: string;
88
handcards: string[];
99
isLocal: boolean;
10-
isAdmin: boolean;
10+
isOwner: boolean;
11+
timeout: NodeJS.Timeout|undefined;
1112

12-
constructor(ws: WebSocket, id: string, name: string, isLocal: boolean = false) {
13+
constructor(ws: WebSocket, id: string|undefined, name: string|undefined, isLocal: boolean = false) {
1314
this.ws = ws;
14-
this.id = id;
15-
this.name = name;
15+
if (id) {
16+
this.id = id;
17+
} else {
18+
this.id = 'user_' + (Math.random() + 1).toString(36).substring(7);
19+
}
20+
if (name) {
21+
this.name = name;
22+
} else {
23+
this.name = 'name_' + (Math.random() + 1).toString(36).substring(7);
24+
}
1625
this.handcards = [];
1726
this.isLocal = isLocal;
18-
this.isAdmin = false;
27+
this.isOwner = false;
1928
}
2029
}

frontend-vue/.env

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# the .env file is tracked by git
2+
# for local changes please use a .env.local, those variables will overload the ones below
3+
VITE_BACKEND_ENDPOINT="ws://localhost:8080"

frontend-vue/.eslintrc.cjs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* eslint-env node */
2+
require('@rushstack/eslint-patch/modern-module-resolution')
3+
4+
module.exports = {
5+
root: true,
6+
'extends': [
7+
'plugin:vue/vue3-essential',
8+
'eslint:recommended',
9+
'@vue/eslint-config-typescript',
10+
'@vue/eslint-config-prettier/skip-formatting'
11+
],
12+
parserOptions: {
13+
ecmaVersion: 'latest'
14+
}
15+
}

frontend-vue/.gitignore

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
.DS_Store
12+
dist
13+
dist-ssr
14+
coverage
15+
*.local
16+
17+
/cypress/videos/
18+
/cypress/screenshots/
19+
20+
# Editor directories and files
21+
.vscode/*
22+
!.vscode/extensions.json
23+
.idea
24+
*.suo
25+
*.ntvs*
26+
*.njsproj
27+
*.sln
28+
*.sw?
29+
30+
*.tsbuildinfo

frontend-vue/.prettierrc.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "https://json.schemastore.org/prettierrc",
3+
"semi": false,
4+
"tabWidth": 2,
5+
"singleQuote": true,
6+
"printWidth": 100,
7+
"trailingComma": "none"
8+
}

frontend-vue/.vscode/extensions.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"recommendations": [
3+
"Vue.volar",
4+
"Vue.vscode-typescript-vue-plugin",
5+
"dbaeumer.vscode-eslint",
6+
"esbenp.prettier-vscode"
7+
]
8+
}

frontend-vue/README.md

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# frontend-vue
2+
3+
This template should help get you started developing with Vue 3 in Vite.
4+
5+
## Recommended IDE Setup
6+
7+
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
8+
9+
## Type Support for `.vue` Imports in TS
10+
11+
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
12+
13+
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
14+
15+
1. Disable the built-in TypeScript Extension
16+
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
17+
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
18+
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
19+
20+
## Customize configuration
21+
22+
See [Vite Configuration Reference](https://vitejs.dev/config/).
23+
24+
## Project Setup
25+
26+
```sh
27+
npm install
28+
```
29+
30+
### Compile and Hot-Reload for Development
31+
32+
```sh
33+
npm run dev
34+
```
35+
36+
### Type-Check, Compile and Minify for Production
37+
38+
```sh
39+
npm run build
40+
```
41+
42+
### Lint with [ESLint](https://eslint.org/)
43+
44+
```sh
45+
npm run lint
46+
```

frontend-vue/env.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="vite/client" />

0 commit comments

Comments
 (0)