Splitted different client states into classes
This commit is contained in:
@@ -5,11 +5,21 @@ CONFIG += c++1z
|
|||||||
DEFINES += QT_DEPRECATED_WARNINGS QT_DISABLE_DEPRECATED_BEFORE=0x060000
|
DEFINES += QT_DEPRECATED_WARNINGS QT_DISABLE_DEPRECATED_BEFORE=0x060000
|
||||||
|
|
||||||
SOURCES += main.cpp \
|
SOURCES += main.cpp \
|
||||||
client.cpp \
|
closedclient.cpp \
|
||||||
|
handshakingclient.cpp \
|
||||||
|
loginclient.cpp \
|
||||||
mcdatastream.cpp \
|
mcdatastream.cpp \
|
||||||
packets.cpp
|
packets.cpp \
|
||||||
|
playclient.cpp \
|
||||||
|
server.cpp \
|
||||||
|
statusclient.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
client.h \
|
closedclient.h \
|
||||||
|
handshakingclient.h \
|
||||||
|
loginclient.h \
|
||||||
mcdatastream.h \
|
mcdatastream.h \
|
||||||
packets.h
|
packets.h \
|
||||||
|
playclient.h \
|
||||||
|
server.h \
|
||||||
|
statusclient.h
|
||||||
|
45
client.h
45
client.h
@@ -1,45 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QDateTime>
|
|
||||||
|
|
||||||
#include "mcdatastream.h"
|
|
||||||
#include "packets.h"
|
|
||||||
|
|
||||||
class QTcpSocket;
|
|
||||||
|
|
||||||
class Client : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void readPacketHandshaking(const packets::handshaking::serverbound::PacketType type, const QByteArray &buffer);
|
|
||||||
void readPacketStatus(const packets::status::serverbound::PacketType type, const QByteArray &buffer);
|
|
||||||
void readPacketLogin(const packets::login::serverbound::PacketType type, const QByteArray &buffer);
|
|
||||||
void readPacketPlay(const packets::play::serverbound::PacketType type, const QByteArray &buffer);
|
|
||||||
|
|
||||||
QTcpSocket *m_socket;
|
|
||||||
McDataStream m_dataStream;
|
|
||||||
|
|
||||||
qint32 m_packetSize;
|
|
||||||
|
|
||||||
SocketState m_state;
|
|
||||||
|
|
||||||
const QDateTime m_connectedSince;
|
|
||||||
QDateTime m_lastKeepAliveSent;
|
|
||||||
QDateTime m_lastKeepAliveReceived;
|
|
||||||
QDateTime m_lastChatMessage;
|
|
||||||
};
|
|
49
closedclient.cpp
Normal file
49
closedclient.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#include "closedclient.h"
|
||||||
|
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
|
|
||||||
|
ClosedClient::ClosedClient(QTcpSocket &socket, Server &server) :
|
||||||
|
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||||
|
{
|
||||||
|
m_socket.setParent(this);
|
||||||
|
|
||||||
|
connect(&m_socket, &QIODevice::readyRead, this, &ClosedClient::readyRead);
|
||||||
|
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||||
|
|
||||||
|
QTimer::singleShot(1000, this, &QObject::deleteLater);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClosedClient::readyRead()
|
||||||
|
{
|
||||||
|
while(m_socket.bytesAvailable())
|
||||||
|
{
|
||||||
|
if(!m_packetSize)
|
||||||
|
{
|
||||||
|
m_packetSize = m_dataStream.readVar<qint32>();
|
||||||
|
qDebug() << "packet size" << m_packetSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_socket.bytesAvailable() < m_packetSize)
|
||||||
|
{
|
||||||
|
qWarning() << "packet not fully available" << m_socket.bytesAvailable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 bytesRead;
|
||||||
|
const auto type = m_dataStream.readVar<qint32>(bytesRead);
|
||||||
|
m_packetSize -= bytesRead;
|
||||||
|
const auto buffer = m_socket.read(m_packetSize);
|
||||||
|
Q_ASSERT(buffer.size() == m_packetSize);
|
||||||
|
m_packetSize = 0;
|
||||||
|
|
||||||
|
readPacket(packets::closed::serverbound::PacketType(type), buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClosedClient::readPacket(packets::closed::serverbound::PacketType type, const QByteArray &buffer)
|
||||||
|
{
|
||||||
|
qWarning() << "does not support receiving any packets" << type << buffer;
|
||||||
|
}
|
32
closedclient.h
Normal file
32
closedclient.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "mcdatastream.h"
|
||||||
|
#include "packets.h"
|
||||||
|
|
||||||
|
class QTcpSocket;
|
||||||
|
class QByteArray;
|
||||||
|
|
||||||
|
class Server;
|
||||||
|
|
||||||
|
class ClosedClient : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ClosedClient(QTcpSocket &socket, Server &server);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void readyRead();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readPacket(packets::closed::serverbound::PacketType type, const QByteArray &buffer);
|
||||||
|
|
||||||
|
QTcpSocket &m_socket;
|
||||||
|
Server &m_server;
|
||||||
|
|
||||||
|
McDataStream m_dataStream;
|
||||||
|
|
||||||
|
qint32 m_packetSize{};
|
||||||
|
};
|
76
handshakingclient.cpp
Normal file
76
handshakingclient.cpp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#include "handshakingclient.h"
|
||||||
|
|
||||||
|
#include <QTcpSocket>
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
|
#include "statusclient.h"
|
||||||
|
#include "loginclient.h"
|
||||||
|
|
||||||
|
HandshakingClient::HandshakingClient(QTcpSocket &socket, Server &server) :
|
||||||
|
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||||
|
{
|
||||||
|
m_socket.setParent(this);
|
||||||
|
|
||||||
|
connect(&m_socket, &QIODevice::readyRead, this, &HandshakingClient::readyRead);
|
||||||
|
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandshakingClient::readyRead()
|
||||||
|
{
|
||||||
|
while(m_socket.bytesAvailable())
|
||||||
|
{
|
||||||
|
if(!m_packetSize)
|
||||||
|
{
|
||||||
|
m_packetSize = m_dataStream.readVar<qint32>();
|
||||||
|
qDebug() << "packet size" << m_packetSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_socket.bytesAvailable() < m_packetSize)
|
||||||
|
{
|
||||||
|
qWarning() << "packet not fully available" << m_socket.bytesAvailable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 bytesRead;
|
||||||
|
const auto type = m_dataStream.readVar<qint32>(bytesRead);
|
||||||
|
m_packetSize -= bytesRead;
|
||||||
|
const auto buffer = m_socket.read(m_packetSize);
|
||||||
|
Q_ASSERT(buffer.size() == m_packetSize);
|
||||||
|
m_packetSize = 0;
|
||||||
|
|
||||||
|
readPacket(packets::handshaking::serverbound::PacketType(type), buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandshakingClient::readPacket(packets::handshaking::serverbound::PacketType type, const QByteArray &buffer)
|
||||||
|
{
|
||||||
|
McDataStream dataStream{const_cast<QByteArray *>(&buffer), QIODevice::ReadOnly};
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
using namespace packets::handshaking;
|
||||||
|
case serverbound::PacketType::Handshake:
|
||||||
|
{
|
||||||
|
qDebug() << type;
|
||||||
|
serverbound::Handshake packet{dataStream};
|
||||||
|
switch (packet.nextState)
|
||||||
|
{
|
||||||
|
using namespace serverbound;
|
||||||
|
case Handshake::SocketState::StatusState:
|
||||||
|
new StatusClient{m_socket, m_server};
|
||||||
|
break;
|
||||||
|
case Handshake::SocketState::LoginState:
|
||||||
|
new LoginClient{m_socket, m_server};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCritical() << "client requested new state" << packet.nextState << "which is not allowed/invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteLater();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
qWarning() << "unknown packet type" << type;
|
||||||
|
}
|
||||||
|
}
|
32
handshakingclient.h
Normal file
32
handshakingclient.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "mcdatastream.h"
|
||||||
|
#include "packets.h"
|
||||||
|
|
||||||
|
class QTcpSocket;
|
||||||
|
class QByteArray;
|
||||||
|
|
||||||
|
class Server;
|
||||||
|
|
||||||
|
class HandshakingClient : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit HandshakingClient(QTcpSocket &socket, Server &parent);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void readyRead();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readPacket(packets::handshaking::serverbound::PacketType type, const QByteArray &buffer);
|
||||||
|
|
||||||
|
QTcpSocket &m_socket;
|
||||||
|
Server &m_server;
|
||||||
|
|
||||||
|
McDataStream m_dataStream;
|
||||||
|
|
||||||
|
qint32 m_packetSize{};
|
||||||
|
};
|
74
loginclient.cpp
Normal file
74
loginclient.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "loginclient.h"
|
||||||
|
|
||||||
|
#include <QTcpSocket>
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
|
#include "playclient.h"
|
||||||
|
|
||||||
|
LoginClient::LoginClient(QTcpSocket &socket, Server &server) :
|
||||||
|
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||||
|
{
|
||||||
|
m_socket.setParent(this);
|
||||||
|
|
||||||
|
connect(&m_socket, &QIODevice::readyRead, this, &LoginClient::readyRead);
|
||||||
|
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoginClient::readyRead()
|
||||||
|
{
|
||||||
|
while(m_socket.bytesAvailable())
|
||||||
|
{
|
||||||
|
if(!m_packetSize)
|
||||||
|
{
|
||||||
|
m_packetSize = m_dataStream.readVar<qint32>();
|
||||||
|
qDebug() << "packet size" << m_packetSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_socket.bytesAvailable() < m_packetSize)
|
||||||
|
{
|
||||||
|
qWarning() << "packet not fully available" << m_socket.bytesAvailable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 bytesRead;
|
||||||
|
const auto type = m_dataStream.readVar<qint32>(bytesRead);
|
||||||
|
m_packetSize -= bytesRead;
|
||||||
|
const auto buffer = m_socket.read(m_packetSize);
|
||||||
|
Q_ASSERT(buffer.size() == m_packetSize);
|
||||||
|
m_packetSize = 0;
|
||||||
|
|
||||||
|
readPacket(packets::login::serverbound::PacketType(type), buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoginClient::readPacket(packets::login::serverbound::PacketType type, const QByteArray &buffer)
|
||||||
|
{
|
||||||
|
McDataStream dataStream(const_cast<QByteArray *>(&buffer), QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
using namespace packets::login;
|
||||||
|
case serverbound::PacketType::Login:
|
||||||
|
{
|
||||||
|
qDebug() << type;
|
||||||
|
QString name;
|
||||||
|
{
|
||||||
|
serverbound::Login packet{dataStream};
|
||||||
|
name = packet.name;
|
||||||
|
}
|
||||||
|
qDebug() << "Name" << name;
|
||||||
|
{
|
||||||
|
clientbound::LoginSuccess packet;
|
||||||
|
const auto uuid = QUuid::createUuid().toString();
|
||||||
|
packet.uuid = uuid.mid(1, uuid.length() - 2);
|
||||||
|
packet.username = name;
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
}
|
||||||
|
new PlayClient{m_socket, m_server};
|
||||||
|
deleteLater();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
qWarning() << "unknown packet type" << type;
|
||||||
|
}
|
||||||
|
}
|
32
loginclient.h
Normal file
32
loginclient.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "mcdatastream.h"
|
||||||
|
#include "packets.h"
|
||||||
|
|
||||||
|
class QTcpSocket;
|
||||||
|
class QByteArray;
|
||||||
|
|
||||||
|
class Server;
|
||||||
|
|
||||||
|
class LoginClient : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit LoginClient(QTcpSocket &socket, Server &server);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void readyRead();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readPacket(packets::login::serverbound::PacketType type, const QByteArray &buffer);
|
||||||
|
|
||||||
|
QTcpSocket &m_socket;
|
||||||
|
Server &m_server;
|
||||||
|
|
||||||
|
McDataStream m_dataStream;
|
||||||
|
|
||||||
|
qint32 m_packetSize{};
|
||||||
|
};
|
44
main.cpp
44
main.cpp
@@ -1,11 +1,7 @@
|
|||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <qlogging.h>
|
#include <qlogging.h>
|
||||||
#include <QTcpServer>
|
|
||||||
#include <QList>
|
|
||||||
#include <QPointer>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#include "client.h"
|
#include "server.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@@ -22,43 +18,7 @@ int main(int argc, char *argv[])
|
|||||||
"%{function}(): "
|
"%{function}(): "
|
||||||
"%{message}"));
|
"%{message}"));
|
||||||
|
|
||||||
QList<QPointer<Client>> clients;
|
Server server;
|
||||||
|
|
||||||
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,&clients](){
|
|
||||||
clients.append(new Client(server.nextPendingConnection()));
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!server.listen(QHostAddress::Any, 25565))
|
|
||||||
qFatal("could not start listening %s", server.errorString().toUtf8().constData());
|
|
||||||
|
|
||||||
qDebug() << "started listening";
|
|
||||||
|
|
||||||
return a.exec();
|
return a.exec();
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
#include "packets.h"
|
#include "packets.h"
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
#include "mcdatastream.h"
|
#include "mcdatastream.h"
|
||||||
|
|
||||||
packets::handshaking::serverbound::Handshake::Handshake(McDataStream &stream)
|
packets::handshaking::serverbound::Handshake::Handshake(McDataStream &stream)
|
||||||
@@ -79,6 +81,7 @@ packets::play::serverbound::InteractEntity::InteractEntity(McDataStream &stream)
|
|||||||
targetX = stream.readFloat();
|
targetX = stream.readFloat();
|
||||||
targetY = stream.readFloat();
|
targetY = stream.readFloat();
|
||||||
targetZ = stream.readFloat();
|
targetZ = stream.readFloat();
|
||||||
|
[[fallthrough]];
|
||||||
case Interact:
|
case Interact:
|
||||||
hand = Hand(stream.readVar<qint32>());
|
hand = Hand(stream.readVar<qint32>());
|
||||||
}
|
}
|
||||||
|
29
packets.h
29
packets.h
@@ -9,8 +9,6 @@
|
|||||||
|
|
||||||
class McDataStream;
|
class McDataStream;
|
||||||
|
|
||||||
enum SocketState { HandshakingState, StatusState, LoginState, PlayState, ClosedState };
|
|
||||||
|
|
||||||
namespace packets {
|
namespace packets {
|
||||||
namespace handshaking {
|
namespace handshaking {
|
||||||
namespace serverbound {
|
namespace serverbound {
|
||||||
@@ -20,16 +18,27 @@ namespace packets {
|
|||||||
Q_ENUM_NS(PacketType)
|
Q_ENUM_NS(PacketType)
|
||||||
|
|
||||||
struct Handshake {
|
struct Handshake {
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
public:
|
||||||
Handshake(McDataStream &stream);
|
Handshake(McDataStream &stream);
|
||||||
|
|
||||||
qint32 protocolVersion;
|
qint32 protocolVersion;
|
||||||
QString serverAddress;
|
QString serverAddress;
|
||||||
quint16 serverPort;
|
quint16 serverPort;
|
||||||
|
|
||||||
|
enum class SocketState { HandshakingState, StatusState, LoginState, PlayState, ClosedState };
|
||||||
|
Q_ENUM(SocketState)
|
||||||
|
|
||||||
SocketState nextState;
|
SocketState nextState;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace clientbound {
|
namespace clientbound {
|
||||||
|
Q_NAMESPACE
|
||||||
|
|
||||||
|
enum class PacketType {};
|
||||||
|
Q_ENUM_NS(PacketType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,4 +229,20 @@ namespace packets {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace closed {
|
||||||
|
namespace serverbound {
|
||||||
|
Q_NAMESPACE
|
||||||
|
|
||||||
|
enum class PacketType {};
|
||||||
|
Q_ENUM_NS(PacketType)
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace clientbound {
|
||||||
|
Q_NAMESPACE
|
||||||
|
|
||||||
|
enum class PacketType {};
|
||||||
|
Q_ENUM_NS(PacketType)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
186
playclient.cpp
Normal file
186
playclient.cpp
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
#include "playclient.h"
|
||||||
|
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
|
#include "closedclient.h"
|
||||||
|
|
||||||
|
PlayClient::PlayClient(QTcpSocket &socket, Server &server) :
|
||||||
|
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||||
|
{
|
||||||
|
m_server.add(*this);
|
||||||
|
|
||||||
|
m_socket.setParent(this);
|
||||||
|
|
||||||
|
connect(&m_socket, &QIODevice::readyRead, this, &PlayClient::readyRead);
|
||||||
|
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||||
|
|
||||||
|
{
|
||||||
|
packets::play::clientbound::JoinGame packet;
|
||||||
|
packet.entityid = 1;
|
||||||
|
packet.gamemode = packets::play::clientbound::JoinGame::Creative;
|
||||||
|
packet.dimension = packets::play::clientbound::JoinGame::Overworld;
|
||||||
|
packet.difficulty = 2;
|
||||||
|
packet.maxPlayers = 255;
|
||||||
|
packet.levelType = QStringLiteral("default");
|
||||||
|
packet.reducedDebugInfo = false;
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
packets::play::clientbound::PluginMessage packet;
|
||||||
|
packet.channel = QStringLiteral("minecraft:brand");
|
||||||
|
packet.data = QByteArrayLiteral("bullshit");
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
packets::play::clientbound::ServerDifficulty packet;
|
||||||
|
packet.difficulty = 2;
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
packets::play::clientbound::SpawnPosition packet;
|
||||||
|
packet.location = std::make_tuple(100, 64, 100);
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
packets::play::clientbound::PlayerAbilities packet;
|
||||||
|
packet.flags = 0x0F;
|
||||||
|
packet.flyingSpeed = 1.;
|
||||||
|
packet.fieldOfViewModifier = 60.;
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayClient::~PlayClient()
|
||||||
|
{
|
||||||
|
m_server.remove(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayClient::keepAlive()
|
||||||
|
{
|
||||||
|
const auto now = QDateTime::currentDateTime();
|
||||||
|
if (!m_lastKeepAliveSent.isValid() || m_lastKeepAliveSent.secsTo(now) >= 1)
|
||||||
|
{
|
||||||
|
packets::play::clientbound::KeepAlive packet;
|
||||||
|
packet.keepAliveId = 0;
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
m_lastKeepAliveSent = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayClient::sendChatMessage()
|
||||||
|
{
|
||||||
|
const auto now = QDateTime::currentDateTime();
|
||||||
|
if (!m_lastChatMessage.isValid() || m_lastChatMessage.secsTo(now) >= 2)
|
||||||
|
{
|
||||||
|
packets::play::clientbound::ChatMessage packet;
|
||||||
|
packet.jsonData = "{"
|
||||||
|
"\"text\": \"Chat message\", "
|
||||||
|
"\"bold\": \"true\" "
|
||||||
|
"}";
|
||||||
|
packet.position = packets::play::clientbound::ChatMessage::Chat;
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
m_lastChatMessage = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayClient::trialDisconnect()
|
||||||
|
{
|
||||||
|
const auto now = QDateTime::currentDateTime();
|
||||||
|
if (m_connectedSince.secsTo(now) >= 20)
|
||||||
|
{
|
||||||
|
packets::play::clientbound::Disconnect packet;
|
||||||
|
packet.reason = "{"
|
||||||
|
"\"text\": \"Your trial has ended.\", "
|
||||||
|
"\"bold\": \"true\" "
|
||||||
|
"}";
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
m_socket.flush();
|
||||||
|
new ClosedClient{m_socket, m_server};
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayClient::readyRead()
|
||||||
|
{
|
||||||
|
while(m_socket.bytesAvailable())
|
||||||
|
{
|
||||||
|
if(!m_packetSize)
|
||||||
|
{
|
||||||
|
m_packetSize = m_dataStream.readVar<qint32>();
|
||||||
|
qDebug() << "packet size" << m_packetSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_socket.bytesAvailable() < m_packetSize)
|
||||||
|
{
|
||||||
|
qWarning() << "packet not fully available" << m_socket.bytesAvailable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 bytesRead;
|
||||||
|
const auto type = m_dataStream.readVar<qint32>(bytesRead);
|
||||||
|
m_packetSize -= bytesRead;
|
||||||
|
const auto buffer = m_socket.read(m_packetSize);
|
||||||
|
Q_ASSERT(buffer.size() == m_packetSize);
|
||||||
|
m_packetSize = 0;
|
||||||
|
|
||||||
|
readPacket(packets::play::serverbound::PacketType(type), buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayClient::readPacket(packets::play::serverbound::PacketType type, const QByteArray &buffer)
|
||||||
|
{
|
||||||
|
McDataStream dataStream(const_cast<QByteArray *>(&buffer), QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
using namespace packets::play;
|
||||||
|
case serverbound::PacketType::ClientSettings:
|
||||||
|
{
|
||||||
|
qDebug() << type;
|
||||||
|
{
|
||||||
|
serverbound::ClientSettings packet{dataStream};
|
||||||
|
qDebug() << "locale" << packet.locale;
|
||||||
|
qDebug() << "viewDistance" << packet.viewDistance;
|
||||||
|
qDebug() << "chatMode" << packet.chatMode;
|
||||||
|
qDebug() << "chatColors" << packet.chatColors;
|
||||||
|
qDebug() << "displayedSkinParts" << packet.displayedSkinParts;
|
||||||
|
qDebug() << "mainHand" << packet.mainHand;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
clientbound::PlayerPositionAndLook packet;
|
||||||
|
packet.x = 50.;
|
||||||
|
packet.y = 64.;
|
||||||
|
packet.z = 50.;
|
||||||
|
packet.yaw = 0.;
|
||||||
|
packet.pitch = 0.;
|
||||||
|
packet.flags = 0;
|
||||||
|
packet.teleportId = 0;
|
||||||
|
packet.serialize(m_dataStream);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case serverbound::PacketType::InteractEntity:
|
||||||
|
{
|
||||||
|
qDebug() << type;
|
||||||
|
serverbound::InteractEntity packet{dataStream};
|
||||||
|
qDebug() << "entityId" << packet.entityId;
|
||||||
|
qDebug() << "type" << packet.type;
|
||||||
|
// qDebug() << "targetX" << packet.targetX;
|
||||||
|
// qDebug() << "targetY" << packet.targetY;
|
||||||
|
// qDebug() << "targetZ" << packet.targetZ;
|
||||||
|
// qDebug() << "hand" << packet.hand;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case serverbound::PacketType::PluginMessage:
|
||||||
|
{
|
||||||
|
qDebug() << type;
|
||||||
|
serverbound::PluginMessage packet{dataStream};
|
||||||
|
qDebug() << "channel" << packet.channel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
qWarning() << "unknown packet type" << type;
|
||||||
|
}
|
||||||
|
}
|
42
playclient.h
Normal file
42
playclient.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "mcdatastream.h"
|
||||||
|
#include "packets.h"
|
||||||
|
|
||||||
|
class QTcpSocket;
|
||||||
|
class QByteArray;
|
||||||
|
|
||||||
|
class Server;
|
||||||
|
|
||||||
|
class PlayClient : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PlayClient(QTcpSocket &socket, Server &server);
|
||||||
|
~PlayClient() override;
|
||||||
|
|
||||||
|
void keepAlive();
|
||||||
|
void sendChatMessage();
|
||||||
|
void trialDisconnect();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void readyRead();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readPacket(packets::play::serverbound::PacketType type, const QByteArray &buffer);
|
||||||
|
|
||||||
|
QTcpSocket &m_socket;
|
||||||
|
Server &m_server;
|
||||||
|
|
||||||
|
McDataStream m_dataStream;
|
||||||
|
|
||||||
|
qint32 m_packetSize{};
|
||||||
|
|
||||||
|
const QDateTime m_connectedSince{QDateTime::currentDateTime()};
|
||||||
|
QDateTime m_lastKeepAliveSent;
|
||||||
|
QDateTime m_lastKeepAliveReceived;
|
||||||
|
QDateTime m_lastChatMessage;
|
||||||
|
};
|
47
server.cpp
Normal file
47
server.cpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#include "server.h"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "playclient.h"
|
||||||
|
#include "handshakingclient.h"
|
||||||
|
|
||||||
|
Server::Server(QObject *parent) :
|
||||||
|
QObject{parent}
|
||||||
|
{
|
||||||
|
m_timer.setInterval(100);
|
||||||
|
connect(&m_timer, &QTimer::timeout, this, &Server::timeout);
|
||||||
|
m_timer.start();
|
||||||
|
|
||||||
|
connect(&m_server, &QTcpServer::newConnection, this, &Server::newConnection);
|
||||||
|
|
||||||
|
if(!m_server.listen(QHostAddress::Any, 25565))
|
||||||
|
qFatal("could not start listening %s", m_server.errorString().toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::add(PlayClient &playClient)
|
||||||
|
{
|
||||||
|
m_playClients.insert(&playClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::remove(PlayClient &playClient)
|
||||||
|
{
|
||||||
|
m_playClients.erase(&playClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::timeout()
|
||||||
|
{
|
||||||
|
for (auto client : m_playClients)
|
||||||
|
{
|
||||||
|
client->keepAlive();
|
||||||
|
client->sendChatMessage();
|
||||||
|
client->trialDisconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::newConnection()
|
||||||
|
{
|
||||||
|
auto * const connection = m_server.nextPendingConnection();
|
||||||
|
if (connection)
|
||||||
|
new HandshakingClient{*connection, *this};
|
||||||
|
//clients.push_back();
|
||||||
|
}
|
31
server.h
Normal file
31
server.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class PlayClient;
|
||||||
|
|
||||||
|
class Server : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Server(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
void add(PlayClient &playClient);
|
||||||
|
void remove(PlayClient &playClient);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void timeout();
|
||||||
|
void newConnection();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTimer m_timer;
|
||||||
|
QTcpServer m_server;
|
||||||
|
|
||||||
|
std::set<PlayClient*> m_playClients;
|
||||||
|
};
|
@@ -1,69 +1,21 @@
|
|||||||
#include "client.h"
|
#include "statusclient.h"
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QUuid>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
Client::Client(QTcpSocket *socket, QObject *parent) :
|
#include "server.h"
|
||||||
QObject(parent), m_socket(socket), m_dataStream(m_socket),
|
|
||||||
m_packetSize(0), m_state(HandshakingState), m_connectedSince(QDateTime::currentDateTime())
|
StatusClient::StatusClient(QTcpSocket &socket, Server &server) :
|
||||||
|
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||||
{
|
{
|
||||||
m_socket->setParent(this);
|
m_socket.setParent(this);
|
||||||
|
|
||||||
connect(m_socket, &QIODevice::readyRead, this, &Client::readyRead);
|
connect(&m_socket, &QIODevice::readyRead, this, &StatusClient::readyRead);
|
||||||
connect(m_socket, &QAbstractSocket::disconnected, this, &Client::disconnected);
|
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||||
|
|
||||||
qDebug() << m_socket->peerPort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::keepAlive()
|
void StatusClient::readyRead()
|
||||||
{
|
{
|
||||||
const auto now = QDateTime::currentDateTime();
|
while(m_socket.bytesAvailable())
|
||||||
if (!m_lastKeepAliveSent.isValid() || m_lastKeepAliveSent.secsTo(now) >= 1)
|
|
||||||
{
|
|
||||||
packets::play::clientbound::KeepAlive packet;
|
|
||||||
packet.keepAliveId = 0;
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
m_lastKeepAliveSent = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::sendChatMessage()
|
|
||||||
{
|
|
||||||
const auto now = QDateTime::currentDateTime();
|
|
||||||
if (!m_lastChatMessage.isValid() || m_lastChatMessage.secsTo(now) >= 2)
|
|
||||||
{
|
|
||||||
packets::play::clientbound::ChatMessage packet;
|
|
||||||
packet.jsonData = "{"
|
|
||||||
"\"text\": \"Chat message\", "
|
|
||||||
"\"bold\": \"true\" "
|
|
||||||
"}";
|
|
||||||
packet.position = packets::play::clientbound::ChatMessage::Chat;
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
m_lastChatMessage = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::trialDisconnect()
|
|
||||||
{
|
|
||||||
const auto now = QDateTime::currentDateTime();
|
|
||||||
if (m_connectedSince.secsTo(now) >= 20)
|
|
||||||
{
|
|
||||||
packets::play::clientbound::Disconnect packet;
|
|
||||||
packet.reason = "{"
|
|
||||||
"\"text\": \"Your trial has ended.\", "
|
|
||||||
"\"bold\": \"true\" "
|
|
||||||
"}";
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
m_socket->flush();
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::readyRead()
|
|
||||||
{
|
|
||||||
while(m_socket->bytesAvailable())
|
|
||||||
{
|
{
|
||||||
if(!m_packetSize)
|
if(!m_packetSize)
|
||||||
{
|
{
|
||||||
@@ -71,69 +23,25 @@ void Client::readyRead()
|
|||||||
qDebug() << "packet size" << m_packetSize;
|
qDebug() << "packet size" << m_packetSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_socket->bytesAvailable() < m_packetSize)
|
if(m_socket.bytesAvailable() < m_packetSize)
|
||||||
{
|
{
|
||||||
qWarning() << "packet not fully available" << m_socket->bytesAvailable();
|
qWarning() << "packet not fully available" << m_socket.bytesAvailable();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qint32 bytesRead;
|
qint32 bytesRead;
|
||||||
const auto type = m_dataStream.readVar<qint32>(bytesRead);
|
const auto type = m_dataStream.readVar<qint32>(bytesRead);
|
||||||
m_packetSize -= bytesRead;
|
m_packetSize -= bytesRead;
|
||||||
const auto buffer = m_socket->read(m_packetSize);
|
const auto buffer = m_socket.read(m_packetSize);
|
||||||
Q_ASSERT(buffer.size() == m_packetSize);
|
Q_ASSERT(buffer.size() == m_packetSize);
|
||||||
m_packetSize = 0;
|
m_packetSize = 0;
|
||||||
|
|
||||||
switch(m_state)
|
readPacket(packets::status::serverbound::PacketType(type), buffer);
|
||||||
{
|
|
||||||
case HandshakingState:
|
|
||||||
readPacketHandshaking(packets::handshaking::serverbound::PacketType(type), buffer);
|
|
||||||
break;
|
|
||||||
case StatusState:
|
|
||||||
readPacketStatus(packets::status::serverbound::PacketType(type), buffer);
|
|
||||||
break;
|
|
||||||
case LoginState:
|
|
||||||
readPacketLogin(packets::login::serverbound::PacketType(type), buffer);
|
|
||||||
break;
|
|
||||||
case PlayState:
|
|
||||||
readPacketPlay(packets::play::serverbound::PacketType(type), buffer);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qWarning() << "unhandled state" << m_state << type << buffer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::disconnected()
|
void StatusClient::readPacket(packets::status::serverbound::PacketType type, const QByteArray &buffer)
|
||||||
{
|
{
|
||||||
qDebug() << m_socket->peerPort();
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::readPacketHandshaking(packets::handshaking::serverbound::PacketType type, const QByteArray &buffer)
|
|
||||||
{
|
|
||||||
qDebug() << type;
|
|
||||||
|
|
||||||
McDataStream dataStream(const_cast<QByteArray *>(&buffer), QIODevice::ReadOnly);
|
|
||||||
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
using namespace packets::handshaking;
|
|
||||||
case serverbound::PacketType::Handshake:
|
|
||||||
{
|
|
||||||
serverbound::Handshake packet(dataStream);
|
|
||||||
m_state = packet.nextState;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
qWarning() << "unknown type!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::readPacketStatus(const packets::status::serverbound::PacketType type, const QByteArray &buffer)
|
|
||||||
{
|
|
||||||
qDebug() << type;
|
|
||||||
|
|
||||||
McDataStream dataStream(const_cast<QByteArray *>(&buffer), QIODevice::ReadOnly);
|
McDataStream dataStream(const_cast<QByteArray *>(&buffer), QIODevice::ReadOnly);
|
||||||
|
|
||||||
switch(type)
|
switch(type)
|
||||||
@@ -141,8 +49,9 @@ void Client::readPacketStatus(const packets::status::serverbound::PacketType typ
|
|||||||
using namespace packets::status;
|
using namespace packets::status;
|
||||||
case serverbound::PacketType::Request:
|
case serverbound::PacketType::Request:
|
||||||
{
|
{
|
||||||
|
qDebug() << type;
|
||||||
{
|
{
|
||||||
serverbound::Request packet(dataStream);
|
serverbound::Request packet{dataStream};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
clientbound::Response packet;
|
clientbound::Response packet;
|
||||||
@@ -173,9 +82,10 @@ void Client::readPacketStatus(const packets::status::serverbound::PacketType typ
|
|||||||
}
|
}
|
||||||
case serverbound::PacketType::Ping:
|
case serverbound::PacketType::Ping:
|
||||||
{
|
{
|
||||||
|
qDebug() << type;
|
||||||
qint64 payload;
|
qint64 payload;
|
||||||
{
|
{
|
||||||
serverbound::Ping packet(dataStream);
|
serverbound::Ping packet{dataStream};
|
||||||
payload = packet.payload;
|
payload = packet.payload;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -186,127 +96,6 @@ void Client::readPacketStatus(const packets::status::serverbound::PacketType typ
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
qWarning() << "unknown type!";
|
qWarning() << "unknown packet type" << type;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::readPacketLogin(const packets::login::serverbound::PacketType type, const QByteArray &buffer)
|
|
||||||
{
|
|
||||||
qDebug() << type;
|
|
||||||
|
|
||||||
McDataStream dataStream(const_cast<QByteArray *>(&buffer), QIODevice::ReadOnly);
|
|
||||||
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
using namespace packets::login;
|
|
||||||
case serverbound::PacketType::Login:
|
|
||||||
{
|
|
||||||
QString name;
|
|
||||||
{
|
|
||||||
serverbound::Login packet(dataStream);
|
|
||||||
name = packet.name;
|
|
||||||
}
|
|
||||||
qDebug() << "Name" << name;
|
|
||||||
{
|
|
||||||
clientbound::LoginSuccess packet;
|
|
||||||
const auto uuid = QUuid::createUuid().toString();
|
|
||||||
packet.uuid = uuid.mid(1, uuid.length() - 2);
|
|
||||||
packet.username = name;
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
}
|
|
||||||
m_state = PlayState;
|
|
||||||
{
|
|
||||||
packets::play::clientbound::JoinGame packet;
|
|
||||||
packet.entityid = 1;
|
|
||||||
packet.gamemode = packets::play::clientbound::JoinGame::Creative;
|
|
||||||
packet.dimension = packets::play::clientbound::JoinGame::Overworld;
|
|
||||||
packet.difficulty = 2;
|
|
||||||
packet.maxPlayers = 255;
|
|
||||||
packet.levelType = QStringLiteral("default");
|
|
||||||
packet.reducedDebugInfo = false;
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
packets::play::clientbound::PluginMessage packet;
|
|
||||||
packet.channel = QStringLiteral("minecraft:brand");
|
|
||||||
packet.data = QByteArrayLiteral("bullshit");
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
packets::play::clientbound::ServerDifficulty packet;
|
|
||||||
packet.difficulty = 2;
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
packets::play::clientbound::SpawnPosition packet;
|
|
||||||
packet.location = std::make_tuple(100, 64, 100);
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
packets::play::clientbound::PlayerAbilities packet;
|
|
||||||
packet.flags = 0x0F;
|
|
||||||
packet.flyingSpeed = 1.;
|
|
||||||
packet.fieldOfViewModifier = 60.;
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
qWarning() << "unknown type!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::readPacketPlay(const packets::play::serverbound::PacketType type, const QByteArray &buffer)
|
|
||||||
{
|
|
||||||
qDebug() << type;
|
|
||||||
|
|
||||||
McDataStream dataStream(const_cast<QByteArray *>(&buffer), QIODevice::ReadOnly);
|
|
||||||
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
using namespace packets::play;
|
|
||||||
case serverbound::PacketType::ClientSettings:
|
|
||||||
{
|
|
||||||
{
|
|
||||||
serverbound::ClientSettings packet(dataStream);
|
|
||||||
qDebug() << "locale" << packet.locale;
|
|
||||||
qDebug() << "viewDistance" << packet.viewDistance;
|
|
||||||
qDebug() << "chatMode" << packet.chatMode;
|
|
||||||
qDebug() << "chatColors" << packet.chatColors;
|
|
||||||
qDebug() << "displayedSkinParts" << packet.displayedSkinParts;
|
|
||||||
qDebug() << "mainHand" << packet.mainHand;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
clientbound::PlayerPositionAndLook packet;
|
|
||||||
packet.x = 50.;
|
|
||||||
packet.y = 64.;
|
|
||||||
packet.z = 50.;
|
|
||||||
packet.yaw = 0.;
|
|
||||||
packet.pitch = 0.;
|
|
||||||
packet.flags = 0;
|
|
||||||
packet.teleportId = 0;
|
|
||||||
packet.serialize(m_dataStream);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case serverbound::PacketType::InteractEntity:
|
|
||||||
{
|
|
||||||
serverbound::InteractEntity packet(dataStream);
|
|
||||||
qDebug() << "entityId" << packet.entityId;
|
|
||||||
qDebug() << "type" << packet.type;
|
|
||||||
// qDebug() << "targetX" << packet.targetX;
|
|
||||||
// qDebug() << "targetY" << packet.targetY;
|
|
||||||
// qDebug() << "targetZ" << packet.targetZ;
|
|
||||||
// qDebug() << "hand" << packet.hand;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case serverbound::PacketType::PluginMessage:
|
|
||||||
{
|
|
||||||
serverbound::PluginMessage packet(dataStream);
|
|
||||||
qDebug() << "channel" << packet.channel;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
qWarning() << "unknown type!";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
32
statusclient.h
Normal file
32
statusclient.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "mcdatastream.h"
|
||||||
|
#include "packets.h"
|
||||||
|
|
||||||
|
class QTcpSocket;
|
||||||
|
class QByteArray;
|
||||||
|
|
||||||
|
class Server;
|
||||||
|
|
||||||
|
class StatusClient : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit StatusClient(QTcpSocket &socket, Server &server);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void readyRead();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readPacket(packets::status::serverbound::PacketType type, const QByteArray &buffer);
|
||||||
|
|
||||||
|
QTcpSocket &m_socket;
|
||||||
|
Server &m_server;
|
||||||
|
|
||||||
|
McDataStream m_dataStream;
|
||||||
|
|
||||||
|
qint32 m_packetSize{};
|
||||||
|
};
|
Reference in New Issue
Block a user