basic packet structure
This commit is contained in:
@@ -2,12 +2,12 @@
|
||||
|
||||
/**
|
||||
* \file PacketDispatcher.h
|
||||
* \brief File containing the sp::protocol::PacketDispatcher class
|
||||
* \brief File containing the td::protocol::PacketDispatcher class
|
||||
*/
|
||||
|
||||
#include <sp/common/NonCopyable.h>
|
||||
#include <sp/protocol/packet/Packets.h>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace sp {
|
||||
@@ -56,6 +56,6 @@ class Dispatcher : private NonCopyable {
|
||||
};
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
} // namespace td
|
||||
|
||||
#include "Dispatcher.inl"
|
||||
@@ -28,11 +28,11 @@ void Dispatcher<T_Enum, T_Handler, T>::UnregisterHandler(T_Handler& handler) {
|
||||
if (pair.second.empty())
|
||||
continue;
|
||||
|
||||
PacketType type = pair.first;
|
||||
auto type = pair.first;
|
||||
|
||||
m_Handlers[type].erase(std::remove(m_Handlers[type].begin(), m_Handlers[type].end(), &handler), m_Handlers[type].end());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
} // namespace td
|
||||
141
include/sp/GenericHandler.h
Normal file
141
include/sp/GenericHandler.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace sp
|
||||
{
|
||||
// This class is inspired by https://arobenko.gitbooks.io/comms-protocols-cpp/content/
|
||||
|
||||
// TCommon is common interface class for all the messages
|
||||
// TAll is all the message types, that need to be handled, bundled in std::tuple
|
||||
template <typename TCommon, typename TAll>
|
||||
class GenericHandler;
|
||||
|
||||
// Big boy to process packets 20 by 20, preventing needlessly copying vtable many times at each inheritance stage
|
||||
template <typename TCommon,
|
||||
typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8, typename T9, typename T10,
|
||||
typename T11, typename T12, typename T13, typename T14, typename T15,
|
||||
typename T16, typename T17, typename T18, typename T19, typename T20,
|
||||
typename... TRest>
|
||||
class GenericHandler<TCommon, std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T11, T13, T14, T15, T16, T17, T18, T19, T20, TRest...> > : public GenericHandler<TCommon, std::tuple<TRest...> >
|
||||
{
|
||||
using Base = GenericHandler<TCommon, std::tuple<TRest...> >;
|
||||
public:
|
||||
using Base::Handle; // Don't hide all Handle() functions from base classes
|
||||
virtual void Handle(T1& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T2& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T3& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T4& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T5& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T6& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T7& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T8& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T9& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T10& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T11& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T12& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T13& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T14& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T15& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T16& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T17& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T18& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T19& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T20& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
};
|
||||
|
||||
// 10 by 10
|
||||
template <typename TCommon,
|
||||
typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8, typename T9, typename T10,
|
||||
typename... TRest>
|
||||
class GenericHandler<TCommon, std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRest...> > : public GenericHandler<TCommon, std::tuple<TRest...> >
|
||||
{
|
||||
using Base = GenericHandler<TCommon, std::tuple<TRest...> >;
|
||||
public:
|
||||
using Base::Handle; // Don't hide all Handle() functions from base classes
|
||||
virtual void Handle(T1& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T2& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T3& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T4& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T5& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T6& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T7& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T8& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T9& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T10& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
};
|
||||
|
||||
// 5 by 5
|
||||
template <typename TCommon,
|
||||
typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename... TRest>
|
||||
class GenericHandler<TCommon, std::tuple<T1, T2, T3, T4, T5, TRest...> > : public GenericHandler<TCommon, std::tuple<TRest...> >
|
||||
{
|
||||
using Base = GenericHandler<TCommon, std::tuple<TRest...> >;
|
||||
public:
|
||||
using Base::Handle; // Don't hide all Handle() functions from base classes
|
||||
virtual void Handle(T1& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T2& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T3& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T4& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T5& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
};
|
||||
|
||||
// Deal with rest with 4 types
|
||||
template <typename TCommon, typename T1, typename T2, typename T3, typename T4>
|
||||
class GenericHandler<TCommon, std::tuple<T1, T2, T3, T4> >
|
||||
{
|
||||
public:
|
||||
virtual ~GenericHandler() {}
|
||||
virtual void Handle(T1& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T2& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T3& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T4& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(TCommon&) { } //Nothing to do
|
||||
};
|
||||
|
||||
// Deal with rest with 3 types
|
||||
template <typename TCommon, typename T1, typename T2, typename T3>
|
||||
class GenericHandler<TCommon, std::tuple<T1, T2, T3> >
|
||||
{
|
||||
public:
|
||||
virtual ~GenericHandler() {}
|
||||
virtual void Handle(T1& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T2& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T3& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(TCommon&) { } //Nothing to do
|
||||
};
|
||||
|
||||
// Deal with rest with 2 types
|
||||
template <typename TCommon, typename T1, typename T2>
|
||||
class GenericHandler<TCommon, std::tuple<T1, T2> >
|
||||
{
|
||||
public:
|
||||
virtual ~GenericHandler() {}
|
||||
virtual void Handle(T1& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(T2& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(TCommon&) { } //Nothing to do
|
||||
};
|
||||
|
||||
// Deal with rest with 1 type
|
||||
template <typename TCommon, typename T1>
|
||||
class GenericHandler<TCommon, std::tuple<T1> >
|
||||
{
|
||||
public:
|
||||
virtual ~GenericHandler() {}
|
||||
virtual void Handle(T1& msg) { this->Handle(static_cast<TCommon&>(msg)); }
|
||||
virtual void Handle(TCommon&) { } //Nothing to do
|
||||
};
|
||||
|
||||
// Deal with rest with 0 type
|
||||
template <typename TCommon>
|
||||
class GenericHandler<TCommon, std::tuple<> >
|
||||
{
|
||||
public:
|
||||
virtual ~GenericHandler() {}
|
||||
virtual void Handle(TCommon&) { } //Nothing to do
|
||||
};
|
||||
|
||||
} // sp
|
||||
38
include/sp/Message.h
Normal file
38
include/sp/Message.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <sp/common/DataBuffer.h>
|
||||
|
||||
namespace sp {
|
||||
class Handler;
|
||||
|
||||
class Message {
|
||||
public:
|
||||
virtual ~Message() {}
|
||||
|
||||
void Write(DataBuffer& buffer) const {
|
||||
buffer << GetId();
|
||||
WriteImpl(buffer);
|
||||
}
|
||||
|
||||
void Read(const DataBuffer& buffer) {
|
||||
ReadImpl(buffer);
|
||||
}
|
||||
|
||||
void Dispatch(Handler& handler) {
|
||||
DispatchImpl(handler);
|
||||
}
|
||||
|
||||
virtual int GetId() const = 0;
|
||||
|
||||
virtual std::string_view GetName() const = 0;
|
||||
|
||||
protected:
|
||||
virtual void DispatchImpl(Handler& handler) = 0;
|
||||
virtual void WriteImpl(DataBuffer& buffer) const = 0;
|
||||
virtual void ReadImpl(const DataBuffer& buffer) = 0;
|
||||
};
|
||||
|
||||
} // namespace sp
|
||||
18
include/sp/MessageBase.h
Normal file
18
include/sp/MessageBase.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <sp/Message.h>
|
||||
|
||||
namespace sp {
|
||||
|
||||
template <typename TDerived>
|
||||
class MessageBase : public Message {
|
||||
protected:
|
||||
virtual void DispatchImpl(Handler& handler) override {
|
||||
handler.Handle(static_cast<TDerived&>(*this));
|
||||
}
|
||||
|
||||
virtual void WriteImpl(DataBuffer& buffer) const = 0;
|
||||
virtual void ReadImpl(const DataBuffer& buffer) = 0;
|
||||
};
|
||||
|
||||
} // namespace sp
|
||||
47
include/sp/Templates.h
Normal file
47
include/sp/Templates.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace sp {
|
||||
|
||||
/// @brief Default case, see field_index specialization for implementation details
|
||||
template <size_t N, typename T, template <size_t, typename> typename U, typename = void>
|
||||
static constexpr size_t field_index = 0;
|
||||
|
||||
/// @brief A templated size_t that counts the number of existing classes U with a "field_name" member
|
||||
/// @tparam N Current counter for recursion (user should always call it with 0)
|
||||
/// @tparam T Can be any type, must be different for each field we want to be counted later (used because we can't have a empty
|
||||
/// template<> specialization nested in a class)
|
||||
/// @tparam U The templated class that will be searched for match
|
||||
template <size_t N, typename T, template <size_t, typename> typename U>
|
||||
static constexpr size_t field_index<N, T, U, std::void_t<decltype(U<N, T>::field_name)>> = 1 + field_index<N + 1, T, U>;
|
||||
|
||||
/// @brief Concat multiple tuples in one big tuple
|
||||
/// @tparam ...input_t Multiple std::tuple types to concat
|
||||
template <typename... input_t>
|
||||
using tuple_cat_t = decltype(std::tuple_cat(std::declval<input_t>()...));
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
constexpr bool tuple_contains_type = false;
|
||||
template <typename T, typename... Ts>
|
||||
constexpr bool tuple_contains_type<T, std::tuple<Ts...>> = std::disjunction_v<std::is_same<T, Ts>...>;
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
constexpr int get_tuple_index = 0;
|
||||
template <typename T, typename... Rest>
|
||||
constexpr int get_tuple_index<T, std::tuple<T, Rest...>> = 0;
|
||||
template <typename T, typename First, typename... Rest>
|
||||
constexpr int get_tuple_index<T, std::tuple<First, Rest...>> = 1 + get_tuple_index<T, std::tuple<Rest...>>;
|
||||
|
||||
// Template black magic to loop at compile time
|
||||
template <std::size_t... indices, class LoopBody>
|
||||
void loop_impl(std::index_sequence<indices...>, LoopBody&& loop_body) {
|
||||
(loop_body(std::integral_constant<std::size_t, indices>{}), ...);
|
||||
}
|
||||
|
||||
template <std::size_t N, class LoopBody>
|
||||
void loop(LoopBody&& loop_body) {
|
||||
loop_impl(std::make_index_sequence<N>{}, std::forward<LoopBody>(loop_body));
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
54
include/sp/common/MacroMap.h
Normal file
54
include/sp/common/MacroMap.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Created by William Swanson in 2012.
|
||||
*
|
||||
* I, William Swanson, dedicate this work to the public domain.
|
||||
* I waive all rights to the work worldwide under copyright law,
|
||||
* including all related and neighboring rights,
|
||||
* to the extent allowed by law.
|
||||
*
|
||||
* You can copy, modify, distribute and perform the work,
|
||||
* even for commercial purposes, all without asking permission.
|
||||
*/
|
||||
|
||||
#ifndef MAP_H_INCLUDED
|
||||
#define MAP_H_INCLUDED
|
||||
|
||||
#define EVAL0(...) __VA_ARGS__
|
||||
#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__)))
|
||||
#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
|
||||
#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
|
||||
#define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
|
||||
#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
|
||||
|
||||
#define MAP_END(...)
|
||||
#define MAP_OUT
|
||||
#define MAP_COMMA ,
|
||||
|
||||
#define MAP_GET_END2() 0, MAP_END
|
||||
#define MAP_GET_END1(...) MAP_GET_END2
|
||||
#define MAP_GET_END(...) MAP_GET_END1
|
||||
#define MAP_NEXT0(test, next, ...) next MAP_OUT
|
||||
#define MAP_NEXT1(test, next) MAP_NEXT0(test, next, 0)
|
||||
#define MAP_NEXT(test, next) MAP_NEXT1(MAP_GET_END test, next)
|
||||
|
||||
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP1)(f, peek, __VA_ARGS__)
|
||||
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP0)(f, peek, __VA_ARGS__)
|
||||
|
||||
#define MAP_LIST_NEXT1(test, next) MAP_NEXT0(test, MAP_COMMA next, 0)
|
||||
#define MAP_LIST_NEXT(test, next) MAP_LIST_NEXT1(MAP_GET_END test, next)
|
||||
|
||||
#define MAP_LIST0(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST1)(f, peek, __VA_ARGS__)
|
||||
#define MAP_LIST1(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST0)(f, peek, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Applies the function macro `f` to each of the remaining parameters.
|
||||
*/
|
||||
#define MAP(f, ...) EVAL(MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
|
||||
|
||||
/**
|
||||
* Applies the function macro `f` to each of the remaining parameters and
|
||||
* inserts commas between the results.
|
||||
*/
|
||||
#define MAP_LIST(f, ...) EVAL(MAP_LIST1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
|
||||
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
// #pragma once
|
||||
|
||||
// #include <array>
|
||||
// #include <string>
|
||||
// #include <sp/Types.h>
|
||||
|
||||
// namespace sp {
|
||||
// namespace protocol {
|
||||
|
||||
// namespace cdata {
|
||||
|
||||
|
||||
// struct PlaceTower {
|
||||
// TowerType m_Type : 4;
|
||||
// PlayerID m_Placer : 4;
|
||||
// TowerCoords m_Position;
|
||||
// };
|
||||
|
||||
// struct UpgradeTower {
|
||||
// TowerID m_Tower : 12;
|
||||
// std::uint8_t m_Upgrade : 4;
|
||||
// };
|
||||
|
||||
// struct SpawnTroop {
|
||||
// EntityType m_Type : 5;
|
||||
// std::uint8_t m_Level : 3;
|
||||
// EntityCoords m_Position;
|
||||
// PlayerID m_Sender;
|
||||
// };
|
||||
|
||||
// struct UseItem {
|
||||
// ShopItem m_Item : 4;
|
||||
// PlayerID m_User : 4;
|
||||
// EntityCoords m_Position;
|
||||
// };
|
||||
|
||||
// struct TeamChange {
|
||||
// PlayerID m_Player : 7;
|
||||
// Team m_NewTeam : 1;
|
||||
// };
|
||||
|
||||
// struct PlayerJoin {
|
||||
// PlayerID m_ID;
|
||||
// std::string m_Name;
|
||||
// };
|
||||
|
||||
// struct End {};
|
||||
|
||||
// } // namespace cdata
|
||||
|
||||
|
||||
// } // namespace protocol
|
||||
// } // namespace sp
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
|
||||
/**
|
||||
* \def DeclareAllPacket
|
||||
* \brief Avoids repetitive operations on commands
|
||||
*/
|
||||
#define DeclareAllCommand() \
|
||||
DeclareCommand(End) \
|
||||
DeclareCommand(PlaceTower) \
|
||||
DeclareCommand(PlayerJoin) \
|
||||
DeclareCommand(SpawnTroop) \
|
||||
DeclareCommand(TeamChange) \
|
||||
DeclareCommand(UpgradeTower) \
|
||||
DeclareCommand(UseItem)
|
||||
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \file CommandDispatcher.h
|
||||
* \brief File containing the sp::protocol::CommandDispatcher class
|
||||
*/
|
||||
|
||||
#include <sp/protocol/Dispatcher.h>
|
||||
#include <sp/protocol/command/Commands.h>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
|
||||
using CommandDispatcher = Dispatcher<CommandType, CommandVisitor, Command>;
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <sp/protocol/command/Commands.h>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
namespace CommandFactory {
|
||||
|
||||
template <typename CommandDerived, typename = typename std::enable_if<std::is_base_of<Command, CommandDerived>::value>::type>
|
||||
std::shared_ptr<CommandDerived> CreateCommand() {
|
||||
return std::make_shared<CommandDerived>();
|
||||
}
|
||||
|
||||
const std::shared_ptr<Command>& CreateReadOnlyCommand(CommandType a_Type);
|
||||
|
||||
} // namespace CommandFactory
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <sp/common/DataBuffer.h>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
|
||||
class Command;
|
||||
|
||||
using CommandPtr = std::shared_ptr<Command>;
|
||||
|
||||
namespace CommandSerializer {
|
||||
|
||||
DataBuffer Serialize(const Command& a_Command);
|
||||
|
||||
std::shared_ptr<Command> Deserialize(DataBuffer& a_Data);
|
||||
|
||||
} // namespace CommandSerializer
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \file CommandVisitor.h
|
||||
* \brief File containing the sp::protocol::CommandVisitor class
|
||||
*/
|
||||
|
||||
#include <sp/protocol/command/Commands.h>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
|
||||
#define DeclareCommand(CommandName, ...) \
|
||||
/** This function is called when the packet processed by CommandVisitor::Check is a CommandName */ \
|
||||
virtual void Visit(const commands::CommandName&) {}
|
||||
|
||||
/**
|
||||
* \class CommandVisitor
|
||||
* \brief This class uses double-dispatch in order to find the real type of a packet
|
||||
*/
|
||||
class CommandVisitor : private NonCopyable {
|
||||
protected:
|
||||
CommandVisitor() {}
|
||||
virtual ~CommandVisitor() {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief Calls the right CommandVisitor::Visit method corresponding to the real type of the packet
|
||||
* \param packet the Command to visit
|
||||
*/
|
||||
void Check(const Command& packet);
|
||||
|
||||
DeclareAllCommand()
|
||||
};
|
||||
|
||||
#undef DeclareCommand
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,111 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \file Commands.h
|
||||
* \brief File containing the definitions of the lockstep commands
|
||||
*/
|
||||
|
||||
#include <sp/Types.h>
|
||||
#include <sp/common/NonCopyable.h>
|
||||
#include <sp/protocol/command/CommandData.h>
|
||||
#include <sp/protocol/command/CommandDeclare.h>
|
||||
#include <memory>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
|
||||
class CommandVisitor;
|
||||
|
||||
/** A Command id is 8 bits wide */
|
||||
using CommandID = std::uint8_t;
|
||||
|
||||
#define DeclareCommand(CommandName, ...) /** CommandName */ CommandName,
|
||||
|
||||
/**
|
||||
* \enum CommandType
|
||||
* \brief Map a Command to an id
|
||||
*/
|
||||
enum class CommandType : CommandID {
|
||||
|
||||
DeclareAllCommand()
|
||||
|
||||
/** The number of Commands */
|
||||
COMMAND_COUNT
|
||||
};
|
||||
|
||||
|
||||
#undef DeclareCommand
|
||||
|
||||
|
||||
class Command : private NonCopyable {
|
||||
public:
|
||||
/**
|
||||
* \return The real type of the Command
|
||||
*/
|
||||
virtual CommandType GetType() const = 0;
|
||||
|
||||
private:
|
||||
/** Use a CommandVisitor to make double-dispatch possible */
|
||||
virtual void Accept(CommandVisitor& a_Visitor) const = 0;
|
||||
|
||||
friend class CommandVisitor;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace commands {
|
||||
|
||||
/**
|
||||
* \class ConcreteCommand
|
||||
* \brief A Command associated with an id and holding data
|
||||
* \tparam PT The Command type
|
||||
* \tparam Data The structure holding the data of the Command (in sp::protocol::data namespace)
|
||||
*/
|
||||
template <CommandType CT, typename Data>
|
||||
class ConcreteCommand : public Command {
|
||||
public:
|
||||
/** The type of the struct holding the data */
|
||||
using CommandDataType = Data;
|
||||
|
||||
/** The structure holding the actual data */
|
||||
CommandDataType m_Data;
|
||||
|
||||
/** Construct the Command with data of type CommandDataType */
|
||||
ConcreteCommand(const CommandDataType& a_Data = {});
|
||||
|
||||
constexpr CommandType GetType() const override {
|
||||
return CT;
|
||||
};
|
||||
|
||||
private:
|
||||
void Accept(CommandVisitor& a_Visitor) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// define SP_INSTANCIATE_COMMANDS
|
||||
// before including this file
|
||||
// if you want to instantiate templates
|
||||
#ifdef SP_INSTANCIATE_COMMANDS
|
||||
#define DeclareCommand(CommandName, ...) \
|
||||
using CommandName = ConcreteCommand<CommandType::CommandName, cdata::CommandName>; \
|
||||
template class ConcreteCommand<CommandType::CommandName, cdata::CommandName>;
|
||||
#else
|
||||
#define DeclareCommand(CommandName, ...) /** Defines the CommandName Command */ \
|
||||
using CommandName = ConcreteCommand<CommandType::CommandName, cdata::CommandName>;
|
||||
#endif
|
||||
|
||||
DeclareAllCommand()
|
||||
|
||||
#undef DeclareCommand
|
||||
|
||||
} // namespace commands
|
||||
|
||||
using LockStep = std::vector<std::shared_ptr<protocol::Command>>;
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,76 +0,0 @@
|
||||
// #pragma once
|
||||
|
||||
// #include <td/Types.h>
|
||||
// #include <vector>
|
||||
// #include <td/protocol/command/Commands.h>
|
||||
|
||||
// // Make it dynamic ?
|
||||
// #define LOCKSTEP_BUFFER_SIZE 10
|
||||
|
||||
// namespace sp {
|
||||
// namespace protocol {
|
||||
|
||||
// struct PlayerInfo {
|
||||
// PlayerID m_PlayerId;
|
||||
// std::string m_PlayerName;
|
||||
// };
|
||||
|
||||
// struct MapData {
|
||||
|
||||
// };
|
||||
|
||||
// namespace pdata {
|
||||
|
||||
// /** Client attempts to login (very basic) */
|
||||
// struct PlayerLogin {
|
||||
// std::string m_PlayerName;
|
||||
// };
|
||||
|
||||
// /** Server indicates success */
|
||||
// struct LoggingSuccess {
|
||||
// PlayerID m_PlayerId;
|
||||
// };
|
||||
|
||||
// /** Player joins the lobby */
|
||||
// struct PlayerJoin {
|
||||
// PlayerInfo m_Player;
|
||||
// };
|
||||
|
||||
// /** Player leaves the lobby */
|
||||
// struct PlayerLeave {
|
||||
// PlayerID m_PlayerId;
|
||||
// };
|
||||
|
||||
// /** Keep alive */
|
||||
// struct KeepAlive {
|
||||
// std::uint64_t m_KeepAliveId;
|
||||
// };
|
||||
|
||||
// /** Can be used by both client and server */
|
||||
// struct Disconnect {
|
||||
// std::string m_Reason;
|
||||
// };
|
||||
|
||||
// /** Chat message */
|
||||
// struct ChatMessage {
|
||||
// std::string m_Text;
|
||||
// };
|
||||
|
||||
// // TODO: handle players joining in the first second
|
||||
|
||||
// struct BeginGame {
|
||||
// MapData m_Map;
|
||||
// std::vector<PlayerInfo> m_BlueTeam;
|
||||
// std::vector<PlayerInfo> m_RedTeam;
|
||||
// // optional, used for players joining mid game
|
||||
// std::vector<LockStep> m_FirstLocksteps;
|
||||
// };
|
||||
|
||||
// struct LockSteps {
|
||||
// std::uint16_t m_FirstFrameNumber;
|
||||
// std::array<LockStep, LOCKSTEP_BUFFER_SIZE> m_LockSteps;
|
||||
// };
|
||||
|
||||
// } // namespace pdata
|
||||
// } // namespace protocol
|
||||
// } // namespace sp
|
||||
@@ -1,48 +0,0 @@
|
||||
// #pragma once
|
||||
|
||||
// /**
|
||||
// * \file PacketDeclare.h
|
||||
// * \brief Holds the definitions of the packets (but not their content)
|
||||
// */
|
||||
|
||||
// namespace sp {
|
||||
// namespace protocol {
|
||||
|
||||
// /**
|
||||
// * \enum PacketSender
|
||||
// * \brief Indicate who should send a packet
|
||||
// */
|
||||
// enum class PacketSenderType {
|
||||
// /** Sent by clients and server */
|
||||
// Both = 1,
|
||||
// /** Sent by clients to the server */
|
||||
// Client,
|
||||
// /** Sent by server to the clients */
|
||||
// Server,
|
||||
// };
|
||||
|
||||
// enum class PacketSendType {
|
||||
// Reliable = 1,
|
||||
// Unreliable,
|
||||
// UnreliableOrdered,
|
||||
// };
|
||||
|
||||
|
||||
// /**
|
||||
// * \def DeclareAllPacket
|
||||
// * \brief Avoids repetitive operations on packets
|
||||
// */
|
||||
// #define DeclareAllPacket() \
|
||||
// DeclarePacket(ChatMessage, Reliable, Both) \
|
||||
// DeclarePacket(BeginGame, Reliable, Server) \
|
||||
// DeclarePacket(Disconnect, Reliable, Both) \
|
||||
// DeclarePacket(KeepAlive, Reliable, Both) \
|
||||
// DeclarePacket(LockSteps, Unreliable, Both) \
|
||||
// DeclarePacket(LoggingSuccess, Reliable, Server) \
|
||||
// DeclarePacket(PlayerJoin, Reliable, Server) \
|
||||
// DeclarePacket(PlayerLeave, Reliable, Server) \
|
||||
// DeclarePacket(PlayerLogin, Reliable, Client) \
|
||||
|
||||
|
||||
// } // namespace protocol
|
||||
// } // namespace sp
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \file PacketDispatcher.h
|
||||
* \brief File containing the sp::protocol::PacketDispatcher class
|
||||
*/
|
||||
|
||||
#include <sp/protocol/Dispatcher.h>
|
||||
#include <sp/protocol/packet/Packets.h>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
|
||||
using PacketDispatcher = Dispatcher<PacketType, PacketVisitor, Packet>;
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <sp/protocol/packet/Packets.h>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
namespace PacketFactory {
|
||||
|
||||
template <typename PacketDerived, typename = typename std::enable_if<std::is_base_of<Packet, PacketDerived>::value>::type>
|
||||
std::unique_ptr<PacketDerived> CreatePacket() {
|
||||
return std::make_unique<PacketDerived>();
|
||||
}
|
||||
|
||||
const std::unique_ptr<Packet>& CreateReadOnlyPacket(PacketType a_Type);
|
||||
|
||||
} // namespace PacketFactory
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <sp/common/DataBuffer.h>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
|
||||
class Packet;
|
||||
|
||||
using PacketPtr = std::unique_ptr<Packet>;
|
||||
|
||||
namespace PacketSerializer {
|
||||
|
||||
DataBuffer Serialize(const Packet& a_Packet);
|
||||
|
||||
std::unique_ptr<Packet> Deserialize(DataBuffer& a_Data);
|
||||
|
||||
} // namespace PacketSerializer
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \file PacketVisitor.h
|
||||
* \brief File containing the sp::protocol::PacketVisitor class
|
||||
*/
|
||||
|
||||
#include <sp/protocol/packet/Packets.h>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
|
||||
#define DeclarePacket(PacketName, ...) \
|
||||
/** This function is called when the packet processed by PacketVisitor::Check is a PacketName */ \
|
||||
virtual void Visit(const packets::PacketName&) {}
|
||||
|
||||
/**
|
||||
* \class PacketVisitor
|
||||
* \brief This class uses double-dispatch in order to find the real type of a packet
|
||||
*/
|
||||
class PacketVisitor : private NonCopyable {
|
||||
protected:
|
||||
PacketVisitor() {}
|
||||
virtual ~PacketVisitor() {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief Calls the right PacketVisitor::Visit method corresponding to the real type of the packet
|
||||
* \param packet the Packet to visit
|
||||
*/
|
||||
void Check(const Packet& packet);
|
||||
|
||||
DeclareAllPacket()
|
||||
};
|
||||
|
||||
#undef DeclarePacket
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
@@ -1,115 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \file Packets.h
|
||||
* \brief File containing the definitions of the packets
|
||||
*/
|
||||
|
||||
#include <sp/common/NonCopyable.h>
|
||||
#include <sp/protocol/packet/PacketData.h>
|
||||
#include <sp/protocol/packet/PacketDeclare.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace sp {
|
||||
namespace protocol {
|
||||
|
||||
class PacketVisitor;
|
||||
|
||||
/** A Packet id is 8 bits wide */
|
||||
using PacketID = std::uint8_t;
|
||||
using PeerID = std::uint16_t;
|
||||
|
||||
#define DeclarePacket(PacketName, ...) /** PacketName */ PacketName,
|
||||
|
||||
/**
|
||||
* \enum PacketType
|
||||
* \brief Map a Packet to an id
|
||||
*/
|
||||
enum class PacketType : PacketID {
|
||||
|
||||
DeclareAllPacket()
|
||||
|
||||
/** The number of packets */
|
||||
PACKET_COUNT
|
||||
};
|
||||
|
||||
|
||||
#undef DeclarePacket
|
||||
|
||||
|
||||
class Packet : private NonCopyable {
|
||||
public:
|
||||
/**
|
||||
* \return The real type of the packet
|
||||
*/
|
||||
virtual PacketType GetType() const = 0;
|
||||
|
||||
/**
|
||||
* \brief The network peer who sent the packet
|
||||
*/
|
||||
PeerID m_Sender;
|
||||
|
||||
private:
|
||||
/** Use a PacketVisitor to make double-dispatch possible */
|
||||
virtual void Accept(PacketVisitor& a_Visitor) const = 0;
|
||||
|
||||
friend class PacketVisitor;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace packets {
|
||||
|
||||
/**
|
||||
* \class ConcretePacket
|
||||
* \brief A Packet associated with an id and holding data
|
||||
* \tparam PT The packet type
|
||||
* \tparam Data The structure holding the data of the packet (in sp::protocol::data namespace)
|
||||
*/
|
||||
template <PacketType PT, typename Data>
|
||||
class ConcretePacket : public Packet {
|
||||
public:
|
||||
/** The type of the struct holding the data */
|
||||
using PacketDataType = Data;
|
||||
|
||||
/** The structure holding the actual data */
|
||||
PacketDataType m_Data;
|
||||
|
||||
/** Construct the packet with data of type PacketDataType */
|
||||
ConcretePacket(const PacketDataType& a_Data = {});
|
||||
|
||||
constexpr PacketType GetType() const override {
|
||||
return PT;
|
||||
};
|
||||
|
||||
private:
|
||||
void Accept(PacketVisitor& a_Visitor) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// define SP_INSTANCIATE_PACKETS
|
||||
// before including this file
|
||||
// if you want to instantiate templates
|
||||
#ifdef SP_INSTANCIATE_PACKETS
|
||||
#define DeclarePacket(PacketName, ...) \
|
||||
using PacketName = ConcretePacket<PacketType::PacketName, pdata::PacketName>; \
|
||||
template class ConcretePacket<PacketType::PacketName, pdata::PacketName>;
|
||||
#else
|
||||
#define DeclarePacket(PacketName, ...) /** Defines the PacketName packet */ \
|
||||
using PacketName = ConcretePacket<PacketType::PacketName, pdata::PacketName>;
|
||||
#endif
|
||||
|
||||
// DeclareAllPacket()
|
||||
|
||||
#undef DeclarePacket
|
||||
|
||||
} // namespace packets
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace sp
|
||||
Reference in New Issue
Block a user