Skip to content

Create a packet

虎視ぞ edited this page Apr 2, 2023 · 1 revision

Create a packet

If you want to create a packet that will be used in your babel app, just follow this short guide, and you will have your packet in no time 😛

  • From this point, I will assume you are in the protocol/packets directory

1. Create a new PacketType in PacketType.hpp

#pragma once

namespace babel {

    enum PacketType {

        // ...,
        YOUR_PACKET_TYPE,
    };

}

2. Now we have to create a header that inherits from the Packet class:

#pragma once

#include "Packet.hpp"

namespace babel {

    class PacketName: public Packet {
        public:
            PacketName() {}

            const PacketType getType() const override;
            const std::string serialize() const override;
            std::unique_ptr<Packet> deserialize(std::vector<std::unique_ptr<PacketField>> packetFields) const override;
    };
}

3. Let's add a string and an int for the sake of the example:

#pragma once

#include "Packet.hpp"

namespace babel {

    class PacketName: public Packet {
        public:
            PacketName() {} // Make sure to leave this constructor, it will be used later.
            PacketName(std::string location, int temperature); // Feel free to replace the fields the packet has

            const std::string getLocation() const;
            const int getTemperature() const;

            const PacketType getType() const override;
            const std::string serialize() const override;
            std::unique_ptr<Packet> deserialize(std::vector<std::unique_ptr<PacketField>> packetFields) const override;

        private:
            const std::string _location = "";
            const int _temperature = "";
    };
}

4. We now need to implement the whole class

#include "PacketName.hpp"
#include "../fields/StringField.hpp"
#include "../fields/IntegerField.hpp"
#include "../serialization/Serializer.hpp"

#include <iostream>

using namespace babel;

PacketName::PacketName(std::string location, int temperature): _temperature(temperature), _location(location) {
}

const std::string PacketName::getLocation() const {
    return (this->_location);
}

const int PacketName::getTemperature() const {
    return (this->_temperature);
}

const PacketType PacketName::getType() const {
    return (PacketType::PACKET_TYPE);
}

const std::string PacketName::serialize() const {
    Serializer serializer(this->getType()); // We create a new Serializer, the type id will be serialized right after the magic header

    serializer << new StringField(this->_location);
    serializer << new IntegerField(this->_temperature);
    return (serializer.serialize());
}

std::unique_ptr<Packet> PacketName::deserialize(std::vector<std::unique_ptr<PacketField>> packetFields) const {
    if (packetFields.size() != 2) // We're checking if there are two fields since our class has only two fields.
        return (nullptr);

    std::unique_ptr<PacketField> field = std::move(packetFields[0]);

    if (field->getType() != FieldType::STRING) // Wrong type for the field, we were expecting a string first
        return (nullptr);
    StringField *locationField = static_cast<StringField*>(field.get());
    std::string location = location->getValue();

    field = std::move(packetFields[1]);
    if (field->getType() != FieldType::INTEGER)
        return (nullptr);
    IntegerField *temperatureField = static_cast<IntegerField*>(field.get());
    int temperature = temperatureField->getValue();

    return (std::unique_ptr<Packet>(new PacketName(location, temperature)));
}

5. Last thing, we need to point the Deserializer to this class so he will use this class for this packet type

../serialization/Deserializer.cpp

// ... Other includes above
#include "../packets/PacketName.hpp"

using namespace babel;

std::unique_ptr<Packet> Deserializer::deserialize(PacketType packetType, std::vector<std::unique_ptr<PacketField>> packetFields) const {
    switch (packetType) {
        // ...
        case PacketType::YOUR_PACKET_TYPE:
            return (PacketName().deserialize(std::move(packetFields))); // We use the default constructor here.
    }

    return (nullptr);
}
That's it !
If you want to serialize the packet you just need to do:
std::string serializedPacket = PacketName("France", 28).serialize();

The deserializer will automatically deserialize it once serializedPacket will be passed as parameters.

Clone this wiki locally