diff --git a/.clang-format b/.clang-format index a050582..e825708 100644 --- a/.clang-format +++ b/.clang-format @@ -1,2 +1,5 @@ BasedOnStyle: LLVM -BreakBeforeBraces: Stroustrup +IndentWidth: 4 +Language: Cpp +PointerAlignment: Left +BreakBeforeBraces: Stroustrup \ No newline at end of file diff --git a/include/advertiser.h b/include/advertiser.h index 34807c1..894beb6 100644 --- a/include/advertiser.h +++ b/include/advertiser.h @@ -9,29 +9,30 @@ #include class Advertiser : public QObject { - Q_OBJECT + Q_OBJECT -public: - Advertiser(QString p_ip, int p_port, int p_ws_port, int p_local_port, - QString p_name, QString p_description, QObject *parent = nullptr); - void contactMasterServer(); + public: + Advertiser(QString p_ip, int p_port, int p_ws_port, int p_local_port, + QString p_name, QString p_description, + QObject* parent = nullptr); + void contactMasterServer(); -signals: + signals: -public slots: - void readData(); - void socketConnected(); - void socketDisconnected(); + public slots: + void readData(); + void socketConnected(); + void socketDisconnected(); -private: - QString ip; - int port; - int ws_port; - int local_port; - QString name; - QString description; + private: + QString ip; + int port; + int ws_port; + int local_port; + QString name; + QString description; - QTcpSocket *socket; + QTcpSocket* socket; }; #endif // MASTER_H diff --git a/include/akashimain.h b/include/akashimain.h index def37ed..b2b52f4 100644 --- a/include/akashimain.h +++ b/include/akashimain.h @@ -16,20 +16,20 @@ class AkashiMain; QT_END_NAMESPACE class AkashiMain : public QMainWindow { - Q_OBJECT + Q_OBJECT -public: - AkashiMain(QWidget *parent = nullptr); - ~AkashiMain(); + public: + AkashiMain(QWidget* parent = nullptr); + ~AkashiMain(); - ConfigManager config_manager; + ConfigManager config_manager; - void generateDefaultConfig(bool backup_old); - void updateConfig(int current_version); + void generateDefaultConfig(bool backup_old); + void updateConfig(int current_version); -private: - Ui::AkashiMain *ui; - Advertiser *advertiser; - Server *server; + private: + Ui::AkashiMain* ui; + Advertiser* advertiser; + Server* server; }; #endif // AKASHIMAIN_H diff --git a/include/aoclient.h b/include/aoclient.h index e452887..349abe2 100644 --- a/include/aoclient.h +++ b/include/aoclient.h @@ -6,24 +6,24 @@ #include class AOClient { -public: - AOClient(QHostAddress p_remote_ip); - ~AOClient(); + public: + AOClient(QHostAddress p_remote_ip); + ~AOClient(); - QString getHwid(); - void setHwid(QString p_hwid); + QString getHwid(); + void setHwid(QString p_hwid); - QString getIpid(); + QString getIpid(); - QHostAddress remote_ip; - QString password; - bool joined; - int current_area; - QString current_char; + QHostAddress remote_ip; + QString password; + bool joined; + int current_area; + QString current_char; -private: - QString hwid; - QString ipid; + private: + QString hwid; + QString ipid; }; #endif // AOCLIENT_H diff --git a/include/aopacket.h b/include/aopacket.h index cc02f20..adbbc02 100644 --- a/include/aopacket.h +++ b/include/aopacket.h @@ -7,14 +7,14 @@ #include class AOPacket { -public: - AOPacket(QString p_header, QStringList p_contents); - AOPacket(QString packet); - QString toString(); - QByteArray toUtf8(); + public: + AOPacket(QString p_header, QStringList p_contents); + AOPacket(QString packet); + QString toString(); + QByteArray toUtf8(); - QString header; - QStringList contents; + QString header; + QStringList contents; }; #endif // PACKET_MANAGER_H diff --git a/include/area_data.h b/include/area_data.h index 527bbcc..4522787 100644 --- a/include/area_data.h +++ b/include/area_data.h @@ -1,11 +1,11 @@ #ifndef AREA_DATA_H #define AREA_DATA_H -#include #include +#include class AreaData { -public: + public: AreaData(QStringList characters); QString name; diff --git a/include/config_manager.h b/include/config_manager.h index 6a9e32c..957c042 100644 --- a/include/config_manager.h +++ b/include/config_manager.h @@ -5,31 +5,31 @@ #include #include -#include #include +#include #include class ConfigManager { -public: - ConfigManager(); - bool initConfig(); - void generateDefaultConfig(bool backup_old); - void updateConfig(int current_version); + public: + ConfigManager(); + bool initConfig(); + void generateDefaultConfig(bool backup_old); + void updateConfig(int current_version); - struct server_settings { - QString ms_ip; - int port; - int ws_port; - int local_port; - QString name; - QString description; - bool advertise_server; - }; + struct server_settings { + QString ms_ip; + int port; + int ws_port; + int local_port; + QString name; + QString description; + bool advertise_server; + }; - bool loadServerSettings(server_settings *settings); + bool loadServerSettings(server_settings* settings); -private: - QSettings *config; + private: + QSettings* config; }; #endif // CONFIG_MANAGER_H diff --git a/include/server.h b/include/server.h index a68e097..0ef90e8 100644 --- a/include/server.h +++ b/include/server.h @@ -7,44 +7,44 @@ #include #include +#include #include #include #include #include #include -#include class Server : public QObject { - Q_OBJECT + Q_OBJECT -public: - Server(int p_port, int p_ws_port, QObject *parent = nullptr); - void start(); + public: + Server(int p_port, int p_ws_port, QObject* parent = nullptr); + void start(); -signals: + signals: -public slots: - void clientConnected(); - void clientDisconnected(); - void clientData(); + public slots: + void clientConnected(); + void clientDisconnected(); + void clientData(); -private: - void handlePacket(AOPacket packet, QTcpSocket *socket); - QTcpSocket *getClient(QString ipid); - void broadcast(AOPacket packet); + private: + void handlePacket(AOPacket packet, QTcpSocket* socket); + QTcpSocket* getClient(QString ipid); + void broadcast(AOPacket packet); - QTcpServer *server; + QTcpServer* server; - int port; - int ws_port; + int port; + int ws_port; - QMap clients; - QString partial_packet; - bool is_partial; + QMap clients; + QString partial_packet; + bool is_partial; - int player_count; - QStringList characters; - QVector areas; + int player_count; + QStringList characters; + QVector areas; }; #endif // SERVER_H diff --git a/src/advertiser.cpp b/src/advertiser.cpp index 1e908b3..6a8dd0b 100644 --- a/src/advertiser.cpp +++ b/src/advertiser.cpp @@ -2,59 +2,61 @@ Advertiser::Advertiser(QString p_ip, int p_port, int p_ws_port, int p_local_port, QString p_name, QString p_description, - QObject *parent) + QObject* parent) : QObject(parent) { - ip = p_ip; - port = p_port; - ws_port = p_ws_port; - local_port = p_local_port; - name = p_name; - description = p_description; + ip = p_ip; + port = p_port; + ws_port = p_ws_port; + local_port = p_local_port; + name = p_name; + description = p_description; } void Advertiser::contactMasterServer() { - socket = new QTcpSocket(this); - connect(socket, SIGNAL(readyRead()), this, SLOT(readData())); - connect(socket, SIGNAL(connected()), this, SLOT(socketConnected())); - connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); + socket = new QTcpSocket(this); + connect(socket, SIGNAL(readyRead()), this, SLOT(readData())); + connect(socket, SIGNAL(connected()), this, SLOT(socketConnected())); + connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); - socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); - socket->connectToHost(ip, port); + socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); + socket->connectToHost(ip, port); } void Advertiser::readData() { - // The information coming back from the MS isn't very useful - // However, it can be useful to see it when debugging - // TODO: master network debug switch - // qDebug() << "From MS:" << socket->readAll(); + // The information coming back from the MS isn't very useful + // However, it can be useful to see it when debugging + // TODO: master network debug switch + // qDebug() << "From MS:" << socket->readAll(); } void Advertiser::socketConnected() { - // TODO: fire a signal here, i18n - qDebug("Connected to the master server"); - QString concat_ports; - if (ws_port == -1) - concat_ports = QString::number(local_port); - else - concat_ports = QString::number(local_port) + "&" + QString::number(ws_port); + // TODO: fire a signal here, i18n + qDebug("Connected to the master server"); + QString concat_ports; + if (ws_port == -1) + concat_ports = QString::number(local_port); + else + concat_ports = + QString::number(local_port) + "&" + QString::number(ws_port); - AOPacket ao_packet("SCC", {concat_ports, name, description, - "akashi v" + QApplication::applicationVersion()}); - QByteArray data = ao_packet.toUtf8(); + AOPacket ao_packet("SCC", + {concat_ports, name, description, + "akashi v" + QApplication::applicationVersion()}); + QByteArray data = ao_packet.toUtf8(); - socket->write(data); - // TODO: master network debug switch - // should be a separate one for MS as well - // qDebug() << "To MS:" << data; - socket->flush(); + socket->write(data); + // TODO: master network debug switch + // should be a separate one for MS as well + // qDebug() << "To MS:" << data; + socket->flush(); } void Advertiser::socketDisconnected() { - // TODO: fire a signal here, i18n - qDebug("Connection to master server lost"); + // TODO: fire a signal here, i18n + qDebug("Connection to master server lost"); } diff --git a/src/akashimain.cpp b/src/akashimain.cpp index cc6a548..5598f4a 100644 --- a/src/akashimain.cpp +++ b/src/akashimain.cpp @@ -1,42 +1,43 @@ #include "include/akashimain.h" #include "ui_akashimain.h" -AkashiMain::AkashiMain(QWidget *parent) +AkashiMain::AkashiMain(QWidget* parent) : QMainWindow(parent), config_manager(), ui(new Ui::AkashiMain) { - ui->setupUi(this); - qDebug("Main application started"); + ui->setupUi(this); + qDebug("Main application started"); - if (config_manager.initConfig()) { - // Config is sound, so proceed with starting the server - // Validate some of the config before passing it on - ConfigManager::server_settings settings; - bool config_valid = config_manager.loadServerSettings(&settings); + if (config_manager.initConfig()) { + // Config is sound, so proceed with starting the server + // Validate some of the config before passing it on + ConfigManager::server_settings settings; + bool config_valid = config_manager.loadServerSettings(&settings); - if (!config_valid) { - // TODO: send signal config invalid - config_manager.generateDefaultConfig(true); + if (!config_valid) { + // TODO: send signal config invalid + config_manager.generateDefaultConfig(true); + } + else { + if (settings.advertise_server) { + // TODO: send signal advertiser started + advertiser = + new Advertiser(settings.ms_ip, settings.port, + settings.ws_port, settings.local_port, + settings.name, settings.description, this); + advertiser->contactMasterServer(); + } + + // TODO: start the server here + // TODO: send signal server starting. + server = new Server(settings.port, settings.ws_port); + server->start(); + } } - else { - if (settings.advertise_server) { - // TODO: send signal advertiser started - advertiser = new Advertiser(settings.ms_ip, settings.port, - settings.ws_port, settings.local_port, - settings.name, settings.description, this); - advertiser->contactMasterServer(); - } - - // TODO: start the server here - // TODO: send signal server starting. - server = new Server(settings.port, settings.ws_port); - server->start(); - } - } } AkashiMain::~AkashiMain() { - delete ui; - delete advertiser; - delete server; + delete ui; + delete advertiser; + delete server; } diff --git a/src/aoclient.cpp b/src/aoclient.cpp index 56061c5..006d582 100644 --- a/src/aoclient.cpp +++ b/src/aoclient.cpp @@ -2,25 +2,26 @@ AOClient::AOClient(QHostAddress p_remote_ip) { - joined = false; - password = ""; - current_area = 0; - current_char = ""; - remote_ip = p_remote_ip; + joined = false; + password = ""; + current_area = 0; + current_char = ""; + remote_ip = p_remote_ip; } QString AOClient::getHwid() { return hwid; } void AOClient::setHwid(QString p_hwid) { - hwid = p_hwid; + hwid = p_hwid; - QCryptographicHash hash(QCryptographicHash::Md5); // Don't need security, just - // hashing for uniqueness - QString concat_ip_id = remote_ip.toString() + p_hwid; - hash.addData(concat_ip_id.toUtf8()); + QCryptographicHash hash( + QCryptographicHash::Md5); // Don't need security, just + // hashing for uniqueness + QString concat_ip_id = remote_ip.toString() + p_hwid; + hash.addData(concat_ip_id.toUtf8()); - ipid = hash.result().toHex().right(8); + ipid = hash.result().toHex().right(8); } QString AOClient::getIpid() { return ipid; } diff --git a/src/aopacket.cpp b/src/aopacket.cpp index ba5b60a..46cbc6e 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -2,40 +2,40 @@ AOPacket::AOPacket(QString p_header, QStringList p_contents) { - header = p_header; - contents = p_contents; + header = p_header; + contents = p_contents; } AOPacket::AOPacket(QString p_packet) { - QStringList packet_contents = p_packet.split("#"); - if (p_packet.at(0) == '#') { - // The header is encrypted with FantaCrypt - // This should never happen with AO2 2.4.3 or newer - // TODO: implement fantacrypt? maybe? - qDebug() << "FantaCrypt packet received"; - } - else { - header = packet_contents[0]; - } - packet_contents.removeFirst(); // Remove header - packet_contents.removeLast(); // Remove anything trailing after delimiter - contents = packet_contents; + QStringList packet_contents = p_packet.split("#"); + if (p_packet.at(0) == '#') { + // The header is encrypted with FantaCrypt + // This should never happen with AO2 2.4.3 or newer + // TODO: implement fantacrypt? maybe? + qDebug() << "FantaCrypt packet received"; + } + else { + header = packet_contents[0]; + } + packet_contents.removeFirst(); // Remove header + packet_contents.removeLast(); // Remove anything trailing after delimiter + contents = packet_contents; } QString AOPacket::toString() { - QString ao_packet = header; - for (int i = 0; i < contents.length(); i++) { - ao_packet += "#" + contents[i]; - } - ao_packet += "#%"; + QString ao_packet = header; + for (int i = 0; i < contents.length(); i++) { + ao_packet += "#" + contents[i]; + } + ao_packet += "#%"; - return ao_packet; + return ao_packet; } QByteArray AOPacket::toUtf8() { - QString packet_string = toString(); - return packet_string.toUtf8(); + QString packet_string = toString(); + return packet_string.toUtf8(); } diff --git a/src/area_data.cpp b/src/area_data.cpp index 8457f9e..5f7c9b0 100644 --- a/src/area_data.cpp +++ b/src/area_data.cpp @@ -2,8 +2,7 @@ AreaData::AreaData(QStringList characters) { - for(QString cur_char : characters) - { + for (QString cur_char : characters) { characters_taken.insert(cur_char, false); } } diff --git a/src/config_manager.cpp b/src/config_manager.cpp index 6e5d59f..b1f766d 100644 --- a/src/config_manager.cpp +++ b/src/config_manager.cpp @@ -2,212 +2,213 @@ ConfigManager::ConfigManager() { - config = new QSettings("config.ini", QSettings::IniFormat); + config = new QSettings("config.ini", QSettings::IniFormat); } // Validate and set up the config bool ConfigManager::initConfig() { - QFileInfo char_list_info("characters.txt"); - if(!(char_list_info.exists() && char_list_info.isFile())) - { - // TODO: signals go here - QFile char_list("characters.txt"); - if (!char_list.open(QIODevice::WriteOnly | QIODevice::Text)) + QFileInfo char_list_info("characters.txt"); + if (!(char_list_info.exists() && char_list_info.isFile())) { + // TODO: signals go here + QFile char_list("characters.txt"); + if (!char_list.open(QIODevice::WriteOnly | QIODevice::Text)) qDebug() << "Couldn't create character list"; - QTextStream file_stream(&char_list); + QTextStream file_stream(&char_list); - qDebug() << "Creating vanilla character list"; + qDebug() << "Creating vanilla character list"; - file_stream << "Adrian\n"; - file_stream << "Apollo\n"; - file_stream << "April\n"; - file_stream << "Armstrong\n"; - file_stream << "Atmey\n"; - file_stream << "Butz\n"; - file_stream << "Diego\n"; - file_stream << "Edgeworth\n"; - file_stream << "Edgeworthw\n"; - file_stream << "Ema\n"; - file_stream << "EmaSkye\n"; - file_stream << "Franny\n"; - file_stream << "Franziska\n"; - file_stream << "Gant\n"; - file_stream << "Gavin\n"; - file_stream << "Gavin K\n"; - file_stream << "Godot\n"; - file_stream << "Gregory\n"; - file_stream << "Grossberg\n"; - file_stream << "Gumshoe\n"; - file_stream << "Gumshoey\n"; - file_stream << "Hawk\n"; - file_stream << "Hobo_Phoenix\n"; - file_stream << "Ini\n"; - file_stream << "Judge\n"; - file_stream << "Judge's Bro\n"; - file_stream << "Klav\n"; - file_stream << "Klavier\n"; - file_stream << "Kristoph\n"; - file_stream << "Lana\n"; - file_stream << "Layton\n"; - file_stream << "Lotta\n"; - file_stream << "Luis\n"; - file_stream << "Maggey\n"; - file_stream << "Manfred\n"; - file_stream << "Marshall\n"; - file_stream << "Matt\n"; - file_stream << "Maya\n"; - file_stream << "Mia\n"; - file_stream << "Miles\n"; - file_stream << "Oldbag\n"; - file_stream << "Payne\n"; - file_stream << "Pearl\n"; - file_stream << "Phoenix\n"; - file_stream << "Valant\n"; - file_stream << "Vasquez\n"; - file_stream << "Wellington\n"; - file_stream << "Winston\n"; - file_stream << "WinstonPayne\n"; - file_stream << "Young Mia\n"; - file_stream << "Zak\n"; + file_stream << "Adrian\n"; + file_stream << "Apollo\n"; + file_stream << "April\n"; + file_stream << "Armstrong\n"; + file_stream << "Atmey\n"; + file_stream << "Butz\n"; + file_stream << "Diego\n"; + file_stream << "Edgeworth\n"; + file_stream << "Edgeworthw\n"; + file_stream << "Ema\n"; + file_stream << "EmaSkye\n"; + file_stream << "Franny\n"; + file_stream << "Franziska\n"; + file_stream << "Gant\n"; + file_stream << "Gavin\n"; + file_stream << "Gavin K\n"; + file_stream << "Godot\n"; + file_stream << "Gregory\n"; + file_stream << "Grossberg\n"; + file_stream << "Gumshoe\n"; + file_stream << "Gumshoey\n"; + file_stream << "Hawk\n"; + file_stream << "Hobo_Phoenix\n"; + file_stream << "Ini\n"; + file_stream << "Judge\n"; + file_stream << "Judge's Bro\n"; + file_stream << "Klav\n"; + file_stream << "Klavier\n"; + file_stream << "Kristoph\n"; + file_stream << "Lana\n"; + file_stream << "Layton\n"; + file_stream << "Lotta\n"; + file_stream << "Luis\n"; + file_stream << "Maggey\n"; + file_stream << "Manfred\n"; + file_stream << "Marshall\n"; + file_stream << "Matt\n"; + file_stream << "Maya\n"; + file_stream << "Mia\n"; + file_stream << "Miles\n"; + file_stream << "Oldbag\n"; + file_stream << "Payne\n"; + file_stream << "Pearl\n"; + file_stream << "Phoenix\n"; + file_stream << "Valant\n"; + file_stream << "Vasquez\n"; + file_stream << "Wellington\n"; + file_stream << "Winston\n"; + file_stream << "WinstonPayne\n"; + file_stream << "Young Mia\n"; + file_stream << "Zak\n"; - char_list.flush(); - char_list.close(); - } + char_list.flush(); + char_list.close(); + } - config->beginGroup("Info"); - QString config_version = config->value("version", "none").toString(); - config->endGroup(); - if (config_version == "none") { - QFileInfo check_file("config.ini"); - // TODO: put proper translatable warnings here - if (!(check_file.exists() && check_file.isFile())) { - // TODO: send signal config doesn't exist - generateDefaultConfig(false); + config->beginGroup("Info"); + QString config_version = config->value("version", "none").toString(); + config->endGroup(); + if (config_version == "none") { + QFileInfo check_file("config.ini"); + // TODO: put proper translatable warnings here + if (!(check_file.exists() && check_file.isFile())) { + // TODO: send signal config doesn't exist + generateDefaultConfig(false); + } + else { + // TODO: send signal config is invalid + generateDefaultConfig(true); + } + return false; + } + else if (config_version != QString::number(CONFIG_VERSION)) { + bool version_number_is_valid; + int current_version = config_version.toInt(&version_number_is_valid); + if (version_number_is_valid) + updateConfig(current_version); + else + generateDefaultConfig(true); // Version number isn't a number at all + // This means the config is invalid + // TODO: send invalid config signal + return false; } else { - // TODO: send signal config is invalid - generateDefaultConfig(true); + // Config is valid and up to date, so let's go ahead + return true; } - return false; - } - else if (config_version != QString::number(CONFIG_VERSION)) { - bool version_number_is_valid; - int current_version = config_version.toInt(&version_number_is_valid); - if (version_number_is_valid) - updateConfig(current_version); - else - generateDefaultConfig(true); // Version number isn't a number at all - // This means the config is invalid - // TODO: send invalid config signal - return false; - } - else { - // Config is valid and up to date, so let's go ahead - return true; - } } // Setting backup_old to true will move the existing config.ini to // config_old.ini void ConfigManager::generateDefaultConfig(bool backup_old) { - qDebug() << "Config is invalid or missing, making a new one..."; - QDir dir = QDir::current(); - if (backup_old) { - // TODO: failsafe if config_old.ini already exists - dir.rename("config.ini", "config_old.ini"); - } + qDebug() << "Config is invalid or missing, making a new one..."; + QDir dir = QDir::current(); + if (backup_old) { + // TODO: failsafe if config_old.ini already exists + dir.rename("config.ini", "config_old.ini"); + } - // Group: Info - // This contains basic metadata about the config - config->beginGroup("Info"); - config->setValue("version", CONFIG_VERSION); - config->endGroup(); + // Group: Info + // This contains basic metadata about the config + config->beginGroup("Info"); + config->setValue("version", CONFIG_VERSION); + config->endGroup(); - // Group: Options - // This contains general configuration - config->beginGroup("Options"); - config->setValue("language", "en"); - config->setValue("hostname", "$H"); - config->setValue("max_players", "100"); - config->setValue("port", "27016"); - config->setValue("webao_enable", "true"); - config->setValue("webao_port", "27017"); - config->setValue("modpass", "password"); - config->setValue("advertise", "true"); - config->setValue("ms_ip", "master.aceattorneyonline.com"); - config->setValue("ms_port", "27016"); - config->setValue("server_name", "My First Server"); - config->setValue("server_description", "This is my flashy new server"); - config->setValue("multiclient_limit", "16"); - config->setValue("max_message_size", "256"); - config->endGroup(); + // Group: Options + // This contains general configuration + config->beginGroup("Options"); + config->setValue("language", "en"); + config->setValue("hostname", "$H"); + config->setValue("max_players", "100"); + config->setValue("port", "27016"); + config->setValue("webao_enable", "true"); + config->setValue("webao_port", "27017"); + config->setValue("modpass", "password"); + config->setValue("advertise", "true"); + config->setValue("ms_ip", "master.aceattorneyonline.com"); + config->setValue("ms_port", "27016"); + config->setValue("server_name", "My First Server"); + config->setValue("server_description", "This is my flashy new server"); + config->setValue("multiclient_limit", "16"); + config->setValue("max_message_size", "256"); + config->endGroup(); } // Ensure version continuity with config versions void ConfigManager::updateConfig(int current_version) { - if (current_version > CONFIG_VERSION) { - // Config version is newer than the latest version, and the config is - // invalid This could also mean the server is out of date, and the user - // should be shown a relevant message Regardless, regen the config anyways - // TODO: send signal config is invalid - generateDefaultConfig(true); - } - else if (current_version < 0) { - // Negative version number? Invalid! - generateDefaultConfig(true); - } - else { - // TODO: send signal config is out of date, and is being updated - // Update the config as needed using a switch. This is nice because we can - // fall through as we go up the version ladder. - switch (current_version) { - case 0: // Version 0 doesn't actually exist, but we should check for it just - // in case - case 1: - config->beginGroup("Info"); - config->setValue("version", CONFIG_VERSION); - config->endGroup(); - break; // This is the newest version, and nothing more needs to be done + if (current_version > CONFIG_VERSION) { + // Config version is newer than the latest version, and the config is + // invalid This could also mean the server is out of date, and the user + // should be shown a relevant message Regardless, regen the config + // anyways + // TODO: send signal config is invalid + generateDefaultConfig(true); + } + else if (current_version < 0) { + // Negative version number? Invalid! + generateDefaultConfig(true); + } + else { + // TODO: send signal config is out of date, and is being updated + // Update the config as needed using a switch. This is nice because we + // can fall through as we go up the version ladder. + switch (current_version) { + case 0: // Version 0 doesn't actually exist, but we should check for it + // just in case + case 1: + config->beginGroup("Info"); + config->setValue("version", CONFIG_VERSION); + config->endGroup(); + break; // This is the newest version, and nothing more needs to be + // done + } } - } } // Validate and retriever settings related to advertising and the server -bool ConfigManager::loadServerSettings(server_settings *settings) +bool ConfigManager::loadServerSettings(server_settings* settings) { - bool port_conversion_success; - bool ws_port_conversion_success; - bool local_port_conversion_success; - config->beginGroup("Options"); - settings->ms_ip = - config->value("ms_ip", "master.aceattorneyonline.com").toString(); - settings->port = - config->value("ms_port", "27016").toInt(&port_conversion_success); - settings->ws_port = - config->value("webao_port", "27017").toInt(&ws_port_conversion_success); - settings->local_port = - config->value("port", "27016").toInt(&local_port_conversion_success); - settings->name = config->value("server_name", "My First Server").toString(); - settings->description = - config->value("server_description", "This is my flashy new server") - .toString(); - config->endGroup(); - if (!port_conversion_success || !ws_port_conversion_success || - !local_port_conversion_success) { - return false; - } - else { - if (config->value("advertise", "true").toString() != "true") - settings->advertise_server = false; - else - settings->advertise_server = true; + bool port_conversion_success; + bool ws_port_conversion_success; + bool local_port_conversion_success; + config->beginGroup("Options"); + settings->ms_ip = + config->value("ms_ip", "master.aceattorneyonline.com").toString(); + settings->port = + config->value("ms_port", "27016").toInt(&port_conversion_success); + settings->ws_port = + config->value("webao_port", "27017").toInt(&ws_port_conversion_success); + settings->local_port = + config->value("port", "27016").toInt(&local_port_conversion_success); + settings->name = config->value("server_name", "My First Server").toString(); + settings->description = + config->value("server_description", "This is my flashy new server") + .toString(); + config->endGroup(); + if (!port_conversion_success || !ws_port_conversion_success || + !local_port_conversion_success) { + return false; + } + else { + if (config->value("advertise", "true").toString() != "true") + settings->advertise_server = false; + else + settings->advertise_server = true; - if (config->value("webao_enable", "true").toString() != "true") - settings->ws_port = -1; + if (config->value("webao_enable", "true").toString() != "true") + settings->ws_port = -1; - return true; - } + return true; + } } diff --git a/src/main.cpp b/src/main.cpp index 878e546..7a159c0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,48 +8,49 @@ #include #include -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - QApplication app(argc, argv); - QApplication::setApplicationName("akashi"); - QApplication::setApplicationVersion("0.0.1"); + QApplication app(argc, argv); + QApplication::setApplicationName("akashi"); + QApplication::setApplicationVersion("0.0.1"); - QSettings config("config.ini", QSettings::IniFormat); - config.beginGroup("Options"); - QString language = config.value("language", QLocale().bcp47Name()).toString(); + QSettings config("config.ini", QSettings::IniFormat); + config.beginGroup("Options"); + QString language = + config.value("language", QLocale().bcp47Name()).toString(); - QTranslator qt_translator; - qt_translator.load("qt_" + language, - QLibraryInfo::location(QLibraryInfo::TranslationsPath)); - app.installTranslator(&qt_translator); + QTranslator qt_translator; + qt_translator.load("qt_" + language, + QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + app.installTranslator(&qt_translator); - QTranslator translator; - translator.load("akashi_" + language, ":/resource/translation/"); - app.installTranslator(&translator); + QTranslator translator; + translator.load("akashi_" + language, ":/resource/translation/"); + app.installTranslator(&translator); - QCommandLineParser parser; - parser.setApplicationDescription( - app.translate("main", "A server for Attorney Online 2")); - parser.addHelpOption(); - parser.addVersionOption(); + QCommandLineParser parser; + parser.setApplicationDescription( + app.translate("main", "A server for Attorney Online 2")); + parser.addHelpOption(); + parser.addVersionOption(); - QCommandLineOption headlessOption( - QStringList() << "l" - << "headless", - app.translate("main", "Run the server without a GUI.")); - QCommandLineOption verboseNetworkOption( - QStringList() << "nv" - << "verbose-network", - app.translate("main", "Write all network traffic to the console.")); - parser.addOption(headlessOption); - parser.addOption(verboseNetworkOption); + QCommandLineOption headlessOption( + QStringList() << "l" + << "headless", + app.translate("main", "Run the server without a GUI.")); + QCommandLineOption verboseNetworkOption( + QStringList() << "nv" + << "verbose-network", + app.translate("main", "Write all network traffic to the console.")); + parser.addOption(headlessOption); + parser.addOption(verboseNetworkOption); - parser.process(app); - bool headless = parser.isSet(headlessOption); + parser.process(app); + bool headless = parser.isSet(headlessOption); - AkashiMain w; - if (!headless) - w.show(); + AkashiMain w; + if (!headless) + w.show(); - return app.exec(); + return app.exec(); } diff --git a/src/server.cpp b/src/server.cpp index 789e589..d90c8ca 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,241 +1,249 @@ #include "include/server.h" -Server::Server(int p_port, int p_ws_port, QObject *parent) : QObject(parent) +Server::Server(int p_port, int p_ws_port, QObject* parent) : QObject(parent) { - server = new QTcpServer(this); - connect(server, SIGNAL(newConnection()), this, SLOT(clientConnected())); + server = new QTcpServer(this); + connect(server, SIGNAL(newConnection()), this, SLOT(clientConnected())); - port = p_port; - ws_port = p_ws_port; + port = p_port; + ws_port = p_ws_port; - player_count = 0; + player_count = 0; } void Server::start() { - // TODO: websockets lul - // Maybe websockets should be handled by a separate intermediate part of the - // code? The idea being that it is a websocket server, and all it does is - // create a local connection to the raw tcp server. The main issue with this - // is that it will cause problems with bans, ipids, etc But perhaps this can - // be negotiated by sending some extra data over? No idea. I'll wait for long - // to read this massive comment and DM me on discord - // - // Upon thinking about this a bit more, I realized basically all of the - // communication only happens via QTcpSocket* pointers. - // If the Qt WebSocket server gives me QTcpSockets to work with, - // then they can all go into the same object. I doubt this is the case, though - if (!server->listen(QHostAddress::Any, port)) { - // TODO: signal server start failed - qDebug() << "Server error:" << server->errorString(); - } - else { - // TODO: signal server start success - qDebug() << "Server listening on" << port; - } + // TODO: websockets lul + // Maybe websockets should be handled by a separate intermediate part of the + // code? The idea being that it is a websocket server, and all it does is + // create a local connection to the raw tcp server. The main issue with this + // is that it will cause problems with bans, ipids, etc But perhaps this can + // be negotiated by sending some extra data over? No idea. I'll wait for + // long to read this massive comment and DM me on discord + // + // Upon thinking about this a bit more, I realized basically all of the + // communication only happens via QTcpSocket* pointers. + // If the Qt WebSocket server gives me QTcpSockets to work with, + // then they can all go into the same object. I doubt this is the case, + // though + if (!server->listen(QHostAddress::Any, port)) { + // TODO: signal server start failed + qDebug() << "Server error:" << server->errorString(); + } + else { + // TODO: signal server start success + qDebug() << "Server listening on" << port; + } - QFile char_list("characters.txt"); - char_list.open(QIODevice::ReadOnly | QIODevice::Text); - while(!char_list.atEnd()) - { - characters.append(char_list.readLine().trimmed()); - } + QFile char_list("characters.txt"); + char_list.open(QIODevice::ReadOnly | QIODevice::Text); + while (!char_list.atEnd()) { + characters.append(char_list.readLine().trimmed()); + } - // TODO: actually read areas from config - areas.append(new AreaData(characters)); - areas[0]->name = "basement lol"; + // TODO: actually read areas from config + areas.append(new AreaData(characters)); + areas[0]->name = "basement lol"; } void Server::clientConnected() { - QTcpSocket *client = server->nextPendingConnection(); - AOClient *ao_client = new AOClient(client->peerAddress()); - clients.insert(client, ao_client); - connect(client, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); - connect(client, SIGNAL(readyRead()), this, SLOT(clientData())); + QTcpSocket* client = server->nextPendingConnection(); + AOClient* ao_client = new AOClient(client->peerAddress()); + clients.insert(client, ao_client); + connect(client, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); + connect(client, SIGNAL(readyRead()), this, SLOT(clientData())); - AOPacket decryptor("decryptor", {"NOENCRYPT"}); // This is the infamous workaround for tsuserver4 - // It should disable fantacrypt completely in any client 2.4.3 or newer - client->write(decryptor.toUtf8()); + AOPacket decryptor( + "decryptor", {"NOENCRYPT"}); // This is the infamous workaround for + // tsuserver4 It should disable fantacrypt + // completely in any client 2.4.3 or newer + client->write(decryptor.toUtf8()); - qDebug() << client->peerAddress().toString() << "connected"; + qDebug() << client->peerAddress().toString() << "connected"; } void Server::clientDisconnected() { - if (QTcpSocket *client = dynamic_cast(sender())) { - qDebug() << client->peerAddress() << "disconnected"; - AOClient* ao_client = clients.value(client); - if (ao_client->joined) - player_count--; - areas.value(ao_client->current_area)->characters_taken[ao_client->current_char] = false; + if (QTcpSocket* client = dynamic_cast(sender())) { + qDebug() << client->peerAddress() << "disconnected"; + AOClient* ao_client = clients.value(client); + if (ao_client->joined) + player_count--; + areas.value(ao_client->current_area) + ->characters_taken[ao_client->current_char] = false; - delete ao_client; - clients.remove(client); - } + delete ao_client; + clients.remove(client); + } } void Server::clientData() { - if (QTcpSocket *client = dynamic_cast(sender())) { - QString data = QString::fromUtf8(client->readAll()); - // qDebug() << "From" << client->peerAddress() << ":" << data; + if (QTcpSocket* client = dynamic_cast(sender())) { + QString data = QString::fromUtf8(client->readAll()); + // qDebug() << "From" << client->peerAddress() << ":" << data; - if (is_partial) { - data = partial_packet + data; - } - if (!data.endsWith("%")) { - is_partial = true; - } + if (is_partial) { + data = partial_packet + data; + } + if (!data.endsWith("%")) { + is_partial = true; + } - QStringList all_packets = data.split("%"); - all_packets.removeLast(); // Remove the entry after the last delimiter + QStringList all_packets = data.split("%"); + all_packets.removeLast(); // Remove the entry after the last delimiter - for (QString single_packet : all_packets) { - AOPacket packet(single_packet); - handlePacket(packet, client); + for (QString single_packet : all_packets) { + AOPacket packet(single_packet); + handlePacket(packet, client); + } } - } } -void Server::handlePacket(AOPacket packet, QTcpSocket *socket) +void Server::handlePacket(AOPacket packet, QTcpSocket* socket) { - // TODO: like everything here should send a signal - qDebug() << "Received packet:" << packet.header << ":" << packet.contents; - AOClient *client = clients.value(socket); - AreaData *area = areas.value(client->current_area); - // Lord forgive me - if (packet.header == "HI") { - AOClient *client = clients.value(socket); - client->setHwid(packet.contents[0]); + // TODO: like everything here should send a signal + qDebug() << "Received packet:" << packet.header << ":" << packet.contents; + AOClient* client = clients.value(socket); + AreaData* area = areas.value(client->current_area); + // Lord forgive me + if (packet.header == "HI") { + AOClient* client = clients.value(socket); + client->setHwid(packet.contents[0]); - AOPacket response("ID", - {"271828", "akashi", QApplication::applicationVersion()}); - socket->write(response.toUtf8()); - } - else if (packet.header == "ID") { - QSettings config("config.ini", QSettings::IniFormat); - config.beginGroup("Options"); - QString max_players = config.value("max_players").toString(); - config.endGroup(); - - // Full feature list as of AO 2.8.5 - // The only ones that are critical to ensuring the server works are - // "noencryption" and "fastloading" - // TODO: make the rest of these user configurable - QStringList feature_list = { - "noencryption", "yellowtext", "prezoom", "flipping", - "customobjections", "fastloading", "deskmod", "evidence", - "cccc_ic_support", "arup", "casing_alserts", "modcall_reason", - "looping_sfx", "additive", "effects"}; - - AOPacket response_pn("PN", {QString::number(player_count), max_players}); - AOPacket response_fl("FL", feature_list); - socket->write(response_pn.toUtf8()); - socket->write(response_fl.toUtf8()); - } - else if (packet.header == "askchaa") { - // TODO: add user configurable content - // For testing purposes, we will just send enough to get things working - AOPacket response("SI", {QString::number(characters.length()), "0", "1"}); - qDebug() << response.toString(); - socket->write(response.toUtf8()); - } - else if (packet.header == "RC") { - AOPacket response("SC", characters); - socket->write(response.toUtf8()); - } - else if (packet.header == "RM") { - AOPacket response("SM", {"~stop.mp3"}); - socket->write(response.toUtf8()); - } - else if (packet.header == "RD") { - player_count++; - client->joined = true; - - QStringList chars_taken; - for(QString cur_char : area->characters_taken.keys()) - { - chars_taken.append(area->characters_taken.value(cur_char) ? QStringLiteral("-1") : QStringLiteral("0")); + AOPacket response( + "ID", {"271828", "akashi", QApplication::applicationVersion()}); + socket->write(response.toUtf8()); } + else if (packet.header == "ID") { + QSettings config("config.ini", QSettings::IniFormat); + config.beginGroup("Options"); + QString max_players = config.value("max_players").toString(); + config.endGroup(); - AOPacket response_cc("CharsCheck", chars_taken); - AOPacket response_op("OPPASS", {"DEADBEEF"}); - AOPacket response_done("DONE", {}); - socket->write(response_cc.toUtf8()); - socket->write(response_op.toUtf8()); - socket->write(response_done.toUtf8()); - } - else if (packet.header == "PW") { - client->password = packet.contents[0]; - } - else if (packet.header == "CC") { - bool argument_ok; - int char_id = packet.contents[1].toInt(&argument_ok); - if(!argument_ok) - return; + // Full feature list as of AO 2.8.5 + // The only ones that are critical to ensuring the server works are + // "noencryption" and "fastloading" + // TODO: make the rest of these user configurable + QStringList feature_list = { + "noencryption", "yellowtext", "prezoom", + "flipping", "customobjections", "fastloading", + "deskmod", "evidence", "cccc_ic_support", + "arup", "casing_alserts", "modcall_reason", + "looping_sfx", "additive", "effects"}; - QString char_selected = characters[char_id]; - bool taken = area->characters_taken.value(char_selected); - if(taken || char_selected == "") - return; - - if(client->current_char != "") { - area->characters_taken[client->current_char] = false; + AOPacket response_pn("PN", + {QString::number(player_count), max_players}); + AOPacket response_fl("FL", feature_list); + socket->write(response_pn.toUtf8()); + socket->write(response_fl.toUtf8()); } - - area->characters_taken[char_selected] = true; - client->current_char = char_selected; - - QStringList chars_taken; - for(QString cur_char : area->characters_taken.keys()) - { - chars_taken.append(area->characters_taken.value(cur_char) ? QStringLiteral("-1") : QStringLiteral("0")); + else if (packet.header == "askchaa") { + // TODO: add user configurable content + // For testing purposes, we will just send enough to get things working + AOPacket response("SI", + {QString::number(characters.length()), "0", "1"}); + qDebug() << response.toString(); + socket->write(response.toUtf8()); } + else if (packet.header == "RC") { + AOPacket response("SC", characters); + socket->write(response.toUtf8()); + } + else if (packet.header == "RM") { + AOPacket response("SM", {"~stop.mp3"}); + socket->write(response.toUtf8()); + } + else if (packet.header == "RD") { + player_count++; + client->joined = true; - AOPacket response_cc("CharsCheck", chars_taken); - AOPacket response_pv("PV", {"271828", "CID", packet.contents[1]}); - socket->write(response_pv.toUtf8()); - socket->write(response_cc.toUtf8()); - } - else if (packet.header == "MS") { - // TODO: validate, validate, validate - broadcast(packet); - } - else if (packet.header == "CT") { - // TODO: commands - // TODO: zalgo strip - broadcast(packet); - } - else if (packet.header == "CH") { - // Why does this packet exist - AOPacket response("CHECK", {}); - socket->write(response.toUtf8()); - } - else if (packet.header == "what") { - AOPacket response("CT", - {"Made with love", "by scatterflower and windrammer"}); - } - else { - qDebug() << "Unimplemented packet:" << packet.header; - qDebug() << packet.contents; - } - socket->flush(); + QStringList chars_taken; + for (QString cur_char : area->characters_taken.keys()) { + chars_taken.append(area->characters_taken.value(cur_char) + ? QStringLiteral("-1") + : QStringLiteral("0")); + } + + AOPacket response_cc("CharsCheck", chars_taken); + AOPacket response_op("OPPASS", {"DEADBEEF"}); + AOPacket response_done("DONE", {}); + socket->write(response_cc.toUtf8()); + socket->write(response_op.toUtf8()); + socket->write(response_done.toUtf8()); + } + else if (packet.header == "PW") { + client->password = packet.contents[0]; + } + else if (packet.header == "CC") { + bool argument_ok; + int char_id = packet.contents[1].toInt(&argument_ok); + if (!argument_ok) + return; + + QString char_selected = characters[char_id]; + bool taken = area->characters_taken.value(char_selected); + if (taken || char_selected == "") + return; + + if (client->current_char != "") { + area->characters_taken[client->current_char] = false; + } + + area->characters_taken[char_selected] = true; + client->current_char = char_selected; + + QStringList chars_taken; + for (QString cur_char : area->characters_taken.keys()) { + chars_taken.append(area->characters_taken.value(cur_char) + ? QStringLiteral("-1") + : QStringLiteral("0")); + } + + AOPacket response_cc("CharsCheck", chars_taken); + AOPacket response_pv("PV", {"271828", "CID", packet.contents[1]}); + socket->write(response_pv.toUtf8()); + socket->write(response_cc.toUtf8()); + } + else if (packet.header == "MS") { + // TODO: validate, validate, validate + broadcast(packet); + } + else if (packet.header == "CT") { + // TODO: commands + // TODO: zalgo strip + broadcast(packet); + } + else if (packet.header == "CH") { + // Why does this packet exist + AOPacket response("CHECK", {}); + socket->write(response.toUtf8()); + } + else if (packet.header == "what") { + AOPacket response( + "CT", {"Made with love", "by scatterflower and windrammer"}); + } + else { + qDebug() << "Unimplemented packet:" << packet.header; + qDebug() << packet.contents; + } + socket->flush(); } void Server::broadcast(AOPacket packet) { - for (QTcpSocket *client : clients.keys()) { - client->write(packet.toUtf8()); - client->flush(); - } + for (QTcpSocket* client : clients.keys()) { + client->write(packet.toUtf8()); + client->flush(); + } } -QTcpSocket *Server::getClient(QString ipid) +QTcpSocket* Server::getClient(QString ipid) { - for (QTcpSocket *client : clients.keys()) { - if (clients.value(client)->getIpid() == ipid) - return client; - } - return nullptr; + for (QTcpSocket* client : clients.keys()) { + if (clients.value(client)->getIpid() == ipid) + return client; + } + return nullptr; }