161 lines
5.8 KiB
C++
161 lines
5.8 KiB
C++
#include "collabsession.h"
|
|
#include "log.h"
|
|
|
|
CollabSession::CollabSession(MainWindow *mainWindow) {
|
|
this->mainWindow = mainWindow;
|
|
}
|
|
|
|
CollabSession *collabInstance = nullptr;
|
|
|
|
void CollabSession::init(MainWindow *mainWindow) {
|
|
if (collabInstance) {
|
|
delete collabInstance;
|
|
}
|
|
collabInstance = new CollabSession(mainWindow);
|
|
}
|
|
|
|
bool CollabSession::connect(QString host, int port) {
|
|
if (!collabInstance) return false;
|
|
|
|
collabInstance->socket = new QTcpSocket();
|
|
collabInstance->socket->connectToHost(host, port);
|
|
|
|
QObject::connect(collabInstance->socket, &QTcpSocket::connected, [=](){
|
|
logInfo("Socket connected to collab server...");
|
|
});
|
|
QObject::connect(collabInstance->socket, &QTcpSocket::disconnected, [=](){
|
|
logInfo("Socket disconnected from collab server...");
|
|
});
|
|
QObject::connect(collabInstance->socket, &QTcpSocket::readyRead, [=](){
|
|
collabInstance->processMessage();
|
|
});
|
|
|
|
if (!collabInstance->socket->waitForConnected(10000)) {
|
|
logError(collabInstance->socket->errorString());
|
|
delete collabInstance->socket;
|
|
collabInstance->socket = nullptr;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CollabSession::processMessage() {
|
|
QByteArray newContent = collabInstance->socket->readAll();
|
|
this->messageBuffer.append(newContent);
|
|
// Process all the available messages in the read buffer.
|
|
while (true) {
|
|
if (this->messageBuffer.size() < 12) {
|
|
break;
|
|
}
|
|
|
|
uint32_t signature = this->messageBuffer.at(0) |
|
|
(this->messageBuffer.at(1) << 8) |
|
|
(this->messageBuffer.at(2) << 16) |
|
|
(this->messageBuffer.at(3) << 24);
|
|
if (signature != 0x98765432) {
|
|
// Invalid signature from server. Unclear how to recover--just disconnect.
|
|
logError("Invalid message signature received from collab server. Disconnecting...");
|
|
this->socket->disconnectFromHost();
|
|
delete this->socket;
|
|
this->socket = nullptr;
|
|
break;
|
|
}
|
|
|
|
uint32_t payloadSize = this->messageBuffer.at(4) |
|
|
(this->messageBuffer.at(5) << 8) |
|
|
(this->messageBuffer.at(6) << 16) |
|
|
(this->messageBuffer.at(7) << 24);
|
|
int messageSize = 12 + payloadSize;
|
|
if (this->messageBuffer.size() < messageSize) {
|
|
break;
|
|
}
|
|
|
|
uint32_t messageType = this->messageBuffer.at(8) |
|
|
(this->messageBuffer.at(9) << 8) |
|
|
(this->messageBuffer.at(10) << 16) |
|
|
(this->messageBuffer.at(11) << 24);
|
|
|
|
QByteArray message = this->messageBuffer.left(messageSize);
|
|
message.remove(0, 12);
|
|
this->messageBuffer = this->messageBuffer.remove(0, messageSize);
|
|
if (message.size() < 2) {
|
|
break;
|
|
}
|
|
|
|
switch (messageType) {
|
|
case SERVER_MESSAGE_BROADCAST_COMMAND:
|
|
int commandType = (message.at(1) << 8) | message.at(0);
|
|
switch (commandType) {
|
|
case COMMAND_BLOCKS_CHANGED:
|
|
this->handleBlocksChangedCommand(message);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CollabSession::createSession(QString sessionName) {
|
|
QByteArray msg = prepareSocketMessage(sessionName.toLocal8Bit(), 0x1);
|
|
logInfo(QString("Joining session: %1").arg(collabInstance->socket->write(QByteArray(msg))));
|
|
}
|
|
|
|
void CollabSession::joinSession(QString sessionName) {
|
|
QByteArray msg = prepareSocketMessage(sessionName.toLocal8Bit(), 0x2);
|
|
logInfo(QString("Joining session: %1").arg(collabInstance->socket->write(QByteArray(msg))));
|
|
}
|
|
|
|
QByteArray CollabSession::prepareSocketMessage(QByteArray message, int messageType) {
|
|
QByteArray header = QByteArray();
|
|
// 4-byte little endian signature is 0x12345678.
|
|
header.append(0x78);
|
|
header.append(0x56);
|
|
header.append(0x34);
|
|
header.append(0x12);
|
|
// 4-byte little endian payload size.
|
|
header.append(message.size() & 0xff);
|
|
header.append((message.size() >> 8) & 0xff);
|
|
header.append((message.size() >> 16) & 0xff);
|
|
header.append((message.size() >> 24) & 0xff);
|
|
// 4-byte little endian message type.
|
|
header.append(messageType & 0xff);
|
|
header.append((messageType >> 8) & 0xff);
|
|
header.append((messageType >> 16) & 0xff);
|
|
header.append((messageType >> 24) & 0xff);
|
|
// Append payload.
|
|
return header + message;
|
|
}
|
|
|
|
void CollabSession::handleBlocksChangedCommand(QByteArray message) {
|
|
uint16_t numBlocks = (message.at(3) << 8) | message.at(2);
|
|
if (message.size() != 4 + numBlocks * 6)
|
|
return;
|
|
|
|
for (int i = 0; i < numBlocks; i++) {
|
|
int index = 4 + i * 6;
|
|
int x = (uint8_t(message.at(index + 1)) << 8) | uint8_t(message.at(index));
|
|
int y = (uint8_t(message.at(index + 3)) << 8) | uint8_t(message.at(index + 2));
|
|
uint16_t metatileId = (uint8_t(message.at(index + 5)) << 8) | uint8_t(message.at(index + 4));
|
|
collabInstance->mainWindow->setBlock(x, y, metatileId, 0, 0, true, false);
|
|
}
|
|
}
|
|
|
|
void CollabSession::onBlockChanged(int x, int y, Block prevBlock, Block newBlock) {
|
|
if (!collabInstance || !collabInstance->socket) return;
|
|
if (prevBlock.rawValue() == newBlock.rawValue()) return;
|
|
|
|
QByteArray message;
|
|
message.append(COMMAND_BLOCKS_CHANGED & 0xFF);
|
|
message.append((COMMAND_BLOCKS_CHANGED >> 8) & 0xFF);
|
|
message.append(0x1);
|
|
message.append('\0');
|
|
message.append(x & 0xFF);
|
|
message.append((x >> 8) & 0xFF);
|
|
message.append(y & 0xFF);
|
|
message.append((y >> 8) & 0xFF);
|
|
message.append(newBlock.tile & 0xFF);
|
|
message.append((newBlock.tile >> 8) & 0xFF);
|
|
QByteArray msg = CollabSession::prepareSocketMessage(message, 0x3);
|
|
collabInstance->socket->write(QByteArray(msg));
|
|
}
|