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
#include <QObject>
#include <QDateTime>
#include "mcdatastream.h"
#include "packets.h"
@@ -14,6 +15,12 @@ class Client : public QObject
public:
explicit Client(QTcpSocket *socket, QObject *parent = nullptr);
SocketState state() const { return m_state; }
void keepAlive();
void sendChatMessage();
void trialDisconnect();
private Q_SLOTS:
void readyRead();
void disconnected();
@@ -30,4 +37,9 @@ private:
qint32 m_packetSize;
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 <qlogging.h>
#include <QTcpServer>
#include <QList>
#include <QPointer>
#include <QTimer>
#include "client.h"
@@ -19,10 +22,37 @@ int main(int argc, char *argv[])
"%{function}(): "
"%{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;
QObject::connect(&server, &QTcpServer::newConnection, [&server](){
new Client(server.nextPendingConnection());
QObject::connect(&server, &QTcpServer::newConnection, [&server,&clients](){
clients.append(new Client(server.nextPendingConnection()));
});
if(!server.listen(QHostAddress::Any, 25565))

View File

@@ -82,6 +82,20 @@ void McDataStream::writeDouble(double value)
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<>
qint32 McDataStream::readVar<qint32>(qint32 &bytesRead)
{

View File

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

View File

@@ -26,7 +26,7 @@ void packets::status::clientbound::Response::serialize(McDataStream &stream)
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketResponse);
tempStream.writeVar<qint32>(qint32(PacketType::Response));
tempStream.writeVar<QString>(jsonResponse);
stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length());
@@ -36,7 +36,7 @@ void packets::status::clientbound::Pong::serialize(McDataStream &stream)
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketPong);
tempStream.writeVar<qint32>(qint32(PacketType::Pong));
tempStream << payload;
stream.writeVar<qint32>(buffer.length());
stream.writeRawData(buffer.constData(), buffer.length());
@@ -51,7 +51,8 @@ void packets::login::clientbound::LoginSuccess::serialize(McDataStream &stream)
{
QByteArray buffer;
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>(username);
stream.writeVar<qint32>(buffer.length());
@@ -68,6 +69,21 @@ packets::play::serverbound::ClientSettings::ClientSettings(McDataStream &stream)
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)
{
channel = stream.readVar<QString>();
@@ -78,31 +94,52 @@ void packets::play::clientbound::ServerDifficulty::serialize(McDataStream &strea
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketServerDifficulty);
tempStream.writeVar<qint32>(qint32(PacketType::ServerDifficulty));
tempStream << difficulty;
stream.writeVar<qint32>(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)
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketPluginMessage);
tempStream.writeVar<qint32>(qint32(PacketType::PluginMessage));
tempStream.writeVar<QString>(channel);
buffer.append(data);
stream.writeVar<qint32>(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)
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketJoinGame);
tempStream.writeVar<qint32>(qint32(PacketType::JoinGame));
tempStream << entityid
<< gamemode
<< dimension
<< quint8(gamemode)
<< qint32(dimension)
<< difficulty
<< maxPlayers;
tempStream.writeVar<QString>(levelType);
@@ -115,7 +152,7 @@ void packets::play::clientbound::PlayerAbilities::serialize(McDataStream &stream
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketPlayerAbilities);
tempStream.writeVar<qint32>(qint32(PacketType::PlayerAbilities));
tempStream << flags;
tempStream.writeFloat(flyingSpeed);
tempStream.writeFloat(fieldOfViewModifier);
@@ -127,7 +164,7 @@ void packets::play::clientbound::PlayerPositionAndLook::serialize(McDataStream &
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketPlayerPositionAndLook);
tempStream.writeVar<qint32>(qint32(PacketType::PlayerPositionAndLook));
tempStream.writeDouble(x);
tempStream.writeDouble(y);
tempStream.writeDouble(z);
@@ -143,8 +180,18 @@ void packets::play::clientbound::SpawnPosition::serialize(McDataStream &stream)
{
QByteArray buffer;
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
tempStream.writeVar<qint32>(PacketSpawnPosition);
tempStream.writeVar<qint32>(qint32(PacketType::SpawnPosition));
tempStream.writePosition(location);
stream.writeVar<qint32>(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 <QString>
#include <QDebug>
#include <QtCore>
#include <tuple>
@@ -12,7 +14,10 @@ enum SocketState { HandshakingState, StatusState, LoginState, PlayState, ClosedS
namespace packets {
namespace handshaking {
namespace serverbound {
enum PacketType { PacketHandshake };
Q_NAMESPACE
enum class PacketType { Handshake };
Q_ENUM_NS(PacketType)
struct Handshake {
Handshake(McDataStream &stream);
@@ -30,7 +35,10 @@ namespace packets {
namespace status {
namespace serverbound {
enum PacketType { PacketRequest, PacketPing };
Q_NAMESPACE
enum class PacketType { Request, Ping };
Q_ENUM_NS(PacketType)
struct Request {
Request(McDataStream &stream);
@@ -44,7 +52,10 @@ namespace packets {
}
namespace clientbound {
enum PacketType { PacketResponse, PacketPong };
Q_NAMESPACE
enum class PacketType { Response, Pong };
Q_ENUM_NS(PacketType)
struct Response {
QString jsonResponse;
@@ -62,7 +73,10 @@ namespace packets {
namespace login {
namespace serverbound {
enum PacketType { PacketLogin };
Q_NAMESPACE
enum class PacketType { Login };
Q_ENUM_NS(PacketType)
struct Login {
Login(McDataStream &stream);
@@ -72,7 +86,10 @@ namespace packets {
}
namespace clientbound {
enum PacketType { PacketLoginSuccess = 0x02 };
Q_NAMESPACE
enum class PacketType { LoginSuccess = 0x02 };
Q_ENUM_NS(PacketType)
struct LoginSuccess {
QString uuid;
@@ -85,7 +102,10 @@ namespace packets {
namespace play {
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 {
ClientSettings(McDataStream &stream);
@@ -98,6 +118,19 @@ namespace packets {
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 {
PluginMessage(McDataStream &stream);
@@ -107,8 +140,11 @@ namespace packets {
}
namespace clientbound {
enum PacketType { PacketServerDifficulty = 0x0D, PacketPluginMessage = 0x19, PacketJoinGame = 0x25, PacketPlayerAbilities = 0x2E, PacketPlayerPositionAndLook = 0x32,
PacketSpawnPosition = 0x49 };
Q_NAMESPACE
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 {
quint8 difficulty;
@@ -116,6 +152,14 @@ namespace packets {
void serialize(McDataStream &stream);
};
struct ChatMessage {
QString jsonData;
enum Position : qint8 { Chat, SystemMessage, GameInfo };
Position position;
void serialize(McDataStream &stream);
};
struct PluginMessage {
QString channel;
QByteArray data;
@@ -123,10 +167,18 @@ namespace packets {
void serialize(McDataStream &stream);
};
struct Disconnect {
QString reason;
void serialize(McDataStream &stream);
};
struct JoinGame {
qint32 entityid;
quint8 gamemode;
qint32 dimension;
enum Gamemode : quint8 { Survival, Creative, Adventure, Spectator, Hardcore = 0x08 };
Gamemode gamemode;
enum Dimension : qint32 { Nether=-1, Overworld=0, End=1 };
Dimension dimension;
quint8 difficulty;
quint8 maxPlayers;
QString levelType;
@@ -160,6 +212,12 @@ namespace packets {
void serialize(McDataStream &stream);
};
struct KeepAlive {
qint64 keepAliveId;
void serialize(McDataStream &stream);
};
}
}
}