Skip to content

Commit

Permalink
Merge pull request #204 from boostcampwm-2024/dev-fe
Browse files Browse the repository at this point in the history
Dev fe
  • Loading branch information
always97 authored Nov 14, 2024
2 parents 221239a + 1bf2e20 commit 5189268
Show file tree
Hide file tree
Showing 41 changed files with 1,440 additions and 113 deletions.
48 changes: 47 additions & 1 deletion FE/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion FE/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"@emotion/styled": "^11.13.0",
"@mui/material": "^6.1.6",
"@tanstack/react-query": "^5.59.19",
"framer-motion": "^11.11.11",
"lottie-react": "^2.4.0",
"lottie-web": "^5.12.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.27.0",
Expand All @@ -40,4 +43,4 @@
"typescript-eslint": "^8.11.0",
"vite": "^5.4.10"
}
}
}
2 changes: 2 additions & 0 deletions FE/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { MainPage } from './pages/MainPage';
import { GameSetupPage } from './pages/GameSetupPage';
import { GamePage } from './pages/GamePage';
import { QuizSetupPage } from './pages/QuizSetupPage';

function App() {
return (
Expand All @@ -10,6 +11,7 @@ function App() {
<Route path="/" element={<MainPage />} />
<Route path="/game/setup" element={<GameSetupPage />} />
<Route path="/game/:gameId" element={<GamePage />} />
<Route path="/quiz/setup" element={<QuizSetupPage />} />
<Route path="*" element={<div>not found</div>} />
</Routes>
</Router>
Expand Down
178 changes: 178 additions & 0 deletions FE/src/api/mocks/SocketMock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import SocketEvents from '@/constants/socketEvents';
import { SocketDataMap } from '../socketEventTypes';

type SocketEvent = keyof SocketDataMap;

export class SocketMock {
private listenerSet: Record<string, ((...args: unknown[]) => void)[]> = {};
private onAnyListenerList: ((event: string, ...args: unknown[]) => void)[] = [];
constructor(url: string) {
console.log(`Mock WebSocket μ—°κ²°: ${url}`);
}
id = 'memememememe';
connected = true;
on(event: string, listener: (...args: unknown[]) => void) {
if (!this.listenerSet[event]) this.listenerSet[event] = [];
this.listenerSet[event].push(listener);
}
onAny(listener: (...args: unknown[]) => void) {
this.onAnyListenerList.push(listener);
}
emit<T extends SocketEvent>(event: T, data: SocketDataMap[T]['request']) {
//μ—¬κΈ°μ„œ μ„œλ²„μ— 데이터 전솑
switch (event) {
case SocketEvents.CHAT_MESSAGE:
return this.handleChat(data as SocketDataMap[typeof SocketEvents.CHAT_MESSAGE]['request']);
case SocketEvents.JOIN_ROOM:
return this.handleJoin(data as SocketDataMap[typeof SocketEvents.JOIN_ROOM]['request']);
case SocketEvents.UPDATE_POSITION:
return this.handlePosition(
data as SocketDataMap[typeof SocketEvents.UPDATE_POSITION]['request']
);
case SocketEvents.UPDATE_ROOM_OPTION:
return this.handleOption(
data as SocketDataMap[typeof SocketEvents.UPDATE_ROOM_OPTION]['request']
);
case SocketEvents.UPDATE_ROOM_QUIZSET:
return this.handleQuiz(
data as SocketDataMap[typeof SocketEvents.UPDATE_ROOM_QUIZSET]['request']
);
default:
return;
}
}
disconnect() {
this.connected = false;
}

//μ—¬κΈ°μ„œ μ„œλ²„ 이벀트λ₯Ό μ‹€ν–‰μ‹œν‚¨λ‹€.
emitServer<T extends SocketEvent>(event: T, data: SocketDataMap[T]['response']) {
if (this.listenerSet[event]) {
this.listenerSet[event].forEach((e) => e(data));
}
this.onAnyListenerList.forEach((e) => e(event, data));
}
delay(second: number) {
return new Promise<void>((resolve) => {
setTimeout(() => resolve(), second * 1000);
});
}
log(message: string) {
this.emitServer('chatMessage', {
playerId: '',
playerName: '[LOG]',
message: message,
timestamp: 0
});
}
//μ‹œλ“œ 기반 랜덀 ν•¨μˆ˜
SEED = 7777;
random() {
this.SEED = (this.SEED * 16807) % 2147483647;
return (this.SEED - 1) / 2147483646;
}

isCurrentJoin = false;
currentPlayerName = '';
players: {
playerId: string;
playerName: string;
playerPosition: [number, number];
}[] = [];

quiz: {
quiz: string;
endTime: number;
startTime: number;
choiceList: { content: string; order: number }[];
} | null = null;

// μ•„λž˜λŠ” μ„œλ²„ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직
private async handleChat(data: SocketDataMap['chatMessage']['request']) {
await this.delay(0.1);
this.emitServer('chatMessage', {
playerId: this.id,
playerName: this.currentPlayerName,
message: data.message,
timestamp: 0
});
}
private async handleJoin(data: SocketDataMap[typeof SocketEvents.JOIN_ROOM]['request']) {
if (this.isCurrentJoin) return;
this.isCurrentJoin = true;
await this.delay(0.1);
this.currentPlayerName = data.playerName;
const currentPlayer: (typeof this.players)[number] = {
playerId: this.id,
playerName: data.playerName,
playerPosition: [0.5, 0.5]
};
this.emitServer(SocketEvents.JOIN_ROOM, {
players: this.players
});
this.emitServer(SocketEvents.JOIN_ROOM, {
players: [currentPlayer]
});
this.players.push(currentPlayer);
}
private async handlePosition(
data: SocketDataMap[typeof SocketEvents.UPDATE_POSITION]['request']
) {
await this.delay(0.1);
const targetPlayer = this.players.find((p) => p.playerId === this.id);
if (targetPlayer) targetPlayer.playerPosition = data.newPosition;
this.emitServer(SocketEvents.UPDATE_POSITION, {
playerId: this.id,
playerPosition: data.newPosition
});
}
private async handleOption(
data: SocketDataMap[typeof SocketEvents.UPDATE_ROOM_OPTION]['request']
) {
await this.delay(0.1);
this.emitServer(SocketEvents.UPDATE_ROOM_OPTION, {
title: data.title,
gameMode: data.gameMode,
maxPlayerCount: data.maxPlayerCount,
isPublic: data.isPublic
});
}
private async handleQuiz(
data: SocketDataMap[typeof SocketEvents.UPDATE_ROOM_QUIZSET]['request']
) {
await this.delay(0.1);
this.emitServer(SocketEvents.UPDATE_ROOM_QUIZSET, data);
}

//ν€΄μ¦ˆ κ΄€λ ¨ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직
setQuiz(quiz: string, quizSecond: number, choiceList: string[]) {
const COUNT_DOWN_TIME = 3000;
this.quiz = {
quiz,
startTime: Date.now() + COUNT_DOWN_TIME,
endTime: Date.now() + COUNT_DOWN_TIME + quizSecond * 1000,
choiceList: choiceList.map((e, i) => ({ content: e, order: i }))
};
this.emitServer('startQuizTime', this.quiz);
}
calculateScore(answer: number) {
const players = this.players.map((p) => {
const [y, x] = p.playerPosition;
const option =
Math.round(x) + Math.floor(y * Math.ceil((this.quiz?.choiceList.length || 0) / 2)) * 2;
return {
playerId: p.playerId,
isAnswer: option === answer,
score: option === answer ? 22 : 0
};
});
const payload = { answer, players };
this.emitServer('endQuizTime', payload);
}

async progressQuiz(quiz: string, quizSecond: number, choiceList: string[], answer: number) {
this.setQuiz(quiz, quizSecond, choiceList);
await this.delay(3 + quizSecond);
this.calculateScore(answer);
}
}
28 changes: 28 additions & 0 deletions FE/src/api/mocks/socketMocks/SocketMockChat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { SocketMock } from '../SocketMock';

export default class SocketMockChat extends SocketMock {
constructor() {
super('');
this.players = Array(10)
.fill(null)
.map((_, i) => ({
playerId: String(i + 1),
playerName: 'player' + i,
playerPosition: [i / 10, i / 10]
}));
this.test1();
}
// 10λͺ…μ˜ μœ μ €κ°€ μ±„νŒ…μ„ 보냄
async test1() {
for (let i = 0; i < 150; i++) {
await this.delay(0.1);
const index = i % this.players.length;
this.emitServer('chatMessage', {
playerId: this.players[index].playerId,
playerName: this.players[index].playerName,
message: String(i),
timestamp: 0
});
}
}
}
48 changes: 48 additions & 0 deletions FE/src/api/mocks/socketMocks/SocketMockLoadTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { SocketMock } from '../SocketMock';

export default class SocketMockLoadTest extends SocketMock {
constructor() {
super('');
this.players = Array(100)
.fill(null)
.map((_, i) => ({
playerId: String(i + 1),
playerName: 'player' + i,
playerPosition: [this.random(), this.random()]
}));
this.testChat();
this.testMove();
}
// 10λͺ…μ˜ μœ μ €κ°€ μ±„νŒ…μ„ 보냄
async testChat() {
const playerCount = this.players.length;
const testTime = 10;
for (let j = 0; j < testTime; j++) {
//10μ΄ˆλ™μ•ˆ
for (let i = 0; i < playerCount; i++) {
await this.delay(1 / playerCount);
this.emitServer('chatMessage', {
playerId: this.players[i].playerId,
playerName: this.players[i].playerName,
message: 'message' + i,
timestamp: 0
});
}
}
}

async testMove() {
const playerCount = this.players.length;
const testTime = 10;
for (let j = 0; j < testTime; j++) {
//10μ΄ˆλ™μ•ˆ
for (let i = 0; i < playerCount; i++) {
await this.delay(1 / playerCount);
this.emitServer('updatePosition', {
playerId: this.players[i].playerId,
playerPosition: [this.random(), this.random()]
});
}
}
}
}
Loading

0 comments on commit 5189268

Please sign in to comment.