Skip to content

Commit

Permalink
Merge pull request #19 from yuru-baku/feature/fusion-2
Browse files Browse the repository at this point in the history
Feature/fusion 2
  • Loading branch information
some-random-int authored Feb 15, 2024
2 parents c6058db + 663f1e5 commit b19eefa
Show file tree
Hide file tree
Showing 263 changed files with 17,055 additions and 13,702 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ build/Release
*/.yarn-integrity

# dotenv environment variable files
*/.env
# */.env
*/.env.development.local
*/.env.test.local
*/.env.production.local
Expand Down
64 changes: 45 additions & 19 deletions backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,61 @@ async function main() {
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function connection(ws: WebSocket, req) {
// on connection create new room or join an open room
const room_id = req.url?.match(/(?<=room=)\w*/);
let room: Room;
if (room_id) { // get open room
room = rooms.get(room_id);
if (!room) {
ws.send(JSON.stringify({ error: `Room with id ${room_id} could not be found...`}));
ws.close();
}
console.log('User joined', room_id);
} else { // create new room
room = new Room(db);
const room_id = req.url?.match(/(?<=roomId=)\w*/)?.at(0);
const name = req.url?.match(/(?<=name=)\w*/)?.at(0);
const user_id = req.url?.match(/(?<=userId=)\w*/)?.at(0);
let room: Room|undefined = rooms.get(room_id);

// if (room_id && room_id !== '' && room_id !== 'undefined') { // get open room
// room = rooms.get(room_id);
// if (!room) {
// ws.send(JSON.stringify({ error: `Room with id ${room_id} could not be found...`}));
// ws.close();
// return;
// }
// console.log('User joined', room.id);
if (!room) { // create new room
room = new Room(db, room_id);
while (rooms.get(room.id)) {
console.log('Room was already taken!');
room = new Room(db);
}
rooms.set(room.id, room);
console.log('User created', room_id);
console.log('User created', room.id);
}
// find user and join
let user = new User(ws, '', 'Random')
room.join(user);
ws.send(JSON.stringify({ action: 'joined', data: { roomId: room.id }}));
let user: User;
// check if user tries to reconnect
const _user = room.users.find((user) => user.id === user_id && user.name === name && user.timeout);
if (_user) {
user = _user;
user.ws = ws;
room.reconnect(user);
} else {
user = new User(ws, undefined, name);
room.join(user);
}
ws.send(JSON.stringify({
action: 'connected',
data: {
roomId: room.id,
users: room.getUserInformations(),
you: {
name: name,
id: user.id,
isOwner: user.isOwner
},
state: room.state,
selectedGame: room.selectedGame
}
}));

ws.on('error', console.error);
ws.on('close', data => {
let userCount = room.leave(user); // is he actually leaving?
if (userCount <= 0) {
rooms.delete(room.id);
}
let userCount = room!.leave(user); // is he actually leaving?
// if (userCount <= 0) {
// rooms.delete(room.id);
// }
});
});

Expand Down
106 changes: 80 additions & 26 deletions backend/src/models/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export class Room {
game: MauMau;
db: Db;

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

join(user: User) {
// notify users
this.users.forEach(u => {
u.ws.send(JSON.stringify({
action: 'join',
user: {
id: user.id,
name: user.name
}
}));
});
this.setUpUserConnection(user, 'joined');

// add user to game
this.users.push(user);

// make admin if first
if (this.users.length === 1) {
this.makeUserAdmin(user);
}
}

reconnect(user: User) {
clearTimeout(user.timeout);
user.timeout = undefined;
this.setUpUserConnection(user, 'reconnected');
}

private setUpUserConnection(user: User, connectionAction: 'joined'|'reconnected') {
console.log(user.id, connectionAction, this.id);

// notify users
this.users
.filter(u => u.id != user.id)
.forEach(u => {
u.ws.send(JSON.stringify({
action: connectionAction,
data: {
user: {
id: user.id,
name: user.name
}
}
}));
});

// listen for actions of normal players
const availableActions = [
'drawCard',
'playCard',
'endTurn'
];
const availableRoomActions = [
'getRoomInfo',
];
user.ws.on('message', (msg: string) => {
const data: any = JSON.parse(msg);
if (availableActions.includes(data.action)) {
// @ts-ignore
this.game[data.action](user, data);
} else if (availableRoomActions.includes(data.action)){
// @ts-ignore
this[data.action](user, data);
}
});
}

makeUserAdmin(user: User) {
user.isAdmin = true;
user.isOwner = true;
// listen for actions of admin
const availableGameActions = [
'start',
Expand All @@ -78,22 +101,53 @@ export class Room {
}

leave(user: User) {
console.log('leaving room');
this.users = this.users.filter(u => u != user); // remove this user
// notify remaining
this.users.forEach(u => {
u.ws.send(JSON.stringify({
action: 'left',
data: {
id: user.id,
name: user.name
}
}));
});
return this.users.length;
console.log(user.id, 'left', this.id);
this.users
.filter(u => u != user)
.forEach(u => {
u.ws.send(JSON.stringify({
action: 'disconnected',
data: {
id: user.id,
name: user.name
}
}));
});
user.timeout = setTimeout(() => {
console.log('triggered timeout')
this.users = this.users.filter(u => u != user); // remove this user
// notify remaining
this.users.forEach(u => {
u.ws.send(JSON.stringify({
action: 'left',
data: {
id: user.id,
name: user.name
}
}));
});
// return this.users.length;
}, 5 * 60 * 1000);
}

getRoomInfo(user: User) {
user.ws.send(JSON.stringify({
action: 'gotRoomInfo',
data: {
you: { name: user.name, isOwner: user.isOwner, id: user.id },
isLocal: false,
selectedGame: this.selectedGame,
state: this.state,
users: this.getUserInformations()
}
}))
}

selectGame() {
// ToDo add multiple games
}

getUserInformations(): { name: string, isOwner: boolean, id: string, disconnected: boolean }[] {
return this.users.map(user => { return { name: user.name, isOwner: user.isOwner, id: user.id, disconnected: user.timeout !== undefined }})
}
}
19 changes: 14 additions & 5 deletions backend/src/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,23 @@ export class User {
name: string;
handcards: string[];
isLocal: boolean;
isAdmin: boolean;
isOwner: boolean;
timeout: NodeJS.Timeout|undefined;

constructor(ws: WebSocket, id: string, name: string, isLocal: boolean = false) {
constructor(ws: WebSocket, id: string|undefined, name: string|undefined, isLocal: boolean = false) {
this.ws = ws;
this.id = id;
this.name = name;
if (id) {
this.id = id;
} else {
this.id = 'user_' + (Math.random() + 1).toString(36).substring(7);
}
if (name) {
this.name = name;
} else {
this.name = 'name_' + (Math.random() + 1).toString(36).substring(7);
}
this.handcards = [];
this.isLocal = isLocal;
this.isAdmin = false;
this.isOwner = false;
}
}
3 changes: 3 additions & 0 deletions frontend-vue/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# the .env file is tracked by git
# for local changes please use a .env.local, those variables will overload the ones below
VITE_BACKEND_ENDPOINT="ws://localhost:8080"
15 changes: 15 additions & 0 deletions frontend-vue/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
}
}
30 changes: 30 additions & 0 deletions frontend-vue/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
.DS_Store
dist
dist-ssr
coverage
*.local

/cypress/videos/
/cypress/screenshots/

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

*.tsbuildinfo
8 changes: 8 additions & 0 deletions frontend-vue/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none"
}
8 changes: 8 additions & 0 deletions frontend-vue/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"recommendations": [
"Vue.volar",
"Vue.vscode-typescript-vue-plugin",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
46 changes: 46 additions & 0 deletions frontend-vue/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frontend-vue

This template should help get you started developing with Vue 3 in Vite.

## Recommended IDE Setup

[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).

## Type Support for `.vue` Imports in TS

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.

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:

1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.

## Customize configuration

See [Vite Configuration Reference](https://vitejs.dev/config/).

## Project Setup

```sh
npm install
```

### Compile and Hot-Reload for Development

```sh
npm run dev
```

### Type-Check, Compile and Minify for Production

```sh
npm run build
```

### Lint with [ESLint](https://eslint.org/)

```sh
npm run lint
```
1 change: 1 addition & 0 deletions frontend-vue/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
Loading

0 comments on commit b19eefa

Please sign in to comment.