openclonk/src/network/C4League.cpp

714 lines
24 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2006-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
/* engine handler of league system */
#include "C4Include.h"
#include "network/C4League.h"
#include "control/C4RoundResults.h"
#include "graphics/C4GraphicsResource.h"
// *** C4LeagueRequestHead
void C4LeagueRequestHead::CompileFunc(StdCompiler *pComp)
{
StdEnumEntry<C4LeagueAction> Actions[] =
{
{ "Start", C4LA_Start },
{ "Update", C4LA_Update },
{ "End", C4LA_End },
{ "Join", C4LA_PlrAuthCheck },
{ "", C4LA_RefQuery },
{ "Auth", C4LA_PlrAuth },
{ "ReportDisconnect", C4LA_ReportDisconnect },
};
pComp->Value(mkNamingAdapt(mkEnumAdaptT<uint8_t>(eAction, Actions), "Action", C4LA_RefQuery));
pComp->Value(mkNamingAdapt(mkParAdapt(CSID, StdCompiler::RCT_IdtfAllowEmpty), "CSID", ""));
pComp->Value(mkNamingAdapt(mkParAdapt(AUID, StdCompiler::RCT_IdtfAllowEmpty), "AUID", ""));
// Auth
pComp->Value(mkNamingAdapt(mkParAdapt(Account, StdCompiler::RCT_All), "Account", ""));
pComp->Value(mkNamingAdapt(mkParAdapt(Password, StdCompiler::RCT_All), "Password", ""));
pComp->Value(mkNamingAdapt(mkParAdapt(NewAccount, StdCompiler::RCT_All), "NewAccount", ""));
pComp->Value(mkNamingAdapt(mkParAdapt(NewPassword, StdCompiler::RCT_All), "NewPassword", ""));
pComp->Value(mkNamingAdapt(fRememberLogin, "RememberLogin", false));
}
void C4LeagueRequestHead::SetAuth(const char *szAccount, const char *szPassword, bool fRememberLogin)
{
Account = szAccount;
Password = szPassword;
this->fRememberLogin = fRememberLogin;
}
void C4LeagueRequestHead::SetNewAccount(const char *szNewAccount)
{
NewAccount = szNewAccount;
}
void C4LeagueRequestHead::SetNewPassword(const char *szNewPassword)
{
NewPassword = szNewPassword;
}
// *** C4LeagueReportDisconnectHead
void C4LeagueReportDisconnectHead::CompileFunc(StdCompiler *pComp)
{
// inherited fields
C4LeagueRequestHead::CompileFunc(pComp);
// reason
StdEnumEntry<C4LeagueDisconnectReason> Reasons[] =
{
{ "", C4LDR_Unknown },
{ "ConnectionFailed", C4LDR_ConnectionFailed},
{ "Desync", C4LDR_Desync },
};
pComp->Value(mkNamingAdapt(mkEnumAdaptT<uint8_t>(eReason, Reasons), "Reason", C4LDR_Unknown));
}
// *** C4LeagueRequestHeadEnd
void C4LeagueRequestHeadEnd::CompileFunc(StdCompiler *pComp)
{
C4LeagueRequestHead::CompileFunc(pComp);
pComp->Value(mkNamingAdapt(mkParAdapt(RecordName, StdCompiler::RCT_All), "RecordName", ""));
if (RecordName.getLength())
pComp->Value(mkNamingAdapt(mkHexAdapt(RecordSHA, sizeof(RecordSHA)), "RecordSHA"));
}
// *** C4LeagueResponseHead
void C4LeagueResponseHead::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkParAdapt(Status, StdCompiler::RCT_IdtfAllowEmpty), "Status", ""));
pComp->Value(mkNamingAdapt(mkParAdapt(CSID, StdCompiler::RCT_IdtfAllowEmpty), "CSID", ""));
pComp->Value(mkNamingAdapt(mkParAdapt(Message, StdCompiler::RCT_All), "Message", ""));
// Auth
pComp->Value(mkNamingAdapt(mkParAdapt(Account, StdCompiler::RCT_All), "Account", ""));
pComp->Value(mkNamingAdapt(mkParAdapt(AUID, StdCompiler::RCT_All), "AUID", ""));
pComp->Value(mkNamingAdapt(mkParAdapt(FBID, StdCompiler::RCT_All), "FBID", ""));
pComp->Value(mkNamingAdapt(mkParAdapt(LoginToken, StdCompiler::RCT_All), "LoginToken", ""));
}
// *** C4LeagueResponseHeadStart
void C4LeagueResponseHeadStart::CompileFunc(StdCompiler *pComp)
{
// Base members
C4LeagueResponseHead::CompileFunc(pComp);
// League name
pComp->Value(mkNamingAdapt(League, "League", ""));
pComp->Value(mkNamingAdapt(StreamingAddr, "StreamTo", ""));
pComp->Value(mkNamingCountAdapt(fHaveSeed, "Seed"));
if (fHaveSeed)
pComp->Value(mkNamingAdapt(iSeed, "Seed", (int32_t)0));
pComp->Value(mkNamingAdapt(iMaxPlayers, "MaxPlayers", (int32_t)0));
}
// *** C4LeagueResponseHeadUpdate
void C4LeagueResponseHeadUpdate::CompileFunc(StdCompiler *pComp)
{
// Base members
C4LeagueResponseHead::CompileFunc(pComp);
// League name
pComp->Value(mkNamingAdapt(League, "League", ""));
// player infos
pComp->Value(mkNamingAdapt(PlrInfos, "PlayerInfos"));
}
// *** C4LeagueRequestHeadAuthCheck
int32_t C4LeagueResponseHeadAuthCheck::getScore(const char *szLeague) const
{
for (int32_t i = 0; i < C4NetMaxLeagues; i++)
if (Leagues[i] == szLeague)
return Scores[i];
return 0;
}
int32_t C4LeagueResponseHeadAuthCheck::getRank(const char *szLeague) const
{
for (int32_t i = 0; i < C4NetMaxLeagues; i++)
if (Leagues[i] == szLeague)
return Ranks[i];
return 0;
}
int32_t C4LeagueResponseHeadAuthCheck::getRankSymbol(const char *szLeague) const
{
for (int32_t i = 0; i < C4NetMaxLeagues; i++)
if (Leagues[i] == szLeague)
return RankSymbols[i];
return 0;
}
const char *C4LeagueResponseHeadAuthCheck::getProgressData(const char *szLeague) const
{
// progress data is the same for all leagues
return ProgressData.getData();
}
void C4LeagueResponseHeadAuthCheck::CompileFunc(StdCompiler *pComp)
{
// Base members
C4LeagueResponseHead::CompileFunc(pComp);
// Leagues, Scores, Ranks
pComp->Value(mkNamingAdapt(mkArrayAdapt(Leagues, C4NetMaxLeagues, ""), "League"));
pComp->Value(mkNamingAdapt(mkArrayAdapt(Scores, C4NetMaxLeagues, 0), "Score"));
pComp->Value(mkNamingAdapt(mkArrayAdapt(Ranks, C4NetMaxLeagues, 0), "Rank"));
pComp->Value(mkNamingAdapt(mkArrayAdapt(RankSymbols, C4NetMaxLeagues, 0), "RankSymbol"));
// Progress data (per scenario; not per league)
pComp->Value(mkNamingAdapt(mkParAdapt(ProgressData, StdCompiler::RCT_All), "ProgressData", ""));
// Clan tag
pComp->Value(mkNamingAdapt(mkParAdapt(ClanTag, StdCompiler::RCT_All), "ClanTag", ""));
}
// *** C4LeagueFBIDList
void C4LeagueFBIDList::Clear()
{
while (pFirst)
{
FBIDItem *pDel = pFirst;
pFirst = pDel->pNext;
delete pDel;
}
}
bool C4LeagueFBIDList::FindFBIDByAccount(const char *szAccount, StdStrBuf *pFBIDOut)
{
assert(szAccount);
if (!szAccount) return false;
for (FBIDItem *pItem = pFirst; pItem; pItem = pItem->pNext)
if (pItem->Account == szAccount)
{
if (pFBIDOut) pFBIDOut->Copy(pItem->FBID);
return true;
}
return false;
}
void C4LeagueFBIDList::RemoveFBIDByAccount(const char *szAccount)
{
FBIDItem *pPrev = nullptr, *pItem = pFirst;
while (pItem)
{
// Delete?
if (pItem->Account == szAccount)
{
(pPrev ? pPrev->pNext : pFirst) = pItem->pNext;
delete pItem;
return;
}
// Next
pPrev = pItem; pItem = pItem->pNext;
}
}
void C4LeagueFBIDList::AddFBID(const char *szFBID, const char *szAccount)
{
// add new FBID item to head of list
assert(szFBID); assert(szAccount);
// remove any existing FBIDs
RemoveFBIDByAccount(szAccount);
// add new entry
FBIDItem *pNewItem = new FBIDItem();
pNewItem->FBID.Copy(szFBID);
pNewItem->Account.Copy(szAccount);
pNewItem->pNext = pFirst;
pFirst = pNewItem;
}
class DisconnectData
{
private:
C4LeagueFBIDList &rFBIDList;
const C4ClientPlayerInfos &rPlayerInfos;
public:
DisconnectData(C4LeagueFBIDList &rFBIDList, const C4ClientPlayerInfos &rPlayerInfos)
: rFBIDList(rFBIDList), rPlayerInfos(rPlayerInfos) {}
void CompileFunc(StdCompiler *pComp)
{
if (pComp->isDeserializer())
{
// compiling not yet needed
assert(!"DisconnectData::CompileFunc not defined for compiler!");
}
else
{
// decompiling: Compile all joined and not removed player infos.
// Compile them even if they're not in the FBID-List, but omit
// the FBID (used for host message)
int32_t i=0; C4PlayerInfo *pInfo;
while ((pInfo = rPlayerInfos.GetPlayerInfo(i++)))
if (pInfo->IsJoined() && !pInfo->IsRemoved())
{
pComp->Name("Player");
try
{
pComp->Value(mkNamingAdapt(mkDecompileAdapt(pInfo->GetID()), "ID"));
StdCopyStrBuf sFBID;
if (rFBIDList.FindFBIDByAccount(pInfo->getLeagueAccount(), &sFBID)) pComp->Value(mkNamingAdapt(mkParAdapt(sFBID, StdCompiler::RCT_IdtfAllowEmpty), "FBID"));
}
catch (StdCompiler::Exception *)
{
pComp->NameEnd();
throw;
}
pComp->NameEnd();
}
}
}
};
// *** C4LeagueClient
bool C4LeagueClient::Start(const C4Network2Reference &Ref)
{
// Create query
eCurrAction = C4LA_Start;
C4LeagueRequestHead Head(eCurrAction);
StdStrBuf QueryText = DecompileToBuf<StdCompilerINIWrite>(
mkInsertAdapt(
mkNamingAdapt(Head, "Request"),
mkNamingAdapt(mkDecompileAdapt(Ref), "Reference"),
false));
// Perform query
return Query(QueryText.getData(), false);
}
bool C4LeagueClient::GetStartReply(StdStrBuf *pMessage, StdStrBuf *pLeague, StdStrBuf *pStreamingAddr, int32_t *pSeed, int32_t *pMaxPlayers)
{
if (!isSuccess() || eCurrAction != C4LA_Start) return false;
// Parse response head
C4LeagueResponseHeadStart Head;
if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(mkNamingAdapt(Head, "Response"), ResultString, "Start Reply"))
return false;
// Get message, league and seed
if (pMessage)
pMessage->Copy(Head.getMessage());
if (pLeague)
pLeague->Copy(Head.getLeague());
if (pStreamingAddr)
pStreamingAddr->Copy(Head.getStreamingAddr());
if (pSeed && Head.haveSeed())
*pSeed = Head.getSeed();
if (pMaxPlayers)
*pMaxPlayers = Head.getMaxPlayers();
// No success?
if (!Head.isSuccess())
return false;
// Got no CSID or empty CSID?
if (!Head.getCSID() || !*Head.getCSID() || *Head.getCSID() == '\0')
{
if (pMessage)
pMessage->Copy(LoadResStr("IDS_LGA_INVALIDRESPONSE3"));
return false;
}
// So save back CSID
CSID = Head.getCSID();
return true;
}
bool C4LeagueClient::Update(const C4Network2Reference &Ref)
{
assert(CSID.getLength());
// Create query
eCurrAction = C4LA_Update;
C4LeagueRequestHead Head(eCurrAction, CSID.getData());
StdStrBuf QueryText = DecompileToBuf<StdCompilerINIWrite>(
mkInsertAdapt(
mkNamingAdapt(Head, "Request"),
mkNamingAdapt(mkDecompileAdapt(Ref), "Reference"),
false));
// Perform query
return Query(QueryText.getData(), false);
}
bool C4LeagueClient::GetUpdateReply(StdStrBuf *pMessage, C4ClientPlayerInfos *pPlayerLeagueInfos)
{
C4LeagueResponseHeadUpdate Reply;
if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(mkNamingAdapt(Reply, "Response"), ResultString, "Update Reply"))
return false;
// Get message
if (pMessage)
pMessage->Copy(Reply.getMessage());
// get plr infos
if (pPlayerLeagueInfos)
*pPlayerLeagueInfos = Reply.GetPlrInfos();
// Success
return true;
}
bool C4LeagueClient::End(const C4Network2Reference &Ref, const char *szRecordName, const BYTE *pRecordSHA)
{
assert(CSID.getLength());
// Create query
eCurrAction = C4LA_End;
C4LeagueRequestHeadEnd Head(eCurrAction, CSID.getData(), szRecordName, pRecordSHA);
StdStrBuf QueryText = DecompileToBuf<StdCompilerINIWrite>(
mkInsertAdapt(
mkNamingAdapt(Head, "Request"),
mkNamingAdapt(mkDecompileAdapt(Ref), "Reference"),
false));
// Perform query
return Query(QueryText.getData(), false);
}
bool C4LeagueClient::GetEndReply(StdStrBuf *pMessage, C4RoundResultsPlayers *pRoundResults)
{
// Parse response head
C4LeagueResponseHead Head;
if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(mkNamingAdapt(Head, "Response"), ResultString, "End Reply"))
return false;
// Get message
if (pMessage)
pMessage->Copy(Head.getMessage());
if (pRoundResults)
CompileFromBuf_LogWarn<StdCompilerINIRead>(mkNamingAdapt(mkNamingAdapt(*pRoundResults, "PlayerInfos"), "Response"), ResultString, "Round Results");
// Done
return Head.isSuccess();
}
bool C4LeagueClient::Auth(const C4PlayerInfo &PlrInfo, const char *szAccount, const char *szPassword, const char *szNewAccount, const char *szNewPassword, bool fRememberLogin)
{
// Build header
eCurrAction = C4LA_PlrAuth;
C4LeagueRequestHead Head(eCurrAction);
Head.SetAuth(szAccount, szPassword, fRememberLogin);
if (szNewAccount)
Head.SetNewAccount(szNewAccount);
if (szNewPassword)
Head.SetNewPassword(szNewPassword);
// Create query
StdStrBuf QueryText = DecompileToBuf<StdCompilerINIWrite>(
mkInsertAdapt(
mkNamingAdapt(Head, "Request"),
mkNamingAdapt(mkDecompileAdapt(PlrInfo), "PlrInfo"),
false));
// Perform query
return Query(QueryText.getData(), false);
}
bool C4LeagueClient::GetAuthReply(StdStrBuf *pMessage, StdStrBuf *pAUID, StdStrBuf *pAccount, bool *pRegister, StdStrBuf *pLoginToken)
{
C4LeagueResponseHead Head;
if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(mkNamingAdapt(Head, "Response"), ResultString, "Auth Reply"))
return false;
// Get message & account
if (pMessage)
pMessage->Copy(Head.getMessage());
if (pAccount)
pAccount->Copy(Head.getAccount());
if (pRegister)
*pRegister = Head.isStatusRegister();
if (pLoginToken)
pLoginToken->Copy(Head.getLoginToken());
// No success?
if (!Head.isSuccess())
return false;
// Check AUID
if (!Head.getAUID() || !*Head.getAUID())
{
pMessage->Ref(LoadResStr("IDS_MSG_LEAGUESERVERREPLYWITHOUTA"));
return false;
}
// Success
if (pAUID)
pAUID->Copy(Head.getAUID());
FBIDList.AddFBID(Head.getFBID(), Head.getAccount());
return true;
}
bool C4LeagueClient::AuthCheck(const C4PlayerInfo &PlrInfo)
{
assert(CSID.getLength());
// Build header
eCurrAction = C4LA_PlrAuthCheck;
C4LeagueRequestHead Head(eCurrAction, CSID.getData(), PlrInfo.getAuthID());
// Create query
StdStrBuf QueryText = DecompileToBuf<StdCompilerINIWrite>(
mkInsertAdapt(
mkNamingAdapt(Head, "Request"),
mkNamingAdapt(mkDecompileAdapt(PlrInfo), "PlrInfo"),
false));
// Perform query
return Query(QueryText.getData(), false);
}
bool C4LeagueClient::GetAuthCheckReply(StdStrBuf *pMessage, const char *szLeague, C4PlayerInfo *pPlrInfo)
{
// Parse response head
C4LeagueResponseHeadAuthCheck Head;
if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(mkNamingAdapt(Head, "Response"), ResultString, "Auth Check Reply"))
return false;
// Get message and additional data
if (pMessage)
pMessage->Copy(Head.getMessage());
if (szLeague && pPlrInfo)
pPlrInfo->SetLeagueData(Head.getAccount(), Head.getClanTag(), Head.getScore(szLeague), Head.getRank(szLeague), Head.getRankSymbol(szLeague), Head.getProgressData(szLeague));
return Head.isSuccess();
}
bool C4LeagueClient::ReportDisconnect(const C4ClientPlayerInfos &rFeedbackClient, C4LeagueDisconnectReason eReason)
{
// Build header
eCurrAction = C4LA_ReportDisconnect;
C4LeagueReportDisconnectHead Head(CSID.getData(), eReason);
// Create query
StdStrBuf QueryText = DecompileToBuf<StdCompilerINIWrite>(
mkInsertAdapt(
mkNamingAdapt(Head, "Request"),
mkNamingAdapt(DisconnectData(FBIDList, rFeedbackClient), "PlayerInfos"),
false));
// Perform query
return Query(QueryText.getData(), false);
}
bool C4LeagueClient::GetReportDisconnectReply(StdStrBuf *pMessage)
{
// Parse response head
C4LeagueResponseHead Head;
if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(mkNamingAdapt(Head, "Response"), ResultString, "Report Disconnect"))
return false;
// Get message
if (pMessage)
pMessage->Copy(Head.getMessage());
// Done
return Head.isSuccess();
}
// *** C4LeagueSignupDialog
C4LeagueSignupDialog::C4LeagueSignupDialog(const char *szPlayerName, const char *szLeagueName, const char *szLeagueServerName, const char *szAccountPref, const char *szPassPref, bool fWarnThirdParty, bool fRegister, bool fRememberLogin)
: C4GUI::Dialog(C4GUI_MessageDlgWdt, 100 /* will be resized as needed */, FormatString(LoadResStr("IDS_DLG_LEAGUESIGNUPON"), szLeagueServerName).getData(), false), strPlayerName(szPlayerName), pChkRememberLogin(nullptr)
{
// get positions
C4GUI::ComponentAligner caMain(GetClientRect(), C4GUI_DefDlgIndent, C4GUI_DefDlgIndent, true);
// place icon
C4Rect rcIcon = caMain.GetFromLeft(C4GUI_IconWdt); rcIcon.Hgt = C4GUI_IconHgt;
C4GUI::Icon *pIcon = new C4GUI::Icon(rcIcon, C4GUI::Ico_Ex_League); AddElement(pIcon);
caMain.GetFromRight(C4GUI_IconWdt/2);
// place message label
// use text with line breaks
StdStrBuf sMsg, sMsgBroken;
if (fRegister)
sMsg.Format(LoadResStr("IDS_MSG_LEAGUE_REGISTRATION"), szPlayerName);
else
sMsg.Format(LoadResStr("IDS_MSG_PASSWORDFORPLAYER"), szPlayerName);
int32_t iLabelHgt = ::GraphicsResource.TextFont.BreakMessage(sMsg.getData(), caMain.GetInnerWidth(), &sMsgBroken, true);
C4GUI::Label *pLblMessage = new C4GUI::Label(sMsgBroken.getData(), caMain.GetFromTop(iLabelHgt), ALeft, C4GUI_MessageFontClr, &::GraphicsResource.TextFont);
AddElement(pLblMessage);
// registering and no account pref available
if (fRegister && (!szAccountPref || !szAccountPref[0]))
// use player name as default for league name
szAccountPref = szPlayerName;
// place username input box
bool fSideEdits=true; int iCtrlHeight;
StdStrBuf sAccountTxt; sAccountTxt.Copy(LoadResStr("IDS_CTL_LEAGUE_ACCOUNT"));
C4GUI::LabeledEdit::GetControlSize(nullptr, &iCtrlHeight, sAccountTxt.getData(), nullptr, fSideEdits);
AddElement(pEdtAccount = new C4GUI::LabeledEdit(caMain.GetFromTop(iCtrlHeight), sAccountTxt.getData(), fSideEdits, szAccountPref));
// registering? Make password field optional
if (fRegister)
{
// place the checkbox
const char *szChkPasswordCaption = LoadResStr("IDS_CTL_LEAGUE_CHK_PLRPW");
C4GUI::CheckBox::GetStandardCheckBoxSize(nullptr, &iCtrlHeight, szChkPasswordCaption, nullptr);
AddElement(pChkPassword = new C4GUI::CheckBox(caMain.GetFromTop(iCtrlHeight), szChkPasswordCaption, false));
pChkPassword->SetOnChecked(new C4GUI::CallbackHandlerNoPar<C4LeagueSignupDialog>(this, &C4LeagueSignupDialog::OnChkPassword));
pChkPassword->SetToolTip(LoadResStr("IDS_DESC_LEAGUECHECKPASSWORD"));
// place password edit boxes
C4GUI::ComponentAligner caTemp = caMain;
const char *szEdtPassCaption = LoadResStr("IDS_CTL_LEAGUE_PLRPW");
const char *szEdtPass2Caption = LoadResStr("IDS_CTL_LEAGUE_PLRPW2");
C4GUI::LabeledEdit::GetControlSize(nullptr, &iCtrlHeight, szEdtPassCaption, nullptr, fSideEdits);
AddElement(pEdtPass = new C4GUI::LabeledEdit(caTemp.GetFromTop(iCtrlHeight), szEdtPassCaption, fSideEdits, szPassPref));
AddElement(pEdtPass2 = new C4GUI::LabeledEdit(caTemp.GetFromTop(iCtrlHeight), szEdtPass2Caption, fSideEdits, szPassPref));
// hide them
pEdtPass->SetVisibility(false);
pEdtPass2->SetVisibility(false);
// save how much to move the controls later
iEdtPassSpace = caTemp.GetHeight() - caMain.GetHeight();
}
else
{
// No password checkbox
pChkPassword = nullptr;
// But a password edit box
const char *szEdtPassCaption = LoadResStr("IDS_CTL_LEAGUE_PLRPW");
C4GUI::LabeledEdit::GetControlSize(nullptr, &iCtrlHeight, szEdtPassCaption, nullptr, fSideEdits);
AddElement(pEdtPass = new C4GUI::LabeledEdit(caMain.GetFromTop(iCtrlHeight), szEdtPassCaption, fSideEdits, szPassPref));
// No second password edit box
pEdtPass2 = nullptr;
// remember login-checkbox
const char *szRememberPasswordCaption = LoadResStr("IDS_CTL_LEAGUE_CHK_REMEMBERLOGIN");
C4GUI::CheckBox::GetStandardCheckBoxSize(nullptr, &iCtrlHeight, szRememberPasswordCaption, nullptr);
AddElement(pChkRememberLogin = new C4GUI::CheckBox(caMain.GetFromTop(iCtrlHeight), szRememberPasswordCaption, fRememberLogin));
pChkRememberLogin->SetToolTip(LoadResStr("IDS_DESC_REMEMBERLOGIN"));
}
// Set password box options
pEdtPass->GetEdit()->SetPasswordMask('*');
if (pEdtPass2)
{
pEdtPass2->GetEdit()->SetPasswordMask('*');
}
// place confirmation buttons
C4GUI::ComponentAligner caButtonArea(caMain.GetFromTop(C4GUI_ButtonAreaHgt), 0,0);
C4Rect rcBtn = caButtonArea.GetCentered(2*C4GUI_DefButton2Wdt+C4GUI_DefButton2HSpace, C4GUI_ButtonHgt);
rcBtn.Wdt = C4GUI_DefButton2Wdt;
pBtnOK = new C4GUI::OKButton(rcBtn);
AddElement(pBtnOK);
rcBtn.x += C4GUI_DefButton2Wdt+C4GUI_DefButton2HSpace;
pBtnAbort = new C4GUI::CancelButton(rcBtn);
AddElement(pBtnAbort);
// resize to actually needed size
SetClientSize(GetClientRect().Wdt, GetClientRect().Hgt - caMain.GetHeight());
// initial focus
SetFocus(fRegister ? pEdtAccount->GetEdit() : pEdtPass->GetEdit(), false);
}
void C4LeagueSignupDialog::UserClose(bool fOK)
{
// Abort? That's always okay
if (!fOK)
{
Dialog::UserClose(fOK);
::pGUI->ShowMessageModal(FormatString(LoadResStr("IDS_MSG_LEAGUESIGNUPCANCELLED"), strPlayerName.getData()).getData(), LoadResStr("IDS_DLG_LEAGUESIGNUP"), C4GUI::MessageDialog::btnOK, C4GUI::Ico_Notify);
return;
}
// Check for empty account name
const char *szAccount = pEdtAccount->GetText();
if (!szAccount || !*szAccount)
{
SetFocus(pEdtAccount->GetEdit(), false);
::pGUI->ShowMessageModal(LoadResStr("IDS_MSG_LEAGUEMISSINGUSERNAME"), LoadResStr("IDS_DLG_INVALIDENTRY"), C4GUI::MessageDialog::btnOK, C4GUI::Ico_Error);
return;
}
// Check for valid username if this is registration
if (pEdtPass2)
{
// Username contains invalid characters
if (SCharCountEx(szAccount, C4League_Name_Valid_Characters) != SLen(szAccount))
{
SetFocus(pEdtAccount->GetEdit(), false);
::pGUI->ShowMessageModal(LoadResStr("IDS_MSG_LEAGUEINVALIDUSERNAME"), LoadResStr("IDS_DLG_INVALIDENTRY"), C4GUI::MessageDialog::btnOK, C4GUI::Ico_Error);
return;
}
// Username is too short
if (SLen(szAccount) < 3)
{
SetFocus(pEdtAccount->GetEdit(), false);
::pGUI->ShowMessageModal(LoadResStr("IDS_MSG_LEAGUEUSERNAMETOOSHORT"), LoadResStr("IDS_DLG_INVALIDENTRY"), C4GUI::MessageDialog::btnOK, C4GUI::Ico_Error);
return;
}
}
// Check password
if (!pChkPassword || pChkPassword->GetChecked())
{
// Check for empty password
const char *szPassword = pEdtPass->GetText();
if (!szPassword || !*szPassword)
{
SetFocus(pEdtPass->GetEdit(), false);
::pGUI->ShowMessageModal(LoadResStr("IDS_MSG_LEAGUEMISSINGPASSWORD"), LoadResStr("IDS_DLG_INVALIDENTRY"), C4GUI::MessageDialog::btnOK, C4GUI::Ico_Error);
return;
}
// Check second password
if (pEdtPass2 && !SEqual(szPassword, pEdtPass2->GetText()))
{
SetFocus(pEdtPass2->GetEdit(), false);
pEdtPass2->GetEdit()->SetText("", false);
::pGUI->ShowMessageModal(LoadResStr("IDS_MSG_LEAGUEMISMATCHPASSWORD"), LoadResStr("IDS_DLG_INVALIDENTRY"), C4GUI::MessageDialog::btnOK, C4GUI::Ico_Error);
return;
}
}
// Okay then
Dialog::UserClose(fOK);
}
bool C4LeagueSignupDialog::ShowModal(const char *szPlayerName, const char *szLeagueName, const char *szLeagueServerName, StdStrBuf *psCUID, StdStrBuf *psPass, bool fWarnThirdParty, bool fRegister, bool *pfRememberLogin)
{
// show league signup dlg modally; return whether user pressed OK and change user and pass buffers in that case
assert(psCUID); assert(psPass);
if (!psCUID || !psPass) return false;
C4LeagueSignupDialog *pDlg = new C4LeagueSignupDialog(szPlayerName, szLeagueName, szLeagueServerName, psCUID->getData(), psPass->getData(), fWarnThirdParty, fRegister, *pfRememberLogin);
bool fResult = ::pGUI->ShowModalDlg(pDlg, false);
if (fResult)
{
psCUID->Copy(pDlg->GetAccount());
if (pDlg->HasPass())
psPass->Copy(pDlg->GetPass());
else
psPass->Clear();
*pfRememberLogin = pDlg->GetRememberLogin();
}
delete pDlg;
return fResult;
}
void C4LeagueSignupDialog::OnChkPassword()
{
if (!pChkPassword) return;
// Show password elements?
if (!pChkPassword->GetChecked())
{
// Enlarge dialog
C4Rect bnds = GetClientRect();
SetClientSize(bnds.Wdt, bnds.Hgt + iEdtPassSpace);
// Show edit controls
pEdtPass->SetVisibility(false);
pEdtPass2->SetVisibility(false);
// Move controls down
bnds = pBtnOK->GetBounds();
pBtnOK->SetPos(bnds.x, bnds.y + iEdtPassSpace);
bnds = pBtnAbort->GetBounds();
pBtnAbort->SetPos(bnds.x, bnds.y + iEdtPassSpace);
}
else
{
// Shrink dialog
C4Rect bnds = GetClientRect();
SetClientSize(bnds.Wdt, bnds.Hgt - iEdtPassSpace);
// Hide edit controls
pEdtPass->SetVisibility(true);
pEdtPass2->SetVisibility(true);
// Move controls down
bnds = pBtnOK->GetBounds();
pBtnOK->SetPos(bnds.x, bnds.y - iEdtPassSpace);
bnds = pBtnAbort->GetBounds();
pBtnAbort->SetPos(bnds.x, bnds.y - iEdtPassSpace);
}
}