Memory management of socket using unique_ptr, many new util functions
This commit is contained in:
1 parent
b39078eedc
commit
fcadff65e2
20 files changed
+365
-101
No files matched your search
@@ -5,6 +5,8 @@ CONFIG += c++1z
|
||||
DEFINES += QT_DEPRECATED_WARNINGS QT_DISABLE_DEPRECATED_BEFORE=0x060000
|
||||
|
||||
SOURCES += main.cpp \
|
||||
chathelper.cpp \
|
||||
chunkhelper.cpp \
|
||||
closedclient.cpp \
|
||||
handshakingclient.cpp \
|
||||
loginclient.cpp \
|
||||
@@ -15,6 +17,8 @@ SOURCES += main.cpp \
|
||||
statusclient.cpp
|
||||
|
||||
HEADERS += \
|
||||
chathelper.h \
|
||||
chunkhelper.h \
|
||||
closedclient.h \
|
||||
handshakingclient.h \
|
||||
loginclient.h \
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "chathelper.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
|
||||
QJsonObject normalTextObj(const QString &text)
|
||||
{
|
||||
return QJsonObject { { "text", text } };
|
||||
}
|
||||
|
||||
QJsonObject boldTextObj(const QString &text)
|
||||
{
|
||||
QJsonObject obj = normalTextObj(text);
|
||||
obj["bold"] = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
QString normalText(const QString &text)
|
||||
{
|
||||
return QJsonDocument{normalTextObj(text)}.toJson();
|
||||
}
|
||||
|
||||
QString boldText(const QString &text)
|
||||
{
|
||||
return QJsonDocument{boldTextObj(text)}.toJson();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
QJsonObject normalTextObj(const QString &text);
|
||||
QJsonObject boldTextObj(const QString &text);
|
||||
|
||||
QString normalText(const QString &text);
|
||||
QString boldText(const QString &text);
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "chunkhelper.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#include "mcdatastream.h"
|
||||
|
||||
QByteArray createChunkSection()
|
||||
{
|
||||
quint8 bitsPerBlock = 8;
|
||||
std::array<qint8, 2> palette { 0, 1 };
|
||||
std::array<qint64, 4096> blocks;
|
||||
|
||||
QByteArray buffer;
|
||||
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
|
||||
tempStream << bitsPerBlock;
|
||||
tempStream.writeVar<qint32>(palette.size());
|
||||
for (const auto &entry : palette)
|
||||
tempStream.writeVar<qint32>(entry);
|
||||
tempStream.writeVar<qint32>(blocks.size());
|
||||
for (const auto &block : blocks)
|
||||
tempStream << block;
|
||||
for (int i = 0; i < blocks.size(); i++)
|
||||
tempStream << '\xFF';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
QByteArray createBiomes()
|
||||
{
|
||||
qint32 biomes[256];
|
||||
std::fill(std::begin(biomes), std::end(biomes), 0);
|
||||
|
||||
QByteArray buffer;
|
||||
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
|
||||
for (const auto &biome : biomes)
|
||||
tempStream << biome;
|
||||
return buffer;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
QByteArray createChunkSection();
|
||||
QByteArray createBiomes();
|
||||
|
||||
+11
-9
@@ -5,20 +5,22 @@
|
||||
|
||||
#include "server.h"
|
||||
|
||||
ClosedClient::ClosedClient(QTcpSocket &socket, Server &server) :
|
||||
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||
ClosedClient::ClosedClient(std::unique_ptr<QTcpSocket> &&socket, Server &server) :
|
||||
QObject{&server}, m_socket{std::move(socket)}, m_server{server}, m_dataStream{m_socket.get()}
|
||||
{
|
||||
m_socket.setParent(this);
|
||||
m_socket->setParent(this);
|
||||
|
||||
connect(&m_socket, &QIODevice::readyRead, this, &ClosedClient::readyRead);
|
||||
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
connect(m_socket.get(), &QIODevice::readyRead, this, &ClosedClient::readyRead);
|
||||
connect(m_socket.get(), &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
|
||||
QTimer::singleShot(1000, this, &QObject::deleteLater);
|
||||
}
|
||||
|
||||
ClosedClient::~ClosedClient() = default;
|
||||
|
||||
void ClosedClient::readyRead()
|
||||
{
|
||||
while(m_socket.bytesAvailable())
|
||||
while(m_socket && m_socket->bytesAvailable())
|
||||
{
|
||||
if(!m_packetSize)
|
||||
{
|
||||
@@ -26,16 +28,16 @@ void ClosedClient::readyRead()
|
||||
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;
|
||||
}
|
||||
|
||||
qint32 bytesRead;
|
||||
const auto type = m_dataStream.readVar<qint32>(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);
|
||||
m_packetSize = 0;
|
||||
|
||||
|
||||
+3
-2
@@ -15,7 +15,8 @@ class ClosedClient : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ClosedClient(QTcpSocket &socket, Server &server);
|
||||
explicit ClosedClient(std::unique_ptr<QTcpSocket> &&socket, Server &server);
|
||||
~ClosedClient() override;
|
||||
|
||||
private slots:
|
||||
void readyRead();
|
||||
@@ -23,7 +24,7 @@ private slots:
|
||||
private:
|
||||
void readPacket(packets::closed::serverbound::PacketType type, const QByteArray &buffer);
|
||||
|
||||
QTcpSocket &m_socket;
|
||||
std::unique_ptr<QTcpSocket> m_socket;
|
||||
Server &m_server;
|
||||
|
||||
McDataStream m_dataStream;
|
||||
|
||||
+15
-11
@@ -6,18 +6,20 @@
|
||||
#include "statusclient.h"
|
||||
#include "loginclient.h"
|
||||
|
||||
HandshakingClient::HandshakingClient(QTcpSocket &socket, Server &server) :
|
||||
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||
HandshakingClient::HandshakingClient(std::unique_ptr<QTcpSocket> &&socket, Server &server) :
|
||||
QObject{&server}, m_socket{std::move(socket)}, m_server{server}, m_dataStream{m_socket.get()}
|
||||
{
|
||||
m_socket.setParent(this);
|
||||
m_socket->setParent(this);
|
||||
|
||||
connect(&m_socket, &QIODevice::readyRead, this, &HandshakingClient::readyRead);
|
||||
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
connect(m_socket.get(), &QIODevice::readyRead, this, &HandshakingClient::readyRead);
|
||||
connect(m_socket.get(), &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
}
|
||||
|
||||
HandshakingClient::~HandshakingClient() = default;
|
||||
|
||||
void HandshakingClient::readyRead()
|
||||
{
|
||||
while(m_socket.bytesAvailable())
|
||||
while(m_socket && m_socket->bytesAvailable())
|
||||
{
|
||||
if(!m_packetSize)
|
||||
{
|
||||
@@ -25,16 +27,16 @@ void HandshakingClient::readyRead()
|
||||
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;
|
||||
}
|
||||
|
||||
qint32 bytesRead;
|
||||
const auto type = m_dataStream.readVar<qint32>(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);
|
||||
m_packetSize = 0;
|
||||
|
||||
@@ -57,10 +59,12 @@ void HandshakingClient::readPacket(packets::handshaking::serverbound::PacketType
|
||||
{
|
||||
using namespace serverbound;
|
||||
case Handshake::SocketState::StatusState:
|
||||
new StatusClient{m_socket, m_server};
|
||||
m_dataStream.setDevice({});
|
||||
new StatusClient{std::move(m_socket), m_server};
|
||||
break;
|
||||
case Handshake::SocketState::LoginState:
|
||||
new LoginClient{m_socket, m_server};
|
||||
m_dataStream.setDevice({});
|
||||
new LoginClient{std::move(m_socket), m_server};
|
||||
break;
|
||||
default:
|
||||
qCritical() << "client requested new state" << packet.nextState << "which is not allowed/invalid";
|
||||
|
||||
+5
-2
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "mcdatastream.h"
|
||||
@@ -15,7 +17,8 @@ class HandshakingClient : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit HandshakingClient(QTcpSocket &socket, Server &parent);
|
||||
explicit HandshakingClient(std::unique_ptr<QTcpSocket> &&socket, Server &parent);
|
||||
~HandshakingClient() override;
|
||||
|
||||
private slots:
|
||||
void readyRead();
|
||||
@@ -23,7 +26,7 @@ private slots:
|
||||
private:
|
||||
void readPacket(packets::handshaking::serverbound::PacketType type, const QByteArray &buffer);
|
||||
|
||||
QTcpSocket &m_socket;
|
||||
std::unique_ptr<QTcpSocket> m_socket;
|
||||
Server &m_server;
|
||||
|
||||
McDataStream m_dataStream;
|
||||
|
||||
+13
-10
@@ -5,18 +5,20 @@
|
||||
#include "server.h"
|
||||
#include "playclient.h"
|
||||
|
||||
LoginClient::LoginClient(QTcpSocket &socket, Server &server) :
|
||||
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||
LoginClient::LoginClient(std::unique_ptr<QTcpSocket> &&socket, Server &server) :
|
||||
QObject{&server}, m_socket{std::move(socket)}, m_server{server}, m_dataStream{m_socket.get()}
|
||||
{
|
||||
m_socket.setParent(this);
|
||||
m_socket->setParent(this);
|
||||
|
||||
connect(&m_socket, &QIODevice::readyRead, this, &LoginClient::readyRead);
|
||||
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
connect(m_socket.get(), &QIODevice::readyRead, this, &LoginClient::readyRead);
|
||||
connect(m_socket.get(), &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
}
|
||||
|
||||
LoginClient::~LoginClient() = default;
|
||||
|
||||
void LoginClient::readyRead()
|
||||
{
|
||||
while(m_socket.bytesAvailable())
|
||||
while(m_socket && m_socket->bytesAvailable())
|
||||
{
|
||||
if(!m_packetSize)
|
||||
{
|
||||
@@ -24,16 +26,16 @@ void LoginClient::readyRead()
|
||||
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;
|
||||
}
|
||||
|
||||
qint32 bytesRead;
|
||||
const auto type = m_dataStream.readVar<qint32>(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);
|
||||
m_packetSize = 0;
|
||||
|
||||
@@ -64,7 +66,8 @@ void LoginClient::readPacket(packets::login::serverbound::PacketType type, const
|
||||
packet.username = name;
|
||||
packet.serialize(m_dataStream);
|
||||
}
|
||||
new PlayClient{m_socket, m_server};
|
||||
m_dataStream.setDevice({});
|
||||
new PlayClient{std::move(m_socket), m_server};
|
||||
deleteLater();
|
||||
break;
|
||||
}
|
||||
|
||||
+3
-2
@@ -15,7 +15,8 @@ class LoginClient : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LoginClient(QTcpSocket &socket, Server &server);
|
||||
explicit LoginClient(std::unique_ptr<QTcpSocket> &&socket, Server &server);
|
||||
~LoginClient() override;
|
||||
|
||||
private slots:
|
||||
void readyRead();
|
||||
@@ -23,7 +24,7 @@ private slots:
|
||||
private:
|
||||
void readPacket(packets::login::serverbound::PacketType type, const QByteArray &buffer);
|
||||
|
||||
QTcpSocket &m_socket;
|
||||
std::unique_ptr<QTcpSocket> m_socket;
|
||||
Server &m_server;
|
||||
|
||||
McDataStream m_dataStream;
|
||||
|
||||
+2
-1
@@ -93,7 +93,8 @@ 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);
|
||||
const char buf[16]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
writeRawData(buf, 16);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||
+56
@@ -93,6 +93,22 @@ packets::play::serverbound::PluginMessage::PluginMessage(McDataStream &stream)
|
||||
//TODO read to end of buffer
|
||||
}
|
||||
|
||||
void packets::play::clientbound::SpawnMob::serialize(McDataStream &stream)
|
||||
{
|
||||
QByteArray buffer;
|
||||
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
|
||||
tempStream.writeVar<qint32>(qint32(PacketType::SpawnMob));
|
||||
tempStream.writeVar<qint32>(entityId);
|
||||
tempStream.writeUuid(uuid);
|
||||
tempStream.writeVar<qint32>(type);
|
||||
tempStream.writeDouble(x);
|
||||
tempStream.writeDouble(y);
|
||||
tempStream.writeDouble(z);
|
||||
tempStream << yaw << pitch << headPitch << velocityX << velocityY << velocityZ;
|
||||
stream.writeVar<qint32>(buffer.length());
|
||||
stream.writeRawData(buffer.constData(), buffer.length());
|
||||
}
|
||||
|
||||
void packets::play::clientbound::ServerDifficulty::serialize(McDataStream &stream)
|
||||
{
|
||||
QByteArray buffer;
|
||||
@@ -179,6 +195,30 @@ void packets::play::clientbound::PlayerPositionAndLook::serialize(McDataStream &
|
||||
stream.writeRawData(buffer.constData(), buffer.length());
|
||||
}
|
||||
|
||||
void packets::play::clientbound::SetExperience::serialize(McDataStream &stream)
|
||||
{
|
||||
QByteArray buffer;
|
||||
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
|
||||
tempStream.writeVar<qint32>(qint32(PacketType::SetExperience));
|
||||
tempStream.writeFloat(experienceBar);
|
||||
tempStream.writeVar<qint32>(level);
|
||||
tempStream.writeVar<qint32>(totalExperience);
|
||||
stream.writeVar<qint32>(buffer.length());
|
||||
stream.writeRawData(buffer.constData(), buffer.length());
|
||||
}
|
||||
|
||||
void packets::play::clientbound::UpdateHealth::serialize(McDataStream &stream)
|
||||
{
|
||||
QByteArray buffer;
|
||||
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
|
||||
tempStream.writeVar<qint32>(qint32(PacketType::UpdateHealth));
|
||||
tempStream.writeFloat(health);
|
||||
tempStream.writeVar<qint32>(food);
|
||||
tempStream.writeFloat(foodSaturation);
|
||||
stream.writeVar<qint32>(buffer.length());
|
||||
stream.writeRawData(buffer.constData(), buffer.length());
|
||||
}
|
||||
|
||||
void packets::play::clientbound::SpawnPosition::serialize(McDataStream &stream)
|
||||
{
|
||||
QByteArray buffer;
|
||||
@@ -198,3 +238,19 @@ void packets::play::clientbound::KeepAlive::serialize(McDataStream &stream)
|
||||
stream.writeVar<qint32>(buffer.length());
|
||||
stream.writeRawData(buffer.constData(), buffer.length());
|
||||
}
|
||||
|
||||
void packets::play::clientbound::ChunkData::serialize(McDataStream &stream)
|
||||
{
|
||||
QByteArray buffer;
|
||||
McDataStream tempStream(&buffer, QIODevice::WriteOnly);
|
||||
tempStream.writeVar<qint32>(qint32(PacketType::ChunkData));
|
||||
tempStream << chunkX << chunkY << fullChunk;
|
||||
tempStream.writeVar<qint32>(primaryBitMask);
|
||||
tempStream.writeVar<qint32>(data.size());
|
||||
tempStream.writeRawData(data.constData(), data.size());
|
||||
tempStream.writeVar<qint32>(blockEntities.size());
|
||||
for (const auto &blockEntitiy : blockEntities)
|
||||
tempStream.writeRawData(blockEntitiy.constData(), blockEntitiy.size());
|
||||
stream.writeVar<qint32>(buffer.length());
|
||||
stream.writeRawData(buffer.constData(), buffer.length());
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <optional>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <QtCore>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
class McDataStream;
|
||||
|
||||
namespace packets {
|
||||
using angle = quint8; // A rotation angle in steps of 1/256 of a full turn
|
||||
|
||||
namespace handshaking {
|
||||
namespace serverbound {
|
||||
Q_NAMESPACE
|
||||
@@ -151,10 +154,29 @@ namespace packets {
|
||||
namespace clientbound {
|
||||
Q_NAMESPACE
|
||||
|
||||
enum class PacketType { ServerDifficulty = 0x0D, ChatMessage = 0x0E, PluginMessage = 0x19, Disconnect = 0x1B, KeepAlive = 0x21,
|
||||
JoinGame = 0x25, PlayerAbilities = 0x2E, PlayerPositionAndLook = 0x32, SpawnPosition = 0x49 };
|
||||
enum class PacketType { SpawnMob = 0x03, ServerDifficulty = 0x0D, ChatMessage = 0x0E, PluginMessage = 0x19, Disconnect = 0x1B,
|
||||
KeepAlive = 0x21, ChunkData = 0x22, JoinGame = 0x25, PlayerAbilities = 0x2E, PlayerPositionAndLook = 0x32,
|
||||
SetExperience = 0x43, UpdateHealth = 0x44, SpawnPosition = 0x49 };
|
||||
Q_ENUM_NS(PacketType)
|
||||
|
||||
// does not work yet, client shows exception
|
||||
struct SpawnMob {
|
||||
qint32 entityId;
|
||||
QUuid uuid;
|
||||
qint32 type;
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
angle yaw;
|
||||
angle pitch;
|
||||
angle headPitch;
|
||||
qint16 velocityX;
|
||||
qint16 velocityY;
|
||||
qint16 velocityZ;
|
||||
|
||||
void serialize(McDataStream &stream);
|
||||
};
|
||||
|
||||
struct ServerDifficulty {
|
||||
quint8 difficulty;
|
||||
|
||||
@@ -216,6 +238,22 @@ namespace packets {
|
||||
void serialize(McDataStream &stream);
|
||||
};
|
||||
|
||||
struct SetExperience {
|
||||
float experienceBar;
|
||||
qint32 level;
|
||||
qint32 totalExperience;
|
||||
|
||||
void serialize(McDataStream &stream);
|
||||
};
|
||||
|
||||
struct UpdateHealth {
|
||||
float health;
|
||||
qint32 food;
|
||||
float foodSaturation;
|
||||
|
||||
void serialize(McDataStream &stream);
|
||||
};
|
||||
|
||||
struct SpawnPosition {
|
||||
std::tuple<qint32, qint16, qint32> location;
|
||||
|
||||
@@ -227,6 +265,17 @@ namespace packets {
|
||||
|
||||
void serialize(McDataStream &stream);
|
||||
};
|
||||
|
||||
struct ChunkData {
|
||||
qint32 chunkX;
|
||||
qint32 chunkY;
|
||||
bool fullChunk;
|
||||
qint32 primaryBitMask;
|
||||
QByteArray data;
|
||||
std::vector<QByteArray> blockEntities;
|
||||
|
||||
void serialize(McDataStream &stream);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+75
-22
@@ -5,21 +5,23 @@
|
||||
|
||||
#include "server.h"
|
||||
#include "closedclient.h"
|
||||
#include "chathelper.h"
|
||||
#include "chunkhelper.h"
|
||||
|
||||
PlayClient::PlayClient(QTcpSocket &socket, Server &server) :
|
||||
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||
PlayClient::PlayClient(std::unique_ptr<QTcpSocket> &&socket, Server &server) :
|
||||
QObject{&server}, m_socket{std::move(socket)}, m_server{server}, m_dataStream{m_socket.get()}
|
||||
{
|
||||
m_server.add(*this);
|
||||
|
||||
m_socket.setParent(this);
|
||||
m_socket->setParent(this);
|
||||
|
||||
connect(&m_socket, &QIODevice::readyRead, this, &PlayClient::readyRead);
|
||||
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
connect(m_socket.get(), &QIODevice::readyRead, this, &PlayClient::readyRead);
|
||||
connect(m_socket.get(), &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
|
||||
{
|
||||
packets::play::clientbound::JoinGame packet;
|
||||
packet.entityid = 1;
|
||||
packet.gamemode = packets::play::clientbound::JoinGame::Creative;
|
||||
packet.gamemode = packets::play::clientbound::JoinGame::Survival;
|
||||
packet.dimension = packets::play::clientbound::JoinGame::Overworld;
|
||||
packet.difficulty = 2;
|
||||
packet.maxPlayers = 255;
|
||||
@@ -50,6 +52,38 @@ PlayClient::PlayClient(QTcpSocket &socket, Server &server) :
|
||||
packet.fieldOfViewModifier = 60.;
|
||||
packet.serialize(m_dataStream);
|
||||
}
|
||||
{
|
||||
packets::play::clientbound::ChunkData packet;
|
||||
packet.fullChunk = true;
|
||||
packet.primaryBitMask = 0b11000; // send only 2 chunks
|
||||
packet.data += createChunkSection();
|
||||
packet.data += createChunkSection();
|
||||
packet.data += createBiomes(); // we are in Overworld
|
||||
|
||||
for (int y = -3; y <= 3; y++)
|
||||
for (int x = -3; x <= 3; x++)
|
||||
{
|
||||
packet.chunkX = x;
|
||||
packet.chunkY = y;
|
||||
packet.serialize(m_dataStream);
|
||||
}
|
||||
}
|
||||
// {
|
||||
// packets::play::clientbound::SpawnMob packet;
|
||||
// packet.entityId = 2;
|
||||
// packet.uuid = QUuid::createUuid();
|
||||
// packet.type = 19;
|
||||
// packet.x = 50.;
|
||||
// packet.y = 50.;
|
||||
// packet.z = 50.;
|
||||
// packet.yaw = 0;
|
||||
// packet.pitch = 0;
|
||||
// packet.headPitch = 0;
|
||||
// packet.velocityX = 0;
|
||||
// packet.velocityY = 0;
|
||||
// packet.velocityZ = 0;
|
||||
// packet.serialize(m_dataStream);
|
||||
// }
|
||||
}
|
||||
|
||||
PlayClient::~PlayClient()
|
||||
@@ -75,36 +109,55 @@ void PlayClient::sendChatMessage()
|
||||
if (!m_lastChatMessage.isValid() || m_lastChatMessage.secsTo(now) >= 2)
|
||||
{
|
||||
packets::play::clientbound::ChatMessage packet;
|
||||
packet.jsonData = "{"
|
||||
"\"text\": \"Chat message\", "
|
||||
"\"bold\": \"true\" "
|
||||
"}";
|
||||
packet.jsonData = normalText(tr("Time chaged to %0").arg(QTime::currentTime().toString()));
|
||||
packet.position = packets::play::clientbound::ChatMessage::Chat;
|
||||
packet.serialize(m_dataStream);
|
||||
m_lastChatMessage = now;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayClient::randomizeStats()
|
||||
{
|
||||
const auto now = QDateTime::currentDateTime();
|
||||
if (!m_lastStats.isValid() || m_lastStats.msecsTo(now) >= 500)
|
||||
{
|
||||
{
|
||||
packets::play::clientbound::SetExperience packet;
|
||||
packet.experienceBar = QRandomGenerator::system()->generateDouble();
|
||||
packet.level = QRandomGenerator::system()->bounded(50);
|
||||
packet.totalExperience = QRandomGenerator::system()->bounded(500);
|
||||
packet.serialize(m_dataStream);
|
||||
}
|
||||
{
|
||||
packets::play::clientbound::UpdateHealth packet;
|
||||
packet.health = QRandomGenerator::system()->generateDouble() * 20;
|
||||
packet.food = QRandomGenerator::system()->bounded(20);
|
||||
packet.foodSaturation = QRandomGenerator::system()->generateDouble() * 5;
|
||||
packet.serialize(m_dataStream);
|
||||
}
|
||||
|
||||
m_lastStats = now;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayClient::trialDisconnect()
|
||||
{
|
||||
const auto now = QDateTime::currentDateTime();
|
||||
if (m_connectedSince.secsTo(now) >= 20)
|
||||
if (m_connectedSince.secsTo(now) >= 30)
|
||||
{
|
||||
packets::play::clientbound::Disconnect packet;
|
||||
packet.reason = "{"
|
||||
"\"text\": \"Your trial has ended.\", "
|
||||
"\"bold\": \"true\" "
|
||||
"}";
|
||||
packet.reason = boldText("Your trial has ended.");
|
||||
packet.serialize(m_dataStream);
|
||||
m_socket.flush();
|
||||
new ClosedClient{m_socket, m_server};
|
||||
m_socket->flush();
|
||||
m_dataStream.setDevice({});
|
||||
new ClosedClient{std::move(m_socket), m_server};
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void PlayClient::readyRead()
|
||||
{
|
||||
while(m_socket.bytesAvailable())
|
||||
while(m_socket && m_socket->bytesAvailable())
|
||||
{
|
||||
if(!m_packetSize)
|
||||
{
|
||||
@@ -112,16 +165,16 @@ void PlayClient::readyRead()
|
||||
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;
|
||||
}
|
||||
|
||||
qint32 bytesRead;
|
||||
const auto type = m_dataStream.readVar<qint32>(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);
|
||||
m_packetSize = 0;
|
||||
|
||||
@@ -181,6 +234,6 @@ void PlayClient::readPacket(packets::play::serverbound::PacketType type, const Q
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qWarning() << "unknown packet type" << type;
|
||||
qWarning() << "unknown packet type" << type << buffer;
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -15,11 +15,12 @@ class PlayClient : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PlayClient(QTcpSocket &socket, Server &server);
|
||||
explicit PlayClient(std::unique_ptr<QTcpSocket> &&socket, Server &server);
|
||||
~PlayClient() override;
|
||||
|
||||
void keepAlive();
|
||||
void sendChatMessage();
|
||||
void randomizeStats();
|
||||
void trialDisconnect();
|
||||
|
||||
private slots:
|
||||
@@ -28,7 +29,7 @@ private slots:
|
||||
private:
|
||||
void readPacket(packets::play::serverbound::PacketType type, const QByteArray &buffer);
|
||||
|
||||
QTcpSocket &m_socket;
|
||||
std::unique_ptr<QTcpSocket> m_socket;
|
||||
Server &m_server;
|
||||
|
||||
McDataStream m_dataStream;
|
||||
@@ -39,4 +40,5 @@ private:
|
||||
QDateTime m_lastKeepAliveSent;
|
||||
QDateTime m_lastKeepAliveReceived;
|
||||
QDateTime m_lastChatMessage;
|
||||
QDateTime m_lastStats;
|
||||
};
|
||||
+6
-2
@@ -1,6 +1,9 @@
|
||||
#include "server.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include "playclient.h"
|
||||
#include "handshakingclient.h"
|
||||
@@ -34,14 +37,15 @@ void Server::timeout()
|
||||
{
|
||||
client->keepAlive();
|
||||
client->sendChatMessage();
|
||||
client->randomizeStats();
|
||||
client->trialDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void Server::newConnection()
|
||||
{
|
||||
auto * const connection = m_server.nextPendingConnection();
|
||||
auto connection = std::unique_ptr<QTcpSocket>(m_server.nextPendingConnection());
|
||||
if (connection)
|
||||
new HandshakingClient{*connection, *this};
|
||||
new HandshakingClient{std::move(connection), *this};
|
||||
//clients.push_back();
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QTcpServer>
|
||||
#include <QPointer>
|
||||
|
||||
#include <set>
|
||||
|
||||
class PlayClient;
|
||||
|
||||
class Server : public QObject
|
||||
|
||||
+30
-30
@@ -1,21 +1,27 @@
|
||||
#include "statusclient.h"
|
||||
|
||||
#include <QTcpSocket>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "server.h"
|
||||
#include "chathelper.h"
|
||||
|
||||
StatusClient::StatusClient(QTcpSocket &socket, Server &server) :
|
||||
QObject{&server}, m_socket{socket}, m_server{server}, m_dataStream{&m_socket}
|
||||
StatusClient::StatusClient(std::unique_ptr<QTcpSocket> &&socket, Server &server) :
|
||||
QObject{&server}, m_socket{std::move(socket)}, m_server{server}, m_dataStream{m_socket.get()}
|
||||
{
|
||||
m_socket.setParent(this);
|
||||
m_socket->setParent(this);
|
||||
|
||||
connect(&m_socket, &QIODevice::readyRead, this, &StatusClient::readyRead);
|
||||
connect(&m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
connect(m_socket.get(), &QIODevice::readyRead, this, &StatusClient::readyRead);
|
||||
connect(m_socket.get(), &QAbstractSocket::disconnected, this, &QObject::deleteLater);
|
||||
}
|
||||
|
||||
StatusClient::~StatusClient() = default;
|
||||
|
||||
void StatusClient::readyRead()
|
||||
{
|
||||
while(m_socket.bytesAvailable())
|
||||
while(m_socket && m_socket->bytesAvailable())
|
||||
{
|
||||
if(!m_packetSize)
|
||||
{
|
||||
@@ -23,16 +29,16 @@ void StatusClient::readyRead()
|
||||
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;
|
||||
}
|
||||
|
||||
qint32 bytesRead;
|
||||
const auto type = m_dataStream.readVar<qint32>(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);
|
||||
m_packetSize = 0;
|
||||
|
||||
@@ -55,27 +61,21 @@ void StatusClient::readPacket(packets::status::serverbound::PacketType type, con
|
||||
}
|
||||
{
|
||||
clientbound::Response packet;
|
||||
packet.jsonResponse =
|
||||
"{"
|
||||
" \"version\": {"
|
||||
" \"name\": \"1.13.1\","
|
||||
" \"protocol\": 401"
|
||||
" },"
|
||||
" \"players\": {"
|
||||
" \"max\": 1000,"
|
||||
" \"online\": 2000,"
|
||||
" \"sample\": ["
|
||||
" {"
|
||||
" \"name\": \"feedc0de\","
|
||||
" \"id\": \"6ebf7396-b6da-40b1-b7d9-9b7961450d5a\""
|
||||
" }"
|
||||
" ]"
|
||||
" }, "
|
||||
" \"description\": {"
|
||||
" \"text\": \"Minecraft server implemented in C++\""
|
||||
" },"
|
||||
" \"favicon\": \"data:image/png;base64,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 truncated
|
||||
"}";
|
||||
packet.jsonResponse = QJsonDocument{QJsonObject {
|
||||
{ "version", QJsonObject {
|
||||
{ "name", "1.13.1" },
|
||||
{ "protocol", 401 }
|
||||
} },
|
||||
{ "players", QJsonObject{
|
||||
{ "max", 1000 },
|
||||
{ "online", 2000 },
|
||||
{ "sample", QJsonArray{
|
||||
QJsonObject{{"name", "feedc0de"}, {"id", "6ebf7396-b6da-40b1-b7d9-9b7961450d5a"}}
|
||||
} }
|
||||
} },
|
||||
{ "description", normalTextObj("Minecraft server implemented in C++") },
|
||||
{ "favicon", "data:image/png;base64,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 truncated
|
||||
}}.toJson();
|
||||
packet.serialize(m_dataStream);
|
||||
}
|
||||
break;
|
||||
|
||||
+3
-2
@@ -15,7 +15,8 @@ class StatusClient : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit StatusClient(QTcpSocket &socket, Server &server);
|
||||
explicit StatusClient(std::unique_ptr<QTcpSocket> &&socket, Server &server);
|
||||
~StatusClient() override;
|
||||
|
||||
private slots:
|
||||
void readyRead();
|
||||
@@ -23,7 +24,7 @@ private slots:
|
||||
private:
|
||||
void readPacket(packets::status::serverbound::PacketType type, const QByteArray &buffer);
|
||||
|
||||
QTcpSocket &m_socket;
|
||||
std::unique_ptr<QTcpSocket> m_socket;
|
||||
Server &m_server;
|
||||
|
||||
McDataStream m_dataStream;
|
||||
|
||||
Reference in new issue
Block a user