void GameHandler::processMessage(NetComputer *computer, MessageIn &message) { GameClient &client = *static_cast<GameClient *>(computer); if (client.status == CLIENT_LOGIN) { if (message.getId() != PGMSG_CONNECT) return; std::string magic_token = message.readString(MAGIC_TOKEN_LENGTH); client.status = CLIENT_QUEUED; // Before the addPendingClient mTokenCollector.addPendingClient(magic_token, &client); return; } else if (client.status != CLIENT_CONNECTED) { return; } switch (message.getId()) { case PGMSG_SAY: handleSay(client, message); break; case PGMSG_NPC_TALK: case PGMSG_NPC_TALK_NEXT: case PGMSG_NPC_SELECT: case PGMSG_NPC_NUMBER: case PGMSG_NPC_STRING: handleNpc(client, message); break; case PGMSG_PICKUP: handlePickup(client, message); break; case PGMSG_USE_ITEM: handleUseItem(client, message); break; case PGMSG_DROP: handleDrop(client, message); break; case PGMSG_WALK: handleWalk(client, message); break; case PGMSG_EQUIP: handleEquip(client, message); break; case PGMSG_UNEQUIP: handleUnequip(client, message); break; case PGMSG_MOVE_ITEM: handleMoveItem(client, message); break; case PGMSG_ATTACK: handleAttack(client, message); break; case PGMSG_USE_SPECIAL_ON_BEING: handleUseSpecialOnBeing(client, message); break; case PGMSG_USE_SPECIAL_ON_POINT: handleUseSpecialOnPoint(client, message); break; case PGMSG_ACTION_CHANGE: handleActionChange(client, message); break; case PGMSG_DIRECTION_CHANGE: handleDirectionChange(client, message); break; case PGMSG_DISCONNECT: handleDisconnect(client, message); break; case PGMSG_TRADE_REQUEST: handleTradeRequest(client, message); break; case PGMSG_TRADE_CANCEL: case PGMSG_TRADE_AGREED: case PGMSG_TRADE_CONFIRM: case PGMSG_TRADE_ADD_ITEM: case PGMSG_TRADE_SET_MONEY: handleTrade(client, message); break; case PGMSG_NPC_BUYSELL: handleNpcBuySell(client, message); break; case PGMSG_RAISE_ATTRIBUTE: handleRaiseAttribute(client, message); break; case PGMSG_LOWER_ATTRIBUTE: handleLowerAttribute(client, message); break; case PGMSG_RESPAWN: // plausibility check is done by character class client.character->respawn(); break; case PGMSG_NPC_POST_SEND: handleNpcPostSend(client, message); break; case PGMSG_PARTY_INVITE: handlePartyInvite(client, message); break; case PGMSG_BEING_EMOTE: handleTriggerEmoticon(client, message); break; default: LOG_WARN("Invalid message type"); client.send(MessageOut(XXMSG_INVALID)); break; } }
void GameHandler::processMessage(NetComputer *comp, MessageIn &message) { GameClient &computer = *static_cast< GameClient * >(comp); MessageOut result; if (computer.status == CLIENT_LOGIN) { if (message.getId() != PGMSG_CONNECT) return; std::string magic_token = message.readString(MAGIC_TOKEN_LENGTH); computer.status = CLIENT_QUEUED; // Before the addPendingClient mTokenCollector.addPendingClient(magic_token, &computer); return; } else if (computer.status != CLIENT_CONNECTED) { return; } switch (message.getId()) { case PGMSG_SAY: { std::string say = message.readString(); if (say.empty()) break; if (say[0] == '@') { CommandHandler::handleCommand(computer.character, say); break; } GameState::sayAround(computer.character, say); std::string msg = computer.character->getName() + " said " + say; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_MSG_PUBLIC, msg); } break; case PGMSG_NPC_TALK: case PGMSG_NPC_TALK_NEXT: case PGMSG_NPC_SELECT: case PGMSG_NPC_NUMBER: case PGMSG_NPC_STRING: { int id = message.readShort(); Actor *o = findActorNear(computer.character, id); if (!o || o->getType() != OBJECT_NPC) { sendError(comp, id, "Not close enough to NPC\n"); break; } NPC *q = static_cast< NPC * >(o); if (message.getId() == PGMSG_NPC_SELECT) { q->select(computer.character, message.readByte()); } else if (message.getId() == PGMSG_NPC_NUMBER) { q->integerReceived(computer.character, message.readLong()); } else if (message.getId() == PGMSG_NPC_STRING) { q->stringReceived(computer.character, message.readString()); } else { q->prompt(computer.character, message.getId() == PGMSG_NPC_TALK); } } break; case PGMSG_PICKUP: { int x = message.readShort(); int y = message.readShort(); Point ppos = computer.character->getPosition(); // TODO: use a less arbitrary value. if (std::abs(x - ppos.x) + std::abs(y - ppos.y) < 48) { MapComposite *map = computer.character->getMap(); Point ipos(x, y); for (FixedActorIterator i(map->getAroundPointIterator(ipos, 0)); i; ++i) { Actor *o = *i; Point opos = o->getPosition(); if (o->getType() == OBJECT_ITEM && opos.x == x && opos.y == y) { Item *item = static_cast< Item * >(o); ItemClass *ic = item->getItemClass(); Inventory(computer.character) .insert(ic->getDatabaseID(), item->getAmount()); GameState::remove(item); // log transaction std::stringstream str; str << "User picked up item " << ic->getDatabaseID() << " at " << opos.x << "x" << opos.y; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ITEM_PICKUP, str.str()); break; } } } } break; case PGMSG_USE_ITEM: { int slot = message.readByte(); Inventory inv(computer.character); if (ItemClass *ic = ItemManager::getItem(inv.getItem(slot))) { if (ic->use(computer.character)) { inv.removeFromSlot(slot, 1); // log transaction std::stringstream str; str << "User used item " << ic->getDatabaseID() << " from slot " << slot; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ITEM_USED, str.str()); } } } break; case PGMSG_DROP: { int slot = message.readByte(); int amount = message.readByte(); Inventory inv(computer.character); if (ItemClass *ic = ItemManager::getItem(inv.getItem(slot))) { int nb = inv.removeFromSlot(slot, amount); Item *item = new Item(ic, amount - nb); item->setMap(computer.character->getMap()); item->setPosition(computer.character->getPosition()); if (!GameState::insert(item)) { // The map is full. Put back into inventory. inv.insert(ic->getDatabaseID(), amount - nb); delete item; break; } // log transaction Point pt = computer.character->getPosition(); std::stringstream str; str << "User dropped item " << ic->getDatabaseID() << " at " << pt.x << "x" << pt.y; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ITEM_DROP, str.str()); } } break; case PGMSG_WALK: { handleWalk(&computer, message); } break; case PGMSG_EQUIP: { int slot = message.readByte(); Inventory(computer.character).equip(slot); } break; case PGMSG_UNEQUIP: { int slot = message.readByte(); if (slot >= 0 && slot < EQUIP_PROJECTILE_SLOT) { Inventory(computer.character).unequip(slot); } } break; case PGMSG_MOVE_ITEM: { int slot1 = message.readByte(); int slot2 = message.readByte(); int amount = message.readByte(); Inventory(computer.character).move(slot1, slot2, amount); // log transaction std::stringstream str; str << "User moved item " << " from slot " << slot1 << " to slot " << slot2; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ITEM_MOVE, str.str()); } break; case PGMSG_ATTACK: { int id = message.readShort(); LOG_DEBUG("Character " << computer.character->getPublicID() << " attacked being " << id); Actor *o = findActorNear(computer.character, id); if (o && o->getType() != OBJECT_NPC) { Being *being = static_cast<Being*>(o); computer.character->setTarget(being); computer.character->setAction(Being::ATTACK); } } break; case PGMSG_USE_SPECIAL: { int specialID = message.readByte(); LOG_DEBUG("Character " << computer.character->getPublicID() << " tries to use his special attack "<<specialID); computer.character->useSpecial(specialID); } case PGMSG_ACTION_CHANGE: { Being::Action action = (Being::Action)message.readByte(); Being::Action current = (Being::Action)computer.character->getAction(); bool logActionChange = true; switch (action) { case Being::STAND: { if (current == Being::SIT) { computer.character->setAction(Being::STAND); logActionChange = false; } } break; case Being::SIT: { if (current == Being::STAND) { computer.character->setAction(Being::SIT); logActionChange = false; } } break; default: break; } // Log the action change only when this is relevant. if (logActionChange) { // log transaction std::stringstream str; str << "User changed action from " << current << " to " << action; accountHandler->sendTransaction( computer.character->getDatabaseID(), TRANS_ACTION_CHANGE, str.str()); } } break; case PGMSG_DIRECTION_CHANGE: { computer.character->setDirection(message.readByte()); } break; case PGMSG_DISCONNECT: { bool reconnectAccount = (bool) message.readByte(); result.writeShort(GPMSG_DISCONNECT_RESPONSE); result.writeByte(ERRMSG_OK); // It is, when control reaches here if (reconnectAccount) { std::string magic_token(utils::getMagicToken()); result.writeString(magic_token, MAGIC_TOKEN_LENGTH); // No accountserver data, the client should remember that accountHandler->playerReconnectAccount( computer.character->getDatabaseID(), magic_token); } // TODO: implement a delayed remove GameState::remove(computer.character); accountHandler->sendCharacterData(computer.character); // Done with the character computer.character->disconnected(); delete computer.character; computer.character = NULL; computer.status = CLIENT_LOGIN; } break; case PGMSG_TRADE_REQUEST: { int id = message.readShort(); if (Trade *t = computer.character->getTrading()) { if (t->request(computer.character, id)) break; } Character *q = findCharacterNear(computer.character, id); if (!q || q->isBusy()) { result.writeShort(GPMSG_TRADE_CANCEL); break; } new Trade(computer.character, q); // log transaction std::string str; str = "User requested trade with " + q->getName(); accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_TRADE_REQUEST, str); } break; case PGMSG_TRADE_CANCEL: case PGMSG_TRADE_AGREED: case PGMSG_TRADE_CONFIRM: case PGMSG_TRADE_ADD_ITEM: case PGMSG_TRADE_SET_MONEY: { std::stringstream str; Trade *t = computer.character->getTrading(); if (!t) break; switch (message.getId()) { case PGMSG_TRADE_CANCEL: t->cancel(); break; case PGMSG_TRADE_CONFIRM: t->confirm(computer.character); break; case PGMSG_TRADE_AGREED: t->agree(computer.character); // log transaction accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_TRADE_END, "User finished trading"); break; case PGMSG_TRADE_SET_MONEY: { int money = message.readLong(); t->setMoney(computer.character, money); // log transaction str << "User added " << money << " money to trade."; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_TRADE_MONEY, str.str()); } break; case PGMSG_TRADE_ADD_ITEM: { int slot = message.readByte(); t->addItem(computer.character, slot, message.readByte()); // log transaction str << "User add item from slot " << slot; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_TRADE_ITEM, str.str()); } break; } } break; case PGMSG_NPC_BUYSELL: { BuySell *t = computer.character->getBuySell(); if (!t) break; int id = message.readShort(); int amount = message.readShort(); t->perform(id, amount); } break; case PGMSG_RAISE_ATTRIBUTE: { int attribute = message.readByte(); AttribmodResponseCode retCode; retCode = computer.character->useCharacterPoint(attribute); result.writeShort(GPMSG_RAISE_ATTRIBUTE_RESPONSE); result.writeByte(retCode); result.writeByte(attribute); if (retCode == ATTRIBMOD_OK ) { accountHandler->updateCharacterPoints( computer.character->getDatabaseID(), computer.character->getCharacterPoints(), computer.character->getCorrectionPoints(), attribute, computer.character->getAttribute(attribute)); // log transaction std::stringstream str; str << "User increased attribute " << attribute; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ATTR_INCREASE, str.str()); } } break; case PGMSG_LOWER_ATTRIBUTE: { int attribute = message.readByte(); AttribmodResponseCode retCode; retCode = computer.character->useCorrectionPoint(attribute); result.writeShort(GPMSG_LOWER_ATTRIBUTE_RESPONSE); result.writeByte(retCode); result.writeByte(attribute); if (retCode == ATTRIBMOD_OK ) { accountHandler->updateCharacterPoints( computer.character->getDatabaseID(), computer.character->getCharacterPoints(), computer.character->getCorrectionPoints(), attribute, computer.character->getAttribute(attribute)); // log transaction std::stringstream str; str << "User decreased attribute " << attribute; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ATTR_DECREASE, str.str()); } } break; case PGMSG_RESPAWN: { computer.character->respawn(); // plausibility check is done by character class } break; case PGMSG_NPC_POST_SEND: { handleSendPost(&computer, message); } break; default: LOG_WARN("Invalid message type"); result.writeShort(XXMSG_INVALID); break; } if (result.getLength() > 0) computer.send(result); }