diff options
author | Yohann Ferreira <bertram@cegetel.net> | 2005-12-27 03:42:40 +0000 |
---|---|---|
committer | Yohann Ferreira <bertram@cegetel.net> | 2005-12-27 03:42:40 +0000 |
commit | 205579c3be58537060785d174f9f67c89444a21b (patch) | |
tree | 31c7c8e0af476e70259650e1c577eaf299f3fc78 /src | |
parent | ad9ecbf35e0d986d704deba6f8f20ad72a94a99e (diff) | |
download | manaserv-205579c3be58537060785d174f9f67c89444a21b.tar.gz manaserv-205579c3be58537060785d174f9f67c89444a21b.tar.bz2 manaserv-205579c3be58537060785d174f9f67c89444a21b.tar.xz manaserv-205579c3be58537060785d174f9f67c89444a21b.zip |
Implemented common chat handling, except for chatting in channels. Also the Channel registering/unregistering isn't there yet and the commands needs to be implemented. Added a small slangs filter to reduce bad words in account names and in conversations a little.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/accounthandler.cpp | 12 | ||||
-rw-r--r-- | src/chathandler.cpp | 175 | ||||
-rw-r--r-- | src/chathandler.h | 34 | ||||
-rw-r--r-- | src/connectionhandler.cpp | 43 | ||||
-rw-r--r-- | src/connectionhandler.h | 19 | ||||
-rw-r--r-- | src/defines.h | 16 | ||||
-rw-r--r-- | src/main.cpp | 52 | ||||
-rw-r--r-- | src/utils/slangsfilter.cpp | 67 | ||||
-rw-r--r-- | src/utils/slangsfilter.h | 43 |
10 files changed, 427 insertions, 38 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index b23ccf37..ad8c046e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -68,7 +68,9 @@ tmwserv_SOURCES = main.cpp \ utils/cipher.h \ utils/cipher.cpp \ utils/logger.h \ - utils/logger.cpp + utils/logger.cpp \ + utils/slangsfilter.h \ + utils/slangsfilter.cpp if BUILD_MYSQL tmwserv_SOURCES += dal/mysqldataprovider.h \ diff --git a/src/accounthandler.cpp b/src/accounthandler.cpp index 7441400e..ca65cd1e 100644 --- a/src/accounthandler.cpp +++ b/src/accounthandler.cpp @@ -28,7 +28,7 @@ #include "messageout.h" #include "configuration.h" #include "utils/logger.h" -#include <cctype> +#include "utils/slangsfilter.h" using tmwserv::Account; using tmwserv::AccountPtr; @@ -150,7 +150,15 @@ void AccountHandler::receiveMessage(NetComputer &computer, MessageIn &message) std::string password = message.readString(); std::string email = message.readString(); - // checking conditions for having a good account. + // Checking if the Name is slang's free. + if (!tmwserv::utils::filterContent(username)) + { + result.writeShort(SMSG_REGISTER_RESPONSE); + result.writeByte(REGISTER_INVALID_USERNAME); + LOG_INFO(username << ": has got bad words in it.", 1) + break; + } + // Checking conditions for having a good account. LOG_INFO(username << " is trying to register.", 1) bool emailValid = false; diff --git a/src/chathandler.cpp b/src/chathandler.cpp index 1a25ce57..73906275 100644 --- a/src/chathandler.cpp +++ b/src/chathandler.cpp @@ -21,14 +21,39 @@ * $Id$ */ +#include <cctype> #include "chathandler.h" +#include "state.h" +#include "being.h" #include "defines.h" -#include <iostream> +#include "utils/logger.h" +#include "utils/slangsfilter.h" void ChatHandler::receiveMessage(NetComputer &computer, MessageIn &message) { - if (computer.getCharacter().get() == NULL) - return; // character not selected + // If not logged in... + if (computer.getAccount().get() == NULL) + { + LOG_INFO("Not logged in, can't chat...", 2) + MessageOut result; + result.writeShort(SMSG_CHAT); + result.writeByte(CHAT_NOLOGIN); + computer.send(result.getPacket()); + return; + } + else + { + // If no character selected yet... + if (computer.getCharacter().get() == NULL) + { + MessageOut result; + result.writeShort(SMSG_CHAT); + result.writeByte(CHAT_NO_CHARACTER_SELECTED); + computer.send(result.getPacket()); + LOG_INFO("No character selected. Can't chat...", 2) + return; // character not selected + } + } switch (message.getId()) { @@ -36,15 +61,55 @@ void ChatHandler::receiveMessage(NetComputer &computer, MessageIn &message) { // chat to people around area std::string text = message.readString(); - short channel = message.readShort(); - std::cout << "Say (" << channel << "): " << text << std::endl; + // If it's slang clean, + if (tmwserv::utils::filterContent(text)) + { + short channel = message.readShort(); + LOG_INFO("Say: (Channel " << channel << "): " << text, 2) + if ( channel == 0 ) // Let's say that is the default channel for now. + { + if ( text.substr(0, 1) == "@" || text.substr(0, 1) == "#" || text.substr(0, 1) == "/" ) + { + // The message is a command. Deal with it. + handleCommand(computer, text); + } + else + { + // The default channel (0) is when the character speaks + // to the characters around him in the map. + // We, then, look for every characters around him and + // send the message to them. + // By 'around', let's say 10 tiles square wide for now. + sayAround(computer, text); + } + } + else + { + // We send the message to the players registered in the channel. + sayInChannel(computer, channel, text); + } + } + else + { + warnPlayerAboutBadWords(computer); + } } break; case CMSG_ANNOUNCE: { std::string text = message.readString(); - std::cout << "Announce: " << text << std::endl; + // If it's slang's free. + if (tmwserv::utils::filterContent(text)) + { + // We send the message to every players in the default channel + // as it is an annouce. + announce(computer, text); + } + else + { + warnPlayerAboutBadWords(computer); + } } break; @@ -52,10 +117,106 @@ void ChatHandler::receiveMessage(NetComputer &computer, MessageIn &message) { std::string user = message.readString(); std::string text = message.readString(); + if (tmwserv::utils::filterContent(text)) + { + // We seek the player to whom the message is told + // and send it to her/him. + sayToPlayer(computer, user, text); + } + else + { + warnPlayerAboutBadWords(computer); + } } break; default: - std::cout << "Invalid message type" << std::endl; + LOG_INFO("Chat: Invalid message type", 2) break; } } + +void ChatHandler::handleCommand(NetComputer &computer, std::string command) +{ + LOG_INFO("Chat: Recieved unhandled command: " << command, 2) + MessageOut result; + result.writeShort(SMSG_CHAT); + result.writeShort(0); // The Channel + result.writeString("SERVER: Unknown or unhandled command."); + computer.send(result.getPacket()); +} + +void ChatHandler::warnPlayerAboutBadWords(NetComputer &computer) +{ + // We could later count if the player is really often unpolite. + MessageOut result; + result.writeShort(SMSG_CHAT); + result.writeShort(0); // The Channel + result.writeString("SERVER: Take care not to use bad words when you speak..."); + computer.send(result.getPacket()); + + LOG_INFO(computer.getCharacter()->getName() << " says bad words.", 2) +} + +void ChatHandler::announce(NetComputer &computer, std::string text) +{ + MessageOut result; + if ( computer.getAccount()->getLevel() == (AccountLevels)AL_ADMIN || + computer.getAccount()->getLevel() == (AccountLevels)AL_GM ) + { + LOG_INFO("ANNOUNCE: " << text, 0) + // Send it to every beings. + result.writeShort(SMSG_ANNOUNCEMENT); + result.writeString(text); + connectionHandler->sendToEveryone(result); + } + else + { + result.writeShort(SMSG_SYSTEM); + result.writeString("Cannot make announcements. You have not enough rights."); + computer.send(result.getPacket()); + LOG_INFO(computer.getCharacter()->getName() << + " couldn't make an announcement due to insufficient rights.", 2) + } +} + +void ChatHandler::sayAround(NetComputer &computer, std::string text) +{ + MessageOut result; + LOG_INFO( computer.getCharacter()->getName() << " says: " << text, 2) + // Send it to every beings around + result.writeShort(SMSG_CHAT); + result.writeShort(0); // The default channel + std::string say = computer.getCharacter()->getName(); + say += ": "; + say += text; + result.writeString(say); + connectionHandler->sendAround(computer.getCharacter(), result); +} + +void ChatHandler::sayToPlayer(NetComputer &computer, std::string playerName, std::string text) +{ + MessageOut result; + LOG_INFO( computer.getCharacter()->getName() << " says to " << playerName + << ": " << text, 2) + // Send it to the being if the being exists + result.writeShort(SMSG_PRIVMSG); + std::string say = computer.getCharacter()->getName(); + say += ": "; + say += text; + result.writeString(say); + connectionHandler->sendTo(playerName, result); +} + +void ChatHandler::sayInChannel(NetComputer &computer, short channel, std::string text) +{ + MessageOut result; + LOG_INFO( computer.getCharacter()->getName() << " says in channel " << channel + << ": " << text, 2) + // TODO: Send it to every beings in channel + result.writeShort(SMSG_CHAT); + result.writeShort(channel); + std::string say = computer.getCharacter()->getName(); + say += ": "; + say += text; + result.writeString(say); +} diff --git a/src/chathandler.h b/src/chathandler.h index 3f9b2307..4c0ebdd6 100644 --- a/src/chathandler.h +++ b/src/chathandler.h @@ -38,6 +38,40 @@ class ChatHandler : public MessageHandler * Receives chat related messages. */ void receiveMessage(NetComputer &computer, MessageIn &message); + + private: + /** + * Deals with command messages + */ + void handleCommand(NetComputer &computer, std::string command); + + /** + * Tells the player to be more polite. + */ + void warnPlayerAboutBadWords(NetComputer &computer); + + /** + * Announce a message to every being in the default channel. + */ + void announce(NetComputer &computer, std::string text); + + /** + * Display a message to every player around one's player + * in the default channel. + * The tile area has been set to 10 for now. + */ + void sayAround(NetComputer &computer, std::string text); + + /** + * Say something private to a player. + */ + void sayToPlayer(NetComputer &computer, std::string playerName, std::string text); + + /** + * Say something in a specific channel. + */ + void sayInChannel(NetComputer &computer, short channel, std::string text); + }; #endif diff --git a/src/connectionhandler.cpp b/src/connectionhandler.cpp index c8ed1c6e..b8172fe0 100644 --- a/src/connectionhandler.cpp +++ b/src/connectionhandler.cpp @@ -21,7 +21,6 @@ */ -#include <iostream> #include <vector> #include <sstream> #include <SDL_net.h> @@ -256,3 +255,45 @@ void ConnectionHandler::sendTo(tmwserv::BeingPtr beingPtr, MessageOut &msg) } } } + +void ConnectionHandler::sendTo(std::string name, MessageOut &msg) +{ + for (NetComputers::iterator i = clients.begin(); + i != clients.end(); + i++) { + if ((*i)->getCharacter().get()->getName() == name) { + (*i)->send(msg.getPacket()); + break; + } + } +} + +void ConnectionHandler::sendToEveryone(MessageOut &msg) +{ + for (NetComputers::iterator i = clients.begin(); + i != clients.end(); + i++) + { + (*i)->send(msg.getPacket()); + break; + } +} + +void ConnectionHandler::sendAround(tmwserv::BeingPtr beingPtr, MessageOut &msg) +{ + for (NetComputers::iterator i = clients.begin(); + i != clients.end(); + i++) { + // See if the other being is near enough, then send the message + if (abs((*i)->getCharacter().get()->getX() - beingPtr.get()->getX()) <= AROUND_AREA_IN_TILES ) + { + if (abs((*i)->getCharacter().get()->getY() - beingPtr.get()->getY()) <= AROUND_AREA_IN_TILES ) + { + (*i)->send(msg.getPacket()); + break; + } + } + } +} + + diff --git a/src/connectionhandler.h b/src/connectionhandler.h index 0d3bfa32..54ed6a06 100644 --- a/src/connectionhandler.h +++ b/src/connectionhandler.h @@ -104,14 +104,31 @@ class ConnectionHandler void registerHandler(unsigned int msgId, MessageHandler *handler); /** - * Send packet to client with matching Being* + * Send packet to client with matching BeingPtr */ void sendTo(tmwserv::BeingPtr, MessageOut &); + /** + * Send packet to client with matching Being name + */ + void sendTo(std::string name, MessageOut &); + + /** + * Send packet to every client, used for announcements. + */ + void sendToEveryone(MessageOut &); + + /** + * Send packet to every client around the client on screen. + */ + void sendAround(tmwserv::BeingPtr, MessageOut &); + private: std::map<unsigned int, MessageHandler*> handlers; NetComputers clients; }; +extern ConnectionHandler *connectionHandler; + #endif diff --git a/src/defines.h b/src/defines.h index 954380ba..f1b27a27 100644 --- a/src/defines.h +++ b/src/defines.h @@ -76,7 +76,14 @@ enum { /** * Points to give to a brand new character */ - POINTS_TO_DISTRIBUTES_AT_LVL1 = 60 + POINTS_TO_DISTRIBUTES_AT_LVL1 = 60, + + // Screen Related +/** + * Determine the area in which a character + * can hear another one speak + */ + AROUND_AREA_IN_TILES = 10 }; /** @@ -219,6 +226,13 @@ enum { CHAR_LIST_NOLOGIN }; +// Chat errors return values +enum { + // CHAT_OK = 0, + CHAT_NOLOGIN = 1, + CHAT_NO_CHARACTER_SELECTED +}; + // Object type enumeration enum { OBJECT_ITEM = 0, diff --git a/src/main.cpp b/src/main.cpp index 052f86c5..46a87b9b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,7 +90,8 @@ ChatHandler *chatHandler = new ChatHandler(); /** Core game message handler */ GameHandler *gameHandler = new GameHandler(); -ConnectionHandler connectionHandler; /**< Primary connection handler */ +/** Primary connection handler */ +ConnectionHandler *connectionHandler = new ConnectionHandler(); /** * SDL timer callback, sends a <code>TMW_WORLD_TICK</code> event. @@ -217,6 +218,7 @@ void deinitialize() delete accountHandler; delete chatHandler; delete gameHandler; + delete connectionHandler; // Get rid of persistent data storage tmwserv::Storage::destroy(); @@ -298,29 +300,29 @@ int main(int argc, char *argv[]) // // Register message handlers - connectionHandler.registerHandler(CMSG_LOGIN, accountHandler); - connectionHandler.registerHandler(CMSG_LOGOUT, accountHandler); - connectionHandler.registerHandler(CMSG_REGISTER, accountHandler); - connectionHandler.registerHandler(CMSG_UNREGISTER, accountHandler); - connectionHandler.registerHandler(CMSG_CHAR_CREATE, accountHandler); - connectionHandler.registerHandler(CMSG_CHAR_SELECT, accountHandler); - connectionHandler.registerHandler(CMSG_CHAR_DELETE, accountHandler); - connectionHandler.registerHandler(CMSG_CHAR_LIST, accountHandler); - - connectionHandler.registerHandler(CMSG_SAY, chatHandler); - connectionHandler.registerHandler(CMSG_ANNOUNCE, chatHandler); - - connectionHandler.registerHandler(CMSG_PICKUP, gameHandler); - connectionHandler.registerHandler(CMSG_USE_OBJECT, gameHandler); - connectionHandler.registerHandler(CMSG_USE_ITEM, gameHandler); // NOTE: this is probably redundant (CMSG_USE_OBJECT) - connectionHandler.registerHandler(CMSG_TARGET, gameHandler); - connectionHandler.registerHandler(CMSG_WALK, gameHandler); - connectionHandler.registerHandler(CMSG_START_TRADE, gameHandler); - connectionHandler.registerHandler(CMSG_START_TALK, gameHandler); - connectionHandler.registerHandler(CMSG_REQ_TRADE, gameHandler); - connectionHandler.registerHandler(CMSG_EQUIP, gameHandler); - - session->startListen(&connectionHandler, SERVER_PORT); + connectionHandler->registerHandler(CMSG_LOGIN, accountHandler); + connectionHandler->registerHandler(CMSG_LOGOUT, accountHandler); + connectionHandler->registerHandler(CMSG_REGISTER, accountHandler); + connectionHandler->registerHandler(CMSG_UNREGISTER, accountHandler); + connectionHandler->registerHandler(CMSG_CHAR_CREATE, accountHandler); + connectionHandler->registerHandler(CMSG_CHAR_SELECT, accountHandler); + connectionHandler->registerHandler(CMSG_CHAR_DELETE, accountHandler); + connectionHandler->registerHandler(CMSG_CHAR_LIST, accountHandler); + + connectionHandler->registerHandler(CMSG_SAY, chatHandler); + connectionHandler->registerHandler(CMSG_ANNOUNCE, chatHandler); + + connectionHandler->registerHandler(CMSG_PICKUP, gameHandler); + connectionHandler->registerHandler(CMSG_USE_OBJECT, gameHandler); + connectionHandler->registerHandler(CMSG_USE_ITEM, gameHandler); // NOTE: this is probably redundant (CMSG_USE_OBJECT) + connectionHandler->registerHandler(CMSG_TARGET, gameHandler); + connectionHandler->registerHandler(CMSG_WALK, gameHandler); + connectionHandler->registerHandler(CMSG_START_TRADE, gameHandler); + connectionHandler->registerHandler(CMSG_START_TALK, gameHandler); + connectionHandler->registerHandler(CMSG_REQ_TRADE, gameHandler); + connectionHandler->registerHandler(CMSG_EQUIP, gameHandler); + + session->startListen(connectionHandler, SERVER_PORT); LOG_INFO("Listening on port " << SERVER_PORT << "...", 0) using namespace tmwserv; @@ -352,7 +354,7 @@ int main(int argc, char *argv[]) // - Handle all messages that are in the message queue // - Update all active objects/beings - state.update(connectionHandler); + state.update(*connectionHandler); } else if (event.type == SDL_QUIT) { running = false; diff --git a/src/utils/slangsfilter.cpp b/src/utils/slangsfilter.cpp new file mode 100644 index 00000000..e950243b --- /dev/null +++ b/src/utils/slangsfilter.cpp @@ -0,0 +1,67 @@ +/* + * 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$ + */ + +#include "slangsfilter.h" + +namespace tmwserv +{ +namespace utils +{ + +/** + * The slang table. Don't be surprised. We need to know about bad words in order + * to keep them out of the players' conversations. +*/ +std::string slangs[] = { +"fuck","shit","slut","whore","bitch", +"END" // This is the terminator, don't remove it. +}; + +bool filterContent(std::string text) +{ + bool good = true; + unsigned int i = 0; + while ( !(slangs[i] == "END") ) + { + for (unsigned int j = 0; j <= text.length(); j++) + { + // We look for slangs into the sentence. + std::string upcasedText = text; + std::string upcasedSlang = slangs[i]; + std::transform(upcasedText.begin(), upcasedText.end(), upcasedText.begin(), + (int(*)(int))std::toupper); + std::transform(upcasedSlang.begin(), upcasedSlang.end(), upcasedSlang.begin(), + (int(*)(int))std::toupper); + if ( upcasedText.substr(j, upcasedSlang.length()) == upcasedSlang ) + { + good = false; + } + } + // Next slang + i++; + } + + return good; +} + +} // ::utils +} // ::tmwserv diff --git a/src/utils/slangsfilter.h b/src/utils/slangsfilter.h new file mode 100644 index 00000000..cb4d2ecc --- /dev/null +++ b/src/utils/slangsfilter.h @@ -0,0 +1,43 @@ +/* + * 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_SLANGSFILTER_H_ +#define _TMWSERV_SLANGSFILTER_H_ + +#include <string> + +namespace tmwserv +{ +namespace utils +{ + + /** + * Useful to filter slangs automatically, by instance. + * @return true if the sentence is slangs clear. + */ + bool filterContent(std::string text); + +} // ::utils +} // ::tmwserv + +#endif |