Implemented more packets for keepAlive, chat and disconnect

This commit is contained in:
2020-07-16 22:37:19 +01:00
parent be8fa7b1f8
commit 63896c5090
7 changed files with 255 additions and 35 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QDateTime>
#include "mcdatastream.h" #include "mcdatastream.h"
#include "packets.h" #include "packets.h"
@@ -14,6 +15,12 @@ class Client : public QObject
public: public:
explicit Client(QTcpSocket *socket, QObject *parent = nullptr); explicit Client(QTcpSocket *socket, QObject *parent = nullptr);
SocketState state() const { return m_state; }
void keepAlive();
void sendChatMessage();
void trialDisconnect();
private Q_SLOTS: private Q_SLOTS:
void readyRead(); void readyRead();
void disconnected(); void disconnected();
@@ -30,4 +37,9 @@ private:
qint32 m_packetSize; qint32 m_packetSize;
SocketState m_state; SocketState m_state;
const QDateTime m_connectedSince;
QDateTime m_lastKeepAliveSent;
QDateTime m_lastKeepAliveReceived;
QDateTime m_lastChatMessage;
}; };

View File

@@ -1,6 +1,9 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <qlogging.h> #include <qlogging.h>
#include <QTcpServer> #include <QTcpServer>
#include <QList>
#include <QPointer>
#include <QTimer>
#include "client.h" #include "client.h"
@@ -19,10 +22,37 @@ int main(int argc, char *argv[])
"%{function}(): " "%{function}(): "
"%{message}")); "%{message}"));
QList<QPointer<Client>> clients;
QTimer timer;
timer.setInterval(100);
QObject::connect(&timer, &QTimer::timeout, [&clients](){
const auto now = QDateTime::currentDateTime();
for (auto iter = std::begin(clients); iter != std::end(clients); )
{
if ((*iter).isNull())
{
iter = clients.erase(iter);
continue;
}
auto &client = **iter;
if (client.state() == PlayState)
{
client.keepAlive();
client.sendChatMessage();
client.trialDisconnect();
}
iter++;
}
});
timer.start();
QTcpServer server; QTcpServer server;
QObject::connect(&server, &QTcpServer::newConnection, [&server](){ QObject::connect(&server, &QTcpServer::newConnection, [&server,&clients](){
new Client(server.nextPendingConnection()); clients.append(new Client(server.nextPendingConnection()));
}); });
if(!server.listen(QHostAddress::Any, 25565)) if(!server.listen(QHostAddress::Any, 25565))

View File

@@ -82,6 +82,20 @@ void McDataStream::writeDouble(double value)
setFloatingPointPrecision(precision); setFloatingPointPrecision(precision);
} }
QUuid McDataStream::readUuid()
{
char buf[16];
readRawData(buf, 16);
return {};
}
void McDataStream::writeUuid(const QUuid &uuid)
{
Q_UNUSED(uuid)
writeRawData("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16);
}
template<> template<>
qint32 McDataStream::readVar<qint32>(qint32 &bytesRead) qint32 McDataStream::readVar<qint32>(qint32 &bytesRead)
{ {

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <QDataStream> #include <QDataStream>
#include <QUuid>
#include <tuple> #include <tuple>
@@ -30,6 +31,9 @@ public:
template<typename T> template<typename T>
void writeVar(T value); void writeVar(T value);
QUuid readUuid();
void writeUuid(const QUuid &uuid);
}; };
template<typename T> template<typename T>

View File

@@ -26,7 +26,7 @@ void packets::status::clientbound::Response::serialize(McDataStream &stream)
{ {
QByteArray buffer; QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly); McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketResponse); tempStream.writeVar<qint32>(qint32(PacketType::Response));
tempStream.writeVar<QString>(jsonResponse); tempStream.writeVar<QString>(jsonResponse);
stream.writeVar<qint32>(buffer.length()); stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length()); stream.writeRawData(buffer.constData(), buffer.length());
@@ -36,7 +36,7 @@ void packets::status::clientbound::Pong::serialize(McDataStream &stream)
{ {
QByteArray buffer; QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly); McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketPong); tempStream.writeVar<qint32>(qint32(PacketType::Pong));
tempStream << payload; tempStream << payload;
stream.writeVar<qint32>(buffer.length()); stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length()); stream.writeRawData(buffer.constData(), buffer.length());
@@ -51,7 +51,8 @@ void packets::login::clientbound::LoginSuccess::serialize(McDataStream &stream)
{ {
QByteArray buffer; QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly); McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketLoginSuccess); tempStream.writeVar<qint32>(qint32(PacketType::LoginSuccess));
//tempStream.writeUuid(uuid);
tempStream.writeVar<QString>(uuid); tempStream.writeVar<QString>(uuid);
tempStream.writeVar<QString>(username); tempStream.writeVar<QString>(username);
stream.writeVar<qint32>(buffer.length()); stream.writeVar<qint32>(buffer.length());
@@ -68,6 +69,21 @@ packets::play::serverbound::ClientSettings::ClientSettings(McDataStream &stream)
mainHand = stream.readVar<qint32>(); mainHand = stream.readVar<qint32>();
} }
packets::play::serverbound::InteractEntity::InteractEntity(McDataStream &stream)
{
entityId = stream.readVar<qint32>();
type = Type(stream.readVar<qint32>());
switch (type)
{
case InteractAt:
targetX = stream.readFloat();
targetY = stream.readFloat();
targetZ = stream.readFloat();
case Interact:
hand = Hand(stream.readVar<qint32>());
}
}
packets::play::serverbound::PluginMessage::PluginMessage(McDataStream &stream) packets::play::serverbound::PluginMessage::PluginMessage(McDataStream &stream)
{ {
channel = stream.readVar<QString>(); channel = stream.readVar<QString>();
@@ -78,31 +94,52 @@ void packets::play::clientbound::ServerDifficulty::serialize(McDataStream &strea
{ {
QByteArray buffer; QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly); McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketServerDifficulty); tempStream.writeVar<qint32>(qint32(PacketType::ServerDifficulty));
tempStream << difficulty; tempStream << difficulty;
stream.writeVar<qint32>(buffer.length()); stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length()); stream.writeRawData(buffer.constData(), buffer.length());
} }
void packets::play::clientbound::ChatMessage::serialize(McDataStream &stream)
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(qint32(PacketType::ChatMessage));
tempStream.writeVar<QString>(jsonData);
tempStream << qint8(position);
stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length());
}
void packets::play::clientbound::PluginMessage::serialize(McDataStream &stream) void packets::play::clientbound::PluginMessage::serialize(McDataStream &stream)
{ {
QByteArray buffer; QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly); McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketPluginMessage); tempStream.writeVar<qint32>(qint32(PacketType::PluginMessage));
tempStream.writeVar<QString>(channel); tempStream.writeVar<QString>(channel);
buffer.append(data); buffer.append(data);
stream.writeVar<qint32>(buffer.length()); stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length()); stream.writeRawData(buffer.constData(), buffer.length());
} }
void packets::play::clientbound::Disconnect::serialize(McDataStream &stream)
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(qint32(PacketType::Disconnect));
tempStream.writeVar<QString>(reason);
stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length());
}
void packets::play::clientbound::JoinGame::serialize(McDataStream &stream) void packets::play::clientbound::JoinGame::serialize(McDataStream &stream)
{ {
QByteArray buffer; QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly); McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketJoinGame); tempStream.writeVar<qint32>(qint32(PacketType::JoinGame));
tempStream << entityid tempStream << entityid
<< gamemode << quint8(gamemode)
<< dimension << qint32(dimension)
<< difficulty << difficulty
<< maxPlayers; << maxPlayers;
tempStream.writeVar<QString>(levelType); tempStream.writeVar<QString>(levelType);
@@ -115,7 +152,7 @@ void packets::play::clientbound::PlayerAbilities::serialize(McDataStream &stream
{ {
QByteArray buffer; QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly); McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketPlayerAbilities); tempStream.writeVar<qint32>(qint32(PacketType::PlayerAbilities));
tempStream << flags; tempStream << flags;
tempStream.writeFloat(flyingSpeed); tempStream.writeFloat(flyingSpeed);
tempStream.writeFloat(fieldOfViewModifier); tempStream.writeFloat(fieldOfViewModifier);
@@ -127,7 +164,7 @@ void packets::play::clientbound::PlayerPositionAndLook::serialize(McDataStream &
{ {
QByteArray buffer; QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly); McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketPlayerPositionAndLook); tempStream.writeVar<qint32>(qint32(PacketType::PlayerPositionAndLook));
tempStream.writeDouble(x); tempStream.writeDouble(x);
tempStream.writeDouble(y); tempStream.writeDouble(y);
tempStream.writeDouble(z); tempStream.writeDouble(z);
@@ -143,8 +180,18 @@ void packets::play::clientbound::SpawnPosition::serialize(McDataStream &stream)
{ {
QByteArray buffer; QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly); McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketSpawnPosition); tempStream.writeVar<qint32>(qint32(PacketType::SpawnPosition));
tempStream.writePosition(location); tempStream.writePosition(location);
stream.writeVar<qint32>(buffer.length()); stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length()); stream.writeRawData(buffer.constData(), buffer.length());
} }
void packets::play::clientbound::KeepAlive::serialize(McDataStream &stream)
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(qint32(PacketType::KeepAlive));
tempStream << keepAliveId;
stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length());
}

View File

@@ -2,6 +2,8 @@
#include <QtGlobal> #include <QtGlobal>
#include <QString> #include <QString>
#include <QDebug>
#include <QtCore>
#include <tuple> #include <tuple>
@@ -12,7 +14,10 @@ enum SocketState { HandshakingState, StatusState, LoginState, PlayState, ClosedS
namespace packets { namespace packets {
namespace handshaking { namespace handshaking {
namespace serverbound { namespace serverbound {
enum PacketType { PacketHandshake }; Q_NAMESPACE
enum class PacketType { Handshake };
Q_ENUM_NS(PacketType)
struct Handshake { struct Handshake {
Handshake(McDataStream &stream); Handshake(McDataStream &stream);
@@ -30,7 +35,10 @@ namespace packets {
namespace status { namespace status {
namespace serverbound { namespace serverbound {
enum PacketType { PacketRequest, PacketPing }; Q_NAMESPACE
enum class PacketType { Request, Ping };
Q_ENUM_NS(PacketType)
struct Request { struct Request {
Request(McDataStream &stream); Request(McDataStream &stream);
@@ -44,7 +52,10 @@ namespace packets {
} }
namespace clientbound { namespace clientbound {
enum PacketType { PacketResponse, PacketPong }; Q_NAMESPACE
enum class PacketType { Response, Pong };
Q_ENUM_NS(PacketType)
struct Response { struct Response {
QString jsonResponse; QString jsonResponse;
@@ -62,7 +73,10 @@ namespace packets {
namespace login { namespace login {
namespace serverbound { namespace serverbound {
enum PacketType { PacketLogin }; Q_NAMESPACE
enum class PacketType { Login };
Q_ENUM_NS(PacketType)
struct Login { struct Login {
Login(McDataStream &stream); Login(McDataStream &stream);
@@ -72,7 +86,10 @@ namespace packets {
} }
namespace clientbound { namespace clientbound {
enum PacketType { PacketLoginSuccess = 0x02 }; Q_NAMESPACE
enum class PacketType { LoginSuccess = 0x02 };
Q_ENUM_NS(PacketType)
struct LoginSuccess { struct LoginSuccess {
QString uuid; QString uuid;
@@ -85,7 +102,10 @@ namespace packets {
namespace play { namespace play {
namespace serverbound { namespace serverbound {
enum PacketType { PacketClientSettings = 0x04, PacketPluginMessage = 0x0A }; Q_NAMESPACE
enum class PacketType { ClientSettings = 0x04, InteractEntity = 0x0E, PluginMessage = 0x0A };
Q_ENUM_NS(PacketType)
struct ClientSettings { struct ClientSettings {
ClientSettings(McDataStream &stream); ClientSettings(McDataStream &stream);
@@ -98,6 +118,19 @@ namespace packets {
qint32 mainHand; qint32 mainHand;
}; };
struct InteractEntity {
InteractEntity(McDataStream &stream);
qint32 entityId;
enum Type : qint32 { Interact, Attack, InteractAt };
Type type;
std::optional<float> targetX;
std::optional<float> targetY;
std::optional<float> targetZ;
enum Hand : qint32 { MainHand, OffHand };
std::optional<Hand> hand;
};
struct PluginMessage { struct PluginMessage {
PluginMessage(McDataStream &stream); PluginMessage(McDataStream &stream);
@@ -107,8 +140,11 @@ namespace packets {
} }
namespace clientbound { namespace clientbound {
enum PacketType { PacketServerDifficulty = 0x0D, PacketPluginMessage = 0x19, PacketJoinGame = 0x25, PacketPlayerAbilities = 0x2E, PacketPlayerPositionAndLook = 0x32, Q_NAMESPACE
PacketSpawnPosition = 0x49 };
enum class PacketType { ServerDifficulty = 0x0D, ChatMessage = 0x0E, PluginMessage = 0x19, Disconnect = 0x1B, KeepAlive = 0x21,
JoinGame = 0x25, PlayerAbilities = 0x2E, PlayerPositionAndLook = 0x32, SpawnPosition = 0x49 };
Q_ENUM_NS(PacketType)
struct ServerDifficulty { struct ServerDifficulty {
quint8 difficulty; quint8 difficulty;
@@ -116,6 +152,14 @@ namespace packets {
void serialize(McDataStream &stream); void serialize(McDataStream &stream);
}; };
struct ChatMessage {
QString jsonData;
enum Position : qint8 { Chat, SystemMessage, GameInfo };
Position position;
void serialize(McDataStream &stream);
};
struct PluginMessage { struct PluginMessage {
QString channel; QString channel;
QByteArray data; QByteArray data;
@@ -123,10 +167,18 @@ namespace packets {
void serialize(McDataStream &stream); void serialize(McDataStream &stream);
}; };
struct Disconnect {
QString reason;
void serialize(McDataStream &stream);
};
struct JoinGame { struct JoinGame {
qint32 entityid; qint32 entityid;
quint8 gamemode; enum Gamemode : quint8 { Survival, Creative, Adventure, Spectator, Hardcore = 0x08 };
qint32 dimension; Gamemode gamemode;
enum Dimension : qint32 { Nether=-1, Overworld=0, End=1 };
Dimension dimension;
quint8 difficulty; quint8 difficulty;
quint8 maxPlayers; quint8 maxPlayers;
QString levelType; QString levelType;
@@ -160,6 +212,12 @@ namespace packets {
void serialize(McDataStream &stream); void serialize(McDataStream &stream);
}; };
struct KeepAlive {
qint64 keepAliveId;
void serialize(McDataStream &stream);
};
} }
} }
} }