Skip to content

Commit

Permalink
Merge pull request #38 from Crazy-Cow/feature/CD-99
Browse files Browse the repository at this point in the history
feat: 소켓 인게임/아웃게임 Controller 분리
  • Loading branch information
ddubbu-dev authored Nov 18, 2024
2 parents fc86496 + 1af086e commit 5960061
Show file tree
Hide file tree
Showing 14 changed files with 269 additions and 216 deletions.
40 changes: 14 additions & 26 deletions src/game/maps/common.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import {
SocketEmitEvtDataGameStateV1Item,
SocketEmitEvtDataGameStateV2,
} from 'socket/type'
import { SocketEmitEvtDataGameState } from 'socket/types/emit'
import { Character, Position } from '../objects/player'

const GROUND_POS = {
Expand All @@ -14,8 +11,7 @@ const MIN_DISTANCE = 2

export type MapInitialType = { remainRunningTime: number }
export type MapStartLoopType = {
handleGameStateV1: (data: SocketEmitEvtDataGameStateV1Item[]) => void
handleGameStateV2: (data: SocketEmitEvtDataGameStateV2) => void
handleGameState: (data: SocketEmitEvtDataGameState) => void
handleGameOver: () => void
}

Expand Down Expand Up @@ -78,22 +74,18 @@ export class CommonMap {
this.characters = this.characters.filter((char) => char.id !== id)
}

convertGameStateV1(): SocketEmitEvtDataGameStateV1Item[] {
return this.characters.map((char) => ({
id: char.id,
position: char.position,
bodyColor: char.bodyColor,
hairColor: char.hairColor,
bellyColor: char.bellyColor,
velocity: char.velocity,
hasTail: char.hasTail,
}))
}

convertGameStateV2(): SocketEmitEvtDataGameStateV2 {
convertGameState(): SocketEmitEvtDataGameState {
return {
remainRunningTime: this.remainRunningTime,
characters: this.convertGameStateV1(),
characters: this.characters.map((char) => ({
id: char.id,
position: char.position,
bodyColor: char.bodyColor,
hairColor: char.hairColor,
bellyColor: char.bellyColor,
velocity: char.velocity,
hasTail: char.hasTail,
})),
}
}

Expand All @@ -102,8 +94,7 @@ export class CommonMap {
}

startGameLoop({
handleGameStateV1,
handleGameStateV2,
handleGameState: handleGameStateV2,
handleGameOver,
}: MapStartLoopType) {
this.loopIdToReduceTime = setInterval(() => {
Expand All @@ -118,10 +109,7 @@ export class CommonMap {
this.loopIdToUpdateGameState = setInterval(() => {
this.updateGameState()

const gameStateV1 = this.convertGameStateV1()
handleGameStateV1(gameStateV1)

const gameStateV2 = this.convertGameStateV2()
const gameStateV2 = this.convertGameState()
handleGameStateV2(gameStateV2)
}, 1000 * this.updateInterval)
}
Expand Down
14 changes: 0 additions & 14 deletions src/game/server/index.type.ts

This file was deleted.

13 changes: 0 additions & 13 deletions src/game/server/index.util.ts

This file was deleted.

28 changes: 0 additions & 28 deletions src/socket/constant.ts

This file was deleted.

31 changes: 31 additions & 0 deletions src/socket/controller/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Socket } from 'socket.io'
import { EmitEventName } from 'socket/types/emit'
import { OnEventData } from 'socket/types/on'

export abstract class BaseController {
socket: Socket
constructor({ socket }: { socket: Socket }) {
this.socket = socket
}

abstract register(): void
abstract disconnect(): void

getUserId(): string {
return this.socket.id
}

broadcast(roomId: string, emitMessage: EmitEventName, data: unknown) {
// self
this.socket.emit<EmitEventName>(emitMessage, data)

// the other
this.socket.to(roomId).emit<EmitEventName>(emitMessage, data)
}

logger = (msg: string, args?: OnEventData) => {
console.log(
`[${this.socket.id}] ${msg} ${args ? JSON.stringify(args) : ''}`
)
}
}
4 changes: 4 additions & 0 deletions src/socket/controller/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import OutgameController from './outgame'
import IngameController from './ingame'

export { OutgameController, IngameController }
49 changes: 49 additions & 0 deletions src/socket/controller/ingame.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Socket } from 'socket.io'
import { BaseController } from './base'
import { OnEventData, OnEventName } from '../types/on'
import { Room } from '../../service/rooms'
import { CommonMap } from '../../game/maps'
import { Character } from '../../game/objects/player'

function handleMove(character: Character, data: OnEventData['move']) {
character.shift = data.shift
character.position = data.character.position
character.velocity = data.character.velocity
character.isOnGround = data.character.isOnGround
}

class IngameController extends BaseController {
socket: Socket
gameMap: CommonMap

register() {
this.socket.on<OnEventName>('move', this.handleMove)
}

disconnect() {
this.gameMap?.removeCharacter(this.socket.id)
}

private handleMove = (data: OnEventData['move']) => {
const character = this.gameMap.findCharacter(this.socket.id)
handleMove(character, data)
}

handleStartGame = (room: Room) => {
this.gameMap = room.gameMap
this.broadcast(room.roomId, 'game.start', { players: room.players })

room.loadGame()

room.startGameLoop({
handleGameState: (data) => {
this.broadcast(room.roomId, 'game.state', data)
},
handleGameOver: () => {
this.broadcast(room.roomId, 'game.over', undefined)
},
})
}
}

export default IngameController
71 changes: 71 additions & 0 deletions src/socket/controller/outgame.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Socket } from 'socket.io'
import { BaseController } from './base'
import { OnEventData, OnEventName } from '../types/on'
import roomService, { Room } from '../../service/rooms'
import userService from '../../service/users'
import { EmitEventData } from '../types/emit'
import IngameController from './ingame'

function getRoomStateDto(room: Room): EmitEventData['room.changeState'] {
return {
roomId: room.roomId,
playerCnt: room.players.length,
state: room.state,
maxPlayerCnt: room.maxPlayerCnt,
}
}

// 로비 ~ 대기실
class OutgameController extends BaseController {
ingameCtrl: IngameController

constructor(props: { socket: Socket; ingameCtrl: IngameController }) {
super(props)
this.ingameCtrl = props.ingameCtrl
}

register() {
this.socket.on<OnEventName>('room.enter', this.handleRoomEnter)
this.socket.on<OnEventName>('room.leave', this.handleRoomLeave)
}

disconnect() {
const userId = this.getUserId()
const room = roomService.leaveRoom(userId)
userService.removeUser(userId)

if (room) {
// user가 존재하던 room
this.broadcastRoomState(room)
}
}

private broadcastRoomState = (room: Room) => {
const data = getRoomStateDto(room)
this.broadcast(room.roomId, 'room.changeState', data)
}

private handleRoomEnter = (args: OnEventData['room.enter']): Room => {
this.logger('room.enter', args)
const userId = this.socket.id
const player = userService.findUserById(userId)
const room = roomService.joinRoom(player)
this.socket.join(room.roomId)
this.broadcastRoomState(room)

if (room.state === 'playing') {
this.ingameCtrl.handleStartGame(room)
}

return room
}

handleRoomLeave = (args: OnEventData['room.leave']) => {
this.logger('room.leave', args)
const userId = this.socket.id
const room = roomService.leaveRoom(userId)
this.broadcastRoomState(room)
}
}

export default OutgameController
6 changes: 3 additions & 3 deletions src/socket/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Server, type Socket as ServerSocket } from 'socket.io'
import { AddressInfo } from 'node:net'
import roomService, { Room } from '../service/rooms'
import { User } from '../service/users'
import { SOCKET_ON_EVT_TYPE } from './constant'
import { initSocket } from '.'
import { OnEventName } from './types/on'

describe('대기실 관련 소켓 통신 테스트', () => {
let io: Server, serverSocket: ServerSocket, clientSocket: ClientSocket
Expand Down Expand Up @@ -36,8 +36,8 @@ describe('대기실 관련 소켓 통신 테스트', () => {
mockRoom.addPlayer(mockPlayer)
roomService.joinRoom = jest.fn().mockReturnValue(mockRoom)

clientSocket.emit(SOCKET_ON_EVT_TYPE.ROOM_ENTER)
serverSocket.on(SOCKET_ON_EVT_TYPE.ROOM_ENTER, () => {
clientSocket.emit('room.enter')
serverSocket.on<OnEventName>('room.enter', () => {
expect(roomService.joinRoom).toHaveBeenCalled()
done() // 테스트 종료 필수
})
Expand Down
Loading

0 comments on commit 5960061

Please sign in to comment.