diff options
Diffstat (limited to 'src/game-server/gamehandler.cpp')
-rw-r--r-- | src/game-server/gamehandler.cpp | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/src/game-server/gamehandler.cpp b/src/game-server/gamehandler.cpp new file mode 100644 index 00000000..b0b036e3 --- /dev/null +++ b/src/game-server/gamehandler.cpp @@ -0,0 +1,245 @@ +/* + * 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 <cassert> +#include <map> + +#include "map.h" +#include "game-server/gameclient.hpp" +#include "game-server/gamehandler.hpp" +#include "game-server/state.hpp" +#include "net/messagein.hpp" +#include "net/messageout.hpp" +#include "net/netcomputer.hpp" +#include "utils/logger.h" + +struct GamePendingLogin +{ + PlayerPtr character; + int timeout; +}; + +typedef std::map< std::string, GamePendingLogin > GamePendingLogins; +typedef std::map< std::string, GameClient * > GamePendingClients; + +/** + * The pending logins represent clients who were given a magic token by the + * account server but who have not yet logged in to the game server. + */ +static GamePendingLogins pendingLogins; + +/** + * The pending clients represent clients who tried to login to the game server, + * but for which no magic token is available yet. This can happen when the + * communication between the account server and client went faster than the + * communication between the account server and the game server. + */ +static GamePendingClients pendingClients; + +/** + * Notification that a particular token has been given to allow a certain + * player to enter the game. + */ +void registerGameClient(std::string const &token, PlayerPtr 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(GPMSG_CONNECT_RESPONSE); + result.writeByte(ERRMSG_OK); + computer->send(result); + } + else + { + GamePendingLogin p; + p.character = ch; + p.timeout = 300; // world ticks + pendingLogins.insert(std::make_pair(token, p)); + } +} + +bool +GameHandler::startListen(enet_uint16 port) +{ + LOG_INFO("Game handler started:", 0); + return ConnectionHandler::startListen(port); +} + +void GameHandler::removeOutdatedPending() +{ + GamePendingLogins::iterator i = pendingLogins.begin(); + GamePendingLogins::iterator 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(peer); +} + +void GameHandler::computerDisconnected(NetComputer *computer) +{ + GamePendingClients::iterator i; + for (i = pendingClients.begin(); i != pendingClients.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() != PGMSG_CONNECT) return; + std::string magic_token = message.readString(32); + GamePendingLogins::iterator i = pendingLogins.find(magic_token); + if (i == pendingLogins.end()) + { + GamePendingClients::iterator i; + for (i = pendingClients.begin(); i != pendingClients.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(GPMSG_CONNECT_RESPONSE); + result.writeByte(ERRMSG_OK); + computer.send(result); + return; + } + + switch (message.getId()) + { + case PGMSG_SAY: + { + std::string say = message.readString(); + gameState->sayAround(computer.getCharacter().get(), say); + } break; + + /* + case PGMSG_PICKUP: + { + // add item to inventory (this is too simplistic atm) + unsigned int itemId = message.readLong(); + + // remove the item from world map + + // send feedback + computer.getCharacter()->addItem(itemId); + result.writeShort(GPMSG_PICKUP_RESPONSE); + result.writeByte(ERRMSG_OK); + } break; + + case PGMSG_USE_ITEM: + { + unsigned int itemId = message.readLong(); + + result.writeShort(GPMSG_USE_RESPONSE); + + if (computer.getCharacter()->hasItem(itemId)) { + // use item + // this should execute a script which will do the appropriate action + // (the script will determine if the item is 1 use only) + result.writeByte(ERRMSG_OK); + } else { + result.writeByte(ERRMSG_FAILURE); + } + } break; + */ + + case PGMSG_WALK: + { + unsigned x = message.readShort(); + unsigned y = message.readShort(); + Point dst = {x, y}; + computer.getCharacter()->setDestination(dst); + + // no response should be required + } break; + + /* + case PGMSG_EQUIP: + { + message.readLong(); // ItemId: Not useful, the inventory knows it + char slot = message.readByte(); + + result.writeShort(GPMSG_EQUIP_RESPONSE); + result.writeByte(computer.getCharacter()->equip(slot) ? + ERRMSG_OK : ERRMSG_FAILURE); + } break; + */ + + case PGMSG_ATTACK: + { + LOG_DEBUG("Player " << computer.getCharacter()->getPublicID() + << " attacks", 0); + computer.getCharacter()->setDirection(message.readByte()); + computer.getCharacter()->setAttacking(true); + } break; + + default: + LOG_WARN("Invalid message type", 0); + result.writeShort(XXMSG_INVALID); + break; + } + + if (result.getLength() > 0) + computer.send(result); +} + +void GameHandler::sendTo(Player *beingPtr, MessageOut &msg) +{ + GameClient *client = beingPtr->getClient(); + assert(client != NULL); + client->send(msg); +} |