summaryrefslogtreecommitdiff
path: root/src/account-server
diff options
context:
space:
mode:
authorBjørn Lindeijer <bjorn@lindeijer.nl>2007-02-04 21:52:17 +0000
committerBjørn Lindeijer <bjorn@lindeijer.nl>2007-02-04 21:52:17 +0000
commitcade1ba618bd1883e044999a0cbda201f1f76dd4 (patch)
tree978d8e0d97b0f5b0eec3a77a8d25e54b870ed786 /src/account-server
parent9c0421f5926d22a44c978fff683c51748a19e976 (diff)
downloadmanaserv-cade1ba618bd1883e044999a0cbda201f1f76dd4.tar.gz
manaserv-cade1ba618bd1883e044999a0cbda201f1f76dd4.tar.bz2
manaserv-cade1ba618bd1883e044999a0cbda201f1f76dd4.tar.xz
manaserv-cade1ba618bd1883e044999a0cbda201f1f76dd4.zip
Added support for switching character by reconnecting to the account server and
fixed the issue where a client is not logged in after registering (patch by Rogier Polak).
Diffstat (limited to 'src/account-server')
-rw-r--r--src/account-server/accounthandler.cpp141
-rw-r--r--src/account-server/accounthandler.hpp3
-rw-r--r--src/account-server/dalstorage.cpp89
-rw-r--r--src/account-server/dalstorage.hpp10
-rw-r--r--src/account-server/serverhandler.cpp23
-rw-r--r--src/account-server/storage.hpp10
6 files changed, 263 insertions, 13 deletions
diff --git a/src/account-server/accounthandler.cpp b/src/account-server/accounthandler.cpp
index 3b0663af..c6a086ea 100644
--- a/src/account-server/accounthandler.cpp
+++ b/src/account-server/accounthandler.cpp
@@ -21,9 +21,11 @@
* $Id$
*/
+#include "account-server/accounthandler.hpp"
+
+#include "defines.h"
#include "configuration.h"
#include "point.h"
-#include "account-server/accounthandler.hpp"
#include "account-server/account.hpp"
#include "account-server/accountclient.hpp"
#include "account-server/serverhandler.hpp"
@@ -36,6 +38,27 @@
#include "utils/logger.h"
#include "utils/stringfilter.h"
+// TODO: Implement a class to handle these tokens more generally
+
+typedef std::map< std::string, AccountClient* > AccountPendingClients;
+typedef std::map< std::string, int > AccountPendingReconnects;
+
+/**
+ * Client is faster then game server
+ */
+static AccountPendingClients pendingClients;
+
+/**
+ * Game server is faster then client
+ */
+static AccountPendingReconnects pendingReconnects;
+
+void
+registerAccountReconnect(int accountID, const std::string& magic_token);
+
+void
+handleReconnectedAccount(AccountClient &computer, int accountID);
+
bool
AccountHandler::startListen(enet_uint16 port)
{
@@ -81,23 +104,33 @@ AccountHandler::processMessage(NetComputer *comp, MessageIn &message)
switch (message.getId())
{
case PAMSG_LOGIN:
+ LOG_DEBUG("Received msg ... PAMSG_LOGIN");
handleLoginMessage(computer, message);
break;
case PAMSG_LOGOUT:
+ LOG_DEBUG("Received msg ... PAMSG_LOGOUT");
handleLogoutMessage(computer);
break;
+ case PAMSG_RECONNECT:
+ LOG_DEBUG("Received msg ... PAMSG_RECONNECT");
+ handleReconnectMessage(computer, message);
+ break;
+
case PAMSG_REGISTER:
+ LOG_DEBUG("Received msg ... PAMSG_REGISTER");
handleRegisterMessage(computer, message);
break;
case PAMSG_UNREGISTER:
+ LOG_DEBUG("Received msg ... PAMSG_UNREGISTER");
handleUnregisterMessage(computer, message);
break;
case PAMSG_EMAIL_CHANGE:
{
+ LOG_DEBUG("Received msg ... PAMSG_EMAIL_CHANGE");
result.writeShort(APMSG_EMAIL_CHANGE_RESPONSE);
if (computer.getAccount().get() == NULL) {
@@ -128,6 +161,7 @@ AccountHandler::processMessage(NetComputer *comp, MessageIn &message)
case PAMSG_EMAIL_GET:
{
+ LOG_DEBUG("Received msg ... PAMSG_EMAIL_GET");
result.writeShort(APMSG_EMAIL_GET_RESPONSE);
if (computer.getAccount().get() == NULL) {
result.writeByte(ERRMSG_NO_LOGIN);
@@ -142,15 +176,18 @@ AccountHandler::processMessage(NetComputer *comp, MessageIn &message)
break;
case PAMSG_PASSWORD_CHANGE:
+ LOG_DEBUG("Received msg ... PAMSG_PASSWORD_CHANGE");
handlePasswordChangeMessage(computer, message);
break;
case PAMSG_CHAR_CREATE:
+ LOG_DEBUG("Received msg ... PAMSG_CHAR_CREATE");
handleCharacterCreateMessage(computer, message);
break;
case PAMSG_CHAR_SELECT:
{
+ LOG_DEBUG("Received msg ... PAMSG_CHAR_SELECT");
result.writeShort(APMSG_CHAR_SELECT_RESPONSE);
if (computer.getAccount().get() == NULL)
@@ -205,6 +242,7 @@ AccountHandler::processMessage(NetComputer *comp, MessageIn &message)
case PAMSG_CHAR_DELETE:
{
+ LOG_DEBUG("Received msg ... PAMSG_CHAR_DELETE");
result.writeShort(APMSG_CHAR_DELETE_RESPONSE);
if (computer.getAccount().get() == NULL)
@@ -244,7 +282,8 @@ AccountHandler::processMessage(NetComputer *comp, MessageIn &message)
break;
default:
- LOG_WARN("Invalid message type");
+ LOG_WARN("AccountHandler::processMessage, Invalid message type "
+ << message.getId());
result.writeShort(XXMSG_INVALID);
break;
}
@@ -340,6 +379,34 @@ AccountHandler::handleLogoutMessage(AccountClient &computer)
}
void
+AccountHandler::handleReconnectMessage(AccountClient &computer, MessageIn &msg)
+{
+ if (computer.getAccount().get() == NULL)
+ {
+ std::string magic_token = msg.readString(32);
+ AccountPendingReconnects::iterator i = pendingReconnects.find(magic_token);
+ if (i == pendingReconnects.end())
+ {
+ for (AccountPendingClients::iterator j = pendingClients.begin(),
+ j_end = pendingClients.end(); j != j_end; ++j)
+ {
+ if (j->second == &computer) return; //Allready inserted
+ }
+ pendingClients.insert(std::make_pair(magic_token, &computer));
+ return; //Waiting for the gameserver, note: using return instead of an else
+ }
+ // Gameserver communication was faster, connect the client
+ int accountID = i->second;
+ pendingReconnects.erase(i);
+ handleReconnectedAccount(computer, accountID);
+ }
+ else
+ {
+ LOG_WARN("Account tried to reconnect, but was allready logged in.");
+ }
+}
+
+void
AccountHandler::handleRegisterMessage(AccountClient &computer, MessageIn &msg)
{
unsigned long clientVersion = msg.readLong();
@@ -400,6 +467,9 @@ AccountHandler::handleRegisterMessage(AccountClient &computer, MessageIn &msg)
AccountPtr acc(new Account(username, password, email));
store.addAccount(acc);
reply.writeByte(ERRMSG_OK);
+
+ // Associate account with connection
+ computer.setAccount(acc);
}
}
@@ -410,6 +480,7 @@ void
AccountHandler::handleUnregisterMessage(AccountClient &computer,
MessageIn &msg)
{
+ LOG_DEBUG("AccountHandler::handleUnregisterMessage");
std::string username = msg.readString();
std::string password = msg.readString();
@@ -424,13 +495,18 @@ AccountHandler::handleUnregisterMessage(AccountClient &computer,
// See if the account exists
Storage &store = Storage::instance("tmw");
AccountPtr accPtr = store.getAccount(username);
-
+ LOG_INFO("Unregister for " << username << " with passwords #" << accPtr->getPassword() << "#" << password << "#");
if (!accPtr.get() || accPtr->getPassword() != password)
{
reply.writeByte(ERRMSG_INVALID_ARGUMENT);
}
else
{
+ // Delete account and associated characters
+ LOG_DEBUG("Farewell " << username << " ...");
+ store.delAccount(accPtr);
+ reply.writeByte(ERRMSG_OK);
+
// If the account to delete is the current account we're logged in.
// Get out of it in memory.
if (computer.getAccount().get() != NULL )
@@ -440,11 +516,6 @@ AccountHandler::handleUnregisterMessage(AccountClient &computer,
computer.unsetAccount();
}
}
-
- // Delete account and associated characters
- LOG_INFO("Farewell " << username << " ...");
- store.delAccount(accPtr);
- reply.writeByte(ERRMSG_OK);
}
}
@@ -627,3 +698,57 @@ AccountHandler::handleCharacterCreateMessage(AccountClient &computer,
computer.send(reply);
}
+
+void
+registerAccountReconnect(int accountID, const std::string& magic_token)
+{
+ AccountPendingClients::iterator i = pendingClients.find(magic_token);
+ if (i == pendingClients.end())
+ {
+ pendingReconnects.insert(std::make_pair(magic_token, accountID));
+ }
+ else
+ {
+ AccountClient &computer = *(i->second);
+ handleReconnectedAccount(computer, accountID);
+ pendingClients.erase(i);
+ }
+}
+
+void
+handleReconnectedAccount(AccountClient &computer, int accountID)
+{
+ MessageOut reply(APMSG_RECONNECT_RESPONSE);
+
+ // Check if the account exists
+ Storage &store = Storage::instance("tmw");
+ AccountPtr acc = store.getAccountByID(accountID);
+
+ // Associate account with connection
+ computer.setAccount(acc);
+
+ reply.writeByte(ERRMSG_OK);
+ computer.send(reply);
+
+ // Return information about available characters
+ Players &chars = computer.getAccount()->getCharacters();
+
+ // Send characters list
+ for (unsigned int i = 0; i < chars.size(); i++)
+ {
+ MessageOut charInfo(APMSG_CHAR_INFO);
+ charInfo.writeByte(i); // Slot
+ charInfo.writeString(chars[i]->getName());
+ charInfo.writeByte((unsigned char) chars[i]->getGender());
+ charInfo.writeByte(chars[i]->getHairStyle());
+ charInfo.writeByte(chars[i]->getHairColor());
+ charInfo.writeByte(chars[i]->getLevel());
+ charInfo.writeShort(chars[i]->getMoney());
+
+ for (int j = 0; j < NB_RSTAT; ++j)
+ {
+ charInfo.writeShort(chars[i]->getRawStat(j));
+ }
+ computer.send(charInfo);
+ }
+}
diff --git a/src/account-server/accounthandler.hpp b/src/account-server/accounthandler.hpp
index 712cde9a..da9140e4 100644
--- a/src/account-server/accounthandler.hpp
+++ b/src/account-server/accounthandler.hpp
@@ -67,6 +67,9 @@ class AccountHandler : public ConnectionHandler
handleLogoutMessage(AccountClient &computer);
void
+ handleReconnectMessage(AccountClient &computer, MessageIn &msg);
+
+ void
handleRegisterMessage(AccountClient &computer, MessageIn &msg);
void
diff --git a/src/account-server/dalstorage.cpp b/src/account-server/dalstorage.cpp
index c4dad80f..5cc8dd0f 100644
--- a/src/account-server/dalstorage.cpp
+++ b/src/account-server/dalstorage.cpp
@@ -155,9 +155,10 @@ DALStorage::open(void)
// we will stick with strategy2 for the moment as we are focusing
// on SQLite.
- // FIXME: The tables should be checked/created at startup in order to avoid
- // a DbSqlQueryExecFailure assert on sqlite while registering.
- // Also, this would initialize connection to the database earlier in memory.
+ // FIXME: The tables should be checked/created at startup in order to
+ // avoid a DbSqlQueryExecFailure assert on sqlite while registering.
+ // Also, this would initialize connection to the database earlier in
+ // memory.
createTable(ACCOUNTS_TBL_NAME, SQL_ACCOUNTS_TABLE);
createTable(CHARACTERS_TBL_NAME, SQL_CHARACTERS_TABLE);
@@ -167,7 +168,7 @@ DALStorage::open(void)
createTable(CHANNELS_TBL_NAME, SQL_CHANNELS_TABLE);
}
catch (const DbConnectionFailure& e) {
- LOG_ERROR("unable to connect to the database: " << e.what());
+ LOG_ERROR("Unable to connect to the database: " << e.what());
}
catch (const DbSqlQueryExecFailure& e) {
LOG_ERROR("SQL query failure: " << e.what());
@@ -269,6 +270,85 @@ DALStorage::getAccount(const std::string& userName)
}
}
+/**
+ * Get an account by ID.
+ */
+AccountPtr
+DALStorage::getAccountByID(int accountID)
+{
+ // connect to the database (if not connected yet).
+ open();
+
+ // look for the account in the list first.
+ Accounts::iterator it = mAccounts.find(accountID);
+
+ if (it != mAccounts.end())
+ return it->second;
+
+ using namespace dal;
+
+ // the account was not in the list, look for it in the database.
+ try {
+ std::ostringstream sql;
+ sql << "select * from " << ACCOUNTS_TBL_NAME << " where id = '"
+ << accountID << "';";
+ const RecordSet& accountInfo = mDb->execSql(sql.str());
+
+ // if the account is not even in the database then
+ // we have no choice but to return nothing.
+ if (accountInfo.isEmpty()) {
+ return AccountPtr(NULL);
+ }
+
+ // specialize the string_to functor to convert
+ // a string to an unsigned int.
+ string_to< unsigned > toUint;
+ unsigned id = toUint(accountInfo(0, 0));
+
+ // create an Account instance
+ // and initialize it with information about the user.
+ AccountPtr account(new Account(accountInfo(0, 1),
+ accountInfo(0, 2),
+ accountInfo(0, 3), id));
+
+ mAccounts.insert(std::make_pair(id, account));
+
+ // load the characters associated with the account.
+ sql.str(std::string());
+ sql << "select id from " << CHARACTERS_TBL_NAME << " where user_id = '"
+ << accountInfo(0, 0) << "';";
+ RecordSet const &charInfo = mDb->execSql(sql.str());
+
+ if (!charInfo.isEmpty())
+ {
+ int size = charInfo.rows();
+ Players players;
+
+ LOG_DEBUG("AccountID: "<< accountID << "; has " << size
+ << " character(s) in database.");
+
+ // Two steps: it seems like multiple requests cannot be alive at the same time.
+ std::vector< unsigned > playerIDs;
+ for (int k = 0; k < size; ++k)
+ {
+ playerIDs.push_back(toUint(charInfo(k, 0)));
+ }
+
+ for (int k = 0; k < size; ++k)
+ {
+ players.push_back(getCharacter(playerIDs[k]));
+ }
+
+ account->setCharacters(players);
+ }
+
+ return account;
+ }
+ catch (const DbSqlQueryExecFailure& e)
+ {
+ return AccountPtr(NULL); // TODO: Throw exception here
+ }
+}
/**
* Gets a character by database ID.
@@ -310,6 +390,7 @@ PlayerPtr DALStorage::getCharacter(int id)
string_to< unsigned short > toUshort;
PlayerData *player = new PlayerData(charInfo(0, 2), toUint(charInfo(0, 0)));
+ player->setAccountID(toUint(charInfo(0, 1)));
player->setGender(toUshort(charInfo(0, 3)));
player->setHairStyle(toUshort(charInfo(0, 4)));
player->setHairColor(toUshort(charInfo(0, 5)));
diff --git a/src/account-server/dalstorage.hpp b/src/account-server/dalstorage.hpp
index d2633e23..674b67f6 100644
--- a/src/account-server/dalstorage.hpp
+++ b/src/account-server/dalstorage.hpp
@@ -66,6 +66,16 @@ class DALStorage: public Storage
getAccount(const std::string& userName);
/**
+ * Get an account by ID.
+ *
+ * @param accountID the ID of the account.
+ *
+ * @return the account associated with the ID.
+ */
+ AccountPtr
+ getAccountByID(int accountID);
+
+ /**
* Gets a character by database ID.
*
* @param id the ID of the character.
diff --git a/src/account-server/serverhandler.cpp b/src/account-server/serverhandler.cpp
index 2340d581..e4ec218f 100644
--- a/src/account-server/serverhandler.cpp
+++ b/src/account-server/serverhandler.cpp
@@ -31,6 +31,9 @@
#include "net/netcomputer.hpp"
#include "utils/logger.h"
+extern void registerAccountReconnect(int accountID,
+ const std::string &magic_token);
+
bool ServerHandler::startListen(enet_uint16 port)
{
LOG_INFO("Game server handler started:");
@@ -91,6 +94,7 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
{
case GAMSG_REGISTER:
{
+ LOG_DEBUG("GAMSG_REGISTER");
// TODO: check the credentials of the game server
std::string address = msg.readString();
int port = msg.readShort();
@@ -118,6 +122,7 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
case GAMSG_PLAYER_DATA:
{
+ LOG_DEBUG("GAMSG_PLAYER_DATA");
int id = msg.readLong();
Storage &store = Storage::instance("tmw");
PlayerPtr ptr = store.getCharacter(id);
@@ -135,6 +140,7 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
case GAMSG_REDIRECT:
{
+ LOG_DEBUG("GAMSG_REDIRECT");
int id = msg.readLong();
std::string magic_token(32, ' ');
for (int i = 0; i < 32; ++i)
@@ -162,8 +168,23 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
}
} break;
+ case GAMSG_PLAYER_RECONNECT:
+ {
+ LOG_DEBUG("GAMSG_PLAYER_RECONNECT");
+ int characterID = msg.readLong();
+ std::string magic_token = msg.readString(32);
+
+ Storage &store = Storage::instance("tmw");
+ PlayerPtr ptr = store.getCharacter(characterID);
+
+ int accountID = ptr->getAccountID();
+ registerAccountReconnect(accountID, magic_token);
+
+ } break;
+
default:
- LOG_WARN("Invalid message type: " << msg.getId());
+ LOG_WARN("ServerHandler::processMessage, Invalid message type: "
+ << msg.getId());
result.writeShort(XXMSG_INVALID);
break;
}
diff --git a/src/account-server/storage.hpp b/src/account-server/storage.hpp
index d530f6f2..031acf4d 100644
--- a/src/account-server/storage.hpp
+++ b/src/account-server/storage.hpp
@@ -173,6 +173,16 @@ class Storage
getAccount(const std::string& userName) = 0;
/**
+ * Get an account by ID.
+ *
+ * @param accountID the ID of the account.
+ *
+ * @return the account associated with the ID.
+ */
+ virtual AccountPtr
+ getAccountByID(int accountID) = 0;
+
+ /**
* Gets a character by database ID.
*
* @param id the ID of the character.