-
Notifications
You must be signed in to change notification settings - Fork 0
Create a packet
虎視ぞ edited this page Apr 2, 2023
·
1 revision
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.