message.ts 3.16 KB
import { RoomDescription, RoomInfo } from "./dataType";
import { keys } from "ts-transformer-keys";

// 서버로 들어오는 메세지 타입을 정의합니다.
// 'result' 속성은 서버 요청 결과에만 포함되는 특별한 속성입니다.
interface ServerInboundMessageMap {
  // 로그인을 시도합니다.
  login: {
    username: string;
  };

  // 방 목록을 요청합니다.
  roomList: {
    result: RoomDescription[];
  };

  // 방에 접속합니다.
  joinRoom: {
    uuid: string;
    result: RoomInfo;
  };

  // 방에서 나갑니다.
  leaveRoom: {};

  // 채팅을 보냅니다.
  chat: {
    message: string;
  };

  // drawer가 단어를 선택합니다.
  chooseWord: {
    word: string;
  };

  // 브러시 정보를 변경합니다.
  setBrush: {
    size: number;
    color: string;
    drawing: boolean;
  };

  // 브러시를 이동합니다.
  moveBrush: {
    x: number;
    y: number;
  };
}

// 서버에서 나가는 메세지 타입을 정의합니다.
interface ServerOutboundMessageMap {
  // 방에 접속 중인 유저 목록이 업데이트 되었습니다.
  updateRoomUser: {
    state: "added" | "updated" | "removed";
    user: {
      username: string;
    };
  };

  // 다른 유저가 채팅을 보냈습니다.
  chat: {
    sender: string;
    message: string;
  };

  // 라운드가 시작되었습니다.
  startRound: {
    round: number;
    duration: number;
    roles: {
      username: string;
      role: "drawer" | "guesser" | "winner" | "spectator";
    };
  };

  // drawer에게 선택할 수 있는 단어가 주어졌습니다.
  wordSet: {
    words: string[];
  };

  // 이번 라운드의 단어가 선택되었습니다.
  wordChosen: {
    length: number;
  };

  // 라운드 타이머 정보를 동기화합니다.
  timer: {
    state: "started" | "stopped";
    time: number;
  };

  // 라운드가 종료되었습니다.
  finishRound: {
    answer: string;
  };

  // 역할이 변경되었습니다.
  role: {
    username: string;
    role: "drawer" | "guesser" | "winner" | "spectator";
  };

  // 보낸 단어가 정답 처리 되었습니다.
  answerAccepted: {
    answer: string;
  };

  // 게임이 종료되었습니다.
  finishGame: {};

  // 브러시 정보가 변경되었습니다.
  setBrush: {
    size: number;
    color: string;
    drawing: boolean;
  };

  // 브러시가 이동되었습니다.
  moveBrush: {
    x: number;
    y: number;
  };
}

export type ServerInboundMessageKey = keyof ServerInboundMessageMap;

export const ServerInboundMessageKeyArray = keys<ServerInboundMessageMap>();

export type ServerInboundMessage<Key extends ServerInboundMessageKey> = Omit<
  ServerInboundMessageMap[Key],
  "result"
>;

export interface ServerResponse<Key extends ServerInboundMessageKey> {
  ok: boolean;
  reason?: string;
  result?: "result" extends keyof ServerInboundMessageMap[Key]
    ? ServerInboundMessageMap[Key]["result"]
    : never;
}

export type ServerOutboundMessage<Key extends keyof ServerOutboundMessageMap> =
  ServerOutboundMessageMap[Key];

export type ServerOutboundMessageKey = keyof ServerOutboundMessageMap;

export const ServerOutboundMessageKeyArray = keys<ServerOutboundMessageMap>();