summaryrefslogtreecommitdiffstats
path: root/src/game-server
diff options
context:
space:
mode:
authorGuillaume Melquiond <guillaume.melquiond@gmail.com>2006-12-30 23:25:42 +0000
committerGuillaume Melquiond <guillaume.melquiond@gmail.com>2006-12-30 23:25:42 +0000
commit723e7454e5d164b9d438a45b0446b56b72f36d83 (patch)
treec942bfe1dc7087c856b9024b251f39cfcfa91f6d /src/game-server
parent7f1c499e4e09ab939d6d31188aaaaf785250a1d5 (diff)
downloadmanaserv-723e7454e5d164b9d438a45b0446b56b72f36d83.tar.gz
manaserv-723e7454e5d164b9d438a45b0446b56b72f36d83.tar.xz
manaserv-723e7454e5d164b9d438a45b0446b56b72f36d83.zip
Almost a complete implementation for warping players between servers.
Diffstat (limited to 'src/game-server')
-rw-r--r--src/game-server/accountconnection.cpp28
-rw-r--r--src/game-server/accountconnection.hpp7
-rw-r--r--src/game-server/gamehandler.cpp125
-rw-r--r--src/game-server/gamehandler.hpp37
-rw-r--r--src/game-server/state.cpp136
-rw-r--r--src/game-server/state.hpp36
6 files changed, 269 insertions, 100 deletions
diff --git a/src/game-server/accountconnection.cpp b/src/game-server/accountconnection.cpp
index ee00a44..ceb0b5d 100644
--- a/src/game-server/accountconnection.cpp
+++ b/src/game-server/accountconnection.cpp
@@ -25,6 +25,7 @@
#include "defines.h"
#include "player.h"
#include "game-server/accountconnection.hpp"
+#include "game-server/gamehandler.hpp"
#include "game-server/mapmanager.hpp"
#include "net/messagein.hpp"
#include "net/messageout.hpp"
@@ -52,6 +53,24 @@ bool AccountConnection::start()
return true;
}
+void AccountConnection::sendPlayerData(Player *p)
+{
+ MessageOut msg(GAMSG_PLAYER_DATA);
+ msg.writeLong(p->getDatabaseID());
+ msg.writeByte(p->getGender());
+ msg.writeByte(p->getHairStyle());
+ msg.writeByte(p->getHairColor());
+ msg.writeByte(p->getLevel());
+ msg.writeShort(p->getMoney());
+ for (int j = 0; j < NB_RSTAT; ++j)
+ msg.writeShort(p->getRawStat(j));
+ Point pos = p->getPosition();
+ msg.writeShort(pos.x);
+ msg.writeShort(pos.y);
+ msg.writeShort(p->getMapId());
+ send(msg);
+}
+
void AccountConnection::processMessage(MessageIn &msg)
{
switch (msg.getId())
@@ -84,6 +103,15 @@ void AccountConnection::processMessage(MessageIn &msg)
mapManager->raiseActive(id);
} break;
+ case AGMSG_REDIRECT_RESPONSE:
+ {
+ int id = msg.readLong();
+ std::string token = msg.readString(32);
+ std::string address = msg.readString();
+ int port = msg.readShort();
+ gameHandler->completeServerChange(id, token, address, port);
+ } break;
+
default:
LOG_WARN("Invalid message type", 0);
break;
diff --git a/src/game-server/accountconnection.hpp b/src/game-server/accountconnection.hpp
index 9741221..9722fe6 100644
--- a/src/game-server/accountconnection.hpp
+++ b/src/game-server/accountconnection.hpp
@@ -26,6 +26,8 @@
#include "net/connection.hpp"
+class Player;
+
/**
* A connection to the account server.
*/
@@ -38,6 +40,11 @@ class AccountConnection: public Connection
*/
bool start();
+ /**
+ * Sends data of given player.
+ */
+ void sendPlayerData(Player *);
+
protected:
/**
* Processes server messages.
diff --git a/src/game-server/gamehandler.cpp b/src/game-server/gamehandler.cpp
index 4347886..c8e2235 100644
--- a/src/game-server/gamehandler.cpp
+++ b/src/game-server/gamehandler.cpp
@@ -32,10 +32,19 @@
#include "net/netcomputer.hpp"
#include "utils/logger.h"
+enum
+{
+ CLIENT_LOGIN = 0,
+ CLIENT_CONNECTED,
+ CLIENT_CHANGE_SERVER
+};
+
struct GameClient: NetComputer
{
- GameClient(ENetPeer *peer): NetComputer(peer), character(NULL) {}
+ GameClient(ENetPeer *peer)
+ : NetComputer(peer), character(NULL), status(CLIENT_LOGIN) {}
Player *character;
+ int status;
};
struct GamePendingLogin
@@ -62,6 +71,21 @@ static GamePendingLogins pendingLogins;
static GamePendingClients pendingClients;
/**
+ * Links a client to a character.
+ */
+static void linkCharacter(GameClient *computer, Player *ch)
+{
+ computer->character = ch;
+ computer->status = CLIENT_CONNECTED;
+ ch->setClient(computer);
+ gameState->insertObject(ch);
+ MessageOut result;
+ result.writeShort(GPMSG_CONNECT_RESPONSE);
+ result.writeByte(ERRMSG_OK);
+ computer->send(result);
+}
+
+/**
* Notification that a particular token has been given to allow a certain
* player to enter the game.
*/
@@ -70,15 +94,8 @@ void registerGameClient(std::string const &token, Player *ch)
GamePendingClients::iterator i = pendingClients.find(token);
if (i != pendingClients.end())
{
- GameClient *computer = i->second;
- computer->character = ch;
- ch->setClient(computer);
- gameState->addObject(ch);
+ linkCharacter(i->second, ch);
pendingClients.erase(i);
- MessageOut result;
- result.writeShort(GPMSG_CONNECT_RESPONSE);
- result.writeByte(ERRMSG_OK);
- computer->send(result);
}
else
{
@@ -89,31 +106,12 @@ void registerGameClient(std::string const &token, Player *ch)
}
}
-bool
-GameHandler::startListen(enet_uint16 port)
+bool GameHandler::startListen(enet_uint16 port)
{
LOG_INFO("Game handler started:", 0);
return ConnectionHandler::startListen(port);
}
-void GameHandler::removeOutdatedPending()
-{
- GamePendingLogins::iterator i = pendingLogins.begin();
-
- while (i != pendingLogins.end())
- {
- if (--i->second.timeout <= 0)
- {
- delete i->second.character;
- pendingLogins.erase(i++);
- }
- else
- {
- ++i;
- }
- }
-}
-
NetComputer *GameHandler::computerConnected(ENetPeer *peer)
{
return new GameClient(peer);
@@ -138,10 +136,62 @@ void GameHandler::computerDisconnected(NetComputer *computer)
delete computer;
}
+void GameHandler::kill(Player *ch)
+{
+ GameClient *client = ch->getClient();
+ assert(client != NULL);
+ client->character = NULL;
+ client->status = CLIENT_LOGIN;
+}
+
+void GameHandler::prepareServerChange(Player *ch)
+{
+ GameClient *client = ch->getClient();
+ assert(client != NULL);
+ client->status = CLIENT_CHANGE_SERVER;
+}
+
+void GameHandler::completeServerChange(int id, std::string const &token,
+ std::string const &address, int port)
+{
+ for (NetComputers::const_iterator i = clients.begin(),
+ i_end = clients.end(); i != i_end; ++i)
+ {
+ GameClient *c = static_cast< GameClient * >(*i);
+ if (c->status == CLIENT_CHANGE_SERVER &&
+ c->character->getDatabaseID() == id)
+ {
+ MessageOut msg(GPMSG_PLAYER_SERVER_CHANGE);
+ msg.writeString(token, 32);
+ msg.writeString(address);
+ msg.writeShort(port);
+ c->send(msg);
+ delete c->character;
+ c->character = NULL;
+ c->status = CLIENT_LOGIN;
+ return;
+ }
+ }
+}
+
void GameHandler::process()
{
ConnectionHandler::process();
- removeOutdatedPending();
+
+ // Removes characters that have been left unconnected for too long.
+ GamePendingLogins::iterator i = pendingLogins.begin();
+ while (i != pendingLogins.end())
+ {
+ if (--i->second.timeout <= 0)
+ {
+ delete i->second.character;
+ pendingLogins.erase(i++);
+ }
+ else
+ {
+ ++i;
+ }
+ }
}
void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
@@ -149,7 +199,7 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
GameClient &computer = *static_cast< GameClient * >(comp);
MessageOut result;
- if (computer.character == NULL)
+ if (computer.status == CLIENT_LOGIN)
{
if (message.getId() != PGMSG_CONNECT) return;
std::string magic_token = message.readString(32);
@@ -164,13 +214,12 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
pendingClients.insert(std::make_pair(magic_token, &computer));
return;
}
- computer.character = i->second.character;
- computer.character->setClient(&computer);
- gameState->addObject(computer.character);
+ linkCharacter(&computer, i->second.character);
pendingLogins.erase(i);
- result.writeShort(GPMSG_CONNECT_RESPONSE);
- result.writeByte(ERRMSG_OK);
- computer.send(result);
+ return;
+ }
+ else if (computer.status != CLIENT_CONNECTED)
+ {
return;
}
@@ -256,6 +305,6 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
void GameHandler::sendTo(Player *beingPtr, MessageOut &msg)
{
GameClient *client = beingPtr->getClient();
- assert(client != NULL);
+ assert(client && client->status == CLIENT_CONNECTED);
client->send(msg);
}
diff --git a/src/game-server/gamehandler.hpp b/src/game-server/gamehandler.hpp
index ceb37cd..f574d9e 100644
--- a/src/game-server/gamehandler.hpp
+++ b/src/game-server/gamehandler.hpp
@@ -27,38 +27,51 @@
#include "player.h"
#include "net/connectionhandler.hpp"
-class GameClient;
-
-/*
- * Manage connections to game server.
+/**
+ * Manages connections to game client.
*/
class GameHandler: public ConnectionHandler
{
public:
+ /**
+ * Processes messages and cleans outdated characters.
+ */
void process();
/**
- * Start the handler
+ * Starts the handler
*/
- bool
- startListen(enet_uint16 port);
+ bool startListen(enet_uint16 port);
/**
- * Send message to the given player.
+ * Sends message to the given player.
*/
void sendTo(Player *, MessageOut &msg);
+ /**
+ * Kills connection with given player.
+ */
+ void kill(Player *);
+
+ /**
+ * Prepares a server change for given player.
+ */
+ void prepareServerChange(Player *);
+
+ /**
+ * Completes a server change for given player ID.
+ */
+ void completeServerChange(int id, std::string const &token,
+ std::string const &address, int port);
+
protected:
NetComputer *computerConnected(ENetPeer *);
void computerDisconnected(NetComputer *);
/**
- * Process messages related to core game events.
+ * Processes messages related to core game events.
*/
void processMessage(NetComputer *computer, MessageIn &message);
-
- private:
- void removeOutdatedPending();
};
extern GameHandler *gameHandler;
diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp
index 5fade89..f7c12d9 100644
--- a/src/game-server/state.cpp
+++ b/src/game-server/state.cpp
@@ -27,6 +27,7 @@
#include "defines.h"
#include "map.h"
#include "point.h"
+#include "game-server/accountconnection.hpp"
#include "game-server/gamehandler.hpp"
#include "game-server/mapcomposite.hpp"
#include "game-server/mapmanager.hpp"
@@ -44,14 +45,14 @@ State::State()
being->setMapId(1);
Point pos = { 720, 900 };
being->setPosition(pos);
- addObject(being);
+ DelayedEvent e = { EVENT_INSERT };
+ enqueueEvent(being, e);
}
}
State::~State()
{
- for (std::map< unsigned, MapComposite * >::iterator i = maps.begin(),
- i_end = maps.end(); i != i_end; ++i)
+ for (Maps::iterator i = maps.begin(), i_end = maps.end(); i != i_end; ++i)
{
delete i->second;
}
@@ -81,6 +82,32 @@ void State::updateMap(MapComposite *map)
(*i)->move();
}
map->update();
+
+ // 4. Just for fun. Should be replaced by a real trigger system.
+ for (MovingObjectIterator i(map->getWholeMapIterator()); i; ++i)
+ {
+ Object *o = *i;
+ if (o->getType() != OBJECT_PLAYER) continue;
+ Point pos = o->getPosition();
+ int x = pos.x / 32, y = pos.y / 32;
+ int m = 0;
+ switch (o->getMapId())
+ {
+ case 1:
+ if (x >= 56 && x <= 60 && y == 12)
+ { m = 3; x = 44; y = 80; }
+ break;
+ case 3:
+ if (x >= 42 && x <= 46 && y == 88)
+ { m = 1; x = 58; y = 17; }
+ break;
+ }
+ if (m != 0)
+ {
+ DelayedEvent e = { EVENT_WARP, m, x * 32 + 16, y * 32 + 16 };
+ enqueueEvent(o, e);
+ }
+ }
}
void State::informPlayer(MapComposite *map, Player *p)
@@ -214,19 +241,12 @@ void State::informPlayer(MapComposite *map, Player *p)
void State::update()
{
- /*
- * Update game state (update AI, etc.)
- */
- for (std::map< unsigned, MapComposite * >::iterator m = maps.begin(),
- m_end = maps.end(); m != m_end; ++m)
+ // Update game state (update AI, etc.)
+ for (Maps::iterator m = maps.begin(), m_end = maps.end(); m != m_end; ++m)
{
MapComposite *map = m->second;
-
updateMap(map);
- /*
- * Inform clients about changes in the game state
- */
for (PlayerIterator p(map->getWholeMapIterator()); p; ++p)
{
informPlayer(map, *p);
@@ -242,42 +262,60 @@ void State::update()
static_cast< Being * >(o)->clearHitsTaken();
}
}
+ }
- // Just for fun. Should be replaced by a real trigger system.
- for (size_t i = map->getObjects().size(); i-- > 0;)
+ // Take care of events that were delayed because of their side effects.
+ for (DelayedEvents::iterator i = delayedEvents.begin(),
+ i_end = delayedEvents.end(); i != i_end; ++i)
+ {
+ DelayedEvent const &e = i->second;
+ Object *o = i->first;
+ switch (e.type)
{
- Object *o = map->getObjects()[i];
- if (o->getType() != OBJECT_PLAYER) continue;
- Point pos = o->getPosition();
- int x = pos.x / 32, y = pos.y / 32;
- int m = 0;
- switch (o->getMapId())
+ case EVENT_REMOVE:
{
- case 1:
- if (x >= 56 && x <= 60 && y == 12)
- { m = 3; x = 44; y = 80; }
- break;
- case 3:
- if (x >= 42 && x <= 46 && y == 88)
- { m = 1; x = 58; y = 17; }
- break;
- }
- if (m != 0)
+ removeObject(o);
+ if (o->getType() == OBJECT_PLAYER)
+ {
+ gameHandler->kill(static_cast< Player * >(o));
+ }
+ delete o;
+ } break;
+
+ case EVENT_INSERT:
+ {
+ insertObject(o);
+ } break;
+
+ case EVENT_WARP:
{
removeObject(o);
- o->setMapId(m);
- pos.x = x * 32; pos.y = y * 32;
+ o->setMapId(e.map);
+ Point pos = { e.x, e.y };
o->setPosition(pos);
- addObject(o);
- }
+ if (mapManager->isActive(e.map))
+ {
+ insertObject(o);
+ }
+ else
+ {
+ assert(o->getType() == OBJECT_PLAYER);
+ Player *p = static_cast< Player * >(o);
+ accountHandler->sendPlayerData(p);
+ MessageOut msg(GAMSG_REDIRECT);
+ msg.writeLong(p->getDatabaseID());
+ accountHandler->send(msg);
+ gameHandler->prepareServerChange(p);
+ }
+ } break;
}
}
+ delayedEvents.clear();
}
-void
-State::addObject(Object *objectPtr)
+void State::insertObject(Object *objectPtr)
{
- unsigned mapId = objectPtr->getMapId();
+ int mapId = objectPtr->getMapId();
MapComposite *map = loadMap(mapId);
if (!map || !map->insert(objectPtr))
{
@@ -300,11 +338,10 @@ State::addObject(Object *objectPtr)
gameHandler->sendTo(playerPtr, mapChangeMessage);
}
-void
-State::removeObject(Object *objectPtr)
+void State::removeObject(Object *objectPtr)
{
- unsigned mapId = objectPtr->getMapId();
- std::map< unsigned, MapComposite * >::iterator m = maps.find(mapId);
+ int mapId = objectPtr->getMapId();
+ Maps::iterator m = maps.find(mapId);
if (m == maps.end()) return;
MapComposite *map = m->second;
@@ -328,9 +365,20 @@ State::removeObject(Object *objectPtr)
map->remove(objectPtr);
}
-MapComposite *State::loadMap(unsigned mapId)
+void State::enqueueEvent(Object *ptr, DelayedEvent const &e)
+{
+ std::pair< DelayedEvents::iterator, bool > p =
+ delayedEvents.insert(std::make_pair(ptr, e));
+ // Delete events take precedence over other events.
+ if (!p.second && e.type == EVENT_REMOVE)
+ {
+ p.first->second.type = EVENT_REMOVE;
+ }
+}
+
+MapComposite *State::loadMap(int mapId)
{
- std::map< unsigned, MapComposite * >::iterator m = maps.find(mapId);
+ Maps::iterator m = maps.find(mapId);
if (m != maps.end()) return m->second;
Map *map = mapManager->getMap(mapId);
assert(map);
@@ -354,7 +402,7 @@ void State::sayAround(Object *obj, std::string text)
msg.writeShort(id);
msg.writeString(text);
- std::map< unsigned, MapComposite * >::iterator m = maps.find(obj->getMapId());
+ Maps::iterator m = maps.find(obj->getMapId());
if (m == maps.end()) return;
MapComposite *map = m->second;
Point speakerPosition = obj->getPosition();
diff --git a/src/game-server/state.hpp b/src/game-server/state.hpp
index 95ba73b..d759da8 100644
--- a/src/game-server/state.hpp
+++ b/src/game-server/state.hpp
@@ -27,9 +27,20 @@
#include <map>
#include <string>
-#include "object.h"
-
class MapComposite;
+class Object;
+
+enum
+{
+ EVENT_REMOVE = 0,
+ EVENT_INSERT,
+ EVENT_WARP
+};
+
+struct DelayedEvent
+{
+ unsigned short type, map, x, y;
+};
/**
* State class contains all information/procedures associated with the game
@@ -37,10 +48,18 @@ class MapComposite;
*/
class State
{
+ typedef std::map< int, MapComposite * > Maps;
+ typedef std::map< Object *, DelayedEvent > DelayedEvents;
+
/**
* List of maps.
*/
- std::map<unsigned int, MapComposite *> maps;
+ Maps maps;
+
+ /**
+ * List of delayed events.
+ */
+ DelayedEvents delayedEvents;
/**
* Updates object states on the map.
@@ -64,12 +83,12 @@ class State
/**
* Loads map into game world.
*/
- MapComposite *loadMap(unsigned mapId);
+ MapComposite *loadMap(int mapId);
/**
- * Adds object to the map.
+ * Inserts an object on the map.
*/
- void addObject(Object *);
+ void insertObject(Object *);
/**
* Removes an object from the map.
@@ -77,6 +96,11 @@ class State
void removeObject(Object *);
/**
+ * Enqueues an event. It will be executed at end of update.
+ */
+ void enqueueEvent(Object *, DelayedEvent const &);
+
+ /**
* Says something around an object.
*/
void sayAround(Object *, std::string text);