diff --git a/Source/ZMMO/Game/UI/FrontEnd/CharServerOpcodes.h b/Source/ZMMO/Game/UI/FrontEnd/CharServerOpcodes.h new file mode 100644 index 0000000..d5016b6 --- /dev/null +++ b/Source/ZMMO/Game/UI/FrontEnd/CharServerOpcodes.h @@ -0,0 +1,46 @@ +#pragma once + +#include "CoreMinimal.h" + +/** + * Opcodes do CharServer (WebSocket) consumidos pelo cliente. Espelha + * `Server/ZeusCharServer/src/protocol/CharOpcodes.ts` (faixa 2000-2099). + * Mantido mínimo: só os opcodes que o front-end usa hoje (auth da Login). + * Ampliar conforme as telas (lista/criação/seleção de personagem) chegarem. + * + * Wire: string = uint16 LE (len) + UTF-8; inteiros LE. O cabeçalho de 32B + * é responsabilidade do UZeusCharServerSubsystem (Send/OnRawMessage operam + * sobre o payload já sem header). + */ +namespace ZMMOCharOp +{ + // Autenticação — payload começa com uint8 method (ver ZMMOCharAuthMethod) + constexpr int32 C_CHAR_AUTH_REQUEST = 2000; + constexpr int32 S_CHAR_AUTH_OK = 2001; // string(accountId)+string(user)+uint64(expiresMs) + constexpr int32 S_CHAR_AUTH_REJECT = 2002; // uint16(reason) +} + +/** + * Método de autenticação enviado como uint8 prefix no payload do + * C_CHAR_AUTH_REQUEST. TOKEN mantém o fluxo Stub/JWT (handoff de outro + * serviço); PASSWORD chama AccountService.login direto no CharServer. + * Espelha `CharAuthMethod` em CharOpcodes.ts. + */ +namespace ZMMOCharAuthMethod +{ + constexpr uint8 TOKEN = 0; + constexpr uint8 PASSWORD = 1; +} + +/** Espelha `CharRejectReason` em CharOpcodes.ts (subset usado no front-end). */ +namespace ZMMOCharRejectReason +{ + constexpr uint16 Unknown = 0; + constexpr uint16 InvalidToken = 1; + constexpr uint16 AccountBanned = 2; + constexpr uint16 AlreadyOnline = 3; + constexpr uint16 InvalidCredentials = 4; + constexpr uint16 AccountLocked = 5; + constexpr uint16 AccountSuspended = 6; + constexpr uint16 CredentialsAuthDisabled = 7; +} diff --git a/Source/ZMMO/Game/UI/FrontEnd/UILoginScreen_Base.cpp b/Source/ZMMO/Game/UI/FrontEnd/UILoginScreen_Base.cpp index b337f4f..83150ed 100644 --- a/Source/ZMMO/Game/UI/FrontEnd/UILoginScreen_Base.cpp +++ b/Source/ZMMO/Game/UI/FrontEnd/UILoginScreen_Base.cpp @@ -51,19 +51,6 @@ namespace return bHas ? DesignStyle : Fallback; } - // Token de DEV: o StubTokenValidator aceita `dev:` ou `dev:`. - // Um nome de usuário comum NÃO valida — então em dev mapeamos para - // `dev:` (o número digitado, se houver; senão 1). Auth real - // (HTTP /auth/login + JWT) entra em tarefa dedicada. - FString MakeDevToken(const FString& User) - { - const FString Trimmed = User.TrimStartAndEnd(); - if (!Trimmed.IsEmpty() && Trimmed.IsNumeric()) - { - return FString::Printf(TEXT("dev:%s"), *Trimmed); - } - return TEXT("dev:1"); - } } void UUILoginScreen_Base::NativePreConstruct() @@ -210,12 +197,10 @@ void UUILoginScreen_Base::HandleLoginClicked() // padrão dos launchers comerciais). SaveOrClearRememberedAccess(User); - // Escopo dev: token aceito pelo StubTokenValidator (senha ignorada no - // stub; mantida na UI para o fluxo real futuro). - const FString Token = MakeDevToken(User); - FZeusPacketWriter W; - W.WriteStringUtf8(Token); + W.WriteUInt8(ZMMOCharAuthMethod::PASSWORD); + W.WriteStringUtf8(User.TrimStartAndEnd()); + W.WriteStringUtf8(Pass); const bool bSent = Char->SendCharRequest( ZMMOCharOp::C_CHAR_AUTH_REQUEST, W.GetBuffer()); @@ -229,7 +214,7 @@ void UUILoginScreen_Base::HandleLoginClicked() bAwaitingAuth = true; SetBusy(true); SetStatus(AuthenticatingText); - UE_LOG(LogZMMO, Log, TEXT("Login: C_CHAR_AUTH_REQUEST enviado (token dev).")); + UE_LOG(LogZMMO, Log, TEXT("Login: C_CHAR_AUTH_REQUEST enviado (PASSWORD).")); } void UUILoginScreen_Base::HandleBackClicked() @@ -278,9 +263,22 @@ void UUILoginScreen_Base::HandleCharRawMessage(int32 Opcode, const TArray R.ReadUInt16(Reason); UE_LOG(LogZMMO, Warning, TEXT("Login: S_CHAR_AUTH_REJECT (reason=%u)."), Reason); SetBusy(false); - SetStatus(FText::Format( - NSLOCTEXT("ZMMO", "LoginRejectFmt", "{0} (cód. {1})"), - RejectedText, FText::AsNumber(Reason))); + + FText Message; + switch (Reason) + { + case ZMMOCharRejectReason::InvalidCredentials: Message = InvalidCredentialsText; break; + case ZMMOCharRejectReason::AccountLocked: Message = AccountLockedText; break; + case ZMMOCharRejectReason::AccountSuspended: Message = AccountSuspendedText; break; + case ZMMOCharRejectReason::AccountBanned: Message = AccountSuspendedText; break; + case ZMMOCharRejectReason::CredentialsAuthDisabled: Message = CredentialsDisabledText; break; + default: + Message = FText::Format( + NSLOCTEXT("ZMMO", "LoginRejectFmt", "{0} (cód. {1})"), + RejectedText, FText::AsNumber(Reason)); + break; + } + SetStatus(Message); } } diff --git a/Source/ZMMO/Game/UI/FrontEnd/UILoginScreen_Base.h b/Source/ZMMO/Game/UI/FrontEnd/UILoginScreen_Base.h index 37a4d95..4424096 100644 --- a/Source/ZMMO/Game/UI/FrontEnd/UILoginScreen_Base.h +++ b/Source/ZMMO/Game/UI/FrontEnd/UILoginScreen_Base.h @@ -18,11 +18,13 @@ class UZeusCharServerSubsystem; * UI_CheckBox_Master). Camada Abstract; o WBP concreto (WBP_Login) herda * DIRETO desta classe (ARQUITETURA.md §3.3). * - * Auth (escopo atual — dev): ao clicar "Entrar", envia C_CHAR_AUTH_REQUEST - * (opcode 2000) pelo WebSocket do UZeusCharServerSubsystem com um token - * `dev:` (StubTokenValidator aceita em dev; auth real virá em tarefa - * dedicada). S_CHAR_AUTH_OK → Flow::RequestEnterServerSelect; reject → - * mensagem de erro. Sem hard-ref de asset de tema (§5). + * Auth: ao clicar "Entrar", envia C_CHAR_AUTH_REQUEST (opcode 2000) pelo + * WebSocket do UZeusCharServerSubsystem como `uint8(PASSWORD) + + * string(user) + string(password)`. CharServer chama AccountService.login + * (Argon2id + lockout). S_CHAR_AUTH_OK → Flow::RequestEnterServerSelect; + * reject (InvalidCredentials/AccountLocked/Suspended/etc.) → status + * mapeado. Sem hard-ref de asset de tema (§5). Contas são criadas no + * servidor via `npm run account`. */ UCLASS(Abstract, Blueprintable) class ZMMO_API UUILoginScreen_Base : public UUIActivatableScreen_Base @@ -51,6 +53,18 @@ protected: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Login") FText RejectedText = FText::FromString(TEXT("Acesso negado pelo Gateway.")); + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Login") + FText InvalidCredentialsText = FText::FromString(TEXT("Usuário ou senha inválidos.")); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Login") + FText AccountLockedText = FText::FromString(TEXT("Conta bloqueada por excesso de tentativas. Aguarde e tente novamente.")); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Login") + FText AccountSuspendedText = FText::FromString(TEXT("Conta suspensa. Contate o suporte.")); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Login") + FText CredentialsDisabledText = FText::FromString(TEXT("Autenticação por credenciais indisponível no servidor.")); + // ---- Widgets do WBP (nomes esperados) ---- UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr Border_Bg;