I'm FanJae.

[Two Faced Poker] Day 4. 방에 아이디 정보나 준비 상태 정보를 받아오기 본문

Toy Project/Two Faced Poker

[Two Faced Poker] Day 4. 방에 아이디 정보나 준비 상태 정보를 받아오기

FanJae 2024. 10. 16. 23:33

1. 결과물

- 상대방이 접속하면 ID와 준비 여부가 나오도록 처리했다.

- 생각보다 이 과정에서 고전을 많이했다.

 

(준비중)


2. 서버 처리

① Getter() 추가

static std::map<std::string, std::set<SOCKET>> chatRooms;
static std::map<std::string, int> Room_count;
const std::map<std::string, std::set<SOCKET>>& GetChatRooms() {
	return chatRooms;
}

const std::map<std::string, int>& GetRoomCounts() {
	return Room_count;
}

- GameManager에서 사용할 용도로 getter를 만들기로 했다.

- static 특성을 그대로 유지하기 위해서이다.

 

② 방에 유저가 입장했을 때, 기존 유저가 새로 들어온 유저의 ID 값을 얻어오기

for (SOCKET target_socket : chatRooms[this->roomName])
{
	if (socket != target_socket)
	{
		join_message = this->ID + " Joined.";
		send(target_socket, join_message.c_str(), join_message.length(), 0);
	
		join_message = GAME_CLIENT_EVENT + LOAD_PLAYER + this->ID;
		std::cout << join_message << std::endl;
		send(target_socket, join_message.c_str(), join_message.length(), 0);
	}
}

 

 

③ 방에 유저가 입장했을 때, 그 유저가 방에 있던 유저의 ID 값을 얻어오기

- 여기서 생각했던 것은 크게 2가지였다. ① 서버가 유저 ID 관리 ② 접속한 클라이언트가 ID를 보내는 방식

- 나의 경우는 ②로 한번 처리해보았다. 특별한 이유가 있다기 보다는 이 방법을 써본적이 없어서 말이다.

- 다만 이 방법을 사용할 경우 ID의 무결성 확인이 필요하다. (Client 변조를 방지한다.)

- 나의 경우 서버가 ID를 만들기 때문에 이 방법을 통해 임의로 ID를 변조하지 않도록 처리하고자 한다.

※ 이 부분에 대해서는 별도 포스트에서 따로 추가해보려고 한다.

private void Pre_Call()
{
    string request = Constants.GAME_CLIENT_EVENT + Constants.GAME_PRE_CALL;
    byte[] buffer = Encoding.UTF8.GetBytes(request);
    socket.Send(buffer);
}

 

- Client에서 채팅방 입장 시점(Client를 기준으로는 객체가 생성되는 시점)에서 Pre_Call()을 호출한다.

- 이것이 호출되면, 해당 방에 기존에 있던 유저에 대해서 GAME_PRE_LOAD_PLAYER라는 이벤트를 보낸다.

void Game_Manager::Handle_Game_Pre_Call(const SOCKET& socket, const std::string& message)
{
	const auto& rooms = GetChatRooms();
	const auto& room_counts = GetRoomCounts();

	auto targetRoom = rooms.find(this->roomName);
	auto targetRoom_count = room_counts.find(this->roomName);
	std::string join_message;
	for (SOCKET target_socket : targetRoom->second)
	{
		if (socket != target_socket && targetRoom_count->second > 1)
		{
			join_message = GAME_CLIENT_EVENT + GAME_PRE_LOAD_PLAYER;
			std::cout << join_message << std::endl;
			send(target_socket, join_message.c_str(), join_message.length(), 0);
		}
	}
}

- 방에 기존에 있던 유저가 서버 쪽으로 메시지를 보내준다.

- 이 정보를 토대로 기존 방에 있던 유저에 대한 정보를 처리해준다.

else if (message.Length >= Constants.GAME_CLIENT_EVENT.Length + Constants.GAME_PRE_LOAD_PLAYER.Length && message.Substring(Constants.GAME_CLIENT_EVENT.Length, Constants.GAME_PRE_LOAD_PLAYER.Length) == Constants.GAME_PRE_LOAD_PLAYER)
{

    string request = Constants.GAME_CLIENT_EVENT + Constants.GAME_PRE_LOAD_ID + My_ID_Label.Text.Substring(6);
    byte[] buffer = Encoding.UTF8.GetBytes(request);
    socket.Send(buffer);

    if (My_Ready.Text == "<준비>")
    {
        request = Constants.GAME_CLIENT_EVENT + Constants.GAME_PRE_LOAD_READY;
        buffer = Encoding.UTF8.GetBytes(request);
        socket.Send(buffer);
    }
    else
    {
        request = Constants.GAME_CLIENT_EVENT + Constants.GAME_PRE_LOAD_DONE;
        buffer = Encoding.UTF8.GetBytes(request);
        socket.Send(buffer);
    }
}

 

- Client에서 이와 같이 보내주면 Server에서 이를 다음과 같이 처리한다.

- 이 정보를 보내준 소켓이 아닌 다른 소켓(방을 새롭게 입장한 녀석)에게 보내준다.

void Game_Manager::Handle_Game_Pre_Load(const SOCKET& socket, const std::string& message)
{
	const auto& rooms = GetChatRooms();
	auto it = rooms.find(this->roomName);
	std::string send_message = "";

	if (message.substr(0, 3) == "ID ")
	{
		send_message = GAME_CLIENT_EVENT + GAME_PRE_LOAD_ID_DONE + message.substr(3);
		std::cout << send_message << std::endl;
	}
	else if (message.substr(0, 5) == "READY")
	{
		send_message = GAME_CLIENT_EVENT + GAME_PRE_LOAD_READY_DONE;
		std::cout << send_message << std::endl;
	}
	else if (message.substr(0, 4) == "Done")
	{
		send_message = GAME_CLIENT_EVENT + GAME_PRE_LOAD_DONE_DONE;
		std::cout << send_message.length() << std::endl;
		std::cout << send_message << std::endl;
	}

	for (SOCKET target_socket : it->second)
	{
		if (socket != target_socket)
		{
			send(target_socket, send_message.c_str(), send_message.length(), 0);
		}
	}

}

 

- Client에서는 이와 같이 받아서 사용이 가능하다.

else if (message.Length >= Constants.GAME_CLIENT_EVENT.Length + Constants.GAME_PRE_LOAD_ID_DONE.Length && message.Substring(Constants.GAME_CLIENT_EVENT.Length, Constants.GAME_PRE_LOAD_ID_DONE.Length) == Constants.GAME_PRE_LOAD_ID_DONE)
{
    Invoke(new Action(() =>
    {
        Vs_ID_Label.Text = "ID : " + message.Substring(Constants.GAME_CLIENT_EVENT.Length + Constants.GAME_PRE_LOAD_ID_DONE.Length);
    }));
}
else if (message.Substring(Constants.GAME_CLIENT_EVENT.Length) == Constants.GAME_PRE_LOAD_READY_DONE)
{
    Invoke(new Action(() =>
    {
        Vs_Ready.Text = "<준비>";

    }));
}
else if (message.Substring(Constants.GAME_CLIENT_EVENT.Length) == Constants.GAME_PRE_LOAD_DONE_DONE)
{
    Invoke(new Action(() =>
    {
        Vs_Ready.Text = "<완료>";

    }));
}

3. TODO

1) Server

- 게임 로직 처리 (카드 비교 및 베팅에 따른 정보 처리 등)

- Client 패킷 검증 필요 (ID 변조 체크)

 

2) Client

- 게임 로직 처리

 

 

 

 

Comments