• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

[Help] how to parse the information sent form the client

Tetraplovisk

New Member
Joined
Jun 22, 2017
Messages
4
Reaction score
0
Hello , i am having a problem i hope you guys can help me figure it out.

So in the client i have this code

C++:
void ProtocolGame::sendRuleViolation(const std::string& target, int reason, int action, const std::string& comment, const std::string& statement, int statementId, bool ipBanishment)
{
    OutputMessagePtr msg(new OutputMessage);
    msg->addU8(Proto::ClientRuleViolation);
    msg->addString(target);
    msg->addU8(reason);
    msg->addU8(action);
    msg->addString(comment);
    msg->addString(statement);
    msg->addU16(statementId);
    msg->addU8(ipBanishment);
    send(msg);
}


and on the server side i have this

C++:
void ProtocolGame::parseRuleViolation(NetworkMessage& msg)
{
   
std::string target = msg.getString();
    uint8_t reason = msg.getByte();
    uint8_t action = msg.getByte();
    std::string comment = msg.getString();
    std::string statement = msg.getString();
    uint16_t statementID = msg.get<uint16_t>();
    uint8_t ipBan = msg.getByte();

}

i am trying to understand how do i get all the variables that were sent to the server, how do i parse everything?

all i got from that is "identifier "variableName" is undefined"

i need to get from the client to the server side: target, reason, action and so on but i have no clue on how to do it.

thanks :)
 
Last edited:
hey thanks for the reply, i have looked into that link but i still dont understand how the parsing part works for exemple what i noticed in this code(that works)

Client side:
C++:
void ProtocolGame::sendRequestTrade(const Position& pos, int thingId, int stackpos, uint creatureId)
{
    OutputMessagePtr msg(new OutputMessage);
    msg->addU8(Proto::ClientRequestTrade);
    addPosition(msg, pos);
    msg->addU16(thingId);
    msg->addU8(stackpos);
    msg->addU32(creatureId);
    send(msg);
}


Server side:

C++:
void ProtocolGame::parseRequestTrade(NetworkMessage& msg)
{
    Position pos = msg.getPosition();
    uint16_t spriteId = msg.get<uint16_t>();
    uint8_t stackpos = msg.getByte();
    uint32_t playerId = msg.get<uint32_t>();
    addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId);
}


is that on the server side the variables are been set in the same order as they were sent by the client and thats it..

i tried the same with my code and it does work for the strings but for the other variables it doenst so... what am i doing wrong here?

also i noticed that when i compile this msg appears "local variable is initialized but not referenced"
 
hey thanks for the reply, i have looked into that link but i still dont understand how the parsing part works for exemple what i noticed in this code(that works)

Client side:
C++:
void ProtocolGame::sendRequestTrade(const Position& pos, int thingId, int stackpos, uint creatureId)
{
    OutputMessagePtr msg(new OutputMessage);
    msg->addU8(Proto::ClientRequestTrade);
    addPosition(msg, pos);
    msg->addU16(thingId);
    msg->addU8(stackpos);
    msg->addU32(creatureId);
    send(msg);
}


Server side:

C++:
void ProtocolGame::parseRequestTrade(NetworkMessage& msg)
{
    Position pos = msg.getPosition();
    uint16_t spriteId = msg.get<uint16_t>();
    uint8_t stackpos = msg.getByte();
    uint32_t playerId = msg.get<uint32_t>();
    addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId);
}


is that on the server side the variables are been set in the same order as they were sent by the client and thats it..

i tried the same with my code and it does work for the strings but for the other variables it doenst so... what am i doing wrong here?

also i noticed that when i compile this msg appears "local variable is initialized but not referenced"
Flash-News/Communication.as at 49fdc03cdd84e1f559b6f80b55bb14b6588c5ab4 · comedinha/Flash-News · GitHub
 
@Tetraplovisk

I don't know if I'm correct, but:

in protocolGame.cpp of forgotten server:
line 381:
C++:
void ProtocolGame::parsePacket(NetworkMessage& msg)
{
    if (!acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN || msg.getLength() <= 0) {
        return;
    }

    uint8_t recvbyte = msg.getByte();

    if (!player) {
        if (recvbyte == 0x0F) {
            disconnect();
        }

        return;
    }

    //a dead player can not performs actions
    if (player->isRemoved() || player->getHealth() <= 0) {
        if (recvbyte == 0x0F) {
            disconnect();
            return;
        }

        if (recvbyte != 0x14) {
            return;
        }
    }

    switch (recvbyte) {
        case 0x14: g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::logout, getThis(), true, false))); break;
        case 0x1D: addGameTask(&Game::playerReceivePingBack, player->getID()); break;
        case 0x1E: addGameTask(&Game::playerReceivePing, player->getID()); break;
        case 0x32: parseExtendedOpcode(msg); break; //otclient extended opcode
        case 0x64: parseAutoWalk(msg); break;
        case 0x65: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTH); break;
        case 0x66: addGameTask(&Game::playerMove, player->getID(), DIRECTION_EAST); break;
        case 0x67: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTH); break;
        case 0x68: addGameTask(&Game::playerMove, player->getID(), DIRECTION_WEST); break;
        case 0x69: addGameTask(&Game::playerStopAutoWalk, player->getID()); break;
        case 0x6A: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHEAST); break;
        case 0x6B: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHEAST); break;
        case 0x6C: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHWEST); break;
        case 0x6D: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHWEST); break;
        case 0x6F: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_NORTH); break;
        case 0x70: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_EAST); break;
        case 0x71: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_SOUTH); break;
        case 0x72: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_WEST); break;
        case 0x78: parseThrow(msg); break;
        case 0x79: parseLookInShop(msg); break;
        case 0x7A: parsePlayerPurchase(msg); break;
        case 0x7B: parsePlayerSale(msg); break;
        case 0x7C: addGameTask(&Game::playerCloseShop, player->getID()); break;
        case 0x7D: parseRequestTrade(msg); break;
        case 0x7E: parseLookInTrade(msg); break;
        case 0x7F: addGameTask(&Game::playerAcceptTrade, player->getID()); break;
        case 0x80: addGameTask(&Game::playerCloseTrade, player->getID()); break;
        case 0x82: parseUseItem(msg); break;
        case 0x83: parseUseItemEx(msg); break;
        case 0x84: parseUseWithCreature(msg); break;
        case 0x85: parseRotateItem(msg); break;
        case 0x87: parseCloseContainer(msg); break;
        case 0x88: parseUpArrowContainer(msg); break;
        case 0x89: parseTextWindow(msg); break;
        case 0x8A: parseHouseWindow(msg); break;
        case 0x8C: parseLookAt(msg); break;
        case 0x8D: parseLookInBattleList(msg); break;
        case 0x8E: /* join aggression */ break;
        case 0x96: parseSay(msg); break;
        case 0x97: addGameTask(&Game::playerRequestChannels, player->getID()); break;
        case 0x98: parseOpenChannel(msg); break;
        case 0x99: parseCloseChannel(msg); break;
        case 0x9A: parseOpenPrivateChannel(msg); break;
        case 0x9E: addGameTask(&Game::playerCloseNpcChannel, player->getID()); break;
        case 0xA0: parseFightModes(msg); break;
        case 0xA1: parseAttack(msg); break;
        case 0xA2: parseFollow(msg); break;
        case 0xA3: parseInviteToParty(msg); break;
        case 0xA4: parseJoinParty(msg); break;
        case 0xA5: parseRevokePartyInvite(msg); break;
        case 0xA6: parsePassPartyLeadership(msg); break;
        case 0xA7: addGameTask(&Game::playerLeaveParty, player->getID()); break;
        case 0xA8: parseEnableSharedPartyExperience(msg); break;
        case 0xAA: addGameTask(&Game::playerCreatePrivateChannel, player->getID()); break;
        case 0xAB: parseChannelInvite(msg); break;
        case 0xAC: parseChannelExclude(msg); break;
        case 0xBE: addGameTask(&Game::playerCancelAttackAndFollow, player->getID()); break;
        case 0xC9: /* update tile */ break;
        case 0xCA: parseUpdateContainer(msg); break;
        case 0xCB: parseBrowseField(msg); break;
        case 0xCC: parseSeekInContainer(msg); break;
        case 0xD2: addGameTask(&Game::playerRequestOutfit, player->getID()); break;
        case 0xD3: parseSetOutfit(msg); break;
        case 0xD4: parseToggleMount(msg); break;
        case 0xDC: parseAddVip(msg); break;
        case 0xDD: parseRemoveVip(msg); break;
        case 0xDE: parseEditVip(msg); break;
        case 0xE6: parseBugReport(msg); break;
        case 0xE7: /* thank you */ break;
        case 0xE8: parseDebugAssert(msg); break;
        case 0xF0: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerShowQuestLog, player->getID()); break;
        case 0xF1: parseQuestLine(msg); break;
        case 0xF2: /* rule violation report */ break;
        case 0xF3: /* get object info */ break;
        case 0xF4: parseMarketLeave(); break;
        case 0xF5: parseMarketBrowse(msg); break;
        case 0xF6: parseMarketCreateOffer(msg); break;
        case 0xF7: parseMarketCancelOffer(msg); break;
        case 0xF8: parseMarketAcceptOffer(msg); break;
        case 0xF9: parseModalWindowAnswer(msg); break;

        default:
            // std::cout << "Player: " << player->getName() << " sent an unknown packet header: 0x" << std::hex << static_cast<uint16_t>(recvbyte) << std::dec << "!" << std::endl;
            break;
    }

    if (msg.isOverrun()) {
        disconnect();
    }
}

line: 477
C++:
case 0xE6: parseBugReport(msg); break;

0xE6 must be the same code that was sent by the client
in your code: line 4
C++:
msg->addU8(Proto::ClientRuleViolation);

It makes possibly to identify what the server must do with each different packet.
Then, you just need to read in the correct order (and, maybe, make some casts to convert units)

If you don't need to read some specific bit, you can skip it in the tfs:
C++:
    msg.skipBytes(2); // will skip the next 2 bytes


It works in the sequency, when you read one time, you can't read it again (I guess), só you need to read only the first bit in the parse (the first code in this post) and then send the rest of the message to the correct function, where it will read in the correct order, store the information in other variables and then do whatever you want to do.


EDIT: I think it's commented in the TFS the correct byte:
C++:
case 0xF2: /* rule violation report */ break;

you can change it to something like
Code:
case 0xF2: doSomethingHere(msg); break;
 
@Tetraplovisk

I don't know if I'm correct, but:

in protocolGame.cpp of forgotten server:
line 381:
C++:
void ProtocolGame::parsePacket(NetworkMessage& msg)
{
    if (!acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN || msg.getLength() <= 0) {
        return;
    }

    uint8_t recvbyte = msg.getByte();

    if (!player) {
        if (recvbyte == 0x0F) {
            disconnect();
        }

        return;
    }

    //a dead player can not performs actions
    if (player->isRemoved() || player->getHealth() <= 0) {
        if (recvbyte == 0x0F) {
            disconnect();
            return;
        }

        if (recvbyte != 0x14) {
            return;
        }
    }

    switch (recvbyte) {
        case 0x14: g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::logout, getThis(), true, false))); break;
        case 0x1D: addGameTask(&Game::playerReceivePingBack, player->getID()); break;
        case 0x1E: addGameTask(&Game::playerReceivePing, player->getID()); break;
        case 0x32: parseExtendedOpcode(msg); break; //otclient extended opcode
        case 0x64: parseAutoWalk(msg); break;
        case 0x65: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTH); break;
        case 0x66: addGameTask(&Game::playerMove, player->getID(), DIRECTION_EAST); break;
        case 0x67: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTH); break;
        case 0x68: addGameTask(&Game::playerMove, player->getID(), DIRECTION_WEST); break;
        case 0x69: addGameTask(&Game::playerStopAutoWalk, player->getID()); break;
        case 0x6A: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHEAST); break;
        case 0x6B: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHEAST); break;
        case 0x6C: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHWEST); break;
        case 0x6D: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHWEST); break;
        case 0x6F: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_NORTH); break;
        case 0x70: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_EAST); break;
        case 0x71: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_SOUTH); break;
        case 0x72: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_WEST); break;
        case 0x78: parseThrow(msg); break;
        case 0x79: parseLookInShop(msg); break;
        case 0x7A: parsePlayerPurchase(msg); break;
        case 0x7B: parsePlayerSale(msg); break;
        case 0x7C: addGameTask(&Game::playerCloseShop, player->getID()); break;
        case 0x7D: parseRequestTrade(msg); break;
        case 0x7E: parseLookInTrade(msg); break;
        case 0x7F: addGameTask(&Game::playerAcceptTrade, player->getID()); break;
        case 0x80: addGameTask(&Game::playerCloseTrade, player->getID()); break;
        case 0x82: parseUseItem(msg); break;
        case 0x83: parseUseItemEx(msg); break;
        case 0x84: parseUseWithCreature(msg); break;
        case 0x85: parseRotateItem(msg); break;
        case 0x87: parseCloseContainer(msg); break;
        case 0x88: parseUpArrowContainer(msg); break;
        case 0x89: parseTextWindow(msg); break;
        case 0x8A: parseHouseWindow(msg); break;
        case 0x8C: parseLookAt(msg); break;
        case 0x8D: parseLookInBattleList(msg); break;
        case 0x8E: /* join aggression */ break;
        case 0x96: parseSay(msg); break;
        case 0x97: addGameTask(&Game::playerRequestChannels, player->getID()); break;
        case 0x98: parseOpenChannel(msg); break;
        case 0x99: parseCloseChannel(msg); break;
        case 0x9A: parseOpenPrivateChannel(msg); break;
        case 0x9E: addGameTask(&Game::playerCloseNpcChannel, player->getID()); break;
        case 0xA0: parseFightModes(msg); break;
        case 0xA1: parseAttack(msg); break;
        case 0xA2: parseFollow(msg); break;
        case 0xA3: parseInviteToParty(msg); break;
        case 0xA4: parseJoinParty(msg); break;
        case 0xA5: parseRevokePartyInvite(msg); break;
        case 0xA6: parsePassPartyLeadership(msg); break;
        case 0xA7: addGameTask(&Game::playerLeaveParty, player->getID()); break;
        case 0xA8: parseEnableSharedPartyExperience(msg); break;
        case 0xAA: addGameTask(&Game::playerCreatePrivateChannel, player->getID()); break;
        case 0xAB: parseChannelInvite(msg); break;
        case 0xAC: parseChannelExclude(msg); break;
        case 0xBE: addGameTask(&Game::playerCancelAttackAndFollow, player->getID()); break;
        case 0xC9: /* update tile */ break;
        case 0xCA: parseUpdateContainer(msg); break;
        case 0xCB: parseBrowseField(msg); break;
        case 0xCC: parseSeekInContainer(msg); break;
        case 0xD2: addGameTask(&Game::playerRequestOutfit, player->getID()); break;
        case 0xD3: parseSetOutfit(msg); break;
        case 0xD4: parseToggleMount(msg); break;
        case 0xDC: parseAddVip(msg); break;
        case 0xDD: parseRemoveVip(msg); break;
        case 0xDE: parseEditVip(msg); break;
        case 0xE6: parseBugReport(msg); break;
        case 0xE7: /* thank you */ break;
        case 0xE8: parseDebugAssert(msg); break;
        case 0xF0: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerShowQuestLog, player->getID()); break;
        case 0xF1: parseQuestLine(msg); break;
        case 0xF2: /* rule violation report */ break;
        case 0xF3: /* get object info */ break;
        case 0xF4: parseMarketLeave(); break;
        case 0xF5: parseMarketBrowse(msg); break;
        case 0xF6: parseMarketCreateOffer(msg); break;
        case 0xF7: parseMarketCancelOffer(msg); break;
        case 0xF8: parseMarketAcceptOffer(msg); break;
        case 0xF9: parseModalWindowAnswer(msg); break;

        default:
            // std::cout << "Player: " << player->getName() << " sent an unknown packet header: 0x" << std::hex << static_cast<uint16_t>(recvbyte) << std::dec << "!" << std::endl;
            break;
    }

    if (msg.isOverrun()) {
        disconnect();
    }
}

line: 477
C++:
case 0xE6: parseBugReport(msg); break;

0xE6 must be the same code that was sent by the client
in your code: line 4
C++:
msg->addU8(Proto::ClientRuleViolation);

It makes possibly to identify what the server must do with each different packet.
Then, you just need to read in the correct order (and, maybe, make some casts to convert units)

If you don't need to read some specific bit, you can skip it in the tfs:
C++:
    msg.skipBytes(2); // will skip the next 2 bytes


It works in the sequency, when you read one time, you can't read it again (I guess), só you need to read only the first bit in the parse (the first code in this post) and then send the rest of the message to the correct function, where it will read in the correct order, store the information in other variables and then do whatever you want to do.


EDIT: I think it's commented in the TFS the correct byte:
C++:
case 0xF2: /* rule violation report */ break;

you can change it to something like
Code:
case 0xF2: doSomethingHere(msg); break;

Thank you man, you really helped me understand how to do it and now my code is working 100% :)

What i notice is that when you read the package in order the debugger doesn't work properly("identifier "variableName" is undefined" is the only msg you get when using watcher).. so to debug all the variables you need to use printf() or something similar.. after i learned that i manage to make the code work 100%.

thanks again :)
 
Back
Top