generated from Persson-dev/Godot-Xmake
Compare commits
4 Commits
65808e9dee
...
770e0281ef
| Author | SHA1 | Date | |
|---|---|---|---|
| 770e0281ef | |||
| 15a385a825 | |||
| 665dc4938f | |||
| ccb6870567 |
25
include/blitz/common/NonCopyable.h
Normal file
25
include/blitz/common/NonCopyable.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file NonCopyable.h
|
||||||
|
* \brief File containing the blitz::NonCopyable class
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class NonCopyable
|
||||||
|
* \brief Class used to make a class non copyable
|
||||||
|
* \note Inherit from this class privately to make a class non copyable
|
||||||
|
*/
|
||||||
|
class NonCopyable {
|
||||||
|
public:
|
||||||
|
NonCopyable(const NonCopyable&) = delete;
|
||||||
|
NonCopyable& operator=(const NonCopyable&) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NonCopyable() {}
|
||||||
|
~NonCopyable() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace blitz
|
||||||
11
include/blitz/common/Types.h
Normal file
11
include/blitz/common/Types.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
|
||||||
|
using EntityID = std::uint64_t;
|
||||||
|
using PeerID = std::int32_t;
|
||||||
|
using PlayerID = PeerID;
|
||||||
|
|
||||||
|
} // namespace blitz
|
||||||
89
include/blitz/protocol/ByteBuffer.h
Normal file
89
include/blitz/protocol/ByteBuffer.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <godot_cpp/variant/packed_byte_array.hpp>
|
||||||
|
#include <godot_cpp/variant/string.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
class PlayerInfo;
|
||||||
|
|
||||||
|
#define Operators(Type, GodotType) \
|
||||||
|
ByteBuffer& operator>>(Type& a_Data) { \
|
||||||
|
a_Data = m_Buffer.decode_##GodotType(m_ReadOffset); \
|
||||||
|
m_ReadOffset += sizeof(a_Data); \
|
||||||
|
return *this; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
ByteBuffer& operator<<(Type a_Data) { \
|
||||||
|
m_Buffer.resize(m_Buffer.size() + sizeof(a_Data)); \
|
||||||
|
m_Buffer.encode_##GodotType(m_Buffer.size() - sizeof(a_Data), a_Data); \
|
||||||
|
return *this; \
|
||||||
|
}
|
||||||
|
|
||||||
|
class ByteBuffer {
|
||||||
|
private:
|
||||||
|
godot::PackedByteArray m_Buffer;
|
||||||
|
std::size_t m_ReadOffset;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ByteBuffer(godot::PackedByteArray&& a_Buffer) : m_Buffer(std::move(a_Buffer)), m_ReadOffset(0) {}
|
||||||
|
ByteBuffer() : m_ReadOffset(0) {
|
||||||
|
m_Buffer.resize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const godot::PackedByteArray& GetByteArray() const {
|
||||||
|
return m_Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
godot::PackedByteArray& GetByteArray() {
|
||||||
|
return m_Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Integers
|
||||||
|
Operators(int8_t, s8);
|
||||||
|
Operators(uint8_t, u8);
|
||||||
|
Operators(int16_t, s16);
|
||||||
|
Operators(uint16_t, u16);
|
||||||
|
Operators(int32_t, s32);
|
||||||
|
Operators(uint32_t, u32);
|
||||||
|
Operators(int64_t, s64);
|
||||||
|
Operators(uint64_t, u64);
|
||||||
|
|
||||||
|
// Reals
|
||||||
|
Operators(float, float);
|
||||||
|
Operators(double, double);
|
||||||
|
|
||||||
|
ByteBuffer& operator<<(const godot::String& a_Data);
|
||||||
|
ByteBuffer& operator>>(godot::String& a_Data);
|
||||||
|
|
||||||
|
ByteBuffer& operator<<(const godot::Vector3& a_Data);
|
||||||
|
ByteBuffer& operator>>(godot::Vector3& a_Data);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ByteBuffer& operator<<(const std::vector<T>& a_Data) {
|
||||||
|
*this << static_cast<std::uint32_t>(a_Data.size());
|
||||||
|
for (const T& data : a_Data) {
|
||||||
|
*this << data;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ByteBuffer& operator>>(std::vector<T>& a_Data) {
|
||||||
|
std::uint32_t arraySize;
|
||||||
|
*this >> arraySize;
|
||||||
|
a_Data.resize(arraySize);
|
||||||
|
for (std::uint32_t i = 0; i < arraySize; i++) {
|
||||||
|
*this >> a_Data[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer& operator<<(const PlayerInfo& a_Data);
|
||||||
|
ByteBuffer& operator>>(PlayerInfo& a_Data);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
72
include/blitz/protocol/PacketData.h
Normal file
72
include/blitz/protocol/PacketData.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <blitz/common/Types.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <godot_cpp/variant/string.hpp>
|
||||||
|
#include <godot_cpp/variant/vector3.hpp>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
struct PlayerInfo {
|
||||||
|
PlayerID m_PlayerId;
|
||||||
|
godot::String m_PlayerName;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace data {
|
||||||
|
|
||||||
|
struct PlayerLogin {
|
||||||
|
godot::String m_PlayerName;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UpdateHealth {
|
||||||
|
float m_NewHealth;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LoggingSuccess {
|
||||||
|
PlayerID m_PlayerId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlayerDeath {};
|
||||||
|
|
||||||
|
struct PlayerJoin {
|
||||||
|
PlayerInfo m_Player;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlayerLeave {
|
||||||
|
PlayerID m_PlayerId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlayerStats {};
|
||||||
|
|
||||||
|
struct PlayerList {
|
||||||
|
std::vector<PlayerInfo> m_Players;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ServerConfig {};
|
||||||
|
|
||||||
|
struct ServerTps {};
|
||||||
|
|
||||||
|
struct UpdateGameState {};
|
||||||
|
|
||||||
|
struct KeepAlive {
|
||||||
|
std::uint64_t m_KeepAliveId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Disconnect {};
|
||||||
|
|
||||||
|
struct ChatMessage {
|
||||||
|
godot::String m_Text;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlayerPositionAndRotation {
|
||||||
|
PlayerID m_Player;
|
||||||
|
godot::Vector3 m_Position;
|
||||||
|
godot::Vector3 m_Rotation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlayerShoot {};
|
||||||
|
|
||||||
|
} // namespace data
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
49
include/blitz/protocol/PacketDeclare.h
Normal file
49
include/blitz/protocol/PacketDeclare.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file PacketDeclare.h
|
||||||
|
* \brief Holds the definitions of the packets (but not their content)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \enum PacketSender
|
||||||
|
* \brief Indicate who should send a packet
|
||||||
|
*/
|
||||||
|
enum class PacketSender {
|
||||||
|
/** Sent by clients and server */
|
||||||
|
Both,
|
||||||
|
/** Sent by clients to the server */
|
||||||
|
Client,
|
||||||
|
/** Sent by server to the clients */
|
||||||
|
Server,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def DeclareAllPacket
|
||||||
|
* \brief Avoids repetitive operations on packets
|
||||||
|
*/
|
||||||
|
#define DeclareAllPacket() \
|
||||||
|
DeclarePacket(ChatMessage, Reliable, Both) \
|
||||||
|
DeclarePacket(Disconnect, Reliable, Both) \
|
||||||
|
DeclarePacket(KeepAlive, Reliable, Both) \
|
||||||
|
DeclarePacket(LoggingSuccess, Reliable, Server) \
|
||||||
|
DeclarePacket(PlayerDeath, Reliable, Server) \
|
||||||
|
DeclarePacket(PlayerJoin, Reliable, Server) \
|
||||||
|
DeclarePacket(PlayerLeave, Reliable, Server) \
|
||||||
|
DeclarePacket(PlayerList, Reliable, Server) \
|
||||||
|
DeclarePacket(PlayerLogin, Reliable, Client) \
|
||||||
|
DeclarePacket(PlayerPositionAndRotation, Reliable, Both) \
|
||||||
|
DeclarePacket(PlayerShoot, Reliable, Both) \
|
||||||
|
DeclarePacket(PlayerStats, Reliable, Server) \
|
||||||
|
DeclarePacket(ServerConfig, Reliable, Server) \
|
||||||
|
DeclarePacket(ServerTps, Reliable, Server) \
|
||||||
|
DeclarePacket(UpdateGameState, Reliable, Server) \
|
||||||
|
DeclarePacket(UpdateHealth, Reliable, Client)
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
58
include/blitz/protocol/PacketDispatcher.h
Normal file
58
include/blitz/protocol/PacketDispatcher.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file PacketDispatcher.h
|
||||||
|
* \brief File containing the blitz::protocol::PacketDispatcher class
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <blitz/common/NonCopyable.h>
|
||||||
|
#include <blitz/protocol/Packets.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
class PacketHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class PacketDispatcher
|
||||||
|
* \brief Class used to dispatch packets
|
||||||
|
*/
|
||||||
|
class PacketDispatcher : private NonCopyable {
|
||||||
|
private:
|
||||||
|
std::map<PacketType, std::vector<PacketHandler*>> m_Handlers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief Constructor
|
||||||
|
*/
|
||||||
|
PacketDispatcher() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Dispatch a packet
|
||||||
|
* \param packet The packet to dispatch
|
||||||
|
*/
|
||||||
|
void Dispatch(const Packet& packet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Register a packet handler
|
||||||
|
* \param type The packet type
|
||||||
|
* \param handler The packet handler
|
||||||
|
*/
|
||||||
|
void RegisterHandler(PacketType type, PacketHandler& handler);
|
||||||
|
/**
|
||||||
|
* \brief Unregister a packet handler
|
||||||
|
* \param type The packet type
|
||||||
|
* \param handler The packet handler
|
||||||
|
*/
|
||||||
|
void UnregisterHandler(PacketType type, PacketHandler& handler);
|
||||||
|
/**
|
||||||
|
* \brief Unregister a packet handler
|
||||||
|
* \param handler The packet handler
|
||||||
|
*/
|
||||||
|
void UnregisterHandler(PacketHandler& handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
21
include/blitz/protocol/PacketFactory.h
Normal file
21
include/blitz/protocol/PacketFactory.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <blitz/protocol/Packets.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
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);
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
} // namespace PacketFactory
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
34
include/blitz/protocol/PacketHandler.h
Normal file
34
include/blitz/protocol/PacketHandler.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file PacketHandler.h
|
||||||
|
* \brief File containing the blitz::protocol::PacketHandler class
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <blitz/protocol/Packets.h>
|
||||||
|
#include <blitz/protocol/PacketVisitor.h>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
class PacketDispatcher;
|
||||||
|
|
||||||
|
#define DeclarePacket(PacketName, ...) virtual void Visit(const packets::PacketName&); virtual void HandlePacket(const packets::PacketName&) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class PacketHandler
|
||||||
|
* \brief Class used to handle packets
|
||||||
|
*/
|
||||||
|
class PacketHandler : public PacketVisitor {
|
||||||
|
public:
|
||||||
|
PacketHandler() {}
|
||||||
|
~PacketHandler() {}
|
||||||
|
|
||||||
|
DeclareAllPacket()
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef DeclarePacket
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
20
include/blitz/protocol/PacketSerializer.h
Normal file
20
include/blitz/protocol/PacketSerializer.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <blitz/protocol/Packets.h>
|
||||||
|
#include <godot_cpp/variant/packed_byte_array.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
using PacketPtr = std::unique_ptr<Packet>;
|
||||||
|
|
||||||
|
namespace PacketSerializer {
|
||||||
|
|
||||||
|
godot::PackedByteArray Serialize(const Packet& a_Packet);
|
||||||
|
|
||||||
|
std::unique_ptr<Packet> Deserialize(godot::PackedByteArray& a_Data);
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
39
include/blitz/protocol/PacketVisitor.h
Normal file
39
include/blitz/protocol/PacketVisitor.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file PacketVisitor.h
|
||||||
|
* \brief File containing the blitz::protocol::PacketVisitor class
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <blitz/protocol/Packets.h>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
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 blitz
|
||||||
112
include/blitz/protocol/Packets.h
Normal file
112
include/blitz/protocol/Packets.h
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file Packets.h
|
||||||
|
* \brief File containing the definitions of the packets
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <blitz/common/NonCopyable.h>
|
||||||
|
#include <blitz/protocol/PacketData.h>
|
||||||
|
#include <blitz/protocol/PacketDeclare.h>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
class PacketVisitor;
|
||||||
|
|
||||||
|
/** A Packet id is 8 bits wide */
|
||||||
|
using PacketID = std::uint8_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 blitz::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 BLITZ_INSTANCIATE_PACKETS
|
||||||
|
// before including this file
|
||||||
|
// if you want to instantiate templates
|
||||||
|
#ifdef BLITZ_INSTANCIATE_PACKETS
|
||||||
|
#define DeclarePacket(PacketName, ...) \
|
||||||
|
using PacketName = ConcretePacket<PacketType::PacketName, data::PacketName>; \
|
||||||
|
template class ConcretePacket<PacketType::PacketName, data::PacketName>;
|
||||||
|
#else
|
||||||
|
#define DeclarePacket(PacketName, ...) /** Defines the PacketName packet */ \
|
||||||
|
using PacketName = ConcretePacket<PacketType::PacketName, data::PacketName>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DeclareAllPacket()
|
||||||
|
|
||||||
|
#undef DeclarePacket
|
||||||
|
|
||||||
|
} // namespace packets
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
@@ -70,13 +70,13 @@ void Lobby::Shutdown() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lobby::OnPlayerConnected(int64_t a_PeerId) {
|
void Lobby::OnPlayerConnected(PeerID a_PeerId) {
|
||||||
if (get_multiplayer()->is_server()) {
|
if (get_multiplayer()->is_server()) {
|
||||||
emit_signal("player_connected", a_PeerId);
|
emit_signal("player_connected", a_PeerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lobby::OnPlayerDisconnected(int64_t a_PeerId) {
|
void Lobby::OnPlayerDisconnected(PeerID a_PeerId) {
|
||||||
if (get_multiplayer()->is_server()) {
|
if (get_multiplayer()->is_server()) {
|
||||||
emit_signal("player_disconnected", a_PeerId);
|
emit_signal("player_disconnected", a_PeerId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ class Lobby : public godot::Node {
|
|||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnPlayerConnected(int64_t a_PeerId);
|
void OnPlayerConnected(PeerID a_PeerId);
|
||||||
void OnPlayerDisconnected(int64_t a_PeerId);
|
void OnPlayerDisconnected(PeerID a_PeerId);
|
||||||
void OnConnectOk();
|
void OnConnectOk();
|
||||||
void OnConnectFail();
|
void OnConnectFail();
|
||||||
void OnServerDisconnected();
|
void OnServerDisconnected();
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "NetworkInterface.h"
|
#include "NetworkInterface.h"
|
||||||
|
|
||||||
|
#include <blitz/protocol/PacketFactory.h>
|
||||||
|
#include <blitz/protocol/PacketSerializer.h>
|
||||||
#include <godot_cpp/classes/multiplayer_api.hpp>
|
#include <godot_cpp/classes/multiplayer_api.hpp>
|
||||||
#include <godot_cpp/classes/multiplayer_peer.hpp>
|
#include <godot_cpp/classes/multiplayer_peer.hpp>
|
||||||
#include <godot_cpp/variant/utility_functions.hpp>
|
#include <godot_cpp/variant/utility_functions.hpp>
|
||||||
@@ -9,49 +11,40 @@ namespace blitz {
|
|||||||
using namespace godot;
|
using namespace godot;
|
||||||
|
|
||||||
void NetworkInterface::_bind_methods() {
|
void NetworkInterface::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("AddPlayer", "a_PlayerId", "a_PlayerName"), &NetworkInterface::AddPlayer);
|
ClassDB::bind_method(D_METHOD("RecievePacketDataReliable", "a_PacketData"), &NetworkInterface::RecievePacketDataReliable);
|
||||||
ClassDB::bind_method(D_METHOD("RemovePlayer", "a_PlayerId"), &NetworkInterface::RemovePlayer);
|
protocol::PacketFactory::Init();
|
||||||
ClassDB::bind_method(D_METHOD("SetPlayerPositionAndRotation", "a_PlayerId", "a_Position", "a_Rotation"),
|
|
||||||
&NetworkInterface::SetPlayerPositionAndRotation);
|
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("AddPlayer", PropertyInfo(Variant::INT, "a_PlayerId"), PropertyInfo(Variant::STRING, "a_PlayerName")));
|
|
||||||
ADD_SIGNAL(MethodInfo("RemovePlayer", PropertyInfo(Variant::INT, "a_PlayerId")));
|
|
||||||
ADD_SIGNAL(MethodInfo("SetPlayerPositionAndRotation", PropertyInfo(Variant::INT, "a_PlayerId"),
|
|
||||||
PropertyInfo(Variant::VECTOR3, "a_Position"), PropertyInfo(Variant::VECTOR3, "a_Rotation")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkInterface::NetworkInterface() {}
|
NetworkInterface::NetworkInterface() {}
|
||||||
|
|
||||||
NetworkInterface::~NetworkInterface() {}
|
NetworkInterface::~NetworkInterface() {}
|
||||||
|
|
||||||
void NetworkInterface::AddPlayer(int64_t a_PlayerId, godot::String a_PlayerName) {
|
|
||||||
emit_signal("AddPlayer", a_PlayerId, a_PlayerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetworkInterface::RemovePlayer(int64_t a_PlayerId) {
|
|
||||||
emit_signal("RemovePlayer", a_PlayerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetworkInterface::SetPlayerPositionAndRotation(int64_t a_PlayerId, Vector3 a_Position, Vector3 a_Rotation) {
|
|
||||||
emit_signal("SetPlayerPositionAndRotation", a_PlayerId, a_Position, a_Rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetworkInterface::_ready() {
|
void NetworkInterface::_ready() {
|
||||||
|
// TODO: unreliable
|
||||||
Dictionary config;
|
Dictionary config;
|
||||||
config["rpc_mode"] = MultiplayerAPI::RPC_MODE_AUTHORITY;
|
config["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER;
|
||||||
config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE;
|
config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE;
|
||||||
config["call_local"] = true;
|
config["call_local"] = true;
|
||||||
config["channel"] = 0;
|
config["channel"] = 0;
|
||||||
rpc_config("AddPlayer", config);
|
rpc_config("RecievePacketDataReliable", config);
|
||||||
rpc_config("RemovePlayer", config);
|
|
||||||
|
|
||||||
Dictionary config2;
|
|
||||||
config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE;
|
|
||||||
config["channel"] = 0;
|
|
||||||
config2["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER;
|
|
||||||
config2["call_local"] = false;
|
|
||||||
rpc_config("SetPlayerPositionAndRotation", config2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkInterface::BroadcastPacket(const protocol::Packet& a_Packet) {
|
||||||
|
PackedByteArray byteArray = protocol::PacketSerializer::Serialize(a_Packet);
|
||||||
|
rpc("RecievePacketDataReliable", byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkInterface::SendPacket(PeerID a_Peer, const protocol::Packet& a_Packet) {
|
||||||
|
PackedByteArray byteArray = protocol::PacketSerializer::Serialize(a_Packet);
|
||||||
|
rpc_id(a_Peer, "RecievePacketDataReliable", byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkInterface::RecievePacketDataReliable(godot::PackedByteArray a_PacketData) {
|
||||||
|
auto packet = protocol::PacketSerializer::Deserialize(a_PacketData);
|
||||||
|
if (packet) {
|
||||||
|
packet->m_Sender = get_multiplayer()->get_remote_sender_id();
|
||||||
|
Dispatch(*packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace blitz
|
} // namespace blitz
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <blitz/protocol/Packets.h>
|
||||||
#include <godot_cpp/classes/node.hpp>
|
#include <godot_cpp/classes/node.hpp>
|
||||||
|
#include <blitz/protocol/PacketDispatcher.h>
|
||||||
|
|
||||||
namespace blitz {
|
namespace blitz {
|
||||||
class NetworkInterface : public godot::Node {
|
class NetworkInterface : public godot::Node, public protocol::PacketDispatcher {
|
||||||
GDCLASS(NetworkInterface, godot::Node)
|
GDCLASS(NetworkInterface, godot::Node)
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
@@ -12,11 +14,13 @@ class NetworkInterface : public godot::Node {
|
|||||||
NetworkInterface();
|
NetworkInterface();
|
||||||
~NetworkInterface();
|
~NetworkInterface();
|
||||||
|
|
||||||
void AddPlayer(int64_t a_PlayerId, godot::String a_PlayerName);
|
void BroadcastPacket(const protocol::Packet& a_Packet);
|
||||||
void RemovePlayer(int64_t a_PlayerId);
|
void SendPacket(PeerID a_Peer, const protocol::Packet& a_Packet);
|
||||||
void SetPlayerPositionAndRotation(int64_t a_PlayerId, godot::Vector3 a_Position, godot::Vector3 a_Rotation);
|
|
||||||
|
|
||||||
void _ready() override;
|
void _ready() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RecievePacketDataReliable(godot::PackedByteArray a_PacketData);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blitz
|
} // namespace blitz
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <godot_cpp/classes/animation_tree.hpp>
|
#include <godot_cpp/classes/animation_tree.hpp>
|
||||||
#include <godot_cpp/classes/character_body3d.hpp>
|
#include <godot_cpp/classes/character_body3d.hpp>
|
||||||
#include <godot_cpp/classes/node3d.hpp>
|
#include <godot_cpp/classes/node3d.hpp>
|
||||||
|
#include <blitz/common/Types.h>
|
||||||
|
|
||||||
namespace blitz {
|
namespace blitz {
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ class Player : public godot::CharacterBody3D {
|
|||||||
godot::Vector3 GetCameraRotation() const;
|
godot::Vector3 GetCameraRotation() const;
|
||||||
void SetCameraRotation(const godot::Vector3& a_Rotation);
|
void SetCameraRotation(const godot::Vector3& a_Rotation);
|
||||||
|
|
||||||
uint64_t GetId() const {
|
PlayerID GetId() const {
|
||||||
return m_PeerId;
|
return m_PeerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ class Player : public godot::CharacterBody3D {
|
|||||||
|
|
||||||
godot::Vector3 m_SnapVector;
|
godot::Vector3 m_SnapVector;
|
||||||
float m_Speed;
|
float m_Speed;
|
||||||
uint64_t m_PeerId;
|
PeerID m_PeerId;
|
||||||
|
|
||||||
friend class World;
|
friend class World;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,17 +28,18 @@ void Server::_ready() {
|
|||||||
m_Lobby->connect("player_disconnected", callable_mp(this, &Server::OnPlayerDisconnect));
|
m_Lobby->connect("player_disconnected", callable_mp(this, &Server::OnPlayerDisconnect));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::OnPlayerConnect(uint64_t a_PeerId) {
|
void Server::OnPlayerConnect(PeerID a_PeerId) {
|
||||||
|
protocol::PlayerInfo playerInfo{a_PeerId, "whoami"};
|
||||||
for (int i = 0; i < m_Peers.size(); i++) {
|
for (int i = 0; i < m_Peers.size(); i++) {
|
||||||
m_NetworkInterface->rpc_id(a_PeerId, "AddPlayer", m_Peers[i], "Aucuneidee");
|
m_NetworkInterface->SendPacket(a_PeerId, protocol::packets::PlayerJoin({m_Peers[i], "whoami"}));
|
||||||
}
|
}
|
||||||
m_Peers.push_back(a_PeerId);
|
m_Peers.push_back(a_PeerId);
|
||||||
m_NetworkInterface->rpc("AddPlayer", a_PeerId, "Aucuneidee");
|
m_NetworkInterface->BroadcastPacket(protocol::packets::PlayerJoin({playerInfo}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::OnPlayerDisconnect(uint64_t a_PeerId) {
|
void Server::OnPlayerDisconnect(PeerID a_PeerId) {
|
||||||
m_Peers.erase(a_PeerId);
|
m_Peers.erase(a_PeerId);
|
||||||
m_NetworkInterface->rpc("RemovePlayer", a_PeerId);
|
m_NetworkInterface->BroadcastPacket(protocol::packets::PlayerLeave({a_PeerId}));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blitz
|
} // namespace blitz
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <godot_cpp/classes/node.hpp>
|
#include <godot_cpp/classes/node.hpp>
|
||||||
|
#include <blitz/common/Types.h>
|
||||||
|
|
||||||
namespace blitz {
|
namespace blitz {
|
||||||
|
|
||||||
@@ -18,14 +19,14 @@ class Server : public godot::Node {
|
|||||||
|
|
||||||
void _ready() override;
|
void _ready() override;
|
||||||
|
|
||||||
void OnPlayerConnect(uint64_t a_PeerId);
|
void OnPlayerConnect(PeerID a_PeerId);
|
||||||
void OnPlayerDisconnect(uint64_t a_PeerId);
|
void OnPlayerDisconnect(PeerID a_PeerId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Lobby* m_Lobby;
|
Lobby* m_Lobby;
|
||||||
NetworkInterface* m_NetworkInterface;
|
NetworkInterface* m_NetworkInterface;
|
||||||
|
|
||||||
godot::TypedArray<uint64_t> m_Peers;
|
godot::TypedArray<PeerID> m_Peers;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blitz
|
} // namespace blitz
|
||||||
@@ -32,37 +32,53 @@ void World::_ready() {
|
|||||||
m_NetworkInterface = Object::cast_to<NetworkInterface>(lobby->find_child("NetworkInterface"));
|
m_NetworkInterface = Object::cast_to<NetworkInterface>(lobby->find_child("NetworkInterface"));
|
||||||
DEV_ASSERT(m_NetworkInterface);
|
DEV_ASSERT(m_NetworkInterface);
|
||||||
|
|
||||||
m_NetworkInterface->connect("AddPlayer", callable_mp(this, &World::AddPlayer));
|
m_NetworkInterface->RegisterHandler(protocol::PacketType::PlayerJoin, *this);
|
||||||
m_NetworkInterface->connect("RemovePlayer", callable_mp(this, &World::RemovePlayer));
|
m_NetworkInterface->RegisterHandler(protocol::PacketType::PlayerLeave, *this);
|
||||||
m_NetworkInterface->connect("SetPlayerPositionAndRotation", callable_mp(this, &World::SetPlayerPositionAndRotation));
|
m_NetworkInterface->RegisterHandler(protocol::PacketType::PlayerPositionAndRotation, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
World::World() {}
|
World::World() {}
|
||||||
|
|
||||||
World::~World() {}
|
World::~World() {
|
||||||
|
if (Engine::get_singleton()->is_editor_hint())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_NetworkInterface->UnregisterHandler(*this);
|
||||||
|
}
|
||||||
|
|
||||||
void World::_process(float delta) {
|
void World::_process(float delta) {
|
||||||
#if DEBUG_ENABLED
|
#if DEBUG_ENABLED
|
||||||
if (Engine::get_singleton()->is_editor_hint())
|
if (Engine::get_singleton()->is_editor_hint())
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
m_PassedTime += delta;
|
||||||
|
if (m_PassedTime < 0.05f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// UtilityFunctions::print(m_PassedTime);
|
||||||
|
|
||||||
|
// m_PassedTime -= 0.05f;
|
||||||
|
// if (m_PassedTime > 0.5f)
|
||||||
|
// m_PassedTime = 0.0f;
|
||||||
|
|
||||||
if (get_multiplayer()->is_server()) {
|
if (get_multiplayer()->is_server()) {
|
||||||
for (int i = 0; i < m_Players->get_child_count(); i++) {
|
for (int i = 0; i < m_Players->get_child_count(); i++) {
|
||||||
Player* player = Object::cast_to<Player>(m_Players->get_child(i));
|
Player* player = Object::cast_to<Player>(m_Players->get_child(i));
|
||||||
DEV_ASSERT(player);
|
DEV_ASSERT(player);
|
||||||
m_NetworkInterface->rpc(
|
m_NetworkInterface->BroadcastPacket(
|
||||||
"SetPlayerPositionAndRotation", player->m_PeerId, player->get_position(), player->GetCameraRotation());
|
protocol::packets::PlayerPositionAndRotation({player->GetId(), player->get_position(), player->GetCameraRotation()}));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Player* player = GetPlayerById(get_multiplayer()->get_unique_id());
|
Player* player = GetPlayerById(get_multiplayer()->get_unique_id());
|
||||||
if (player)
|
if (player) {
|
||||||
m_NetworkInterface->rpc("SetPlayerPositionAndRotation", get_multiplayer()->get_unique_id(), player->get_position(),
|
m_NetworkInterface->BroadcastPacket(protocol::packets::PlayerPositionAndRotation(
|
||||||
player->GetCameraRotation());
|
{get_multiplayer()->get_unique_id(), player->get_position(), player->GetCameraRotation()}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* World::GetPlayerById(uint64_t a_PlayerId) {
|
Player* World::GetPlayerById(PlayerID a_PlayerId) {
|
||||||
String stringId = UtilityFunctions::var_to_str(a_PlayerId);
|
String stringId = UtilityFunctions::var_to_str(a_PlayerId);
|
||||||
for (int i = 0; i < m_Players->get_child_count(); i++) {
|
for (int i = 0; i < m_Players->get_child_count(); i++) {
|
||||||
Node* player = m_Players->get_child(i);
|
Node* player = m_Players->get_child(i);
|
||||||
@@ -73,8 +89,25 @@ Player* World::GetPlayerById(uint64_t a_PlayerId) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::AddPlayer(int32_t a_PlayerId, String a_PlayerName) {
|
void World::HandlePacket(const protocol::packets::PlayerJoin& a_PlayerJoin) {
|
||||||
UtilityFunctions::print("New Player with id : ", a_PlayerId);
|
const protocol::PlayerInfo& playerInfo = a_PlayerJoin.m_Data.m_Player;
|
||||||
|
AddPlayer(playerInfo.m_PlayerId, playerInfo.m_PlayerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::HandlePacket(const protocol::packets::PlayerLeave& a_PlayerLeave) {
|
||||||
|
RemovePlayer(a_PlayerLeave.m_Data.m_PlayerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::HandlePacket(const protocol::packets::PlayerPositionAndRotation& a_PlayerPos) {
|
||||||
|
const auto& data = a_PlayerPos.m_Data;
|
||||||
|
if (data.m_Player == get_multiplayer()->get_unique_id() || data.m_Player != a_PlayerPos.m_Sender)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetPlayerPositionAndRotation(data.m_Player, data.m_Position, data.m_Rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::AddPlayer(PlayerID a_PlayerId, String a_PlayerName) {
|
||||||
|
UtilityFunctions::print("New Player with id : ", a_PlayerId, " and name ", a_PlayerName);
|
||||||
if (a_PlayerId == get_multiplayer()->get_unique_id()) {
|
if (a_PlayerId == get_multiplayer()->get_unique_id()) {
|
||||||
Ref<PackedScene> serverScene = ResourceLoader::get_singleton()->load(FirstPersonPlayerScenePath);
|
Ref<PackedScene> serverScene = ResourceLoader::get_singleton()->load(FirstPersonPlayerScenePath);
|
||||||
FirstPersonPlayer* player = Object::cast_to<FirstPersonPlayer>(serverScene->instantiate());
|
FirstPersonPlayer* player = Object::cast_to<FirstPersonPlayer>(serverScene->instantiate());
|
||||||
@@ -90,7 +123,7 @@ void World::AddPlayer(int32_t a_PlayerId, String a_PlayerName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::RemovePlayer(int32_t a_PlayerId) {
|
void World::RemovePlayer(PlayerID a_PlayerId) {
|
||||||
UtilityFunctions::print("Removing Player with id : ", a_PlayerId);
|
UtilityFunctions::print("Removing Player with id : ", a_PlayerId);
|
||||||
Player* player = GetPlayerById(a_PlayerId);
|
Player* player = GetPlayerById(a_PlayerId);
|
||||||
if (player) {
|
if (player) {
|
||||||
@@ -98,10 +131,7 @@ void World::RemovePlayer(int32_t a_PlayerId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::SetPlayerPositionAndRotation(int64_t a_PlayerId, Vector3 a_Position, Vector3 a_Rotation) {
|
void World::SetPlayerPositionAndRotation(PlayerID a_PlayerId, const Vector3& a_Position, const Vector3& a_Rotation) {
|
||||||
if (a_PlayerId == get_multiplayer()->get_unique_id())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Player* player = GetPlayerById(a_PlayerId);
|
Player* player = GetPlayerById(a_PlayerId);
|
||||||
if (player) {
|
if (player) {
|
||||||
player->set_position(a_Position);
|
player->set_position(a_Position);
|
||||||
|
|||||||
21
src/World.h
21
src/World.h
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
#include <godot_cpp/classes/node3d.hpp>
|
#include <godot_cpp/classes/node3d.hpp>
|
||||||
|
|
||||||
|
#include <blitz/protocol/PacketHandler.h>
|
||||||
|
|
||||||
namespace blitz {
|
namespace blitz {
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class NetworkInterface;
|
class NetworkInterface;
|
||||||
|
|
||||||
class World : public godot::Node3D {
|
class World : public godot::Node3D, public protocol::PacketHandler {
|
||||||
GDCLASS(World, godot::Node3D)
|
GDCLASS(World, godot::Node3D)
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
@@ -16,19 +18,24 @@ class World : public godot::Node3D {
|
|||||||
World();
|
World();
|
||||||
~World();
|
~World();
|
||||||
|
|
||||||
|
// Godot overrides
|
||||||
|
void _ready() override;
|
||||||
void _process(float delta);
|
void _process(float delta);
|
||||||
|
|
||||||
void _ready() override;
|
Player* GetPlayerById(PlayerID a_PlayerId);
|
||||||
|
|
||||||
Player* GetPlayerById(uint64_t a_PlayerId);
|
void HandlePacket(const protocol::packets::PlayerJoin&) override;
|
||||||
|
void HandlePacket(const protocol::packets::PlayerLeave&) override;
|
||||||
void AddPlayer(int32_t a_PlayerId, godot::String a_PlayerName);
|
void HandlePacket(const protocol::packets::PlayerPositionAndRotation&) override;
|
||||||
void RemovePlayer(int32_t a_PlayerId);
|
|
||||||
void SetPlayerPositionAndRotation(int64_t a_PlayerId, godot::Vector3 a_Position, godot::Vector3 a_Rotation);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NetworkInterface* m_NetworkInterface;
|
NetworkInterface* m_NetworkInterface;
|
||||||
godot::Node* m_Players;
|
godot::Node* m_Players;
|
||||||
float m_PassedTime;
|
float m_PassedTime;
|
||||||
|
|
||||||
|
|
||||||
|
void AddPlayer(PlayerID a_PlayerId, godot::String a_PlayerName);
|
||||||
|
void RemovePlayer(PlayerID a_PlayerId);
|
||||||
|
void SetPlayerPositionAndRotation(PlayerID a_PlayerId, const godot::Vector3& a_Position, const godot::Vector3& a_Rotation);
|
||||||
};
|
};
|
||||||
} // namespace blitz
|
} // namespace blitz
|
||||||
49
src/blitz/protocol/ByteBuffer.cpp
Normal file
49
src/blitz/protocol/ByteBuffer.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#include <blitz/protocol/ByteBuffer.h>
|
||||||
|
|
||||||
|
#include <blitz/protocol/PacketData.h>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
ByteBuffer& ByteBuffer::operator>>(PlayerInfo& a_Data) {
|
||||||
|
*this >> a_Data.m_PlayerId >> a_Data.m_PlayerName;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer& ByteBuffer::operator<<(const PlayerInfo& a_Data) {
|
||||||
|
*this << a_Data.m_PlayerId << a_Data.m_PlayerName;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer& ByteBuffer::operator<<(const godot::Vector3& a_Data) {
|
||||||
|
*this << a_Data.x << a_Data.y << a_Data.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer& ByteBuffer::operator>>(godot::Vector3& a_Data) {
|
||||||
|
*this >> a_Data.x >> a_Data.y >> a_Data.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer& ByteBuffer::operator>>(godot::String& a_Data) {
|
||||||
|
int nullPos = m_Buffer.find(0, m_ReadOffset);
|
||||||
|
// TODO: error handling
|
||||||
|
if (nullPos < 0)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
godot::PackedByteArray stringBuffer = m_Buffer.slice(m_ReadOffset, nullPos);
|
||||||
|
a_Data = stringBuffer.get_string_from_utf8();
|
||||||
|
m_ReadOffset = nullPos + 1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer& ByteBuffer::operator<<(const godot::String& a_Data) {
|
||||||
|
godot::PackedByteArray stringBuffer = a_Data.to_utf8_buffer();
|
||||||
|
m_Buffer.append_array(stringBuffer);
|
||||||
|
// ends the string
|
||||||
|
*this << static_cast<std::uint8_t>(0);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
37
src/blitz/protocol/PacketDispatcher.cpp
Normal file
37
src/blitz/protocol/PacketDispatcher.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#include <blitz/protocol/PacketDispatcher.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <blitz/protocol/PacketHandler.h>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
void PacketDispatcher::RegisterHandler(PacketType type, PacketHandler& handler) {
|
||||||
|
auto found = std::find(m_Handlers[type].begin(), m_Handlers[type].end(), &handler);
|
||||||
|
if (found == m_Handlers[type].end())
|
||||||
|
m_Handlers[type].push_back(&handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDispatcher::UnregisterHandler(PacketType type, PacketHandler& handler) {
|
||||||
|
m_Handlers[type].erase(std::remove(m_Handlers[type].begin(), m_Handlers[type].end(), &handler), m_Handlers[type].end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDispatcher::UnregisterHandler(PacketHandler& handler) {
|
||||||
|
for (auto& pair : m_Handlers) {
|
||||||
|
if (pair.second.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PacketType type = pair.first;
|
||||||
|
|
||||||
|
m_Handlers[type].erase(std::remove(m_Handlers[type].begin(), m_Handlers[type].end(), &handler), m_Handlers[type].end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PacketDispatcher::Dispatch(const Packet& packet) {
|
||||||
|
PacketType type = packet.GetType();
|
||||||
|
for (PacketHandler* handler : m_Handlers[type])
|
||||||
|
handler->Check(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
32
src/blitz/protocol/PacketFactory.cpp
Normal file
32
src/blitz/protocol/PacketFactory.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include <blitz/protocol/PacketFactory.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
namespace PacketFactory {
|
||||||
|
|
||||||
|
using PacketCreator = std::function<std::unique_ptr<Packet>()>;
|
||||||
|
|
||||||
|
#define DeclarePacket(PacketName, ...) std::make_unique<packets::PacketName>(),
|
||||||
|
|
||||||
|
static std::array<std::unique_ptr<Packet>, static_cast<std::size_t>(PacketType::PACKET_COUNT)> Packets;
|
||||||
|
|
||||||
|
void Init() {
|
||||||
|
Packets = {
|
||||||
|
|
||||||
|
DeclareAllPacket()
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::unique_ptr<Packet>& CreateReadOnlyPacket(PacketType a_Type) {
|
||||||
|
assert(a_Type < PacketType::PACKET_COUNT);
|
||||||
|
return Packets[static_cast<std::size_t>(a_Type)];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PacketFactory
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
14
src/blitz/protocol/PacketHandler.cpp
Normal file
14
src/blitz/protocol/PacketHandler.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include <blitz/protocol/PacketHandler.h>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
#define DeclarePacket(PacketName, ...) \
|
||||||
|
void PacketHandler::Visit(const packets::PacketName& a_Packet) { \
|
||||||
|
HandlePacket(a_Packet); \
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclareAllPacket()
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
294
src/blitz/protocol/PacketSerializer.cpp
Normal file
294
src/blitz/protocol/PacketSerializer.cpp
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
#include <blitz/protocol/PacketSerializer.h>
|
||||||
|
|
||||||
|
#include <blitz/protocol/ByteBuffer.h>
|
||||||
|
#include <blitz/protocol/PacketFactory.h>
|
||||||
|
#include <blitz/protocol/PacketVisitor.h>
|
||||||
|
|
||||||
|
#include <godot_cpp/variant/utility_functions.hpp>
|
||||||
|
#include <godot_cpp/variant/variant.hpp>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
namespace PacketSerializer {
|
||||||
|
|
||||||
|
#define DeclarePacket(PacketName, ...) \
|
||||||
|
void Visit(const packets::PacketName& a_Packet) override { \
|
||||||
|
const auto& packetData = a_Packet.m_Data; \
|
||||||
|
SerializePacketData(packetData); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void SerializePacketData(const packets::PacketName::PacketDataType& a_Packet);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Serializer : public PacketVisitor {
|
||||||
|
private:
|
||||||
|
ByteBuffer& m_Buffer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Serializer(ByteBuffer& a_Buffer) : m_Buffer(a_Buffer) {}
|
||||||
|
|
||||||
|
void Serialize(const Packet& a_Packet) {
|
||||||
|
m_Buffer << static_cast<PacketID>(a_Packet.GetType());
|
||||||
|
Check(a_Packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclareAllPacket()
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef DeclarePacket
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define DeclarePacket(PacketName, ...) \
|
||||||
|
void Visit(const packets::PacketName& a_Packet) override { \
|
||||||
|
auto packetPtr = PacketFactory::CreatePacket<packets::PacketName>(); \
|
||||||
|
auto& packetData = packetPtr->m_Data; \
|
||||||
|
\
|
||||||
|
DeserializePacketData(packetData); \
|
||||||
|
\
|
||||||
|
m_Packet = std::move(packetPtr); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void DeserializePacketData(packets::PacketName::PacketDataType& a_Packet);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Deserializer : public PacketVisitor {
|
||||||
|
private:
|
||||||
|
ByteBuffer& m_Buffer;
|
||||||
|
PacketPtr m_Packet;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Deserializer(ByteBuffer&& a_Buffer) : m_Buffer(a_Buffer) {}
|
||||||
|
|
||||||
|
bool Deserialize(const PacketPtr& a_Packet) {
|
||||||
|
try {
|
||||||
|
Check(*a_Packet.get());
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketPtr& GetPacket() {
|
||||||
|
return m_Packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclareAllPacket()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
godot::PackedByteArray Serialize(const Packet& a_Packet) {
|
||||||
|
ByteBuffer stream;
|
||||||
|
|
||||||
|
Serializer serializer(stream);
|
||||||
|
serializer.Serialize(a_Packet);
|
||||||
|
|
||||||
|
return stream.GetByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Packet> Deserialize(godot::PackedByteArray& a_Data) {
|
||||||
|
ByteBuffer stream(std::move(a_Data));
|
||||||
|
|
||||||
|
PacketID packetId;
|
||||||
|
stream >> packetId;
|
||||||
|
|
||||||
|
if (packetId >= static_cast<PacketID>(PacketType::PACKET_COUNT))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
PacketType packetType = PacketType(packetId);
|
||||||
|
|
||||||
|
// for double-dispatch
|
||||||
|
const PacketPtr& emptyPacket = PacketFactory::CreateReadOnlyPacket(packetType);
|
||||||
|
|
||||||
|
Deserializer deserializer(std::move(stream));
|
||||||
|
if (deserializer.Deserialize(emptyPacket)) {
|
||||||
|
PacketPtr packet = std::move(deserializer.GetPacket());
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------
|
||||||
|
// Packet serializer implementation
|
||||||
|
//----------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::PlayerLogin& a_Packet) {
|
||||||
|
m_Buffer << a_Packet.m_PlayerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::PlayerLogin& a_Packet) {
|
||||||
|
m_Buffer >> a_Packet.m_PlayerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::UpdateHealth& a_Packet) {
|
||||||
|
m_Buffer << a_Packet.m_NewHealth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::UpdateHealth& a_Packet) {
|
||||||
|
m_Buffer >> a_Packet.m_NewHealth;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::LoggingSuccess& a_Packet) {
|
||||||
|
m_Buffer << a_Packet.m_PlayerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::LoggingSuccess& a_Packet) {
|
||||||
|
m_Buffer >> a_Packet.m_PlayerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::PlayerDeath& a_Packet) {}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::PlayerDeath& a_Packet) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::PlayerJoin& a_Packet) {
|
||||||
|
m_Buffer << a_Packet.m_Player;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::PlayerJoin& a_Packet) {
|
||||||
|
m_Buffer >> a_Packet.m_Player;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::PlayerLeave& a_Packet) {
|
||||||
|
m_Buffer << a_Packet.m_PlayerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::PlayerLeave& a_Packet) {
|
||||||
|
m_Buffer >> a_Packet.m_PlayerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::PlayerList& a_Packet) {
|
||||||
|
m_Buffer << a_Packet.m_Players;
|
||||||
|
// m_Buffer << static_cast<std::uint8_t>(a_Packet.m_Players.size());
|
||||||
|
// for (auto player : a_Packet.m_Players) {
|
||||||
|
// m_Buffer << player.m_PlayerId << player.m_PlayerName;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::PlayerList& a_Packet) {
|
||||||
|
m_Buffer >> a_Packet.m_Players;
|
||||||
|
// std::uint8_t playerCount;
|
||||||
|
// m_Buffer >> playerCount;
|
||||||
|
// for (std::uint8_t i = 0; i < playerCount; i++) {
|
||||||
|
// PlayerInfo player;
|
||||||
|
// m_Buffer >> player.m_PlayerId >> player.m_PlayerName;
|
||||||
|
// a_Packet.m_Players.push_back(player);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::PlayerStats& a_Packet) {}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::PlayerStats& a_Packet) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::ServerConfig& a_Packet) {}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::ServerConfig& a_Packet) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::ServerTps& a_Packet) {}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::ServerTps& a_Packet) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::UpdateGameState& a_Packet) {}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::UpdateGameState& a_Packet) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::KeepAlive& a_Packet) {
|
||||||
|
m_Buffer << a_Packet.m_KeepAliveId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::KeepAlive& a_Packet) {
|
||||||
|
m_Buffer >> a_Packet.m_KeepAliveId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::Disconnect& a_Packet) {}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::Disconnect& a_Packet) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::ChatMessage& a_Packet) {
|
||||||
|
m_Buffer << a_Packet.m_Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::ChatMessage& a_Packet) {
|
||||||
|
m_Buffer >> a_Packet.m_Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::PlayerPositionAndRotation& a_Packet) {
|
||||||
|
m_Buffer << a_Packet.m_Player << a_Packet.m_Position << a_Packet.m_Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::PlayerPositionAndRotation& a_Packet) {
|
||||||
|
m_Buffer >> a_Packet.m_Player >> a_Packet.m_Position >> a_Packet.m_Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Serializer::SerializePacketData(const data::PlayerShoot& a_Packet) {}
|
||||||
|
|
||||||
|
void Deserializer::DeserializePacketData(data::PlayerShoot& a_Packet) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace PacketSerializer
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
11
src/blitz/protocol/PacketVisitor.cpp
Normal file
11
src/blitz/protocol/PacketVisitor.cpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include <blitz/protocol/PacketVisitor.h>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
void PacketVisitor::Check(const Packet& a_Packet) {
|
||||||
|
a_Packet.Accept(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
18
src/blitz/protocol/Packets.cpp
Normal file
18
src/blitz/protocol/Packets.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#define BLITZ_INSTANCIATE_PACKETS
|
||||||
|
#include <blitz/protocol/Packets.h>
|
||||||
|
|
||||||
|
#include <blitz/protocol/PacketVisitor.h>
|
||||||
|
|
||||||
|
namespace blitz {
|
||||||
|
namespace protocol {
|
||||||
|
|
||||||
|
template <PacketType PT, typename Data>
|
||||||
|
packets::ConcretePacket<PT, Data>::ConcretePacket(const PacketDataType& a_Data) : m_Data(a_Data) {}
|
||||||
|
|
||||||
|
template <PacketType PT, typename Data>
|
||||||
|
void packets::ConcretePacket<PT, Data>::Accept(PacketVisitor& a_Visitor) const {
|
||||||
|
a_Visitor.Visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace blitz
|
||||||
@@ -17,15 +17,15 @@
|
|||||||
using namespace godot;
|
using namespace godot;
|
||||||
|
|
||||||
static void RegisterClasses() {
|
static void RegisterClasses() {
|
||||||
ClassDB::register_class<blitz::Player>();
|
GDREGISTER_CLASS(blitz::Player);
|
||||||
ClassDB::register_class<blitz::SpringArmPivot>();
|
GDREGISTER_CLASS(blitz::SpringArmPivot);
|
||||||
ClassDB::register_class<blitz::FirstPersonPlayer>();
|
GDREGISTER_CLASS(blitz::FirstPersonPlayer);
|
||||||
ClassDB::register_class<blitz::MainMenu>();
|
GDREGISTER_CLASS(blitz::MainMenu);
|
||||||
ClassDB::register_class<blitz::Lobby>();
|
GDREGISTER_CLASS(blitz::Lobby);
|
||||||
ClassDB::register_class<blitz::World>();
|
GDREGISTER_CLASS(blitz::World);
|
||||||
ClassDB::register_class<blitz::Main>();
|
GDREGISTER_CLASS(blitz::Main);
|
||||||
ClassDB::register_class<blitz::NetworkInterface>();
|
GDREGISTER_CLASS(blitz::NetworkInterface);
|
||||||
ClassDB::register_class<blitz::Server>();
|
GDREGISTER_CLASS(blitz::Server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize_example_module(ModuleInitializationLevel p_level) {
|
void initialize_example_module(ModuleInitializationLevel p_level) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ add_rules("mode.debug", "mode.release")
|
|||||||
set_languages("c++20")
|
set_languages("c++20")
|
||||||
|
|
||||||
-- use latest 4.x version by default
|
-- use latest 4.x version by default
|
||||||
add_requires("godotcpp4")
|
add_requires("godotcpp4 4.2")
|
||||||
|
|
||||||
|
|
||||||
includes("tasks.lua")
|
includes("tasks.lua")
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ target(PROJECT_NAME)
|
|||||||
-- more on https://xmake.io/#/manual/project_target?id=targetadd_files
|
-- more on https://xmake.io/#/manual/project_target?id=targetadd_files
|
||||||
add_files("../src/**.cpp")
|
add_files("../src/**.cpp")
|
||||||
|
|
||||||
|
add_includedirs("../include")
|
||||||
|
|
||||||
-- change the output name
|
-- change the output name
|
||||||
set_basename(PROJECT_NAME .. ".$(os)_$(mode)_$(arch)")
|
set_basename(PROJECT_NAME .. ".$(os)_$(mode)_$(arch)")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user