Merge pull request #4 from Degulleo/DO-49-서버-내-항복-무승부요청-소켓
DO-49 서버 멀티 플레이를 위한 기능 작업
This commit is contained in:
commit
26812781a2
8
app.js
8
app.js
@ -49,9 +49,9 @@ async function connectDB(){
|
|||||||
// 연결 종료 처리
|
// 연결 종료 처리
|
||||||
process.on("SIGINT", async ()=> {
|
process.on("SIGINT", async ()=> {
|
||||||
await client.close();
|
await client.close();
|
||||||
console.log("Database Connected");
|
console.log("Database Disconnected");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
})
|
});
|
||||||
} catch (err){
|
} catch (err){
|
||||||
console.error("DB 연결 실패: " + err);
|
console.error("DB 연결 실패: " + err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@ -78,12 +78,12 @@ app.use('/users', usersRouter);
|
|||||||
app.use('/leaderboard', leaderboardRouter);
|
app.use('/leaderboard', leaderboardRouter);
|
||||||
app.use('/coins', coinsRouter);
|
app.use('/coins', coinsRouter);
|
||||||
|
|
||||||
// catch 404 and forward to error handler
|
// catch 404 and forward to error handlers
|
||||||
app.use(function(req, res, next) {
|
app.use(function(req, res, next) {
|
||||||
next(createError(404));
|
next(createError(404));
|
||||||
});
|
});
|
||||||
|
|
||||||
// error handler
|
// error handlers
|
||||||
app.use(function(err, req, res, next) {
|
app.use(function(err, req, res, next) {
|
||||||
// set locals, only providing error in development
|
// set locals, only providing error in development
|
||||||
res.locals.message = err.message;
|
res.locals.message = err.message;
|
||||||
|
4
bin/www
4
bin/www
@ -7,7 +7,7 @@
|
|||||||
var app = require('../app');
|
var app = require('../app');
|
||||||
var debug = require('debug')('tictactoe-server:server');
|
var debug = require('debug')('tictactoe-server:server');
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
var game = require('../game');
|
var socketModule = require('../socket');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get port from environment and store in Express.
|
* Get port from environment and store in Express.
|
||||||
@ -25,7 +25,7 @@ var server = http.createServer(app);
|
|||||||
/**
|
/**
|
||||||
* 게임 서버 실행
|
* 게임 서버 실행
|
||||||
*/
|
*/
|
||||||
game(server);
|
socketModule(server);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen on provided port, on all network interfaces.
|
* Listen on provided port, on all network interfaces.
|
||||||
|
56
game.js
56
game.js
@ -1,56 +0,0 @@
|
|||||||
const {v4: uuidv4} = require('uuid');
|
|
||||||
|
|
||||||
module.exports = function(server) {
|
|
||||||
|
|
||||||
const io = require('socket.io')(server, {
|
|
||||||
transports: ['websocket']
|
|
||||||
});
|
|
||||||
|
|
||||||
// 방 정보
|
|
||||||
var rooms = [];
|
|
||||||
var socketRooms = new Map();
|
|
||||||
|
|
||||||
io.on('connection', function(socket) {
|
|
||||||
console.log('Connected: ' + socket.id);
|
|
||||||
if (rooms.length > 0) {
|
|
||||||
var roomId = rooms.shift();
|
|
||||||
socket.join(roomId)
|
|
||||||
socket.emit('joinRoom', { roomId: roomId });
|
|
||||||
socket.to(roomId).emit('startGame', { roomId: socket.id });
|
|
||||||
socketRooms.set(socket.id, roomId);
|
|
||||||
} else {
|
|
||||||
var roomId = uuidv4();
|
|
||||||
socket.join(roomId);
|
|
||||||
socket.emit('createRoom', { room: roomId });
|
|
||||||
rooms.push(roomId);
|
|
||||||
socketRooms.set(socket.id, roomId);
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.on('leaveRoom', function(roomData) {
|
|
||||||
socket.leave(roomData.roomId);
|
|
||||||
socket.emit('exitRoom');
|
|
||||||
socket.to(roomData.roomId).emit('endGame');
|
|
||||||
|
|
||||||
// 방 만든 후 혼자 들어갔다가 나갈 때 rooms에서 방 삭제
|
|
||||||
var roomId = socketRooms.get(socket.id);
|
|
||||||
const roomIdx = rooms.indexOf(roomId);
|
|
||||||
if (roomIdx !== -1) {
|
|
||||||
rooms.splice(roomIdx, 1);
|
|
||||||
console.log('Room removed:', roomId);
|
|
||||||
}
|
|
||||||
|
|
||||||
socketRooms.delete(socket.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('doPlayer', function(moveData) {
|
|
||||||
const roomId = moveData.roomId;
|
|
||||||
const position = moveData.position;
|
|
||||||
|
|
||||||
socket.to(roomId).emit('doOpponent', { position: position });
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('disconnect', function(reason) {
|
|
||||||
console.log('Disconnected: ' + socket.id + ', Reason: ' + reason);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
@ -165,11 +165,14 @@ router.post("/score-update", async function (req, res, next) {
|
|||||||
requiredPoints = 10; // 1~4급은 10점 필요
|
requiredPoints = 10; // 1~4급은 10점 필요
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let advancement = 0;
|
||||||
|
|
||||||
// 승급 확인
|
// 승급 확인
|
||||||
if (userScore >= requiredPoints) {
|
if (userScore >= requiredPoints) {
|
||||||
if (userRating > 1) { // 1급보다 높은 급수인 경우만 승급 가능
|
if (userRating > 1) { // 1급보다 높은 급수인 경우만 승급 가능
|
||||||
userRating -= 1; // 급수 상승 (숫자는 작을수록 높은 급수)
|
userRating -= 1; // 급수 상승 (숫자는 작을수록 높은 급수)
|
||||||
userScore = 0; // 승급 후 포인트 초기화
|
userScore = 0; // 승급 후 포인트 초기화
|
||||||
|
advancement++;
|
||||||
} else {
|
} else {
|
||||||
// 1급인 경우 더 이상 승급 불가능, 최대 포인트로 유지
|
// 1급인 경우 더 이상 승급 불가능, 최대 포인트로 유지
|
||||||
userScore = requiredPoints;
|
userScore = requiredPoints;
|
||||||
@ -181,6 +184,7 @@ router.post("/score-update", async function (req, res, next) {
|
|||||||
if (userRating < 18) { // 18급보다 낮은 급수인 경우만 강등 가능
|
if (userRating < 18) { // 18급보다 낮은 급수인 경우만 강등 가능
|
||||||
userRating += 1; // 급수 하락 (숫자가 커짐)
|
userRating += 1; // 급수 하락 (숫자가 커짐)
|
||||||
userScore = 0; // 강등 후 포인트 초기화
|
userScore = 0; // 강등 후 포인트 초기화
|
||||||
|
advancement--
|
||||||
} else {
|
} else {
|
||||||
// 18급인 경우 더 이상 강등 불가능, 최소 포인트로 유지
|
// 18급인 경우 더 이상 강등 불가능, 최소 포인트로 유지
|
||||||
userScore = -requiredPoints + 1;
|
userScore = -requiredPoints + 1;
|
||||||
@ -210,6 +214,8 @@ router.post("/score-update", async function (req, res, next) {
|
|||||||
score: Number(userScore),
|
score: Number(userScore),
|
||||||
win: Number(winCount),
|
win: Number(winCount),
|
||||||
lose: Number(loseCount),
|
lose: Number(loseCount),
|
||||||
|
// 승급, 강등 여부 추가 -1 :강등, 0: 변화 없음 , 1: 승급
|
||||||
|
isAdvancement: Number(advancement),
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
138
socket/handlers/gameEvents.js
Normal file
138
socket/handlers/gameEvents.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
const { logger } = require('../../utils/logger');
|
||||||
|
|
||||||
|
module.exports = function(io, socket, gameState) {
|
||||||
|
// 플레이어 움직임 처리
|
||||||
|
socket.on('doPlayer', function(moveData) {
|
||||||
|
try {
|
||||||
|
const roomId = moveData.roomId;
|
||||||
|
const position = moveData.position;
|
||||||
|
|
||||||
|
socket.to(roomId).emit('doOpponent', { position: position });
|
||||||
|
|
||||||
|
logger.debug(`플레이어 ${socket.id}의 움직임, 위치: ${position}, 방: ${roomId}`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`플레이어 움직임 처리 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "움직임 처리 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 항복 요청
|
||||||
|
socket.on('requestSurrender', function(data) {
|
||||||
|
try {
|
||||||
|
const roomId = data.roomId;
|
||||||
|
const message = "상대방이 항복했습니다.";
|
||||||
|
|
||||||
|
socket.to(roomId).emit('doSurrender', { message });
|
||||||
|
socket.emit('surrenderConfirmed', { message: "항복 요청이 전송되었습니다." });
|
||||||
|
|
||||||
|
logger.info(`항복 요청: 플레이어 ${socket.id}, 방 ${roomId}`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`항복 처리 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "항복 처리 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 무승부 신청 보내기
|
||||||
|
socket.on('requestDraw', function(data) {
|
||||||
|
try {
|
||||||
|
const roomId = data.roomId;
|
||||||
|
const message = "상대방이 무승부 요청을 보냈습니다.";
|
||||||
|
|
||||||
|
socket.to(roomId).emit('receiveDrawRequest', { message });
|
||||||
|
socket.emit('drawRequestSent', { message: "무승부 요청이 전송되었습니다." });
|
||||||
|
|
||||||
|
logger.info(`무승부 요청: 플레이어 ${socket.id}, 방 ${roomId}`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`무승부 요청 처리 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "무승부 요청 처리 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 무승부 수락
|
||||||
|
socket.on('acceptDraw', function(data) {
|
||||||
|
try {
|
||||||
|
const roomId = data.roomId;
|
||||||
|
const message = "상대방이 무승부를 수락했습니다.";
|
||||||
|
|
||||||
|
socket.to(roomId).emit('drawAccepted', { message });
|
||||||
|
socket.emit('drawConfirmed', { message: "무승부 수락이 완료되었습니다." });
|
||||||
|
|
||||||
|
logger.info(`무승부 수락: 플레이어 ${socket.id}, 방 ${roomId}`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`무승부 수락 처리 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "무승부 수락 처리 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 무승부 거절
|
||||||
|
socket.on('rejectDraw', function(data) {
|
||||||
|
try {
|
||||||
|
const roomId = data.roomId;
|
||||||
|
const message = "상대방이 무승부를 거절했습니다.";
|
||||||
|
|
||||||
|
socket.to(roomId).emit('drawRejected', { message });
|
||||||
|
socket.emit('drawRejectionConfirmed', { message: "무승부 거절이 완료되었습니다." });
|
||||||
|
|
||||||
|
logger.info(`무승부 거절: 플레이어 ${socket.id}, 방 ${roomId}`);
|
||||||
|
} catch(err) {
|
||||||
|
logger.error(`무승부 거절 처리 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "무승부 거절 처리 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 재대결 신청
|
||||||
|
socket.on('requestRevenge', function(data) {
|
||||||
|
try {
|
||||||
|
const roomId = data.roomId;
|
||||||
|
const message = "상대방이 재대결을 신청했습니다.";
|
||||||
|
|
||||||
|
socket.to(roomId).emit('receiveRevengeRequest', { message });
|
||||||
|
socket.emit('revengeRequestSent', { message: "재대결 신청이 전송되었습니다." });
|
||||||
|
|
||||||
|
logger.info(`재대결 요청: 플레이어 ${socket.id}, 방 ${roomId}`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`재대결 신청 처리 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "재대결 신청 처리 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 재대결 수락
|
||||||
|
socket.on('acceptRevenge', function(data) {
|
||||||
|
try {
|
||||||
|
const roomId = data.roomId;
|
||||||
|
let isBlack = data.isBlack;
|
||||||
|
const message = "상대방이 재대결을 수락했습니다.";
|
||||||
|
|
||||||
|
|
||||||
|
socket.to(roomId).emit('revengeAccepted', {
|
||||||
|
message,
|
||||||
|
isBlack: isBlack,
|
||||||
|
});
|
||||||
|
socket.emit('revengeConfirmed', {
|
||||||
|
message: "재대결 수락이 완료되었습니다.",
|
||||||
|
isBlack: !isBlack,
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info(`재대결 수락: 플레이어 ${socket.id}, 방 ${roomId}`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`재대결 수락 처리 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "재대결 수락 처리 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 재대결 거절
|
||||||
|
socket.on('rejectRevenge', function(data) {
|
||||||
|
try {
|
||||||
|
const roomId = data.roomId;
|
||||||
|
const message = "상대방이 재대결을 거절했습니다.";
|
||||||
|
|
||||||
|
socket.to(roomId).emit('revengeRejected', { message });
|
||||||
|
socket.emit('revengeRejectionConfirmed', {message: "재대결 거절이 완료되었습니다."});
|
||||||
|
|
||||||
|
logger.info(`재대결 거절: 플레이어 ${socket.id}, 방 ${roomId}`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`재대결 거절 처리 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "재대결 거절 처리 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
88
socket/handlers/matchmaking.js
Normal file
88
socket/handlers/matchmaking.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
const { v4: uuidv4 } = require('uuid');
|
||||||
|
const { logger } = require('../../utils/logger');
|
||||||
|
|
||||||
|
module.exports = function(io, socket, gameState) {
|
||||||
|
socket.on('registerPlayer', function(data) {
|
||||||
|
try {
|
||||||
|
const rating = data.rating;
|
||||||
|
const nickname = data.nickname;
|
||||||
|
gameState.playerRating.set(socket.id, rating);
|
||||||
|
gameState.nickname.set(socket.id, nickname);
|
||||||
|
|
||||||
|
logger.info(`플레이어 등록: ID ${socket.id}, 닉네임: ${nickname}, 급수 ${rating}`);
|
||||||
|
|
||||||
|
// 급수에 따른 매칭 진행
|
||||||
|
findMatch(socket, rating, nickname);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`플레이어 등록 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "플레이어 등록 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const findMatch = (socket, playerRating, nickname) => {
|
||||||
|
let matchedRoom = null;
|
||||||
|
|
||||||
|
// 1. 같은 급수의 방 찾기
|
||||||
|
matchedRoom = gameState.rooms.find(room =>
|
||||||
|
Math.abs(gameState.playerRating.get(room.hostId) - playerRating) === 0);
|
||||||
|
|
||||||
|
// 2. 같은 급수 방이 없으면 ±1급 범위로 확장
|
||||||
|
if (!matchedRoom) {
|
||||||
|
matchedRoom = gameState.rooms.find(room =>
|
||||||
|
Math.abs(gameState.playerRating.get(room.hostId) - playerRating) <= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchedRoom) {
|
||||||
|
const roomId = matchedRoom.roomId;
|
||||||
|
|
||||||
|
// 매칭된 방은 대기 목록에서 제거
|
||||||
|
gameState.rooms = gameState.rooms.filter(room => room.roomId !== roomId);
|
||||||
|
|
||||||
|
// 방 입장
|
||||||
|
socket.join(roomId);
|
||||||
|
gameState.socketRooms.set(socket.id, roomId);
|
||||||
|
|
||||||
|
// 흑백 여부 결정 50% 확률
|
||||||
|
let isHostFirst = Math.random() < 0.5;
|
||||||
|
|
||||||
|
// 클라이언트에게 방 정보 전송 (상대 급수 정보 포함)
|
||||||
|
socket.emit('joinRoom', {
|
||||||
|
roomId: roomId,
|
||||||
|
opponentRating: gameState.playerRating.get(matchedRoom.hostId),
|
||||||
|
opponentNickname: gameState.nickname.get(matchedRoom.hostId),
|
||||||
|
isBlack: !isHostFirst
|
||||||
|
});
|
||||||
|
|
||||||
|
// 상대방에게 게임 시작 알림 (내 닉네임과 급수 정보 포함)
|
||||||
|
socket.to(roomId).emit('startGame', {
|
||||||
|
opponentId: socket.id,
|
||||||
|
opponentRating: playerRating,
|
||||||
|
opponentNickname: nickname,
|
||||||
|
isBlack: isHostFirst
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info(`매칭 성공: ${socket.id}(${playerRating}급) - ${matchedRoom.hostId}(${gameState.playerRating.get(matchedRoom.hostId)}급)`);
|
||||||
|
}
|
||||||
|
// 4. 매칭된 방이 없으면 새 방 생성
|
||||||
|
else {
|
||||||
|
|
||||||
|
const roomId = uuidv4();
|
||||||
|
socket.join(roomId);
|
||||||
|
|
||||||
|
gameState.rooms.push({
|
||||||
|
roomId: roomId,
|
||||||
|
hostId: socket.id,
|
||||||
|
rating: playerRating
|
||||||
|
});
|
||||||
|
|
||||||
|
gameState.socketRooms.set(socket.id, roomId);
|
||||||
|
socket.emit('createRoom', {
|
||||||
|
roomId: roomId,
|
||||||
|
message: "대기 중... 비슷한 상대를 찾고 있습니다."
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info(`대기방 생성: ID ${socket.id}, 급수 ${playerRating}, 방 ID ${roomId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
24
socket/handlers/roomEvents.js
Normal file
24
socket/handlers/roomEvents.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const { logger } = require('../../utils/logger');
|
||||||
|
|
||||||
|
module.exports = function(io, socket, gameState) {
|
||||||
|
// 방 나가기 이벤트
|
||||||
|
socket.on('leaveRoom', function(roomData) {
|
||||||
|
try {
|
||||||
|
const roomId = roomData.roomId;
|
||||||
|
|
||||||
|
socket.leave(roomId);
|
||||||
|
socket.emit('exitRoom',{message: "방을 떠났습니다."});
|
||||||
|
socket.to(roomId).emit('endGame', { message: "상대방이 방을 떠났습니다." });
|
||||||
|
|
||||||
|
// 혼자 대기 중인 경우 대기방 목록에서 제거
|
||||||
|
gameState.rooms = gameState.rooms.filter(room => room.roomId !== roomId);
|
||||||
|
// 매핑 정보 삭제
|
||||||
|
gameState.socketRooms.delete(socket.id);
|
||||||
|
|
||||||
|
logger.info(`방 나가기 처리: 플레이어 ${socket.id}, 방 ${roomId}`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`방 나가기 처리 중 오류: ${err}`);
|
||||||
|
socket.emit('error', { message: "방 나가기 처리 중 오류가 발생했습니다." });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
56
socket/index.js
Normal file
56
socket/index.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
const {v4: uuidv4} = require('uuid');
|
||||||
|
const matchmakingHandlers = require('./handlers/matchmaking');
|
||||||
|
const roomEventHandlers = require('./handlers/roomEvents');
|
||||||
|
const gameEventHandlers = require('./handlers/gameEvents');
|
||||||
|
const { logger } = require('../utils/logger');
|
||||||
|
|
||||||
|
// 전역 상태 객체 (모든 핸들러에서 공유)
|
||||||
|
const gameState = {
|
||||||
|
rooms: [], // {roomId, hostId, rating} 형태로 저장
|
||||||
|
socketRooms: new Map(), // 소켓ID와 방ID 매핑
|
||||||
|
playerRating: new Map(), // 소켓ID와 플레이어 급수 매핑
|
||||||
|
nickname: new Map() // 플레이어 닉네임
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = function(server) {
|
||||||
|
const io = require('socket.io')(server, {
|
||||||
|
transports: ['websocket']
|
||||||
|
});
|
||||||
|
|
||||||
|
io.on('connection', function(socket) {
|
||||||
|
console.log('Connected: ' + socket.id);
|
||||||
|
|
||||||
|
// 매칭 관련 이벤트 핸들러 등록
|
||||||
|
matchmakingHandlers(io, socket, gameState)
|
||||||
|
|
||||||
|
// 방 관련 이벤트 핸들러 등록
|
||||||
|
roomEventHandlers(io, socket, gameState);
|
||||||
|
|
||||||
|
// 게임 내 이벤트 핸들러 등록
|
||||||
|
gameEventHandlers(io, socket, gameState);
|
||||||
|
|
||||||
|
|
||||||
|
// 연결 해제 시 정리
|
||||||
|
socket.on('disconnect', function(reason) {
|
||||||
|
logger.info('Disconnected: ' + socket.id + ', Reason: ' + reason);
|
||||||
|
|
||||||
|
// 해당 소켓이 속한 방 찾기
|
||||||
|
const roomId = gameState.socketRooms.get(socket.id);
|
||||||
|
|
||||||
|
if (roomId) {
|
||||||
|
// 상대방에게 연결 끊김 알림
|
||||||
|
socket.to(roomId).emit('opponentDisconnected', {
|
||||||
|
message: "상대방의 연결이 끊어졌습니다."
|
||||||
|
});
|
||||||
|
|
||||||
|
// 대기방 목록에서 제거
|
||||||
|
gameState.rooms = gameState.rooms.filter(room => room.roomId !== roomId);
|
||||||
|
|
||||||
|
gameState.socketRooms.delete(socket.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 플레이어 급수 정보 제거
|
||||||
|
gameState.playerRating.delete(socket.id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
40
utils/logger.js
Normal file
40
utils/logger.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* 간단한 로거 유틸리티
|
||||||
|
*/
|
||||||
|
const logger = {
|
||||||
|
/**
|
||||||
|
* 디버그 레벨 로그
|
||||||
|
* @param {string} message - 로그 메시지
|
||||||
|
*/
|
||||||
|
debug: (message) => {
|
||||||
|
if (process.env.LOG_LEVEL === 'debug') {
|
||||||
|
console.log(`[DEBUG] ${new Date().toISOString()}: ${message}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 정보 레벨 로그
|
||||||
|
* @param {string} message - 로그 메시지
|
||||||
|
*/
|
||||||
|
info: (message) => {
|
||||||
|
console.log(`[INFO] ${new Date().toISOString()}: ${message}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 경고 레벨 로그
|
||||||
|
* @param {string} message - 로그 메시지
|
||||||
|
*/
|
||||||
|
warn: (message) => {
|
||||||
|
console.warn(`[WARN] ${new Date().toISOString()}: ${message}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 에러 레벨 로그
|
||||||
|
* @param {string} message - 로그 메시지
|
||||||
|
*/
|
||||||
|
error: (message) => {
|
||||||
|
console.error(`[ERROR] ${new Date().toISOString()}: ${message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = { logger };
|
Loading…
x
Reference in New Issue
Block a user