From 351f050dd77c7dfae7ab901b9dab08336e59b4fc Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Tue, 23 May 2006 05:35:13 +0000 Subject: Split server into three logical servers: an account server, a chat server, and a game server. --- src/gamehandler.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 198 insertions(+), 4 deletions(-) (limited to 'src/gamehandler.cpp') diff --git a/src/gamehandler.cpp b/src/gamehandler.cpp index ff4a0dde..dc14fd2a 100644 --- a/src/gamehandler.cpp +++ b/src/gamehandler.cpp @@ -23,23 +23,184 @@ #include "gamehandler.h" +#include #include +#include #include "messagein.h" #include "messageout.h" #include "netcomputer.h" #include "packet.h" +#include "state.h" -void GameHandler::receiveMessage(NetComputer &comp, MessageIn &message) +using tmwserv::BeingPtr; + +class GameClient: public NetComputer { - ClientComputer &computer = static_cast< ClientComputer & >(comp); - if (computer.getCharacter().get() == NULL) - return; + public: + /** + * Constructor. + */ + GameClient(GameHandler *, ENetPeer *); + + /** + * Destructor. + */ + ~GameClient(); + + /** + * Set the selected character associated with connection. + */ + void setCharacter(BeingPtr ch); + + /** + * Deselect the character associated with connection. + */ + void unsetCharacter(); + + /** + * Get character associated with the connection. + */ + BeingPtr getCharacter() { return mCharacterPtr; } + + private: + /** Character associated with the conneciton. */ + BeingPtr mCharacterPtr; +}; + +GameClient::GameClient(GameHandler *handler, ENetPeer *peer): + NetComputer(handler, peer), + mCharacterPtr(NULL) +{ +} + +GameClient::~GameClient() +{ + unsetCharacter(); +} + + +void GameClient::setCharacter(tmwserv::BeingPtr ch) +{ + assert(mCharacterPtr.get() == NULL); + tmwserv::State &state = tmwserv::State::instance(); + mCharacterPtr = ch; + state.addBeing(mCharacterPtr, mCharacterPtr->getMapId()); +} + +void GameClient::unsetCharacter() +{ + if (mCharacterPtr.get() == NULL) return; + // remove being from world + tmwserv::State &state = tmwserv::State::instance(); + state.removeBeing(mCharacterPtr); + mCharacterPtr = tmwserv::BeingPtr(NULL); +} + +struct GamePendingLogin +{ + tmwserv::BeingPtr character; + int timeout; +}; + +typedef std::map< std::string, GamePendingLogin > GamePendingLogins; +static GamePendingLogins pendingLogins; + +typedef std::map< std::string, GameClient * > GamePendingClients; +static GamePendingClients pendingClients; + +void registerGameClient(std::string const &token, tmwserv::BeingPtr ch) +{ + GamePendingClients::iterator i = pendingClients.find(token); + if (i != pendingClients.end()) + { + GameClient *computer = i->second; + computer->setCharacter(ch); + pendingClients.erase(i); + MessageOut result; + result.writeShort(SMSG_GAMESRV_CONNECT_RESPONSE); + result.writeByte(GSRV_CONNECT_OK); + computer->send(result.getPacket()); + } + else + { + GamePendingLogin p; + p.character = ch; + p.timeout = 300; // world ticks + pendingLogins.insert(std::make_pair(token, p)); + } +} + +void GameHandler::removeOutdatedPending() +{ + GamePendingLogins::iterator i = pendingLogins.begin(), next; + while (i != pendingLogins.end()) + { + next = i; ++next; + if (--i->second.timeout <= 0) pendingLogins.erase(i); + i = next; + } +} +NetComputer *GameHandler::computerConnected(ENetPeer *peer) +{ + return new GameClient(this, peer); +} + +void GameHandler::computerDisconnected(NetComputer *computer) +{ + for (GamePendingClients::iterator i = pendingClients.begin(), i_end = pendingClients.end(); + i != i_end; ++i) + { + if (i->second == computer) + { + pendingClients.erase(i); + break; + } + } + delete computer; +} + +void GameHandler::process() +{ + ConnectionHandler::process(); + removeOutdatedPending(); +} + +void GameHandler::processMessage(NetComputer *comp, MessageIn &message) +{ + GameClient &computer = *static_cast< GameClient * >(comp); MessageOut result; + if (computer.getCharacter().get() == NULL) { + if (message.getId() != CMSG_GAMESRV_CONNECT) return; + std::string magic_token = message.readString(32); + GamePendingLogins::iterator i = pendingLogins.find(magic_token); + if (i == pendingLogins.end()) + { + for (GamePendingClients::iterator i = pendingClients.begin(), i_end = pendingClients.end(); + i != i_end; ++i) { + if (i->second == &computer) return; + } + pendingClients.insert(std::make_pair(magic_token, &computer)); + return; + } + computer.setCharacter(i->second.character); + pendingLogins.erase(i); + result.writeShort(SMSG_GAMESRV_CONNECT_RESPONSE); + result.writeByte(GSRV_CONNECT_OK); + computer.send(result.getPacket()); + return; + } + switch (message.getId()) { + case CMSG_SAY: + { + std::string say = message.readString(); + sayAround(computer, say); + } break; + case CMSG_PICKUP: { // add item to inventory (this is too simplistic atm) @@ -121,3 +282,36 @@ void GameHandler::receiveMessage(NetComputer &comp, MessageIn &message) if (result.getPacket()->length > 0) computer.send(result.getPacket()); } + +void GameHandler::sayAround(GameClient &computer, std::string const &text) +{ + BeingPtr beingPtr = computer.getCharacter(); + MessageOut msg; + msg.writeShort(SMSG_SAY); + msg.writeString(beingPtr->getName()); + msg.writeString(text); + unsigned speakerMapId = beingPtr->getMapId(); + std::pair speakerXY = beingPtr->getXY(); + for (NetComputers::iterator i = clients.begin(), i_end = clients.end(); + i != i_end; ++i) + { + // See if the other being is near enough, then send the message + tmwserv::Being const *listener = static_cast< GameClient * >(*i)->getCharacter().get(); + if (!listener || listener->getMapId() != speakerMapId) continue; + std::pair listenerXY = listener->getXY(); + if (abs(listenerXY.first - speakerXY.first ) > (int)AROUND_AREA_IN_TILES) continue; + if (abs(listenerXY.second - speakerXY.second) > (int)AROUND_AREA_IN_TILES) continue; + (*i)->send(msg.getPacket()); + } +} + +void GameHandler::sendTo(BeingPtr beingPtr, MessageOut &msg) +{ + for (NetComputers::iterator i = clients.begin(), i_end = clients.end(); + i != i_end; ++i) { + if (static_cast< GameClient * >(*i)->getCharacter().get() == beingPtr.get()) { + (*i)->send(msg.getPacket()); + break; + } + } +} -- cgit v1.2.3-60-g2f50