Originally Posted by
Master674
That looks really really awesome. Is that login screen animated or is it just a picture?
How did you manage to add that account creation tool? Does it perform HTTP requests or is it directly connecting to your core?
The login screen is a combination of animated models and images. The "Login Screen" button on the bottom right brings up a menu that lets you set the quality level of the login screen. The screenshot shows high. Ultra has many more animated models and adds fog (particle effects use up a lot of processing power in WoW). The lowest quality is 2d (just a image). An old video I have shows this off: https://www.youtube.com/watch?featur...PBPagtYA#t=72s
You cannot perform HTTP requests in WoW, though you can exit WoW and visit a URL.
Essentially I look for where strings are sent to the server and where a value is sent to the client.
On the login screen the only place a variable string is sent to the server is logging in. Username is sent and the password field encrypted is sent.
So what I do is when the "Create Account" button is pressed, I tell the client with a variable that I am now going to be creating an account. This changes the error messages.
The client sends to the server "?username?password?" as the username field (replacing with the relevant details), and random encrypted password. The server listens for a username that begins with "?" then validates and processes the data. It creates the account if all is valid. It will return a different error message (realm is full, you are ban, etc) depending on how far it gets through validation. The variable I flagged earlier will change these error messages client side to different things like, "Username can only contain letters A-Z and numeric values".
As you can only send 50 characters per login (username field) and you cannot login twice at the same time, I send the email field using a different character a few seconds later. A similar method is applied.
It's just problem solving - working with the resources you have.
Client side code:
Code:
function CreateAccountFinal(self)
CreateAccountFrame:Hide();
local username = AccountNameEditBox:GetText();
local email = AccountEmailEditBox:GetText();
local password = AccountPasswordEditBox:GetText();
local cpassword = AccountPasswordConfirmEditBox:GetText();
if ( password ~= cpassword ) then
GlueDialog_Show("REALM_TOURNAMENT_WARNING", "Account creation failed.\n\rPasswords do not match.", nil);
return;
elseif ( strlen(username) < 3 or strlen(email) < 5 or strlen(password) < 4 or strfind(username, "[^%w]") or strfind(password, "[^%w]") --[[or strfind(email, "[^%w]")]] ) then
GlueDialog_Show("REALM_TOURNAMENT_WARNING", "Account creation failed.\n\rOnly alphanumerical characters (A-Z, 0-9) allowed!", nil);
return;
end
local info = table.concat({"?", username, "?", password, "?"});
CreateAccountReply = true;
DefaultServerLogin(info, tostring(math.random(1, 100000)));
AccountCreateButton:Disable();
email = string.gsub(email, "%@", "%~")
info = table.concat({"&", username, "&", email, "&"});
SAVE_INFO = info
SAVE_EVENT = true
AccountEmailEditBox:SetText("");
if not SAVE_FRAME then
SAVE_FRAME = CreateFrame("Frame")
SAVE_FRAME:SetScript("OnUpdate", UpdateAccountEmail)
end
end
function UpdateAccountEmail(self, elapsed)
if (SAVE_EVENT) then
SAVE_TIMER = SAVE_TIMER + elapsed
if (SAVE_TIMER > 3) then
SAVE_TIMER = 0
SAVE_EVENT = false
if (SAVE_INFO) then
CreateAccountReply = true;
DefaultServerLogin(SAVE_INFO, tostring(math.random(1, 100000)));
AccountCreateButton:Enable();
SAVE_INFO = nil
end
end
end
end
Server side:
Code:
string AccountName = (char*)&m_challenge.I;
if (AccountName.substr(0, 1) == "?")
{
if (AccountName.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?") != string::npos)
{
LOG_ERROR("[AuthChallenge]: Tried to create account with illegal characters.");
SendChallengeError(CE_NO_ACCOUNT); //Well **** you for editing the files!
return;
}
int pass_start = AccountName.find("?", 1) + 1;
if (pass_start < 4) //No username
{
LOG_ERROR("[AuthChallenge] Tried to create account with no account name.");
SendChallengeError(CE_NO_ACCOUNT);
return;
}
int pass_end = AccountName.rfind("?");
if (pass_end <= pass_start) //No password
{
LOG_ERROR("[AuthChallenge] Tried to create account with no password.");
SendChallengeError(CE_NO_ACCOUNT);
return;
}
int name_len = pass_start - 2;
int pass_len = pass_end - pass_start;
string username = AccountName.substr(1, name_len);
string password = AccountName.substr(pass_start, pass_len);
m_account = AccountMgr::getSingleton().GetAccount(username);
if (m_account != 0)
{
LOG_ERROR("[AuthChallenge] Account creation failed: account name already taken.");
SendChallengeError(CE_ACCOUNT_IN_USE);
return;
}
string cmd = username + " " + password + " NULL"; //Prepare command for CreateAccount
char acct[50];
memcpy(acct, cmd.c_str(), 50); //CreateAccount doesn't take const char*
LogonConsole::getSingleton().CreateAccount(acct);
SendChallengeError(CE_SERVER_FULL); //Success!
LOG_BASIC("[AuthChallenge] Client %s has created an account with name: \"%s\"", GetRemoteIP().c_str(), username.c_str());
return;
}
if (AccountName.substr(0, 1) == "&")
{
if (AccountName.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?.~&") != string::npos)
{
LOG_ERROR("[AuthChallenge]: Tried to update account with illegal chars. %s", AccountName.c_str());
SendChallengeError(CE_NO_ACCOUNT); //Well **** you for editing the files!
return;
}
int pass_start = AccountName.find("&", 1) + 1;
if (pass_start < 4) //No username
{
LOG_ERROR("[AuthChallenge] Tried to update account with no account name.");
SendChallengeError(CE_NO_ACCOUNT);
return;
}
int pass_end = AccountName.rfind("&");
if (pass_end <= pass_start) //No password
{
LOG_ERROR("[AuthChallenge] Tried to update account with no email.");
SendChallengeError(CE_NO_ACCOUNT);
return;
}
int name_len = pass_start - 2;
int pass_len = pass_end - pass_start;
string username = AccountName.substr(1, name_len);
string email = AccountName.substr(pass_start, pass_len);
for (uint8 i = 0; i < email.length(); i++)
{
if (email[i] == '~')
{
email[i] = '@';
break;
}
}
m_account = AccountMgr::getSingleton().GetAccount(username);
if (m_account == 0)
{
LOG_ERROR("[AuthChallenge] Account update failed: account does not exist.");
SendChallengeError(CE_ACCOUNT_IN_USE);
return;
}
std::stringstream query;
query << "UPDATE `accounts` SET `email` = '" << email << "' WHERE `login` = '" << username << "' AND `email` = 'NULL';";
sLogonSQL->WaitExecuteNA(query.str().c_str());
SendChallengeError(CE_SERVER_FULL); //Success!
return;
}