Study/Project

VV 3. 로그인 기능

에린_1 2024. 10. 29. 15:58
728x90

VV

서버와의 연결이 성공했으므로 서로 정보를 전달할 수 있어야 한다.
로그인 UI가 있으므로 ID, PW TextBox에 입력한 Text를 로그인 버튼을 누르면 서버로 전송해야 한다.

// LoginWidget.h
UCLASS()
class VERSUSVILLAGE_API ULoginWidget : public UUserWidget
{
    GENERATED_BODY()

    public:
    virtual void NativeConstruct() override;

    UFUNCTION()
    void OnLoginButtonClicked();

protected:
    UPROPERTY(meta = (BindWidget))
    class UEditableTextBox* IDTextBox;

    UPROPERTY(meta = (BindWidget))
    class UEditableTextBox* PWTextBox;

    UPROPERTY(meta = (BindWidget))
    class UButton* LoginButton;

private:
    void SendDataToServer(FString ID, FString PW);
};
//LoginWidget.cpp
void ULoginWidget::NativeConstruct()
{
    Super::NativeConstruct();
    UE_LOG(LogTemp, Log, TEXT("NativeConstruct Called"));
    // Click Login Button
    if (LoginButton)
    {
        LoginButton->OnClicked.AddDynamic(this, &ULoginWidget::OnLoginButtonClicked);
    }
}

void ULoginWidget::OnLoginButtonClicked()
{
    FString ID = IDTextBox->GetText().ToString();
    FString PW = PWTextBox->GetText().ToString();

    if (!ID.IsEmpty() && !PW.IsEmpty())
    {
        SendDataToServer(ID, PW);
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("ID 또는 PW가 입력되지 않았습니다."));
    }
}

void ULoginWidget::SendDataToServer(FString ID, FString PW)
{
    UMyGameInstance* GameInstance = Cast<UMyGameInstance>(GetWorld()->GetGameInstance());

    if (GameInstance && GameInstance->NetworkManager)
    {
        FString DataToSend = FString::Printf(TEXT("ID: %s, PW: %s"), *ID, *PW);
        GameInstance->NetworkManager->SendData(DataToSend);
        UE_LOG(LogTemp, Log, TEXT("데이터 전송 완료: %s"), *DataToSend);
    }
    else
    {
        UE_LOG(LogTemp, Error, TEXT("NetworkManager가 유효하지 않습니다."));
    }
}

성공적으로 Log가 찍히고 있는것을 확인할 수 있다.

이제 서버에서 잘 받는지 확인을 해야한다.

서버에서 아무것도 못읽는 것을 중단점을 찍어가면서 확인할 수 있었고, 그 이유를 발견할 수 있었다. 서버에서는 PacketHeader를 토대로 받고 있었기 때문에 잘못된 곳을 참조하고 있어서 읽지 못했다. 그래서 대대적인 수정 작업에 들어갔다.

일단 msgID에 들어갈 프로토콜을 UE5, SERVER에 정의해두었다. 

void UNetworkManager::SendLoginRequest(FString ID, FString PW)
{
	if (ClientSocket)
	{
		hbServerEngine::PacketHeader Header;
		Header.MsgID = LOGIN_REQUEST_MSG_ID;
		Header.TotalSize = sizeof(hbServerEngine::PacketHeader) + ID.Len() + PW.Len() + 2;
		Header.Attribute = 0;

		FString DataToSend = FString::Printf(TEXT("%s|%s"), *ID, *PW);

		TArray<uint8> PacketData;
		PacketData.SetNumUninitialized(Header.TotalSize);

		FMemory::Memcpy(PacketData.GetData(), &Header, sizeof(hbServerEngine::PacketHeader));

		FTCHARToUTF8 Converter(*DataToSend);
		FMemory::Memcpy(PacketData.GetData() + sizeof(hbServerEngine::PacketHeader), Converter.Get(), Converter.Length());


		int32 Sent = 0;
		ClientSocket->Send(PacketData.GetData(), PacketData.Num(), Sent);
		UE_LOG(LogTemp, Log, TEXT("Login request sent: ID = %s, PW = %s"), *ID, *PW);
	}
}

추가적으로 UE5에서 서버로 보내는 코드를 수정했다.

성공적으로 클라이언트에서 보낸 ID와 PW를 서버에서 받을 수 있었고, 받은 데이터를 토대로 검증을 완료했다.

bool ValidateUserCredentials(const string& ID, const string& PW)
{
	char EscapeID[256];
	char EscapePW[256];
	mysql_real_escape_string(&mysql, EscapeID, ID.c_str(), ID.length());
	mysql_real_escape_string(&mysql, EscapePW, PW.c_str(), PW.length());

	MYSQL_RES* Res;
	MYSQL_ROW Row;

	string Query = "SELECT * FROM vv.users WHERE user_nickname='" + std::string(EscapeID) + "' AND user_pw='" + std::string(EscapePW) + "'";

	if (mysql_query(&mysql, Query.c_str()))
	{
		std::cerr << "MySQL query error : " << mysql_error(&mysql) << std::endl;
		std::cerr.flush();
		return false;
	}

	Res = mysql_store_result(&mysql);
	if (Res == nullptr)
	{
		return false;
	}

	Row = mysql_fetch_row(Res);
	bool bIsValid = false;
	if (Row != nullptr)
	{
		bIsValid = true;
	}
	mysql_free_result(Res);

	return bIsValid;
}

 

728x90