Exemple #1
0
void ChatHandler::handleCommand(ChatClient &computer, const std::string &command)
{
    LOG_INFO("Chat: Received unhandled command: " << command);
    MessageOut result;
    result.writeShort(CPMSG_ERROR);
    result.writeByte(CHAT_UNHANDLED_COMMAND);
    computer.send(result);
}
Exemple #2
0
/**
 * Sets message fields describing character look.
 */
static void serializeLooks(Character *ch, MessageOut &msg, bool full)
{
    const Possessions &poss = ch->getPossessions();
    static int const nb_slots = 4;
    static int const slots[nb_slots] =
    {
        EQUIP_FIGHT1_SLOT,
        EQUIP_HEAD_SLOT,
        EQUIP_TORSO_SLOT,
        EQUIP_LEGS_SLOT
    };

    // Bitmask describing the changed entries.
    int changed = (1 << nb_slots) - 1;
    if (!full)
    {
        // TODO: do not assume the whole equipment changed, when an update is asked for.
        changed = (1 << nb_slots) - 1;
    }

    int items[nb_slots];
    // Partially build both kinds of packet, to get their sizes.
    int mask_full = 0, mask_diff = 0;
    int nb_full = 0, nb_diff = 0;
    for (int i = 0; i < nb_slots; ++i)
    {
        int id = poss.equipment[slots[i]];
        ItemClass *eq;
        items[i] = id && (eq = ItemManager::getItem(id)) ? eq->getSpriteID() : 0;
        if (changed & (1 << i))
        {
            // Skip slots that have not changed, when sending an update.
            ++nb_diff;
            mask_diff |= 1 << i;
        }
        if (items[i])
        {
            /* If we are sending the whole equipment, only filled slots have to
               be accounted for, as the other ones will be automatically cleared. */
            ++nb_full;
            mask_full |= 1 << i;
        }
    }

    // Choose the smaller payload.
    if (nb_full <= nb_diff) full = true;

    /* Bitmask enumerating the sent slots.
       Setting the upper bit tells the client to clear the slots beforehand. */
    int mask = full ? mask_full | (1 << 7) : mask_diff;

    msg.writeByte(mask);
    for (int i = 0; i < nb_slots; ++i)
    {
        if (mask & (1 << i)) msg.writeShort(items[i]);
    }
}
Exemple #3
0
void ChatHandler::warnPlayerAboutBadWords(ChatClient &computer)
{
    // We could later count if the player is really often unpolite.
    MessageOut result;
    result.writeShort(CPMSG_ERROR);
    result.writeByte(CHAT_USING_BAD_WORDS); // The Channel
    computer.send(result);

    LOG_INFO(computer.characterName << " says bad words.");
}
Exemple #4
0
void Server::generalChatMsg(Uint32 sender, std::string msg){
    if (chat_mode && sender != 0) // The sender 0 (zero) is the server itself!
        std::cout << msg << std::endl;

    std::map<Uint32, Client*>::iterator p;
    for (p = mClients.begin(); p != mClients.end(); p++){
        if(p->first != sender){ // don't sentd the message to the original sender.
            MessageOut* messageout = new MessageOut(MSG_CHAT);
            messageout->writeString(msg);
            messageout->addCRC();
            Connection::putMessage(p->second->getSocket(), messageout);
            delete messageout;
        }
    }
}
Exemple #5
0
/**
 * Sets message fields describing character look.
 */
static void serializeLooks(Character *ch, MessageOut &msg)
{
    const EquipData &equipData = ch->getPossessions().getEquipment();

    // We'll use a set to check whether we already sent the update for the given
    // item instance.
    std::set<unsigned> itemInstances;

    // The map storing the info about the look changes to send
    //{ slot type id, item id }
    std::map <unsigned, unsigned> lookChanges;

    // Note that we can send several updates on the same slot type as different
    // items may have been equipped.
    for (EquipData::const_iterator it = equipData.begin(),
         it_end = equipData.end(); it != it_end; ++it)
    {
        if (!itemManager->isEquipSlotVisible(it->first))
            continue;

        if (!it->second.itemInstance
            || itemInstances.insert(it->second.itemInstance).second)
        {
            // When the insertion succeeds, its the first time
            // we encounter the item, so we can send the look change.
            // We also send empty slots for unequipment handling.
            lookChanges.insert(
                std::make_pair<unsigned, unsigned>(it->first,
                                                   it->second.itemId));
        }
    }

    if (lookChanges.size() > 0)
    {
        // Number of look changes to send
        msg.writeInt8(lookChanges.size());

        for (std::map<unsigned, unsigned>::const_iterator it2 =
             lookChanges.begin(), it2_end = lookChanges.end();
             it2 != it2_end; ++it2)
        {
            msg.writeInt8(it2->first);
            msg.writeInt16(it2->second);
        }
    }
}
Exemple #6
0
/**
 * Sets message fields describing character look.
 */
static void serializeLooks(Entity *ch, MessageOut &msg)
{
    auto *characterComponent = ch->getComponent<CharacterComponent>();
    msg.writeInt8(characterComponent->getHairStyle());
    msg.writeInt8(characterComponent->getHairColor());
    const EquipData &equipData =
            characterComponent->getPossessions().getEquipment();
    const InventoryData &inventoryData =
            characterComponent->getPossessions().getInventory();

    // The map storing the info about the look changes to send
    //{ slot type id, item id }
    std::map<unsigned, unsigned> lookChanges;

    // Note that we can send several updates on the same slot type as different
    // items may have been equipped.
    for (EquipData::const_iterator it = equipData.begin(),
         it_end = equipData.end(); it != it_end; ++it)
    {
        InventoryData::const_iterator itemIt = inventoryData.find(*it);

        if (!itemManager->isEquipSlotVisible(itemIt->second.equipmentSlot))
            continue;

        lookChanges.insert(std::make_pair(
                itemIt->second.equipmentSlot,
                itemIt->second.itemId));
    }

    if (!lookChanges.empty())
    {
        // Number of look changes to send
        msg.writeInt8(lookChanges.size());

        for (std::map<unsigned, unsigned>::const_iterator it =
             lookChanges.begin(), it_end = lookChanges.end();
             it != it_end; ++it)
        {
            msg.writeInt8(it->first);
            msg.writeInt16(it->second);
        }
    }
}
Exemple #7
0
void ChatHandler::sayToPlayer(ChatClient &computer,
                              const std::string &playerName,
                              const std::string &text)
{
    MessageOut result;
    LOG_DEBUG(computer.characterName << " says to " << playerName << ": "
              << text);
    // Send it to the being if the being exists
    result.writeShort(CPMSG_PRIVMSG);
    result.writeString(computer.characterName);
    result.writeString(text);
    for (NetComputers::iterator i = clients.begin(), i_end = clients.end();
         i != i_end; ++i) {
        if (static_cast< ChatClient * >(*i)->characterName == playerName)
        {
            (*i)->send(result);
            break;
        }
    }
}
Exemple #8
0
void CharacterComponent::serialize(Entity &entity, MessageOut &msg)
{
    auto *beingComponent = entity.getComponent<BeingComponent>();

    // general character properties
    msg.writeInt8(getAccountLevel());
    msg.writeInt8(beingComponent->getGender());
    msg.writeInt8(getHairStyle());
    msg.writeInt8(getHairColor());
    msg.writeInt16(getAttributePoints());
    msg.writeInt16(getCorrectionPoints());


    const AttributeMap &attributes = beingComponent->getAttributes();
    std::map<const AttributeInfo *, const Attribute *> attributesToSend;
    for (auto &attributeIt : attributes)
    {
        if (attributeIt.first->persistent)
            attributesToSend.insert(std::make_pair(attributeIt.first,
                                                   &attributeIt.second));
    }
    msg.writeInt16(attributesToSend.size());
    for (auto &attributeIt : attributesToSend)
    {
        msg.writeInt16(attributeIt.first->id);
        msg.writeDouble(attributeIt.second->getBase());
        msg.writeDouble(attributeIt.second->getModifiedAttribute());
    }

    // status effects currently affecting the character
    auto &statusEffects = beingComponent->getStatusEffects();
    msg.writeInt16(statusEffects.size());
    for (auto &statusIt : statusEffects)
    {
        msg.writeInt16(statusIt.first);
        msg.writeInt16(statusIt.second.time);
    }

    // location
    msg.writeInt16(entity.getMap()->getID());
    const Point &pos = entity.getComponent<ActorComponent>()->getPosition();
    msg.writeInt16(pos.x);
    msg.writeInt16(pos.y);

    // kill count
    msg.writeInt16(getKillCountSize());
    for (auto &killCountIt : mKillCount)
    {
        msg.writeInt16(killCountIt.first);
        msg.writeInt32(killCountIt.second);
    }

    // character abilities
    auto &abilities = entity.getComponent<AbilityComponent>()->getAbilities();
    msg.writeInt16(abilities.size());
    for (auto &abilityIt : abilities) {
        msg.writeInt32(abilityIt.first);
    }

    // questlog
    msg.writeInt16(mQuestlog.size());
    for (auto questlogIt : mQuestlog) {
        QuestInfo &quest = questlogIt.second;
        msg.writeInt16(quest.id);
        msg.writeInt8(quest.state);
        msg.writeString(quest.title);
        msg.writeString(quest.description);
    }

    // inventory - must be last because size isn't transmitted
    const Possessions &poss = getPossessions();

    const InventoryData &inventoryData = poss.getInventory();
    for (InventoryData::const_iterator itemIt = inventoryData.begin(),
         itemIt_end = inventoryData.end(); itemIt != itemIt_end; ++itemIt)
    {
        msg.writeInt16(itemIt->first);           // slot id
        msg.writeInt16(itemIt->second.itemId);
        msg.writeInt16(itemIt->second.amount);
        msg.writeInt8(itemIt->second.equipmentSlot);
    }
}
Exemple #9
0
void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
{
    MessageOut result;
    GameServer *server = static_cast<GameServer *>(comp);

    switch (msg.getId())
    {
        case GAMSG_REGISTER:
        {
            LOG_DEBUG("GAMSG_REGISTER");
            // TODO: check the credentials of the game server
            server->address = msg.readString();
            server->port = msg.readInt16();
            const std::string password = msg.readString();

            // checks the version of the remote item database with our local copy
            unsigned int dbversion = msg.readInt32();
            LOG_INFO("Game server uses itemsdatabase with version " << dbversion);

            LOG_DEBUG("AGMSG_REGISTER_RESPONSE");
            MessageOut outMsg(AGMSG_REGISTER_RESPONSE);
            if (dbversion == storage->getItemDatabaseVersion())
            {
                LOG_DEBUG("Item databases between account server and "
                    "gameserver are in sync");
                outMsg.writeInt16(DATA_VERSION_OK);
            }
            else
            {
                LOG_DEBUG("Item database of game server has a wrong version");
                outMsg.writeInt16(DATA_VERSION_OUTDATED);
            }
            if (password == Configuration::getValue("net_password", "changeMe"))
            {
                outMsg.writeInt16(PASSWORD_OK);
                comp->send(outMsg);

                // transmit global world state variables
                std::map<std::string, std::string> variables;
                variables = storage->getAllWorldStateVars(0);
                for (std::map<std::string, std::string>::iterator i = variables.begin();
                     i != variables.end();
                     i++)
                {
                    outMsg.writeString(i->first);
                    outMsg.writeString(i->second);
                }
            }
            else
            {
                LOG_INFO("The password given by " << server->address << ':' << server->port << " was bad.");
                outMsg.writeInt16(PASSWORD_BAD);
                comp->disconnect(outMsg);
                break;
            }

            LOG_INFO("Game server " << server->address << ':' << server->port
                     << " wants to register " << (msg.getUnreadLength() / 2)
                     << " maps.");

            while (msg.getUnreadLength())
            {
                int id = msg.readInt16();
                LOG_INFO("Registering map " << id << '.');
                if (GameServer *s = getGameServerFromMap(id))
                {
                    LOG_ERROR("Server Handler: map is already registered by "
                              << s->address << ':' << s->port << '.');
                }
                else
                {
                    MessageOut outMsg(AGMSG_ACTIVE_MAP);
                    outMsg.writeInt16(id);
                    std::map<std::string, std::string> variables;
                    variables = storage->getAllWorldStateVars(id);
                    for (std::map<std::string, std::string>::iterator i = variables.begin();
                         i != variables.end();
                         i++)
                    {
                        outMsg.writeString(i->first);
                        outMsg.writeString(i->second);
                    }
                    comp->send(outMsg);
                    MapStatistics &m = server->maps[id];
                    m.nbThings = 0;
                    m.nbMonsters = 0;
                }
            }
        } break;

        case GAMSG_PLAYER_DATA:
        {
            LOG_DEBUG("GAMSG_PLAYER_DATA");
            int id = msg.readInt32();
            if (Character *ptr = storage->getCharacter(id, NULL))
            {
                deserializeCharacterData(*ptr, msg);
                if (!storage->updateCharacter(ptr))
                {
                    LOG_ERROR("Failed to update character "
                              << id << '.');
                }
                delete ptr;
            }
            else
            {
                LOG_ERROR("Received data for non-existing character "
                          << id << '.');
            }
        } break;

        case GAMSG_PLAYER_SYNC:
        {
            LOG_DEBUG("GAMSG_PLAYER_SYNC");
            GameServerHandler::syncDatabase(msg);
        } break;

        case GAMSG_REDIRECT:
        {
            LOG_DEBUG("GAMSG_REDIRECT");
            int id = msg.readInt32();
            std::string magic_token(utils::getMagicToken());
            if (Character *ptr = storage->getCharacter(id, NULL))
            {
                int mapId = ptr->getMapId();
                if (GameServer *s = getGameServerFromMap(mapId))
                {
                    registerGameClient(s, magic_token, ptr);
                    result.writeInt16(AGMSG_REDIRECT_RESPONSE);
                    result.writeInt32(id);
                    result.writeString(magic_token, MAGIC_TOKEN_LENGTH);
                    result.writeString(s->address);
                    result.writeInt16(s->port);
                }
                else
                {
                    LOG_ERROR("Server Change: No game server for map " <<
                              mapId << '.');
                }
                delete ptr;
            }
            else
            {
                LOG_ERROR("Received data for non-existing character "
                          << id << '.');
            }
        } break;

        case GAMSG_PLAYER_RECONNECT:
        {
            LOG_DEBUG("GAMSG_PLAYER_RECONNECT");
            int id = msg.readInt32();
            std::string magic_token = msg.readString(MAGIC_TOKEN_LENGTH);

            if (Character *ptr = storage->getCharacter(id, NULL))
            {
                int accountID = ptr->getAccountID();
                AccountClientHandler::prepareReconnect(magic_token, accountID);
                delete ptr;
            }
            else
            {
                LOG_ERROR("Received data for non-existing character "
                          << id << '.');
            }
        } break;

        case GAMSG_GET_VAR_CHR:
        {
            int id = msg.readInt32();
            std::string name = msg.readString();
            std::string value = storage->getQuestVar(id, name);
            result.writeInt16(AGMSG_GET_VAR_CHR_RESPONSE);
            result.writeInt32(id);
            result.writeString(name);
            result.writeString(value);
        } break;

        case GAMSG_SET_VAR_CHR:
        {
            int id = msg.readInt32();
            std::string name = msg.readString();
            std::string value = msg.readString();
            storage->setQuestVar(id, name, value);
        } break;

        case GAMSG_SET_VAR_WORLD:
        {
            std::string name = msg.readString();
            std::string value = msg.readString();
            // save the new value to the database
            storage->setWorldStateVar(name, value);
            // relay the new value to all gameservers
            for (ServerHandler::NetComputers::iterator i = clients.begin();
                i != clients.end();
                i++)
            {
                MessageOut varUpdateMessage(AGMSG_SET_VAR_WORLD);
                varUpdateMessage.writeString(name);
                varUpdateMessage.writeString(value);
                (*i)->send(varUpdateMessage);
            }
        } break;

        case GAMSG_SET_VAR_MAP:
        {
            int mapid = msg.readInt32();
            std::string name = msg.readString();
            std::string value = msg.readString();
            storage->setWorldStateVar(name, mapid, value);
        } break;

        case GAMSG_BAN_PLAYER:
        {
            int id = msg.readInt32();
            int duration = msg.readInt32();
            storage->banCharacter(id, duration);
        } break;

        case GAMSG_CHANGE_PLAYER_LEVEL:
        {
            int id = msg.readInt32();
            int level = msg.readInt16();
            storage->setPlayerLevel(id, level);
        } break;

        case GAMSG_CHANGE_ACCOUNT_LEVEL:
        {
            int id = msg.readInt32();
            int level = msg.readInt16();

            // get the character so we can get the account id
            Character *c = storage->getCharacter(id, NULL);
            if (c)
            {
                storage->setAccountLevel(c->getAccountID(), level);
            }
        } break;

        case GAMSG_STATISTICS:
        {
            while (msg.getUnreadLength())
            {
                int mapId = msg.readInt16();
                ServerStatistics::iterator i = server->maps.find(mapId);
                if (i == server->maps.end())
                {
                    LOG_ERROR("Server " << server->address << ':'
                              << server->port << " should not be sending stati"
                              "stics for map " << mapId << '.');
                    // Skip remaining data.
                    break;
                }
                MapStatistics &m = i->second;
                m.nbThings = msg.readInt16();
                m.nbMonsters = msg.readInt16();
                int nb = msg.readInt16();
                m.players.resize(nb);
                for (int j = 0; j < nb; ++j)
                {
                    m.players[j] = msg.readInt32();
                }
            }
        } break;

        case GCMSG_REQUEST_POST:
        {
            // Retrieve the post for user
            LOG_DEBUG("GCMSG_REQUEST_POST");
            result.writeInt16(CGMSG_POST_RESPONSE);

            // get the character id
            int characterId = msg.readInt32();

            // send the character id of sender
            result.writeInt32(characterId);

            // get the character based on the id
            Character *ptr = storage->getCharacter(characterId, NULL);
            if (!ptr)
            {
                // Invalid character
                LOG_ERROR("Error finding character id for post");
                break;
            }

            // get the post for that character
            Post *post = postalManager->getPost(ptr);

            // send the post if valid
            if (post)
            {
                for (unsigned int i = 0; i < post->getNumberOfLetters(); ++i)
                {
                    // get each letter, send the sender's name,
                    // the contents and any attachments
                    Letter *letter = post->getLetter(i);
                    result.writeString(letter->getSender()->getName());
                    result.writeString(letter->getContents());
                    std::vector<InventoryItem> items = letter->getAttachments();
                    for (unsigned int j = 0; j < items.size(); ++j)
                    {
                        result.writeInt16(items[j].itemId);
                        result.writeInt16(items[j].amount);
                    }
                }

                // clean up
                postalManager->clearPost(ptr);
            }

        } break;

        case GCMSG_STORE_POST:
        {
            // Store the letter for the user
            LOG_DEBUG("GCMSG_STORE_POST");
            result.writeInt16(CGMSG_STORE_POST_RESPONSE);

            // get the sender and receiver
            int senderId = msg.readInt32();
            std::string receiverName = msg.readString();

            // for sending it back
            result.writeInt32(senderId);

            // get their characters
            Character *sender = storage->getCharacter(senderId, NULL);
            Character *receiver = storage->getCharacter(receiverName);
            if (!sender || !receiver)
            {
                // Invalid character
                LOG_ERROR("Error finding character id for post");
                result.writeInt8(ERRMSG_INVALID_ARGUMENT);
                break;
            }

            // get the letter contents
            std::string contents = msg.readString();

            std::vector< std::pair<int, int> > items;
            while (msg.getUnreadLength())
            {
                items.push_back(std::pair<int, int>(msg.readInt16(), msg.readInt16()));
            }

            // save the letter
            LOG_DEBUG("Creating letter");
            Letter *letter = new Letter(0, sender, receiver);
            letter->addText(contents);
            for (unsigned int i = 0; i < items.size(); ++i)
            {
                InventoryItem item;
                item.itemId = items[i].first;
                item.amount = items[i].second;
                letter->addAttachment(item);
            }
            postalManager->addLetter(letter);

            result.writeInt8(ERRMSG_OK);
        } break;

        case GAMSG_TRANSACTION:
        {
            LOG_DEBUG("TRANSACTION");
            int id = msg.readInt32();
            int action = msg.readInt32();
            std::string message = msg.readString();

            Transaction trans;
            trans.mCharacterId = id;
            trans.mAction = action;
            trans.mMessage = message;
            storage->addTransaction(trans);
        } break;

        case GCMSG_PARTY_INVITE:
            chatHandler->handlePartyInvite(msg);
            break;

        default:
            LOG_WARN("ServerHandler::processMessage, Invalid message type: "
                     << msg.getId());
            result.writeInt16(XXMSG_INVALID);
            break;
    }

    // return result
    if (result.getLength() > 0)
        comp->send(result);
}
Exemple #10
0
void ChatHandler::processRaw(MessageOut &outMsg, const std::string &line)
{
    size_t pos = line.find(":");
    if (pos == std::string::npos)
    {
        const int i = atoi(line.c_str());
        if (line.length() <= 3)
            outMsg.writeInt8(static_cast<unsigned char>(i));
        else if (line.length() <= 5)
            outMsg.writeInt16(static_cast<int16_t>(i));
        else
            outMsg.writeInt32(i);
    }
    else
    {
        const std::string header = line.substr(0, pos);
        if (header.length() != 1)
            return;
        std::string data = line.substr(pos + 1);
        int i = 0;

        switch (header[0])
        {
            case '1':
            case '2':
            case '4':
                i = atoi(data.c_str());
                break;
            default:
                break;
        }

        switch (header[0])
        {
            case '1':
                outMsg.writeInt8(static_cast<unsigned char>(i));
                break;
            case '2':
                outMsg.writeInt16(static_cast<int16_t>(i));
                break;
            case '4':
                outMsg.writeInt32(i);
                break;
            case 'c':
            {
                pos = line.find(",");
                if (pos != std::string::npos)
                {
                    const uint16_t x = static_cast<const uint16_t>(
                        atoi(data.substr(0, pos).c_str()));
                    data = data.substr(pos + 1);
                    pos = line.find(",");
                    if (pos == std::string::npos)
                        break;

                    const uint16_t y = static_cast<const uint16_t>(
                        atoi(data.substr(0, pos).c_str()));
                    const int dir = atoi(data.substr(pos + 1).c_str());
                    outMsg.writeCoordinates(x, y,
                        static_cast<unsigned char>(dir));
                }
                break;
            }
            case 't':
                outMsg.writeString(data, static_cast<int>(data.length()));
                break;
            default:
                break;
        }
    }
}
Exemple #11
0
void ChatHandler::processMessage(NetComputer *comp, MessageIn &message)
{
    ChatClient &computer = *static_cast< ChatClient * >(comp);
    MessageOut result;

    if (computer.characterName.empty())
    {
        if (message.getId() != PCMSG_CONNECT) return;

        std::string magic_token = message.readString(MAGIC_TOKEN_LENGTH);
        mTokenCollector.addPendingClient(magic_token, &computer);
        sendGuildRejoin(computer);
        return;
    }

    switch (message.getId())
    {
        case PCMSG_CHAT:
            handleChatMessage(computer, message);
            break;

        case PCMSG_ANNOUNCE:
            handleAnnounceMessage(computer, message);
            break;

        case PCMSG_PRIVMSG:
            handlePrivMsgMessage(computer, message);
            break;

        case PCMSG_WHO:
            handleWhoMessage(computer);
            break;

        case PCMSG_ENTER_CHANNEL:
            handleEnterChannelMessage(computer, message);
            break;

        case PCMSG_USER_MODE:
            handleModeChangeMessage(computer, message);
            break;

        case PCMSG_KICK_USER:
            handleKickUserMessage(computer, message);

        case PCMSG_QUIT_CHANNEL:
            handleQuitChannelMessage(computer, message);
            break;

        case PCMSG_LIST_CHANNELS:
            handleListChannelsMessage(computer, message);
            break;

        case PCMSG_LIST_CHANNELUSERS:
            handleListChannelUsersMessage(computer, message);
            break;

        case PCMSG_TOPIC_CHANGE:
            handleTopicChange(computer, message);
            break;

        case PCMSG_DISCONNECT:
            handleDisconnectMessage(computer, message);
            break;

        case PCMSG_GUILD_CREATE:
            handleGuildCreation(computer, message);
            break;

        case PCMSG_GUILD_INVITE:
            handleGuildInvitation(computer, message);
            break;

        case PCMSG_GUILD_ACCEPT:
            handleGuildAcceptInvite(computer, message);
            break;

        case PCMSG_GUILD_GET_MEMBERS:
            handleGuildRetrieveMembers(computer, message);
            break;

        case PCMSG_GUILD_PROMOTE_MEMBER:
            handleGuildMemberLevelChange(computer, message);
            break;

        case PCMSG_GUILD_KICK_MEMBER:
            handleGuildMemberKick(computer, message);

        case PCMSG_GUILD_QUIT:
            handleGuildQuit(computer, message);
            break;

        case PCMSG_PARTY_INVITE:
            handlePartyInvite(computer, message);
            break;

        case PCMSG_PARTY_ACCEPT_INVITE:
            handlePartyAcceptInvite(computer, message);
            break;

        case PCMSG_PARTY_QUIT:
            handlePartyQuit(computer);
            break;

        case PCMSG_PARTY_REJECT_INVITE:
            handlePartyRejection(computer, message);
            break;

        default:
            LOG_WARN("ChatHandler::processMessage, Invalid message type"
                     << message.getId());
            result.writeShort(XXMSG_INVALID);
            break;
    }

    if (result.getLength() > 0)
        computer.send(result);
}
Exemple #12
0
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);
}