4 Commits

Author SHA1 Message Date
e8367cd91c MessagePrinter (Fixes #2)
All checks were successful
Linux arm64 / Build (push) Successful in 15s
2025-03-04 12:01:15 +01:00
fa6ba74068 operator<< for VarInt 2025-03-04 11:44:40 +01:00
d501c0181d fix encapsulate/decapsulated
All checks were successful
Linux arm64 / Build (push) Successful in 14s
2025-03-04 10:59:18 +01:00
680f72f881 emplace instead of push 2025-03-03 22:55:17 +01:00
12 changed files with 168 additions and 22 deletions

View File

@@ -14,7 +14,8 @@ using UpgradeTowerFields = std::tuple<
sp::BitField<std::uint16_t, sp::BitField<std::uint16_t,
sp::Field<std::uint16_t, 12>, //<- m_Tower sp::Field<std::uint16_t, 12>, //<- m_Tower
sp::Field<std::uint8_t, 4> //<- m_Upgrade sp::Field<std::uint8_t, 4> //<- m_Upgrade
> >,
sp::VarInt //<- just for testing
>; >;
DeclarePacket(UpgradeTower){ DeclarePacket(UpgradeTower){

View File

@@ -0,0 +1,26 @@
#pragma once
#include <cxxabi.h>
#include <string>
namespace sp {
template <typename T>
std::string GetClassName(const T& a_Value) {
int status;
char* demangled = abi::__cxa_demangle(typeid(a_Value).name(), 0, 0, &status);
if (status != 0)
return "";
return std::string(demangled);
}
template <typename T>
std::string GetClassName() {
int status;
char* demangled = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
if (status != 0)
return "";
return std::string(demangled);
}
} // namespace sp

View File

@@ -7,6 +7,7 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <ostream>
namespace sp { namespace sp {
@@ -55,6 +56,11 @@ class VarInt {
* \param var The variable integer to deserialize * \param var The variable integer to deserialize
*/ */
friend DataBuffer& operator>>(DataBuffer& in, VarInt& var); friend DataBuffer& operator>>(DataBuffer& in, VarInt& var);
/**
* \brief overriding stream operator
*/
friend std::ostream& operator<<(std::ostream& a_Stream, const sp::VarInt& a_VarInt);
}; };
} // namespace sp } // namespace sp

View File

@@ -48,11 +48,12 @@ Stream<IOTag, MessageDispatcher, MessageFactory, TOptions...>::Stream(
template <typename IOTag, typename MessageDispatcher, typename MessageFactory, typename... TOptions> template <typename IOTag, typename MessageDispatcher, typename MessageFactory, typename... TOptions>
void Stream<IOTag, MessageDispatcher, MessageFactory, TOptions...>::SendMessage(const MessageBase& a_Message) { void Stream<IOTag, MessageDispatcher, MessageFactory, TOptions...>::SendMessage(const MessageBase& a_Message) {
DataBuffer data = a_Message.Write(); DataBuffer data = a_Message.Write();
DataBuffer encapsulated = std::apply([&data](const auto&... a_Options) { TupleForEach([&data](const auto&... a_Options) {
return Encapsulate(data, a_Options...); data = Encapsulate(data, a_Options...);
}, m_Options); }, m_Options);
DataBuffer finalData; DataBuffer finalData;
finalData << VarInt{encapsulated.GetSize()} << encapsulated; finalData.Reserve(data.GetSize() + sizeof(VarInt::MAX_VALUE));
finalData << VarInt{data.GetSize()} << data;
m_Interface.Write(finalData); m_Interface.Write(finalData);
} }
@@ -93,8 +94,8 @@ void Stream<IOTag, MessageDispatcher, MessageFactory, TOptions...>::RecieveMessa
DataBuffer buffer; DataBuffer buffer;
buffer = m_Interface.Read(lenghtValue); buffer = m_Interface.Read(lenghtValue);
buffer = std::apply([&buffer, lenghtValue](const auto&... a_Options) { TupleForEach([&buffer, lenghtValue](const auto&... a_Options) {
return Decapsulate(buffer, a_Options...); buffer = Decapsulate(buffer, a_Options...);
}, m_Options); }, m_Options);
VarInt packetType; VarInt packetType;

View File

@@ -70,29 +70,32 @@ class BitField {
* \tparam ValueType the type of the value to store * \tparam ValueType the type of the value to store
* \tparam IAlignment 0 means no alignment * \tparam IAlignment 0 means no alignment
*/ */
template <typename ValueType, int IAlignment> template <typename ValueType, std::size_t IAlignment>
class Field { class Field {
public: public:
using StorageType = ValueType;
static constexpr std::size_t AlignmentValue = IAlignment;
// Provide an access to the stored value // Provide an access to the stored value
ValueType& GetValue() { StorageType& GetValue() {
return m_Value; return m_Value;
} }
const ValueType& GetValue() const { const StorageType& GetValue() const {
return m_Value; return m_Value;
} }
Field& operator=(const ValueType& value) { Field& operator=(const StorageType& value) {
m_Value = value; m_Value = value;
return *this; return *this;
} }
constexpr int GetAlignment() const { constexpr std::size_t GetAlignment() const {
return IAlignment; return IAlignment;
} }
private: private:
ValueType m_Value; StorageType m_Value;
}; };
namespace details { namespace details {

View File

@@ -0,0 +1,19 @@
#pragma once
#include <ostream>
#include <sp/common/Reflection.h>
#include <sp/protocol/message/MessagePrinterImpl.h>
/**
* \brief Prints a message in a human readable string
*/
template <typename TBase, typename... TOptions>
std::ostream& operator<<(std::ostream& a_Stream, const sp::MessageBase<TBase, TOptions...>& a_Message) {
a_Stream
<< sp::GetClassName(a_Message)
<< sp::details::IdPrinter<TOptions...>::PrintMessageId()
<< "["
<< sp::details::PrintFields(a_Message.GetFields())
<< "]";
return a_Stream;
}

View File

@@ -31,7 +31,7 @@ struct ArrayFiller<TBase, TMessage, TMessages...> {
template <typename TBase, typename TMessage> template <typename TBase, typename TMessage>
struct ArrayFiller<TBase, TMessage> { struct ArrayFiller<TBase, TMessage> {
static void ArrayAppend(details::ArrayType<TBase>& array) { static void ArrayAppend(details::ArrayType<TBase>& array) {
array.push_back([]() -> std::unique_ptr<TBase> { return std::make_unique<TMessage>(); }); array.emplace_back([]() -> std::unique_ptr<TBase> { return std::make_unique<TMessage>(); });
} }
}; };

View File

@@ -4,7 +4,7 @@ namespace sp {
namespace option { namespace option {
// Provide static numeric ID, to facilitate implementation of GetIdImpl() // Provide static numeric ID, to facilitate implementation of GetIdImpl()
template <std::intmax_t TId> template <std::uintmax_t TId>
struct StaticNumIdImpl {}; struct StaticNumIdImpl {};
// Facilitate implementation of DispatchImpl() // Facilitate implementation of DispatchImpl()
@@ -39,10 +39,10 @@ struct MessageImplParsedOptions<> {
template <std::intmax_t TId, typename... TOptions> template <std::uintmax_t TId, typename... TOptions>
struct MessageImplParsedOptions<option::StaticNumIdImpl<TId>, TOptions...> : public MessageImplParsedOptions<TOptions...> { struct MessageImplParsedOptions<option::StaticNumIdImpl<TId>, TOptions...> : public MessageImplParsedOptions<TOptions...> {
static const bool HasStaticNumIdImpl = true; static const bool HasStaticNumIdImpl = true;
static const std::intmax_t MsgId = TId; static const std::uintmax_t MsgId = TId;
}; };
template <typename TActual, typename... TOptions> template <typename TActual, typename... TOptions>

View File

@@ -0,0 +1,81 @@
#pragma once
#include <sstream>
#include <sp/protocol/MessageBase.h>
namespace sp {
namespace details {
template <typename... TOptions>
struct IdPrinter {};
template <>
struct IdPrinter<> {
static std::string PrintMessageId() {
return "";
}
};
template <typename TOption, typename... TOptions>
struct IdPrinter<TOption, TOptions...> {
static std::string PrintMessageId() {
return IdPrinter<TOptions...>::PrintMessageId();
}
};
template <typename... TOptions, std::uintmax_t TId>
struct IdPrinter<option::StaticNumIdImpl<TId>, TOptions...> {
static std::string PrintMessageId() {
return "(Id: " + std::to_string(TId) + ")";
}
};
template <typename T>
std::string PrintData(const T& a_Data) {
std::stringstream sStream;
sStream << a_Data;
return sStream.str();
}
template <>
std::string PrintData<char>(const char& a_Data) {
return std::to_string(a_Data);
}
template <>
std::string PrintData<unsigned char>(const unsigned char& a_Data) {
return std::to_string(a_Data);
}
template <typename... TFields>
std::string PrintFields(const std::tuple<TFields...>& a_Fields);
template <typename TField, unsigned int IAlignment>
struct FieldPrinter {
static std::string PrintField(const sp::Field<TField, IAlignment>& a_Field) {
return GetClassName<TField>() + "=" + PrintData(a_Field.GetValue());
}
};
template <unsigned int IAlignment, typename TContainer, typename... TFields>
struct FieldPrinter<sp::BitField<TContainer, TFields...>, IAlignment> {
static std::string PrintField(const sp::Field<sp::BitField<TContainer, TFields...>, IAlignment>& a_Field) {
return "BitField<" + GetClassName<TContainer>() + ">[" + PrintFields(a_Field.GetValue().GetFields()) + "]";
}
};
template <typename... TFields>
std::string PrintFields(const std::tuple<TFields...>& a_Fields) {
std::string concat;
TupleForEach(
[&concat](const auto& a_Field) {
using TField = typename std::decay<decltype(a_Field)>::type;
constexpr std::size_t alignment = TField::AlignmentValue;
concat += FieldPrinter<typename TField::StorageType, alignment>::PrintField(a_Field) + ", ";
},
a_Fields);
return concat.substr(0, concat.size() - 2);
}
} // namespace details
} // namespace sp

View File

@@ -81,7 +81,7 @@ class MessageImplFieldsReadBase : public TBase {
} }
// reading field in bitfield // reading field in bitfield
template <typename TFieldType, typename TField, int IAlignment> template <typename TFieldType, typename TField, std::size_t IAlignment>
void ReadField(Field<TField, IAlignment>& field, TFieldType data, std::size_t offset) { void ReadField(Field<TField, IAlignment>& field, TFieldType data, std::size_t offset) {
static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8; static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8;
// we suppose that the first element is at the highest bits // we suppose that the first element is at the highest bits
@@ -118,7 +118,7 @@ class MessageImplFieldsWriteBase : public TBase {
} }
// writing field in bitfield // writing field in bitfield
template <typename TFieldType, typename TField, int IAlignment> template <typename TFieldType, typename TField, std::size_t IAlignment>
void WriteField(const Field<TField, IAlignment>& field, TFieldType& data, std::size_t offset) const { void WriteField(const Field<TField, IAlignment>& field, TFieldType& data, std::size_t offset) const {
static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8; static constexpr std::size_t TotalBitCount = sizeof(TFieldType) * 8;
// we suppose that the first element is at the highest bits // we suppose that the first element is at the highest bits

View File

@@ -1,7 +1,7 @@
#include <sp/common/VarInt.h> #include <sp/common/VarInt.h>
#include <stdexcept>
#include <sp/common/DataBuffer.h> #include <sp/common/DataBuffer.h>
#include <stdexcept>
namespace sp { namespace sp {
@@ -49,4 +49,9 @@ DataBuffer& operator>>(DataBuffer& in, VarInt& var) {
return in; return in;
} }
std::ostream& operator<<(std::ostream& a_Stream, const sp::VarInt& a_VarInt) {
a_Stream << a_VarInt.GetValue();
return a_Stream;
}
} // namespace sp } // namespace sp

View File

@@ -5,10 +5,12 @@
#include <sp/default/DefaultPacketDispatcher.h> #include <sp/default/DefaultPacketDispatcher.h>
#include <sp/extensions/Extensions.h> #include <sp/extensions/Extensions.h>
#include <sp/protocol/MessagePrinter.h>
class KeepAliveHandler : public sp::PacketHandler { class KeepAliveHandler : public sp::PacketHandler {
void Handle(const KeepAlivePacket& packet) { void Handle(const KeepAlivePacket& packet) {
std::cout << "KeepAlive handled !\n"; std::cout << "KeepAlive handled !!\n";
std::cout << packet << std::endl;
} }
void Handle(const DisconnectPacket& packet) { void Handle(const DisconnectPacket& packet) {
@@ -21,12 +23,14 @@ class KeepAliveHandler : public sp::PacketHandler {
}; };
int main() { int main() {
auto upgradeTower = std::make_unique<UpgradeTowerPacket>(std::make_tuple(666, 9)); auto upgradeTower = std::make_unique<UpgradeTowerPacket>(std::make_tuple(666, 9), 789);
auto keepAlive = std::make_unique<KeepAlivePacket>(6969);
sp::PacketMessage* msg = upgradeTower.get(); sp::PacketMessage* msg = upgradeTower.get();
auto handler = std::make_shared<KeepAliveHandler>(); auto handler = std::make_shared<KeepAliveHandler>();
msg->Dispatch(*handler); msg->Dispatch(*handler);
keepAlive->Dispatch(*handler);
sp::DataBuffer buffer = msg->Write(); sp::DataBuffer buffer = msg->Write();
@@ -36,7 +40,7 @@ int main() {
auto upgradeTower2 = std::make_unique<UpgradeTowerPacket>(); auto upgradeTower2 = std::make_unique<UpgradeTowerPacket>();
upgradeTower2->Read(buffer); upgradeTower2->Read(buffer);
std::cout << "Test : " << (unsigned)upgradeTower2->GetTowerId() << "\n"; std::cout << "Test : " << *upgradeTower2 << "\n";
sp::PacketFactory factory; sp::PacketFactory factory;
auto packet = factory.CreateMessage(msgId); auto packet = factory.CreateMessage(msgId);