diff options
author | David Athay <ko2fan@gmail.com> | 2007-06-26 19:50:02 +0000 |
---|---|---|
committer | David Athay <ko2fan@gmail.com> | 2007-06-26 19:50:02 +0000 |
commit | 301ffe1048fb23548f72759b6ed0ca98e9109ff4 (patch) | |
tree | c765b6df9a83227b1d40bb59949b768fbc4c1574 | |
parent | 99263173738dfd6ca4ba822e0a112f1c7c17661c (diff) | |
download | manaserv-301ffe1048fb23548f72759b6ed0ca98e9109ff4.tar.gz manaserv-301ffe1048fb23548f72759b6ed0ca98e9109ff4.tar.bz2 manaserv-301ffe1048fb23548f72759b6ed0ca98e9109ff4.tar.xz manaserv-301ffe1048fb23548f72759b6ed0ca98e9109ff4.zip |
Merged guilds-and-parties branch to trunk
26 files changed, 1648 insertions, 17 deletions
@@ -9,11 +9,38 @@ aliasing and sped up sqrt. * src/game-server/character.cpp: Fixed initial attribute status. +2007-04-28 David Athay <ko2fan@gmail.com> + + * src/chat-server/chathandler.cpp, + src/account-server/guildmanager.cpp: Fixed bug where + the guild creator was never added to the guild. + +2007-04-22 David Athay <ko2fan@gmail.com> + + * src/chat-server/chathandler.cpp, + src/account-server/guildmanager.cpp, + src/account-server/guildmanager.hpp, + src/account-server/serverhandler.cpp, + src/account-server/storage.hpp, src/account-server/dalstorage.cpp, + src/account-server/dalstorage.hpp, src/defines.h, + src/game-server/gamehandler.cpp, + src/game-server/accountconnection.cpp, + src/game-server/accountconnection.hpp: Added quitting guilds. + 2007-04-11 Philipp Sehmisch <tmw@crushnet.org> * src/game-server/being.cpp: Using effective attributes instead of base attributes for damage calculation. +2007-04-05 David Athay <ko2fan@gmail.com> + + * src/chat-server/chathandler.hpp, + src/chat-server/chathandler.cpp, + src/account-server/guildmanager.cpp, + src/account-server/guildmanager.hpp, src/defines.h: + Added user joining and leaving, plus stopped non guild members + joining guild channels. + 2007-03-31 Bjørn Lindeijer <bjorn@lindeijer.nl> * src/Makefile.am, src/game-server/testing.cpp, @@ -52,10 +79,42 @@ src/Makefile.am: Renamed "Controlled" to "Monster" and moved it into the game-server directory. +2007-03-30 David Athay <ko2fan@gmail.com> + + * src/chat-server/chathandler.cpp, + src/chat-server/chathandler.hpp, + src/account-server/accounthandler.hpp, + src/account-server/guildmanager.cpp, + src/account-server/guildmanager.hpp, + src/account-server/guild.cpp, src/account-server/guild.hpp, + src/account-server/serverhandler.cpp, + src/account-server/serverhandler.hpp, + src/account-server/storage.hpp, src/account-server/storage.cpp, + src/account-server/characterdata.hpp, + src/game-server/accountconnection.cpp, + src/defines: Added rejoining guilds the player belongs to. + * src/account-server/serverhandler.hpp, + src/chat-server/chathandler.cpp: Player now joins guild channels + upon connecting to the chat server. + * src/acccount-server/dalstorage.cpp: Fixed bug with creating + guilds. + +2007-03-25 David Athay <ko2fan@gmail.com> + + * src/chat-server/chathandler.cpp, + src/chat-server/chathandler.hpp, + src/account-server/serverhandler.cpp, + src/account-server/serverhandler.hpp, + src/account-server/dalstorage.cpp, + src/account-server/dalstorage.hpp, + src/defines.h, src/game-server/gamehandler.cpp, + src/game-server/gamehandler.hpp, + src/game-server/accountconnection.cpp: Implemented inviting + users to guilds. + 2007-03-23 Eugenio Favalli <elvenprogrammer@gmail.com> - * accountserver.cbp, gameserver.cbp: Updated and fixed Code::Blocks - project files. + * tmw.cbp: Updated and fixed Code::Blocks project files. 2007-03-23 Bjørn Lindeijer <bjorn@lindeijer.nl> @@ -101,6 +160,26 @@ src/account-server/accounthandler.cpp: Fixed two compiler warnings and corrected a spelling error. +2007-03-19 David Athay <ko2fan@gmail.com> + + * src/Makefile.am, src/account-server/accounthandler.cpp, + src/account-server/characterdata.hpp, + src/account-server/dalstorage.cpp, + src/account-server/dalstorage.hpp, + src/account-server/main-account.cpp, + src/account-server/serverhandler.cpp, + src/account-server/serverhandler.hpp, + src/account-server/storage.hpp, src/chat-server/chathandler.cpp, + src/account-server/guild.cpp, src/account-server/guild.h, + src/account-server/guildmanager.cpp, + src/account-server/guildmanager.hpp, + src/chat-server/chathandler.hpp, src/defines.h, + src/game-server/accountconnection.cpp, + src/game-server/accountconnection.hpp, + src/game-server/gamehandler.cpp, src/game-server/gamehandler.hpp, + src/game-server/mapmanager.cpp, src/game-server/mapmanager.hpp, + src/net/netcomputer.cpp : Add first stage of guild system. + 2007-03-18 Rogier Polak <rogier.l.a.polak@gmail.com> * src/net/netcomputer.cpp: Corrected the debug message for big-endian diff --git a/src/Makefile.am b/src/Makefile.am index fbf488a8..69ff347e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,6 +27,10 @@ tmwserv_account_SOURCES = \ account-server/dalstorage.hpp \ account-server/dalstorage.cpp \ account-server/dalstoragesql.hpp \ + account-server/guild.cpp \ + account-server/guild.h \ + account-server/guildmanager.cpp \ + account-server/guildmanager.h \ account-server/serverhandler.hpp \ account-server/serverhandler.cpp \ account-server/storage.hpp \ diff --git a/src/account-server/accounthandler.cpp b/src/account-server/accounthandler.cpp index 52ea2b33..c86d06de 100644 --- a/src/account-server/accounthandler.cpp +++ b/src/account-server/accounthandler.cpp @@ -29,6 +29,8 @@ #include "account-server/account.hpp" #include "account-server/accountclient.hpp" #include "account-server/characterdata.hpp" +#include "account-server/guild.hpp" +#include "account-server/guildmanager.hpp" #include "account-server/serverhandler.hpp" #include "account-server/storage.hpp" #include "chat-server/chathandler.hpp" diff --git a/src/account-server/accounthandler.hpp b/src/account-server/accounthandler.hpp index 1c0de2e4..d7058906 100644 --- a/src/account-server/accounthandler.hpp +++ b/src/account-server/accounthandler.hpp @@ -28,6 +28,7 @@ #include "utils/tokencollector.hpp" class AccountClient; +class CharacterData; /** * Manages the data stored in user accounts and provides a reliable interface @@ -126,6 +127,12 @@ class AccountHandler : public ConnectionHandler void handleCharacterDeleteMessage(AccountClient &computer, MessageIn &msg); + + /** + * Send guild join for each guild the player belongs to + */ + void + handleGuildJoining(AccountClient &computer, CharacterData *character); }; extern AccountHandler * accountHandler; diff --git a/src/account-server/characterdata.hpp b/src/account-server/characterdata.hpp index c7ac3dea..8d7e2599 100644 --- a/src/account-server/characterdata.hpp +++ b/src/account-server/characterdata.hpp @@ -154,6 +154,13 @@ class CharacterData: public AbstractCharacterData /** Adds an inventory item to the inventory. */ void addItemToInventory(const InventoryItem& item); + + /** Add a guild to the character */ + void addGuild(const std::string &name) { mGuilds.push_back(name); } + + /** Returns a list of guilds the player belongs to */ + std::vector<std::string> + getGuilds() const { return mGuilds; } private: CharacterData(CharacterData const &); @@ -175,6 +182,8 @@ class CharacterData: public AbstractCharacterData Point mPos; //!< Position the being is at. std::vector< InventoryItem > mInventory; //!< All the possesions of //!< the character. + std::vector<std::string> mGuilds; //!< All the guilds the player + //!< belongs to. }; // Utility typedefs diff --git a/src/account-server/dalstorage.cpp b/src/account-server/dalstorage.cpp index 8ae497e1..fd6c8419 100644 --- a/src/account-server/dalstorage.cpp +++ b/src/account-server/dalstorage.cpp @@ -27,6 +27,8 @@ #include "configuration.h" #include "point.h" #include "account-server/characterdata.hpp" +#include "account-server/guild.hpp" +#include "account-server/guildmanager.hpp" #include "account-server/dalstoragesql.hpp" #include "dal/dalexcept.h" #include "dal/dataproviderfactory.h" @@ -67,6 +69,22 @@ class character_by_id int mID; /**< the ID to look for */ }; +/** +* Functor used to search a character by name in Characters. + */ +class character_by_name +{ +public: + character_by_name(const std::string &name) + : mName(name) + {} + + bool operator()(CharacterPtr const &elem) const + { return elem->getName() == mName; } + +private: + std::string mName; /**< the name to look for */ +}; /** * Constructor. @@ -168,6 +186,8 @@ DALStorage::open(void) createTable(WORLD_ITEMS_TBL_NAME, SQL_WORLD_ITEMS_TABLE); createTable(INVENTORIES_TBL_NAME, SQL_INVENTORIES_TABLE); createTable(CHANNELS_TBL_NAME, SQL_CHANNELS_TABLE); + createTable(GUILDS_TBL_NAME, SQL_GUILDS_TABLE); + createTable(GUILD_MEMBERS_TBL_NAME, SQL_GUILD_MEMBERS_TABLE); } catch (const DbConnectionFailure& e) { LOG_ERROR("(DALStorage::open #1) Unable to connect to the database: " @@ -429,6 +449,81 @@ CharacterPtr DALStorage::getCharacter(int id) } } +/** +* Gets a character by character name. + */ +CharacterPtr DALStorage::getCharacter(const std::string &name) +{ + // connect to the database (if not connected yet). + open(); + + // look for the character in the list first. + Characters::iterator it_end = mCharacters.end(), + it = std::find_if(mCharacters.begin(), it_end, character_by_name(name)); + + if (it != it_end) + return *it; + + using namespace dal; + + // the account was not in the list, look for it in the database. + try { + std::ostringstream sql; + sql << "select * from " << CHARACTERS_TBL_NAME << " where name = '" + << name << "';"; + RecordSet const &charInfo = mDb->execSql(sql.str()); + + // if the character is not even in the database then + // we have no choice but to return nothing. + if (charInfo.isEmpty()) + { + return CharacterPtr(NULL); + } + + // specialize the string_to functor to convert + // a string to an unsigned int. + string_to< unsigned > toUint; + + // specialize the string_to functor to convert + // a string to an unsigned short. + string_to< unsigned short > toUshort; + + CharacterData *character = new CharacterData(charInfo(0, 2), + toUint(charInfo(0, 0))); + character->setAccountID(toUint(charInfo(0, 1))); + character->setGender(toUshort(charInfo(0, 3))); + character->setHairStyle(toUshort(charInfo(0, 4))); + character->setHairColor(toUshort(charInfo(0, 5))); + character->setLevel(toUshort(charInfo(0, 6))); + character->setMoney(toUint(charInfo(0, 7))); + Point pos(toUshort(charInfo(0, 8)), toUshort(charInfo(0, 9))); + character->setPosition(pos); + for (int i = 0; i < NB_BASE_ATTRIBUTES; ++i) + { + character->setBaseAttribute(i, toUshort(charInfo(0, 11 + i))); + } + + int mapId = toUint(charInfo(0, 10)); + if (mapId > 0) + { + character->setMapId(mapId); + } + else + { + // Set character to default map and one of the default location + // Default map is to be 1, as not found return value will be 0. + character->setMapId((int)config.getValue("defaultMap", 1)); + } + + CharacterPtr ptr(character); + mCharacters.push_back(ptr); + return ptr; + } + catch (const DbSqlQueryExecFailure& e) + { + return CharacterPtr(NULL); // TODO: Throw exception here + } +} /** * Return the list of all Emails addresses. @@ -640,6 +735,7 @@ DALStorage::updateCharacter(CharacterPtr character) return false; } } + return true; } @@ -1028,3 +1124,175 @@ void DALStorage::unloadAccount(AccountPtr const &account) flush(account); mAccounts.erase(account->getID()); } + +/** + * Add a guild + */ +void DALStorage::addGuild(Guild* guild) +{ +#if defined (SQLITE_SUPPORT) + // Reopen the db in this thread for sqlite, to avoid + // Library Call out of sequence problem due to thread safe. + close(); +#endif + open(); + + std::ostringstream insertSql; + insertSql << "insert into " << GUILDS_TBL_NAME + << " (name) " + << " values (\"" + << guild->getName() << "\");"; + mDb->execSql(insertSql.str()); + + std::ostringstream selectSql; + selectSql << "select id from " << GUILDS_TBL_NAME + << " where name = \"" << guild->getName() << "\";"; + const dal::RecordSet& guildInfo = mDb->execSql(selectSql.str()); + string_to<unsigned int> toUint; + unsigned id = toUint(guildInfo(0, 0)); + guild->setId(id); +} + +/** + * Remove guild + */ +void DALStorage::removeGuild(Guild* guild) +{ +#if defined (SQLITE_SUPPORT) + // Reopen the db in this thread for sqlite, to avoid + // Library Call out of sequence problem due to thread safe. + close(); +#endif + open(); + + std::ostringstream sql; + sql << "delete from " << GUILDS_TBL_NAME + << " where id = '" + << guild->getId() << "';"; + mDb->execSql(sql.str()); +} + +/** + * add a member to a guild + */ +void DALStorage::addGuildMember(int guildId, const std::string &memberName) +{ +#if defined (SQLITE_SUPPORT) + // Reopen the db in this thread for sqlite, to avoid + // Library Call out of sequence problem due to thread safe. + close(); +#endif + open(); + + std::ostringstream sql; + + try + { + sql << "insert into " << GUILD_MEMBERS_TBL_NAME + << " (guild_id, member_name)" + << " values (" + << guildId << ", \"" + << memberName << "\");"; + mDb->execSql(sql.str()); + } + catch (const dal::DbSqlQueryExecFailure& e) { + // TODO: throw an exception. + LOG_ERROR("SQL query failure: " << e.what()); + } +} + +/** +* remove a member from a guild + */ +void DALStorage::removeGuildMember(int guildId, const std::string &memberName) +{ +#if defined (SQLITE_SUPPORT) + // Reopen the db in this thread for sqlite, to avoid + // Library Call out of sequence problem due to thread safe. + close(); +#endif + open(); + + std::ostringstream sql; + + try + { + sql << "delete from " << GUILD_MEMBERS_TBL_NAME + << " where member_name = \"" + << memberName << "\" and guild_id = '" + << guildId << "';"; + mDb->execSql(sql.str()); + } + catch (const dal::DbSqlQueryExecFailure& e) { + // TODO: throw an exception. + LOG_ERROR("SQL query failure: " << e.what()); + } +} + +/** + * get a list of guilds + */ +std::list<Guild*> DALStorage::getGuildList() +{ +#if defined (SQLITE_SUPPORT) + // Reopen the db in this thread for sqlite, to avoid + // Library Call out of sequence problem due to thread safe. + close(); +#endif + open(); + + std::list<Guild*> guilds; + std::stringstream sql; + string_to<short> toShort; + + /** + * Get the guilds stored in the db. + */ + + try + { + sql << "select id, name from " << GUILDS_TBL_NAME << ";"; + const dal::RecordSet& guildInfo = mDb->execSql(sql.str()); + + // check that at least 1 guild was returned + if(guildInfo.isEmpty()) + { + return guilds; + } + + // loop through every row in the table and assign it to a guild + for ( unsigned int i = 0; i < guildInfo.rows(); ++i) + { + Guild* guild = new Guild(guildInfo(i,1)); + guild->setId(toShort(guildInfo(i,0))); + guilds.push_back(guild); + } + + /** + * Add the members to the guilds. + */ + + for (std::list<Guild*>::iterator itr = guilds.begin(); + itr != guilds.end(); + ++itr) + { + std::ostringstream memberSql; + memberSql << "select member_name from " << GUILD_MEMBERS_TBL_NAME + << " where guild_id = '" << (*itr)->getId() << "';"; + const dal::RecordSet& memberInfo = mDb->execSql(memberSql.str()); + + for (unsigned int j = 0; j < memberInfo.rows(); ++j) + { + CharacterPtr character = getCharacter(memberInfo(j,0)); + character->addGuild((*itr)->getName()); + (*itr)->addMember(character.get()); + } + } + } + catch (const dal::DbSqlQueryExecFailure& e) { + // TODO: throw an exception. + LOG_ERROR("SQL query failure: " << e.what()); + } + + return guilds; +} diff --git a/src/account-server/dalstorage.hpp b/src/account-server/dalstorage.hpp index e6f6d185..a99bc5d2 100644 --- a/src/account-server/dalstorage.hpp +++ b/src/account-server/dalstorage.hpp @@ -28,6 +28,8 @@ #include "account-server/storage.hpp" #include "dal/dataprovider.h" +class Guild; + /** * A storage class that relies on DAL. * @@ -84,6 +86,15 @@ class DALStorage: public Storage * @return the character associated to the ID. */ CharacterPtr getCharacter(int id); + + /** + * Gets a character by character name. + * + * @param name of the character + * + * @return the character associated to the name + */ + CharacterPtr getCharacter(const std::string &name); /** * Add a new account. @@ -152,6 +163,41 @@ class DALStorage: public Storage updateChannels(std::map<short, ChatChannel>& channelList); /** + * Add a new guild + * + */ + void + addGuild(Guild* guild); + + /** + * Delete a guild + * + */ + void + removeGuild(Guild* guild); + + /** + * Add member to guild + * + */ + void + addGuildMember(int guild_id, const std::string &member_name); + + /* + * Remove member from guild + */ + void + removeGuildMember(int guildId, const std::string &memberName); + + /** + * Get guild list + *@return a list of guilds + * + */ + std::list<Guild*> + getGuildList(); + + /** * Save changes to the database permanently. * * @exception tmwserv::dal::DbSqlQueryExecFailure. diff --git a/src/account-server/dalstoragesql.hpp b/src/account-server/dalstoragesql.hpp index c4a433af..df141f69 100644 --- a/src/account-server/dalstoragesql.hpp +++ b/src/account-server/dalstoragesql.hpp @@ -334,6 +334,55 @@ const std::string SQL_CHANNELS_TABLE( ");" ); +/** + * TABLE: tmw_guilds. + * Store player guilds + */ +const std::string GUILDS_TBL_NAME("tmw_guilds"); +const std::string SQL_GUILDS_TABLE( + "CREATE TABLE tmw_guilds (" +#if defined (MYSQL_SUPPORT) + "id INTEGER PRIMARY KEY AUTO_INCREMENT," + "name VARCHAR(32) NOT NULL UNIQUE," + "FOREIGN KEY (name) REFERENCES tmw_characters(name)" +#elif defined (SQLITE_SUPPORT) + "id INTEGER PRIMARY KEY," + "name TEXT NOT NULL UNIQUE," + "FOREIGN KEY (name) REFERENCES tmw_characters(name)" +#elif defined (POSTGRESQL_SUPPORT) + "id SERIAL PRIMARY KEY," + "name TEXT NOT NULL UNIQUE," + "FOREIGN KEY (name) REFERENCES tmw_characters(name)" +#endif + ");" +); + +/** + * TABLE: tmw_guild_members. + * Store guild members + */ +const std::string GUILD_MEMBERS_TBL_NAME("tmw_guild_members"); +const std::string SQL_GUILD_MEMBERS_TABLE( + "CREATE TABLE tmw_guild_members (" +#if defined (MYSQL_SUPPORT) + "guild_id INTEGER NOT NULL," + "member_name VARCHAR(32) NOT NULL," + "FOREIGN KEY (guild_id) REFERENCES tmw_guilds(id)," + "FOREIGN KEY (member_name) REFERENCES tmw_characters(name)" +#elif defined (SQLITE_SUPPORT) + "guild_id INTEGER NOT NULL," + "member_name TEXT NOT NULL," + "FOREIGN KEY (guild_id) REFERENCES tmw_guilds(id)," + "FOREIGN KEY (member_name) REFERENCES tmw_characters(name)" +#elif defined (POSTGRESQL_SUPPORT) + "guild_id INTEGER NOT NULL," + "member_name TEXT NOT NULL," + "FOREIGN KEY (guild_id) REFERENCES tmw_guilds(id)," + "FOREIGN KEY (member_name) REFERENCES tmw_characters(name)" +#endif + ");" +); + } // anonymous namespace diff --git a/src/account-server/guild.cpp b/src/account-server/guild.cpp new file mode 100644 index 00000000..2e339ec1 --- /dev/null +++ b/src/account-server/guild.cpp @@ -0,0 +1,107 @@ +/* + * guild.cpp + * A file part of The Mana World + * + * Created by David Athay on 01/03/2007. + * + * Copyright (c) 2007, The Mana World Development Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * My name may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + * $Id$ + */ + +#include "guild.hpp" + +#include "account-server/characterdata.hpp" +#include "account-server/storage.hpp" + +Guild::Guild(const std::string &name) : +mName(name) +{ + +} + +Guild::~Guild() +{ + +} + +void Guild::addMember(CharacterData* player) +{ + mMembers.push_back(player); +} + +void Guild::removeMember(CharacterData* player) +{ + mMembers.remove(player); +} + +bool Guild::checkLeader(CharacterData* player) +{ + CharacterData* leader = mMembers.front(); + if(leader == player) + return true; + return false; +} + +bool Guild::checkInvited(const std::string &name) +{ + return (std::find(mInvited.begin(), mInvited.end(), name) != mInvited.end()); +} + +void Guild::addInvited(const std::string &name) +{ + mInvited.push_back(name); +} + +const std::string& Guild::getName() const +{ + return mName; +} + +std::string Guild::getMember(int i) const +{ + int x = 0; + for(guildMembers::const_iterator itr = mMembers.begin(); + itr != mMembers.end(); + ++itr, ++x) + { + if(x == i) + { + CharacterData *player = (*itr); + return player->getName(); + } + } + return ""; +} + +bool Guild::checkInGuild(const std::string &name) +{ + for(guildMembers::iterator itr = mMembers.begin(); itr != mMembers.end(); ++itr) + { + CharacterData *player = (*itr); + if(player->getName() == name) + { + return true; + } + } + return false; +} diff --git a/src/account-server/guild.hpp b/src/account-server/guild.hpp new file mode 100644 index 00000000..c91b6467 --- /dev/null +++ b/src/account-server/guild.hpp @@ -0,0 +1,109 @@ +/* + * The Mana World Server + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or any later version. + * + * The Mana World is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with The Mana World; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMWSERV_ACCOUNTSERVER_GUILD_H_ +#define _TMWSERV_ACCOUNTSERVER_GUILD_H_ + +#include <string> +#include <list> + +class CharacterData; + +class Guild +{ +public: + typedef std::list<CharacterData*> guildMembers; + Guild(const std::string &name); + ~Guild(); + + /** + * Add a member to the guild. + */ + void addMember(CharacterData* player); + + /** + * Remove a member from the guild. + */ + void removeMember(CharacterData* player); + + /** + * Check player is the leader of the guild. + */ + bool checkLeader(CharacterData* player); + + /** + * Set the ID of the guild. + */ + void setId(short id) + { + mId = id; + } + + /** + * Check if player has been invited to the guild. + */ + bool checkInvited(const std::string &name); + + /** + * Add a player to the invite list. + */ + void addInvited(const std::string &name); + + /** + * Returns the name of the guild. + */ + const std::string& getName() const; + + /** + * Returns the ID of the guild. + */ + short getId() const + { + return mId; + } + + /** + * Returns the total number of members in the guild. + */ + short totalMembers() const + { + return mMembers.size(); + } + + /** + * Get a member in the guild + */ + std::string getMember(int i) const; + + /** + * Find member by name + */ + bool checkInGuild(const std::string &name); + +private: + short mId; + std::string mName; + std::list<CharacterData*> mMembers; + std::list<std::string> mInvited; +}; + +#endif diff --git a/src/account-server/guildmanager.cpp b/src/account-server/guildmanager.cpp new file mode 100644 index 00000000..9fbec8c1 --- /dev/null +++ b/src/account-server/guildmanager.cpp @@ -0,0 +1,136 @@ +/* + * guildmanager.cpp + * A file part of The Mana World + * + * Created by David Athay on 01/03/2007. + * + * Copyright (c) 2007, The Mana World Development Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * My name may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + * $Id$ + */ + +#include "guildmanager.hpp" + +#include "account-server/characterdata.hpp" +#include "account-server/guild.hpp" +#include "account-server/storage.hpp" + +GuildManager::GuildManager() +{ + // Load stored guilds from db + Storage &store = Storage::instance("tmw"); + mGuilds = store.getGuildList(); +} + +GuildManager::~GuildManager() +{ + for(std::list<Guild*>::iterator itr = mGuilds.begin(); itr != mGuilds.end(); ++itr) + { + Guild *guild = (*itr); + delete guild; + } +} + +short GuildManager::createGuild(const std::string &name, CharacterData* player) +{ + Guild *guild = new Guild(name); + // Add guild to db + Storage &store = Storage::instance("tmw"); + store.addGuild(guild); + + // Make sure to add guild to mGuilds before searching for it + // to add the player + mGuilds.push_back(guild); + addGuildMember(guild->getId(), player); + + return guild->getId(); +} + +void GuildManager::removeGuild(short guildId) +{ + Guild *guild = findById(guildId); + if(!guild) + return; + Storage &store = Storage::instance("tmw"); + store.removeGuild(guild); +} + +void GuildManager::addGuildMember(short guildId, CharacterData *player) +{ + Guild *guild = findById(guildId); + if(!guild) + return; + Storage &store = Storage::instance("tmw"); + store.addGuildMember(guildId, player->getName()); + guild->addMember(player); +} + +void GuildManager::removeGuildMember(short guildId, CharacterData *player) +{ + Guild *guild = findById(guildId); + if(!guild) + return; + Storage &store = Storage::instance("tmw"); + store.removeGuildMember(guildId, player->getName()); + guild->removeMember(player); + if(guild->totalMembers() == 0) + { + removeGuild(guildId); + } +} + +Guild *GuildManager::findById(short id) +{ + for(std::list<Guild*>::iterator itr = mGuilds.begin(); itr != mGuilds.end(); ++itr) + { + Guild *guild = (*itr); + if(guild->getId() == id) + { + return guild; + } + } + return NULL; +} + +Guild *GuildManager::findByName(const std::string &name) +{ + std::list<Guild*>::iterator itr = mGuilds.begin(); + for(; itr != mGuilds.end(); ++itr) + { + Guild *guild = (*itr); + if(guild->getName() == name) + { + return guild; + } + } + return NULL; +} + +bool GuildManager::doesExist(const std::string &name) +{ + Guild *guild = findByName(name); + if(guild) + { + return true; + } + return false; +} diff --git a/src/account-server/guildmanager.hpp b/src/account-server/guildmanager.hpp new file mode 100644 index 00000000..97ec87c3 --- /dev/null +++ b/src/account-server/guildmanager.hpp @@ -0,0 +1,76 @@ +/* + * guildmanager.hpp + * A file part of The Mana World + * + * Created by David Athay on 05/03/2007. + * + * Copyright (c) 2007, The Mana World Development Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * My name may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + * $Id$ + */ + +#include <list> + +class Guild; +class CharacterData; + +class GuildManager +{ +public: + /* + * Constructor/Destructor + */ + GuildManager(); + ~GuildManager(); + + /* + * Create/Remove guild + */ + short createGuild(const std::string &name, CharacterData *player); + void removeGuild(short guildId); + + /* + * Add member to guild + */ + void addGuildMember(short guildId, CharacterData *player); + + /* + * Remove member from guild + */ + void removeGuildMember(short guildId, CharacterData *player); + + /* + * Search for guilds + */ + Guild *findById(short id); + Guild *findByName(const std::string &name); + + /* + * Check if guild exists + */ + bool doesExist(const std::string &name); + +private: + std::list<Guild*> mGuilds; +}; + +extern GuildManager *guildManager; diff --git a/src/account-server/main-account.cpp b/src/account-server/main-account.cpp index fd3037b2..70cde480 100644 --- a/src/account-server/main-account.cpp +++ b/src/account-server/main-account.cpp @@ -35,6 +35,7 @@ #include "resourcemanager.h" #include "skill.h" #include "account-server/accounthandler.hpp" +#include "account-server/guildmanager.hpp" #include "account-server/serverhandler.hpp" #include "account-server/storage.hpp" #include "chat-server/chatchannelmanager.hpp" @@ -69,6 +70,9 @@ ServerHandler *serverHandler; /** Chat Channels Manager */ ChatChannelManager *chatChannelManager; + +/** Guild Manager */ +GuildManager *guildManager; /** Callback used when SIGQUIT signal is received. */ void closeGracefully(int dummy) @@ -147,6 +151,8 @@ void initialize() stringFilter = new StringFilter(&config); // Initialize the Chat channels manager chatChannelManager = new ChatChannelManager(); + // Initialise the guild manager + guildManager = new GuildManager(); // --- Initialize the global handlers // FIXME: Make the global handlers global vars or part of a bigger @@ -204,6 +210,7 @@ void deinitialize() // Destroy Managers delete chatChannelManager; + delete guildManager; // Get rid of persistent data storage Storage::destroy(); diff --git a/src/account-server/serverhandler.cpp b/src/account-server/serverhandler.cpp index b1fba564..47c23966 100644 --- a/src/account-server/serverhandler.cpp +++ b/src/account-server/serverhandler.cpp @@ -24,9 +24,13 @@ #include <cassert> #include <sstream> +#include "account-server/accountclient.hpp" #include "account-server/characterdata.hpp" +#include "account-server/guildmanager.hpp" #include "account-server/serverhandler.hpp" #include "account-server/storage.hpp" +#include "chat-server/chathandler.hpp" +#include "chat-server/chatchannelmanager.hpp" #include "net/messagein.hpp" #include "net/messageout.hpp" #include "net/netcomputer.hpp" @@ -175,6 +179,167 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg) mTokenCollector.addPendingConnect(magic_token, accountID); } break; + + case GAMSG_GUILD_CREATE: + { + LOG_DEBUG("GAMSG_GUILD_CREATE"); + + result.writeShort(AGMSG_GUILD_CREATE_RESPONSE); + // Check if the guild name is taken already + int playerId = msg.readLong(); + std::string guildName = msg.readString(); + if (guildManager->findByName(guildName) != NULL) + { + result.writeByte(ERRMSG_ALREADY_TAKEN); + break; + } + result.writeByte(ERRMSG_OK); + + Storage &store = Storage::instance("tmw"); + CharacterPtr ptr = store.getCharacter(playerId); + + // Add guild to character data. + ptr->addGuild(guildName); + + // Who to send data to at the other end + result.writeLong(playerId); + + short guildId = guildManager->createGuild(guildName, ptr.get()); + result.writeShort(guildId); + result.writeString(guildName); + result.writeShort(1); + enterChannel(guildName, ptr.get()); + } break; + + case GAMSG_GUILD_INVITE: + { + // Add Inviting member to guild here + LOG_DEBUG("Received msg ... GAMSG_GUILD_INVITE"); + result.writeShort(AGMSG_GUILD_INVITE_RESPONSE); + // Check if user can invite users + int playerId = msg.readLong(); + short id = msg.readShort(); + std::string member = msg.readString(); + Guild *guild = guildManager->findById(id); + + Storage &store = Storage::instance("tmw"); + CharacterPtr ptr = store.getCharacter(playerId); + + if (!guild->checkLeader(ptr.get())) + { + // Return that the user doesnt have the rights to invite. + result.writeByte(ERRMSG_INSUFFICIENT_RIGHTS); + break; + } + + if (guild->checkInGuild(member)) + { + // Return that invited member already in guild. + result.writeByte(ERRMSG_ALREADY_TAKEN); + break; + } + + // Send invite to player using chat server + if (store.doesCharacterNameExist(member)) + { + sendInvite(member, ptr->getName(), guild->getName()); + } + + guild->addInvited(member); + result.writeByte(ERRMSG_OK); + } break; + + case GAMSG_GUILD_ACCEPT: + { + // Add accepting into guild + LOG_DEBUG("Received msg ... GAMSG_GUILD_ACCEPT"); + result.writeShort(AGMSG_GUILD_ACCEPT_RESPONSE); + int playerId = msg.readLong(); + std::string guildName = msg.readString(); + Guild *guild = guildManager->findByName(guildName); + if (!guild) + { + // Return the guild does not exist. + result.writeByte(ERRMSG_INVALID_ARGUMENT); + break; + } + + Storage &store = Storage::instance("tmw"); + CharacterPtr ptr = store.getCharacter(playerId); + + if (!guild->checkInvited(ptr->getName())) + { + // Return the user was not invited. + result.writeByte(ERRMSG_INSUFFICIENT_RIGHTS); + break; + } + + if (guild->checkInGuild(ptr->getName())) + { + // Return that the player is already in the guild. + result.writeByte(ERRMSG_ALREADY_TAKEN); + break; + } + + result.writeByte(ERRMSG_OK); + + // Who to send data to at the other end + result.writeLong(playerId); + + // The guild id and guild name they have joined + result.writeShort(guild->getId()); + result.writeString(guildName); + + // Add member to guild + guildManager->addGuildMember(guild->getId(), ptr.get()); + + // Add guild to character + ptr->addGuild(guildName); + + // Enter Guild Channel + enterChannel(guildName, ptr.get()); + } break; + + case GAMSG_GUILD_GET_MEMBERS: + { + LOG_DEBUG("Received msg ... GAMSG_GUILD_GET_MEMBERS"); + result.writeShort(AGMSG_GUILD_GET_MEMBERS_RESPONSE); + int playerId = msg.readLong(); + short guildId = msg.readShort(); + Guild *guild = guildManager->findById(guildId); + if (!guild) + { + result.writeByte(ERRMSG_INVALID_ARGUMENT); + break; + } + result.writeByte(ERRMSG_OK); + result.writeLong(playerId); + result.writeShort(guildId); + for (int i = 0; i < guild->totalMembers(); ++i) + { + result.writeString(guild->getMember(i)); + } + } break; + + case GAMSG_GUILD_QUIT: + { + LOG_DEBUG("Received msg ... GAMSG_GUILD_QUIT"); + result.writeShort(AGMSG_GUILD_QUIT_RESPONSE); + int playerId = msg.readLong(); + short guildId = msg.readShort(); + Guild *guild = guildManager->findById(guildId); + if (!guild) + { + result.writeByte(ERRMSG_INVALID_ARGUMENT); + break; + } + Storage &store = Storage::instance("tmw"); + CharacterPtr ptr = store.getCharacter(playerId); + guildManager->removeGuildMember(guildId, ptr.get()); + result.writeByte(ERRMSG_OK); + result.writeLong(playerId); + result.writeShort(guildId); + } break; default: LOG_WARN("ServerHandler::processMessage, Invalid message type: " @@ -187,3 +352,59 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg) if (result.getLength() > 0) comp->send(result); } + +void ServerHandler::enterChannel(const std::string &name, CharacterData *player) +{ + MessageOut result(CPMSG_ENTER_CHANNEL_RESPONSE); + short channelId = chatChannelManager->getChannelId(name); + if (!chatChannelManager->isChannelRegistered(channelId)) + { + // Channel doesnt exist yet so create one + channelId = chatChannelManager->registerPrivateChannel( + name, + "Guild Channel", + ""); + } + + if (chatChannelManager->addUserInChannel(player->getName(), channelId)) + { + result.writeByte(ERRMSG_OK); + + // The user entered the channel, now give him the channel id, the announcement string + // and the user list. + result.writeShort(channelId); + result.writeString(name); + result.writeString(chatChannelManager->getChannelAnnouncement(channelId)); + std::vector< std::string > const &userList = + chatChannelManager->getUserListInChannel(channelId); + for (std::vector< std::string >::const_iterator i = userList.begin(), + i_end = userList.end(); + i != i_end; ++i) + { + result.writeString(*i); + } + + // Send an CPMSG_UPDATE_CHANNEL to warn other clients a user went + // in the channel. + chatHandler->warnUsersAboutPlayerEventInChat(channelId, + player->getName(), + CHAT_EVENT_NEW_PLAYER); + + } + + chatHandler->sendGuildEnterChannel(result, player->getName()); +} + +void ServerHandler::sendInvite(const std::string &invitedName, const std::string &inviterName, + const std::string &guildName) +{ + // TODO: Separate account and chat server + chatHandler->sendGuildInvite(invitedName, inviterName, guildName); +} + +CharacterPtr ServerHandler::getCharacter(const std::string &name) +{ + Storage &store = Storage::instance("tmw"); + CharacterPtr character = store.getCharacter(name); + return character; +} diff --git a/src/account-server/serverhandler.hpp b/src/account-server/serverhandler.hpp index 9de15a89..5c57f03b 100644 --- a/src/account-server/serverhandler.hpp +++ b/src/account-server/serverhandler.hpp @@ -30,6 +30,8 @@ #include "net/connectionhandler.hpp" #include "utils/countedptr.h" +class AccountClient; + /** * Manages communications with all the game servers. This class also keeps * track of the maps each game server supports. @@ -52,6 +54,16 @@ class ServerHandler: public ConnectionHandler * Sends a magic token and character data to the relevant game server. */ void registerGameClient(std::string const &, CharacterPtr); + + /** + * Get character (temp used by chat server). + */ + CharacterPtr getCharacter(const std::string &name); + + /** + * Make client join the specified guild channel + */ + void enterChannel(const std::string &guildName, CharacterData *player); protected: /** @@ -71,6 +83,13 @@ class ServerHandler: public ConnectionHandler void computerDisconnected(NetComputer *comp); private: + + /** + * Send invite to user + */ + void sendInvite(const std::string &invitedName, const std::string &inviterName, + const std::string &guildName); + struct Server { std::string address; diff --git a/src/account-server/storage.hpp b/src/account-server/storage.hpp index 15f0a5ff..c0abf004 100644 --- a/src/account-server/storage.hpp +++ b/src/account-server/storage.hpp @@ -29,6 +29,7 @@ #include "account-server/account.hpp" #include "account-server/characterdata.hpp" +#include "account-server/guild.hpp" #include "chat-server/chatchannel.hpp" /** @@ -191,6 +192,15 @@ class Storage * @return the character associated to the ID. */ virtual CharacterPtr getCharacter(int id) = 0; + + /** + * Gets a character by name. + * + * @param name the name of the character. + * + * @return the character associated to the name. + */ + virtual CharacterPtr getCharacter(const std::string &name) = 0; /** * Add a new account. @@ -265,6 +275,41 @@ class Storage updateChannels(std::map<short, ChatChannel>& channelList) = 0; /** + * Add a new guild + * + */ + virtual void + addGuild(Guild* guild) = 0; + + /** + * Delete a guild + * + */ + virtual void + removeGuild(Guild* guild) = 0; + + /** + * Add member to guild + * + */ + virtual void + addGuildMember(int guild_id, const std::string &member_name) = 0; + + /** + * Remove member from guild + */ + virtual void + removeGuildMember(int guildId, const std::string &memberName) = 0; + + /** + * Get guild list + *@return a list of guilds + * + */ + virtual std::list<Guild*> + getGuildList() = 0; + + /** * Saves the changes to all the accounts permanently. */ virtual void flushAll() = 0; diff --git a/src/chat-server/chathandler.cpp b/src/chat-server/chathandler.cpp index 75c8d915..d9c2360f 100644 --- a/src/chat-server/chathandler.cpp +++ b/src/chat-server/chathandler.cpp @@ -22,6 +22,10 @@ */ #include "defines.h" +#include "account-server/characterdata.hpp" +#include "account-server/guild.hpp" +#include "account-server/guildmanager.hpp" +#include "account-server/serverhandler.hpp" #include "chat-server/chatchannelmanager.hpp" #include "chat-server/chathandler.hpp" #include "net/connectionhandler.hpp" @@ -155,12 +159,14 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) pendingClients.insert(std::make_pair(magic_token, &computer)); return; } + computer.characterName = i->second.character; computer.accountLevel = i->second.level; pendingLogins.erase(i); result.writeShort(CPMSG_CONNECT_RESPONSE); result.writeByte(ERRMSG_OK); computer.send(result); + sendGuildRejoin(computer); return; } @@ -274,6 +280,12 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) result.writeByte(ERRMSG_INVALID_ARGUMENT); break; } + + if(guildManager->doesExist(channelName)) + { + result.writeByte(ERRMSG_INVALID_ARGUMENT); + break; + } // If it's slang's free. if (stringFilter->filterContent(channelName) && @@ -327,6 +339,11 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) result.writeShort(CPMSG_UNREGISTER_CHANNEL_RESPONSE); short channelId = message.readShort(); + std::string channelName = chatChannelManager->getChannelName(channelId); + + // Get character based on name. + CharacterPtr character = serverHandler->getCharacter(computer.characterName); + if (!chatChannelManager->isChannelRegistered(channelId)) { result.writeByte(ERRMSG_INVALID_ARGUMENT); @@ -342,6 +359,16 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) else result.writeByte(ERRMSG_FAILURE); } + else if (guildManager->doesExist(channelName)) + { + Guild *guild = guildManager->findByName(channelName); + if (guild->checkLeader(character.get())) + { + chatChannelManager->removeChannel(channelId); + guildManager->removeGuild(guild->getId()); + result.writeByte(ERRMSG_OK); + } + } else { result.writeByte(ERRMSG_INSUFFICIENT_RIGHTS); @@ -392,6 +419,17 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) break; } } + + if (guildManager->doesExist(channelName)) + { + Guild *guild = guildManager->findByName(channelName); + if (!guild->checkInGuild(computer.characterName)) + { + result.writeByte(ERRMSG_INVALID_ARGUMENT); + break; + } + sendUserJoined(channelId, computer.characterName); + } if (chatChannelManager->addUserInChannel(computer.characterName, channelId)) { result.writeByte(ERRMSG_OK); @@ -400,8 +438,10 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) result.writeShort(channelId); result.writeString(channelName); result.writeString(chatChannelManager->getChannelAnnouncement(channelId)); - std::vector< std::string > const &userList = chatChannelManager->getUserListInChannel(channelId); - for (std::vector< std::string >::const_iterator i = userList.begin(), i_end = userList.end(); + std::vector< std::string > const &userList = + chatChannelManager->getUserListInChannel(channelId); + for (std::vector< std::string >::const_iterator i = userList.begin(), + i_end = userList.end(); i != i_end; ++i) { result.writeString(*i); } @@ -427,6 +467,8 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) { result.writeShort(CPMSG_QUIT_CHANNEL_RESPONSE); short channelId = message.readShort(); + std::string channelName = chatChannelManager->getChannelName(channelId); + if (channelId != 0 && chatChannelManager->isChannelRegistered(channelId)) { if (chatChannelManager->removeUserFromChannel(computer.characterName, channelId)) @@ -438,6 +480,11 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) warnUsersAboutPlayerEventInChat(channelId, computer.characterName, CHAT_EVENT_LEAVING_PLAYER); + if(guildManager->doesExist(channelName)) + { + // Send a user left message + sendUserLeft(channelId, computer.characterName); + } } else { @@ -456,7 +503,8 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) result.writeShort(CPMSG_LIST_CHANNELS_RESPONSE); short numberOfPublicChannels; - std::istringstream channels(chatChannelManager->getPublicChannelNames(&numberOfPublicChannels)); + std::istringstream channels(chatChannelManager->getPublicChannelNames( + &numberOfPublicChannels)); for(int i = 0; i < numberOfPublicChannels; ++i) { @@ -468,6 +516,27 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) } } break; + + case PCMSG_LIST_CHANNELUSERS: + { + result.writeShort(CPMSG_LIST_CHANNELUSERS_RESPONSE); + + std::string channelName = message.readString(); + + result.writeString(channelName); + + // get user list + std::vector<std::string> channelList; + channelList = chatChannelManager->getUserListInChannel( + chatChannelManager->getChannelId(channelName)); + + // add a user at a time + for(int i = 0; i < channelList.size(); ++i) + { + result.writeString(channelList[i]); + } + + } break; case PCMSG_DISCONNECT: { @@ -597,3 +666,75 @@ void ChatHandler::sendInChannel(short channelId, MessageOut &msg) } } } + +void ChatHandler::sendGuildEnterChannel(const MessageOut &msg, const std::string &name) +{ + for (NetComputers::iterator i = clients.begin(), i_end = clients.end(); + i != i_end; ++i) { + if (static_cast< ChatClient * >(*i)->characterName == name) + { + (*i)->send(msg); + break; + } + } +} + +void ChatHandler::sendGuildInvite(const std::string &invitedName, const std::string &inviterName, + const std::string &guildName) +{ + MessageOut msg(CPMSG_GUILD_INVITED); + msg.writeString(inviterName); + msg.writeString(guildName); + for (NetComputers::iterator i = clients.begin(), i_end = clients.end(); + i != i_end; ++i) { + if (static_cast< ChatClient * >(*i)->characterName == invitedName) + { + (*i)->send(msg); + break; + } + } +} + +void ChatHandler::sendGuildRejoin(ChatClient &computer) +{ + // Get character based on name. + CharacterPtr character = serverHandler->getCharacter(computer.characterName); + + // Get list of guilds and check what rights they have. + std::vector<std::string> guilds = character->getGuilds(); + for(unsigned int i = 0; i != guilds.size(); ++i) + { + Guild *guild = guildManager->findByName(guilds[i]); + short leader = 0; + if(!guild) + { + return; + } + if(guild->checkLeader(character.get())) + { + leader = 1; + } + MessageOut msg(CPMSG_GUILD_REJOIN); + msg.writeString(guild->getName()); + msg.writeShort(guild->getId()); + msg.writeShort(leader); + computer.send(msg); + serverHandler->enterChannel(guild->getName(), character.get()); + } +} + +void ChatHandler::sendUserJoined(short channelId, const std::string &name) +{ + MessageOut msg(CPMSG_USERJOINED); + msg.writeShort(channelId); + msg.writeString(name); + sendInChannel(channelId, msg); +} + +void ChatHandler::sendUserLeft(short channelId, const std::string &name) +{ + MessageOut msg(CPMSG_USERLEFT); + msg.writeShort(channelId); + msg.writeString(name); + sendInChannel(channelId, msg); +} diff --git a/src/chat-server/chathandler.hpp b/src/chat-server/chathandler.hpp index 19c5f464..cda3f27e 100644 --- a/src/chat-server/chathandler.hpp +++ b/src/chat-server/chathandler.hpp @@ -49,6 +49,25 @@ class ChatHandler : public ConnectionHandler */ bool startListen(enet_uint16 port); + + /** + * Tell a list of user about an event in a chatchannel about a player. + */ + void warnUsersAboutPlayerEventInChat(short channelId, + std::string const &userName, + char eventId); + + /** + * Send Chat and Guild Info to chat client, so that they can + * join the correct channels. + */ + void sendGuildEnterChannel(const MessageOut &msg, const std::string &name); + + /** + * Send guild invite. + */ + void sendGuildInvite(const std::string &invitedName, const std::string &inviterName, + const std::string &guildName); protected: /** @@ -57,6 +76,11 @@ class ChatHandler : public ConnectionHandler void processMessage(NetComputer *computer, MessageIn &message); NetComputer *computerConnected(ENetPeer *); void computerDisconnected(NetComputer *); + + /** + * Send messages for each guild the character belongs to. + */ + void sendGuildRejoin(ChatClient &computer); private: /** @@ -92,17 +116,20 @@ class ChatHandler : public ConnectionHandler void sendInChannel(short channelId, MessageOut &); /** - * Tell a list of user about an event in a chatchannel about a player. - */ - void warnUsersAboutPlayerEventInChat(short channelId, - std::string const &userName, - char eventId); - - /** * Removes outdated pending logins. These are connected clients that * still haven't sent in their magic token. */ void removeOutdatedPending(); + + /** + * Send user joined message. + */ + void sendUserJoined(short channelId, const std::string &name); + + /** + * Send user left message. + */ + void sendUserLeft(short channelId, const std::string &name); }; /** @@ -110,4 +137,6 @@ class ChatHandler : public ConnectionHandler */ void registerChatClient(std::string const &, std::string const &, int); +extern ChatHandler *chatHandler; + #endif diff --git a/src/defines.h b/src/defines.h index ccd4a191..73e50ed3 100644 --- a/src/defines.h +++ b/src/defines.h @@ -165,6 +165,23 @@ enum { PGMSG_USE_ITEM = 0x0300, // L item id GPMSG_USE_RESPONSE = 0x0301, // B error GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W amount }* + + // Guild + PGMSG_GUILD_CREATE = 0x0350, // S name + GPMSG_GUILD_CREATE_RESPONSE = 0x0351, // B error, W id + PGMSG_GUILD_INVITE = 0x0352, // W id, S name + GPMSG_GUILD_INVITE_RESPONSE = 0x0353, // B error + PGMSG_GUILD_ACCEPT = 0x0354, // S name + GPMSG_GUILD_ACCEPT_RESPONSE = 0x0355, // B error + PGMSG_GUILD_GET_MEMBERS = 0x0356, // W id + GPMSG_GUILD_GET_MEMBERS_RESPONSE = 0x0357, // S names + GPMSG_GUILD_JOINED = 0x0358, // W id, S name + GPMSG_GUILD_LEFT = 0x0359, // W id + PGMSG_GUILD_QUIT = 0x0360, // W id + GPMSG_GUILD_QUIT_RESPONSE = 0x0361, // B error, W id + + CPMSG_GUILD_INVITED = 0x0370, // S name, S name + CPMSG_GUILD_REJOIN = 0x0371, // S name, W id, W rights // Chat CPMSG_ERROR = 0x0401, // B error @@ -186,6 +203,10 @@ enum { CPMSG_QUIT_CHANNEL_RESPONSE = 0x0422, // B error PCMSG_LIST_CHANNELS = 0x0423, // - CPMSG_LIST_CHANNELS_RESPONSE = 0x0424, // W number of channels, S channels + CPMSG_USERJOINED = 0x0425, // W channel, S name + CPMSG_USERLEFT = 0x0426, // W channel, S name + PCMSG_LIST_CHANNELUSERS = 0x0427, // S channel + CPMSG_LIST_CHANNELUSERS_RESPONSE = 0x0428, // S users // Inter-server GAMSG_REGISTER = 0x0500, // S address, W port, { W map id }* @@ -195,6 +216,16 @@ enum { GAMSG_REDIRECT = 0x0530, // L id AGMSG_REDIRECT_RESPONSE = 0x0531, // L id, B*32 token, S game address, W game port GAMSG_PLAYER_RECONNECT = 0x0532, // L id, B*32 token + GAMSG_GUILD_CREATE = 0x0550, // S name + AGMSG_GUILD_CREATE_RESPONSE = 0x0551, // B error, W id + GAMSG_GUILD_INVITE = 0x0552, // W id, S name + AGMSG_GUILD_INVITE_RESPONSE = 0x0553, // B error + GAMSG_GUILD_ACCEPT = 0x0554, // S name + AGMSG_GUILD_ACCEPT_RESPONSE = 0x0555, // B error + GAMSG_GUILD_GET_MEMBERS = 0x0556, // W id + AGMSG_GUILD_GET_MEMBERS_RESPONSE = 0x0557, // S names + GAMSG_GUILD_QUIT = 0x0558, // W id + AGMSG_GUILD_QUIT_RESPONSE = 0x0559, // B error XXMSG_INVALID = 0x7FFF }; @@ -207,7 +238,8 @@ enum { ERRMSG_NO_LOGIN, // the user is not yet logged ERRMSG_NO_CHARACTER_SELECTED, // the user needs a character ERRMSG_INSUFFICIENT_RIGHTS, // the user is not privileged - ERRMSG_INVALID_ARGUMENT // part of the received message was invalid + ERRMSG_INVALID_ARGUMENT, // part of the received message was invalid + ERRMSG_ALREADY_TAKEN // name used was already taken }; // Login specific return values diff --git a/src/game-server/accountconnection.cpp b/src/game-server/accountconnection.cpp index e54605ff..e9ea2256 100644 --- a/src/game-server/accountconnection.cpp +++ b/src/game-server/accountconnection.cpp @@ -25,8 +25,11 @@ #include "defines.h" #include "game-server/accountconnection.hpp" #include "game-server/gamehandler.hpp" +#include "game-server/map.hpp" +#include "game-server/mapcomposite.hpp" #include "game-server/mapmanager.hpp" #include "game-server/character.hpp" +#include "game-server/state.hpp" #include "net/messagein.hpp" #include "net/messageout.hpp" #include "utils/logger.h" @@ -86,6 +89,119 @@ void AccountConnection::processMessage(MessageIn &msg) int port = msg.readShort(); gameHandler->completeServerChange(id, token, address, port); } break; + + case AGMSG_GUILD_CREATE_RESPONSE: + { + if(msg.readByte() == ERRMSG_OK) + { + int playerId = msg.readLong(); + + MessageOut result(GPMSG_GUILD_CREATE_RESPONSE); + result.writeByte(ERRMSG_OK); + + /* Create a message that the player has joined the guild + * Output the guild ID and guild name + * Send a 1 if the player has rights + * to invite users, otherwise 0. + */ + MessageOut out(GPMSG_GUILD_JOINED); + out.writeShort(msg.readShort()); + out.writeString(msg.readString()); + out.writeShort(msg.readShort()); + + Character *player = gameHandler->messageMap[playerId]; + if(player) + { + gameHandler->sendTo(player, result); + gameHandler->sendTo(player, out); + } + } + } break; + + case AGMSG_GUILD_INVITE_RESPONSE: + { + if(msg.readByte() == ERRMSG_OK) + { + int playerId = msg.readLong(); + + MessageOut result(GPMSG_GUILD_INVITE_RESPONSE); + result.writeByte(ERRMSG_OK); + + Character *player = gameHandler->messageMap[playerId]; + if(player) + { + gameHandler->sendTo(player, result); + } + } + } break; + + case AGMSG_GUILD_ACCEPT_RESPONSE: + { + if(msg.readByte() == ERRMSG_OK) + { + int playerId = msg.readLong(); + + MessageOut result(GPMSG_GUILD_ACCEPT_RESPONSE); + result.writeByte(ERRMSG_OK); + + /* Create a message that the player has joined the guild + * Output the guild ID and guild name + * Send a 0 for invite rights, since player has been invited + * they wont have any rights to invite other users yet. + */ + MessageOut out(GPMSG_GUILD_JOINED); + out.writeShort(msg.readShort()); + out.writeString(msg.readString()); + out.writeShort(0); + + Character *player = gameHandler->messageMap[playerId]; + if(player) + { + gameHandler->sendTo(player, result); + gameHandler->sendTo(player, out); + } + } + } break; + + case AGMSG_GUILD_GET_MEMBERS_RESPONSE: + { + if(msg.readByte() != ERRMSG_OK) + break; + int playerId = msg.readLong(); + short guildId = msg.readShort(); + + MessageOut result(GPMSG_GUILD_GET_MEMBERS_RESPONSE); + result.writeByte(ERRMSG_OK); + result.writeShort(guildId); + while(msg.getUnreadLength()) + { + result.writeString(msg.readString()); + } + + Character *player = gameHandler->messageMap[playerId]; + if(player) + { + gameHandler->sendTo(player, result); + } + } break; + + case AGMSG_GUILD_QUIT_RESPONSE: + { + if(msg.readByte() != ERRMSG_OK) + break; + int playerId = msg.readLong(); + short guildId = msg.readShort(); + + MessageOut result(GPMSG_GUILD_QUIT_RESPONSE); + result.writeByte(ERRMSG_OK); + result.writeShort(guildId); + + Character *player = gameHandler->messageMap[playerId]; + if(player) + { + gameHandler->sendTo(player, result); + } + } break; default: LOG_WARN("Invalid message type"); @@ -101,3 +217,49 @@ void AccountConnection::playerReconnectAccount(int id, const std::string magic_t msg.writeString(magic_token, MAGIC_TOKEN_LENGTH); send(msg); } + +void AccountConnection::playerCreateGuild(int id, const std::string &guildName) +{ + LOG_INFO("Send GAMSG_GUILD_CREATE"); + MessageOut msg(GAMSG_GUILD_CREATE); + msg.writeLong(id); + msg.writeString(guildName); + send(msg); +} + +void AccountConnection::playerInviteToGuild(int id, short guildId, const std::string &member) +{ + LOG_INFO("Send GAMSG_GUILD_INVITE"); + MessageOut msg(GAMSG_GUILD_INVITE); + msg.writeLong(id); + msg.writeShort(guildId); + msg.writeString(member); + send(msg); +} + +void AccountConnection::playerAcceptInvite(int id, const std::string &guildName) +{ + LOG_INFO("Send GAMSG_GUILD_ACCEPT"); + MessageOut msg(GAMSG_GUILD_ACCEPT); + msg.writeLong(id); + msg.writeString(guildName); + send(msg); +} + +void AccountConnection::getGuildMembers(int id, short guildId) +{ + LOG_INFO("Send GAMSG_GUILD_GET_MEMBERS"); + MessageOut msg(GAMSG_GUILD_GET_MEMBERS); + msg.writeLong(id); + msg.writeShort(guildId); + send(msg); +} + +void AccountConnection::quitGuild(int id, short guildId) +{ + LOG_INFO("Send GAMSG_GUILD_QUIT"); + MessageOut msg(GAMSG_GUILD_QUIT); + msg.writeLong(id); + msg.writeShort(guildId); + send(msg); +} diff --git a/src/game-server/accountconnection.hpp b/src/game-server/accountconnection.hpp index 24ee1598..700a85ca 100644 --- a/src/game-server/accountconnection.hpp +++ b/src/game-server/accountconnection.hpp @@ -50,6 +50,30 @@ class AccountConnection: public Connection */ void playerReconnectAccount(int id, const std::string magic_token); + /** + * Sends create guild message + */ + void playerCreateGuild(int id, const std::string &guildName); + + /** + * Sends invite message + */ + void playerInviteToGuild(int id, short guildId, const std::string &name); + + /** + * Sends accept message + */ + void playerAcceptInvite(int id, const std::string &name); + + /** + * Sends get guild members message. + */ + void getGuildMembers(int id, short guildId); + + /** + * Sends quit guild message. + */ + void quitGuild(int id, short guildId); protected: /** diff --git a/src/game-server/gamehandler.cpp b/src/game-server/gamehandler.cpp index 81f7a1e5..1ca4f756 100644 --- a/src/game-server/gamehandler.cpp +++ b/src/game-server/gamehandler.cpp @@ -258,6 +258,48 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message) computer.character = NULL; computer.status = CLIENT_LOGIN; } break; + + case PGMSG_GUILD_CREATE: + { + std::string name = message.readString(); + int characterId = computer.character->getDatabaseID(); + messageMap[characterId] = computer.character; + accountHandler->playerCreateGuild(characterId, name); + } break; + + case PGMSG_GUILD_INVITE: + { + short guildId = message.readShort(); + std::string member = message.readString(); + int characterId = computer.character->getDatabaseID(); + messageMap[characterId] = computer.character; + accountHandler->playerInviteToGuild(characterId, guildId, member); + } break; + + case PGMSG_GUILD_ACCEPT: + { + std::string guildName = message.readString(); + int characterId = computer.character->getDatabaseID(); + messageMap[characterId] = computer.character; + accountHandler->playerAcceptInvite(characterId, guildName); + } break; + + case PGMSG_GUILD_GET_MEMBERS: + { + short guildId = message.readShort(); + int characterId = computer.character->getDatabaseID(); + messageMap[characterId] = computer.character; + accountHandler->getGuildMembers(characterId, guildId); + } break; + + case PGMSG_GUILD_QUIT: + { + short guildId = message.readShort(); + int characterId = computer.character->getDatabaseID(); + messageMap[characterId] = computer.character; + accountHandler->quitGuild(characterId, guildId); + } break; + default: LOG_WARN("Invalid message type"); result.writeShort(XXMSG_INVALID); diff --git a/src/game-server/gamehandler.hpp b/src/game-server/gamehandler.hpp index 1e39e750..85a38674 100644 --- a/src/game-server/gamehandler.hpp +++ b/src/game-server/gamehandler.hpp @@ -85,6 +85,12 @@ class GameHandler: public ConnectionHandler */ void completeServerChange(int id, std::string const &token, std::string const &address, int port); + + /** + * Map of character's and their id used for getting which character to + * forward account server messages back to. + */ + std::map<int, Character*> messageMap; /** * Combines a client with it's character. diff --git a/src/game-server/mapmanager.cpp b/src/game-server/mapmanager.cpp index dcb91363..dac57cac 100644 --- a/src/game-server/mapmanager.cpp +++ b/src/game-server/mapmanager.cpp @@ -130,3 +130,8 @@ bool MapManager::isActive(int mapId) const assert(i != maps.end()); return i->second.isActive; } + +short MapManager::numberOfMaps() const +{ + return maps.size(); +} diff --git a/src/game-server/mapmanager.hpp b/src/game-server/mapmanager.hpp index 1ba7c8c7..8693dbfe 100644 --- a/src/game-server/mapmanager.hpp +++ b/src/game-server/mapmanager.hpp @@ -73,6 +73,11 @@ class MapManager * Gets the activity status of the map. */ bool isActive(int) const; + + /** + * Gets the number of maps + */ + short numberOfMaps() const; /** * Destructor. diff --git a/src/net/netcomputer.cpp b/src/net/netcomputer.cpp index 47d7ea1a..345b408d 100644 --- a/src/net/netcomputer.cpp +++ b/src/net/netcomputer.cpp @@ -92,10 +92,11 @@ operator <<(std::ostream &os, const NetComputer &comp) << ((comp.mPeer->address.host & 0xff000000) >> 24); else // big-endian - os << ((comp.mPeer->address.host & 0xff000000) >> 24) << "." - << ((comp.mPeer->address.host & 0x00ff0000) >> 16) << "." - << ((comp.mPeer->address.host & 0x0000ff00) >> 8) << "." - << ((comp.mPeer->address.host & 0x000000ff) >> 0); + // TODO: test this + os << ((comp.mPeer->address.host & 0xff000000) >> 24) << "." + << ((comp.mPeer->address.host & 0x00ff0000) >> 16) << "." + << ((comp.mPeer->address.host & 0x0000ff00) >> 8) << "." + << ((comp.mPeer->address.host & 0x000000ff)); return os; } |