clang format, and indentation change

This commit is contained in:
scatterflower 2020-08-25 07:07:08 -05:00
parent be8d8b215e
commit 42df56942b
16 changed files with 613 additions and 596 deletions

View File

@ -1,2 +1,5 @@
BasedOnStyle: LLVM BasedOnStyle: LLVM
BreakBeforeBraces: Stroustrup IndentWidth: 4
Language: Cpp
PointerAlignment: Left
BreakBeforeBraces: Stroustrup

View File

@ -9,29 +9,30 @@
#include <QTcpSocket> #include <QTcpSocket>
class Advertiser : public QObject { class Advertiser : public QObject {
Q_OBJECT Q_OBJECT
public: public:
Advertiser(QString p_ip, int p_port, int p_ws_port, int p_local_port, Advertiser(QString p_ip, int p_port, int p_ws_port, int p_local_port,
QString p_name, QString p_description, QObject *parent = nullptr); QString p_name, QString p_description,
void contactMasterServer(); QObject* parent = nullptr);
void contactMasterServer();
signals: signals:
public slots: public slots:
void readData(); void readData();
void socketConnected(); void socketConnected();
void socketDisconnected(); void socketDisconnected();
private: private:
QString ip; QString ip;
int port; int port;
int ws_port; int ws_port;
int local_port; int local_port;
QString name; QString name;
QString description; QString description;
QTcpSocket *socket; QTcpSocket* socket;
}; };
#endif // MASTER_H #endif // MASTER_H

View File

@ -16,20 +16,20 @@ class AkashiMain;
QT_END_NAMESPACE QT_END_NAMESPACE
class AkashiMain : public QMainWindow { class AkashiMain : public QMainWindow {
Q_OBJECT Q_OBJECT
public: public:
AkashiMain(QWidget *parent = nullptr); AkashiMain(QWidget* parent = nullptr);
~AkashiMain(); ~AkashiMain();
ConfigManager config_manager; ConfigManager config_manager;
void generateDefaultConfig(bool backup_old); void generateDefaultConfig(bool backup_old);
void updateConfig(int current_version); void updateConfig(int current_version);
private: private:
Ui::AkashiMain *ui; Ui::AkashiMain* ui;
Advertiser *advertiser; Advertiser* advertiser;
Server *server; Server* server;
}; };
#endif // AKASHIMAIN_H #endif // AKASHIMAIN_H

View File

@ -6,24 +6,24 @@
#include <QTcpSocket> #include <QTcpSocket>
class AOClient { class AOClient {
public: public:
AOClient(QHostAddress p_remote_ip); AOClient(QHostAddress p_remote_ip);
~AOClient(); ~AOClient();
QString getHwid(); QString getHwid();
void setHwid(QString p_hwid); void setHwid(QString p_hwid);
QString getIpid(); QString getIpid();
QHostAddress remote_ip; QHostAddress remote_ip;
QString password; QString password;
bool joined; bool joined;
int current_area; int current_area;
QString current_char; QString current_char;
private: private:
QString hwid; QString hwid;
QString ipid; QString ipid;
}; };
#endif // AOCLIENT_H #endif // AOCLIENT_H

View File

@ -7,14 +7,14 @@
#include <QStringList> #include <QStringList>
class AOPacket { class AOPacket {
public: public:
AOPacket(QString p_header, QStringList p_contents); AOPacket(QString p_header, QStringList p_contents);
AOPacket(QString packet); AOPacket(QString packet);
QString toString(); QString toString();
QByteArray toUtf8(); QByteArray toUtf8();
QString header; QString header;
QStringList contents; QStringList contents;
}; };
#endif // PACKET_MANAGER_H #endif // PACKET_MANAGER_H

View File

@ -1,11 +1,11 @@
#ifndef AREA_DATA_H #ifndef AREA_DATA_H
#define AREA_DATA_H #define AREA_DATA_H
#include <QString>
#include <QMap> #include <QMap>
#include <QString>
class AreaData { class AreaData {
public: public:
AreaData(QStringList characters); AreaData(QStringList characters);
QString name; QString name;

View File

@ -5,31 +5,31 @@
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QFileInfo>
#include <QFile> #include <QFile>
#include <QFileInfo>
#include <QSettings> #include <QSettings>
class ConfigManager { class ConfigManager {
public: public:
ConfigManager(); ConfigManager();
bool initConfig(); bool initConfig();
void generateDefaultConfig(bool backup_old); void generateDefaultConfig(bool backup_old);
void updateConfig(int current_version); void updateConfig(int current_version);
struct server_settings { struct server_settings {
QString ms_ip; QString ms_ip;
int port; int port;
int ws_port; int ws_port;
int local_port; int local_port;
QString name; QString name;
QString description; QString description;
bool advertise_server; bool advertise_server;
}; };
bool loadServerSettings(server_settings *settings); bool loadServerSettings(server_settings* settings);
private: private:
QSettings *config; QSettings* config;
}; };
#endif // CONFIG_MANAGER_H #endif // CONFIG_MANAGER_H

View File

@ -7,44 +7,44 @@
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
#include <QFile>
#include <QMap> #include <QMap>
#include <QSettings> #include <QSettings>
#include <QString> #include <QString>
#include <QTcpServer> #include <QTcpServer>
#include <QTcpSocket> #include <QTcpSocket>
#include <QFile>
class Server : public QObject { class Server : public QObject {
Q_OBJECT Q_OBJECT
public: public:
Server(int p_port, int p_ws_port, QObject *parent = nullptr); Server(int p_port, int p_ws_port, QObject* parent = nullptr);
void start(); void start();
signals: signals:
public slots: public slots:
void clientConnected(); void clientConnected();
void clientDisconnected(); void clientDisconnected();
void clientData(); void clientData();
private: private:
void handlePacket(AOPacket packet, QTcpSocket *socket); void handlePacket(AOPacket packet, QTcpSocket* socket);
QTcpSocket *getClient(QString ipid); QTcpSocket* getClient(QString ipid);
void broadcast(AOPacket packet); void broadcast(AOPacket packet);
QTcpServer *server; QTcpServer* server;
int port; int port;
int ws_port; int ws_port;
QMap<QTcpSocket *, AOClient *> clients; QMap<QTcpSocket*, AOClient*> clients;
QString partial_packet; QString partial_packet;
bool is_partial; bool is_partial;
int player_count; int player_count;
QStringList characters; QStringList characters;
QVector<AreaData*> areas; QVector<AreaData*> areas;
}; };
#endif // SERVER_H #endif // SERVER_H

View File

@ -2,59 +2,61 @@
Advertiser::Advertiser(QString p_ip, int p_port, int p_ws_port, Advertiser::Advertiser(QString p_ip, int p_port, int p_ws_port,
int p_local_port, QString p_name, QString p_description, int p_local_port, QString p_name, QString p_description,
QObject *parent) QObject* parent)
: QObject(parent) : QObject(parent)
{ {
ip = p_ip; ip = p_ip;
port = p_port; port = p_port;
ws_port = p_ws_port; ws_port = p_ws_port;
local_port = p_local_port; local_port = p_local_port;
name = p_name; name = p_name;
description = p_description; description = p_description;
} }
void Advertiser::contactMasterServer() void Advertiser::contactMasterServer()
{ {
socket = new QTcpSocket(this); socket = new QTcpSocket(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(readData())); connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
connect(socket, SIGNAL(connected()), this, SLOT(socketConnected())); connect(socket, SIGNAL(connected()), this, SLOT(socketConnected()));
connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
socket->connectToHost(ip, port); socket->connectToHost(ip, port);
} }
void Advertiser::readData() void Advertiser::readData()
{ {
// The information coming back from the MS isn't very useful // The information coming back from the MS isn't very useful
// However, it can be useful to see it when debugging // However, it can be useful to see it when debugging
// TODO: master network debug switch // TODO: master network debug switch
// qDebug() << "From MS:" << socket->readAll(); // qDebug() << "From MS:" << socket->readAll();
} }
void Advertiser::socketConnected() void Advertiser::socketConnected()
{ {
// TODO: fire a signal here, i18n // TODO: fire a signal here, i18n
qDebug("Connected to the master server"); qDebug("Connected to the master server");
QString concat_ports; QString concat_ports;
if (ws_port == -1) if (ws_port == -1)
concat_ports = QString::number(local_port); concat_ports = QString::number(local_port);
else else
concat_ports = QString::number(local_port) + "&" + QString::number(ws_port); concat_ports =
QString::number(local_port) + "&" + QString::number(ws_port);
AOPacket ao_packet("SCC", {concat_ports, name, description, AOPacket ao_packet("SCC",
"akashi v" + QApplication::applicationVersion()}); {concat_ports, name, description,
QByteArray data = ao_packet.toUtf8(); "akashi v" + QApplication::applicationVersion()});
QByteArray data = ao_packet.toUtf8();
socket->write(data); socket->write(data);
// TODO: master network debug switch // TODO: master network debug switch
// should be a separate one for MS as well // should be a separate one for MS as well
// qDebug() << "To MS:" << data; // qDebug() << "To MS:" << data;
socket->flush(); socket->flush();
} }
void Advertiser::socketDisconnected() void Advertiser::socketDisconnected()
{ {
// TODO: fire a signal here, i18n // TODO: fire a signal here, i18n
qDebug("Connection to master server lost"); qDebug("Connection to master server lost");
} }

View File

@ -1,42 +1,43 @@
#include "include/akashimain.h" #include "include/akashimain.h"
#include "ui_akashimain.h" #include "ui_akashimain.h"
AkashiMain::AkashiMain(QWidget *parent) AkashiMain::AkashiMain(QWidget* parent)
: QMainWindow(parent), config_manager(), ui(new Ui::AkashiMain) : QMainWindow(parent), config_manager(), ui(new Ui::AkashiMain)
{ {
ui->setupUi(this); ui->setupUi(this);
qDebug("Main application started"); qDebug("Main application started");
if (config_manager.initConfig()) { if (config_manager.initConfig()) {
// Config is sound, so proceed with starting the server // Config is sound, so proceed with starting the server
// Validate some of the config before passing it on // Validate some of the config before passing it on
ConfigManager::server_settings settings; ConfigManager::server_settings settings;
bool config_valid = config_manager.loadServerSettings(&settings); bool config_valid = config_manager.loadServerSettings(&settings);
if (!config_valid) { if (!config_valid) {
// TODO: send signal config invalid // TODO: send signal config invalid
config_manager.generateDefaultConfig(true); 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() AkashiMain::~AkashiMain()
{ {
delete ui; delete ui;
delete advertiser; delete advertiser;
delete server; delete server;
} }

View File

@ -2,25 +2,26 @@
AOClient::AOClient(QHostAddress p_remote_ip) AOClient::AOClient(QHostAddress p_remote_ip)
{ {
joined = false; joined = false;
password = ""; password = "";
current_area = 0; current_area = 0;
current_char = ""; current_char = "";
remote_ip = p_remote_ip; remote_ip = p_remote_ip;
} }
QString AOClient::getHwid() { return hwid; } QString AOClient::getHwid() { return hwid; }
void AOClient::setHwid(QString p_hwid) void AOClient::setHwid(QString p_hwid)
{ {
hwid = p_hwid; hwid = p_hwid;
QCryptographicHash hash(QCryptographicHash::Md5); // Don't need security, just QCryptographicHash hash(
// hashing for uniqueness QCryptographicHash::Md5); // Don't need security, just
QString concat_ip_id = remote_ip.toString() + p_hwid; // hashing for uniqueness
hash.addData(concat_ip_id.toUtf8()); 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; } QString AOClient::getIpid() { return ipid; }

View File

@ -2,40 +2,40 @@
AOPacket::AOPacket(QString p_header, QStringList p_contents) AOPacket::AOPacket(QString p_header, QStringList p_contents)
{ {
header = p_header; header = p_header;
contents = p_contents; contents = p_contents;
} }
AOPacket::AOPacket(QString p_packet) AOPacket::AOPacket(QString p_packet)
{ {
QStringList packet_contents = p_packet.split("#"); QStringList packet_contents = p_packet.split("#");
if (p_packet.at(0) == '#') { if (p_packet.at(0) == '#') {
// The header is encrypted with FantaCrypt // The header is encrypted with FantaCrypt
// This should never happen with AO2 2.4.3 or newer // This should never happen with AO2 2.4.3 or newer
// TODO: implement fantacrypt? maybe? // TODO: implement fantacrypt? maybe?
qDebug() << "FantaCrypt packet received"; qDebug() << "FantaCrypt packet received";
} }
else { else {
header = packet_contents[0]; header = packet_contents[0];
} }
packet_contents.removeFirst(); // Remove header packet_contents.removeFirst(); // Remove header
packet_contents.removeLast(); // Remove anything trailing after delimiter packet_contents.removeLast(); // Remove anything trailing after delimiter
contents = packet_contents; contents = packet_contents;
} }
QString AOPacket::toString() QString AOPacket::toString()
{ {
QString ao_packet = header; QString ao_packet = header;
for (int i = 0; i < contents.length(); i++) { for (int i = 0; i < contents.length(); i++) {
ao_packet += "#" + contents[i]; ao_packet += "#" + contents[i];
} }
ao_packet += "#%"; ao_packet += "#%";
return ao_packet; return ao_packet;
} }
QByteArray AOPacket::toUtf8() QByteArray AOPacket::toUtf8()
{ {
QString packet_string = toString(); QString packet_string = toString();
return packet_string.toUtf8(); return packet_string.toUtf8();
} }

View File

@ -2,8 +2,7 @@
AreaData::AreaData(QStringList characters) AreaData::AreaData(QStringList characters)
{ {
for(QString cur_char : characters) for (QString cur_char : characters) {
{
characters_taken.insert(cur_char, false); characters_taken.insert(cur_char, false);
} }
} }

View File

@ -2,212 +2,213 @@
ConfigManager::ConfigManager() ConfigManager::ConfigManager()
{ {
config = new QSettings("config.ini", QSettings::IniFormat); config = new QSettings("config.ini", QSettings::IniFormat);
} }
// Validate and set up the config // Validate and set up the config
bool ConfigManager::initConfig() bool ConfigManager::initConfig()
{ {
QFileInfo char_list_info("characters.txt"); QFileInfo char_list_info("characters.txt");
if(!(char_list_info.exists() && char_list_info.isFile())) if (!(char_list_info.exists() && char_list_info.isFile())) {
{ // TODO: signals go here
// TODO: signals go here QFile char_list("characters.txt");
QFile char_list("characters.txt"); if (!char_list.open(QIODevice::WriteOnly | QIODevice::Text))
if (!char_list.open(QIODevice::WriteOnly | QIODevice::Text))
qDebug() << "Couldn't create character list"; 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 << "Adrian\n";
file_stream << "Apollo\n"; file_stream << "Apollo\n";
file_stream << "April\n"; file_stream << "April\n";
file_stream << "Armstrong\n"; file_stream << "Armstrong\n";
file_stream << "Atmey\n"; file_stream << "Atmey\n";
file_stream << "Butz\n"; file_stream << "Butz\n";
file_stream << "Diego\n"; file_stream << "Diego\n";
file_stream << "Edgeworth\n"; file_stream << "Edgeworth\n";
file_stream << "Edgeworthw\n"; file_stream << "Edgeworthw\n";
file_stream << "Ema\n"; file_stream << "Ema\n";
file_stream << "EmaSkye\n"; file_stream << "EmaSkye\n";
file_stream << "Franny\n"; file_stream << "Franny\n";
file_stream << "Franziska\n"; file_stream << "Franziska\n";
file_stream << "Gant\n"; file_stream << "Gant\n";
file_stream << "Gavin\n"; file_stream << "Gavin\n";
file_stream << "Gavin K\n"; file_stream << "Gavin K\n";
file_stream << "Godot\n"; file_stream << "Godot\n";
file_stream << "Gregory\n"; file_stream << "Gregory\n";
file_stream << "Grossberg\n"; file_stream << "Grossberg\n";
file_stream << "Gumshoe\n"; file_stream << "Gumshoe\n";
file_stream << "Gumshoey\n"; file_stream << "Gumshoey\n";
file_stream << "Hawk\n"; file_stream << "Hawk\n";
file_stream << "Hobo_Phoenix\n"; file_stream << "Hobo_Phoenix\n";
file_stream << "Ini\n"; file_stream << "Ini\n";
file_stream << "Judge\n"; file_stream << "Judge\n";
file_stream << "Judge's Bro\n"; file_stream << "Judge's Bro\n";
file_stream << "Klav\n"; file_stream << "Klav\n";
file_stream << "Klavier\n"; file_stream << "Klavier\n";
file_stream << "Kristoph\n"; file_stream << "Kristoph\n";
file_stream << "Lana\n"; file_stream << "Lana\n";
file_stream << "Layton\n"; file_stream << "Layton\n";
file_stream << "Lotta\n"; file_stream << "Lotta\n";
file_stream << "Luis\n"; file_stream << "Luis\n";
file_stream << "Maggey\n"; file_stream << "Maggey\n";
file_stream << "Manfred\n"; file_stream << "Manfred\n";
file_stream << "Marshall\n"; file_stream << "Marshall\n";
file_stream << "Matt\n"; file_stream << "Matt\n";
file_stream << "Maya\n"; file_stream << "Maya\n";
file_stream << "Mia\n"; file_stream << "Mia\n";
file_stream << "Miles\n"; file_stream << "Miles\n";
file_stream << "Oldbag\n"; file_stream << "Oldbag\n";
file_stream << "Payne\n"; file_stream << "Payne\n";
file_stream << "Pearl\n"; file_stream << "Pearl\n";
file_stream << "Phoenix\n"; file_stream << "Phoenix\n";
file_stream << "Valant\n"; file_stream << "Valant\n";
file_stream << "Vasquez\n"; file_stream << "Vasquez\n";
file_stream << "Wellington\n"; file_stream << "Wellington\n";
file_stream << "Winston\n"; file_stream << "Winston\n";
file_stream << "WinstonPayne\n"; file_stream << "WinstonPayne\n";
file_stream << "Young Mia\n"; file_stream << "Young Mia\n";
file_stream << "Zak\n"; file_stream << "Zak\n";
char_list.flush(); char_list.flush();
char_list.close(); char_list.close();
} }
config->beginGroup("Info"); config->beginGroup("Info");
QString config_version = config->value("version", "none").toString(); QString config_version = config->value("version", "none").toString();
config->endGroup(); config->endGroup();
if (config_version == "none") { if (config_version == "none") {
QFileInfo check_file("config.ini"); QFileInfo check_file("config.ini");
// TODO: put proper translatable warnings here // TODO: put proper translatable warnings here
if (!(check_file.exists() && check_file.isFile())) { if (!(check_file.exists() && check_file.isFile())) {
// TODO: send signal config doesn't exist // TODO: send signal config doesn't exist
generateDefaultConfig(false); 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 { else {
// TODO: send signal config is invalid // Config is valid and up to date, so let's go ahead
generateDefaultConfig(true); 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 // Setting backup_old to true will move the existing config.ini to
// config_old.ini // config_old.ini
void ConfigManager::generateDefaultConfig(bool backup_old) void ConfigManager::generateDefaultConfig(bool backup_old)
{ {
qDebug() << "Config is invalid or missing, making a new one..."; qDebug() << "Config is invalid or missing, making a new one...";
QDir dir = QDir::current(); QDir dir = QDir::current();
if (backup_old) { if (backup_old) {
// TODO: failsafe if config_old.ini already exists // TODO: failsafe if config_old.ini already exists
dir.rename("config.ini", "config_old.ini"); dir.rename("config.ini", "config_old.ini");
} }
// Group: Info // Group: Info
// This contains basic metadata about the config // This contains basic metadata about the config
config->beginGroup("Info"); config->beginGroup("Info");
config->setValue("version", CONFIG_VERSION); config->setValue("version", CONFIG_VERSION);
config->endGroup(); config->endGroup();
// Group: Options // Group: Options
// This contains general configuration // This contains general configuration
config->beginGroup("Options"); config->beginGroup("Options");
config->setValue("language", "en"); config->setValue("language", "en");
config->setValue("hostname", "$H"); config->setValue("hostname", "$H");
config->setValue("max_players", "100"); config->setValue("max_players", "100");
config->setValue("port", "27016"); config->setValue("port", "27016");
config->setValue("webao_enable", "true"); config->setValue("webao_enable", "true");
config->setValue("webao_port", "27017"); config->setValue("webao_port", "27017");
config->setValue("modpass", "password"); config->setValue("modpass", "password");
config->setValue("advertise", "true"); config->setValue("advertise", "true");
config->setValue("ms_ip", "master.aceattorneyonline.com"); config->setValue("ms_ip", "master.aceattorneyonline.com");
config->setValue("ms_port", "27016"); config->setValue("ms_port", "27016");
config->setValue("server_name", "My First Server"); config->setValue("server_name", "My First Server");
config->setValue("server_description", "This is my flashy new server"); config->setValue("server_description", "This is my flashy new server");
config->setValue("multiclient_limit", "16"); config->setValue("multiclient_limit", "16");
config->setValue("max_message_size", "256"); config->setValue("max_message_size", "256");
config->endGroup(); config->endGroup();
} }
// Ensure version continuity with config versions // Ensure version continuity with config versions
void ConfigManager::updateConfig(int current_version) void ConfigManager::updateConfig(int current_version)
{ {
if (current_version > CONFIG_VERSION) { if (current_version > CONFIG_VERSION) {
// Config version is newer than the latest version, and the config is // 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 // 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 // should be shown a relevant message Regardless, regen the config
// TODO: send signal config is invalid // anyways
generateDefaultConfig(true); // TODO: send signal config is invalid
} generateDefaultConfig(true);
else if (current_version < 0) { }
// Negative version number? Invalid! else if (current_version < 0) {
generateDefaultConfig(true); // Negative version number? Invalid!
} generateDefaultConfig(true);
else { }
// TODO: send signal config is out of date, and is being updated else {
// Update the config as needed using a switch. This is nice because we can // TODO: send signal config is out of date, and is being updated
// fall through as we go up the version ladder. // Update the config as needed using a switch. This is nice because we
switch (current_version) { // can fall through as we go up the version ladder.
case 0: // Version 0 doesn't actually exist, but we should check for it just switch (current_version) {
// in case case 0: // Version 0 doesn't actually exist, but we should check for it
case 1: // just in case
config->beginGroup("Info"); case 1:
config->setValue("version", CONFIG_VERSION); config->beginGroup("Info");
config->endGroup(); config->setValue("version", CONFIG_VERSION);
break; // This is the newest version, and nothing more needs to be done 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 // 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 port_conversion_success;
bool ws_port_conversion_success; bool ws_port_conversion_success;
bool local_port_conversion_success; bool local_port_conversion_success;
config->beginGroup("Options"); config->beginGroup("Options");
settings->ms_ip = settings->ms_ip =
config->value("ms_ip", "master.aceattorneyonline.com").toString(); config->value("ms_ip", "master.aceattorneyonline.com").toString();
settings->port = settings->port =
config->value("ms_port", "27016").toInt(&port_conversion_success); config->value("ms_port", "27016").toInt(&port_conversion_success);
settings->ws_port = settings->ws_port =
config->value("webao_port", "27017").toInt(&ws_port_conversion_success); config->value("webao_port", "27017").toInt(&ws_port_conversion_success);
settings->local_port = settings->local_port =
config->value("port", "27016").toInt(&local_port_conversion_success); config->value("port", "27016").toInt(&local_port_conversion_success);
settings->name = config->value("server_name", "My First Server").toString(); settings->name = config->value("server_name", "My First Server").toString();
settings->description = settings->description =
config->value("server_description", "This is my flashy new server") config->value("server_description", "This is my flashy new server")
.toString(); .toString();
config->endGroup(); config->endGroup();
if (!port_conversion_success || !ws_port_conversion_success || if (!port_conversion_success || !ws_port_conversion_success ||
!local_port_conversion_success) { !local_port_conversion_success) {
return false; return false;
} }
else { else {
if (config->value("advertise", "true").toString() != "true") if (config->value("advertise", "true").toString() != "true")
settings->advertise_server = false; settings->advertise_server = false;
else else
settings->advertise_server = true; settings->advertise_server = true;
if (config->value("webao_enable", "true").toString() != "true") if (config->value("webao_enable", "true").toString() != "true")
settings->ws_port = -1; settings->ws_port = -1;
return true; return true;
} }
} }

View File

@ -8,48 +8,49 @@
#include <QSettings> #include <QSettings>
#include <QTranslator> #include <QTranslator>
int main(int argc, char *argv[]) int main(int argc, char* argv[])
{ {
QApplication app(argc, argv); QApplication app(argc, argv);
QApplication::setApplicationName("akashi"); QApplication::setApplicationName("akashi");
QApplication::setApplicationVersion("0.0.1"); QApplication::setApplicationVersion("0.0.1");
QSettings config("config.ini", QSettings::IniFormat); QSettings config("config.ini", QSettings::IniFormat);
config.beginGroup("Options"); config.beginGroup("Options");
QString language = config.value("language", QLocale().bcp47Name()).toString(); QString language =
config.value("language", QLocale().bcp47Name()).toString();
QTranslator qt_translator; QTranslator qt_translator;
qt_translator.load("qt_" + language, qt_translator.load("qt_" + language,
QLibraryInfo::location(QLibraryInfo::TranslationsPath)); QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&qt_translator); app.installTranslator(&qt_translator);
QTranslator translator; QTranslator translator;
translator.load("akashi_" + language, ":/resource/translation/"); translator.load("akashi_" + language, ":/resource/translation/");
app.installTranslator(&translator); app.installTranslator(&translator);
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription( parser.setApplicationDescription(
app.translate("main", "A server for Attorney Online 2")); app.translate("main", "A server for Attorney Online 2"));
parser.addHelpOption(); parser.addHelpOption();
parser.addVersionOption(); parser.addVersionOption();
QCommandLineOption headlessOption( QCommandLineOption headlessOption(
QStringList() << "l" QStringList() << "l"
<< "headless", << "headless",
app.translate("main", "Run the server without a GUI.")); app.translate("main", "Run the server without a GUI."));
QCommandLineOption verboseNetworkOption( QCommandLineOption verboseNetworkOption(
QStringList() << "nv" QStringList() << "nv"
<< "verbose-network", << "verbose-network",
app.translate("main", "Write all network traffic to the console.")); app.translate("main", "Write all network traffic to the console."));
parser.addOption(headlessOption); parser.addOption(headlessOption);
parser.addOption(verboseNetworkOption); parser.addOption(verboseNetworkOption);
parser.process(app); parser.process(app);
bool headless = parser.isSet(headlessOption); bool headless = parser.isSet(headlessOption);
AkashiMain w; AkashiMain w;
if (!headless) if (!headless)
w.show(); w.show();
return app.exec(); return app.exec();
} }

View File

@ -1,241 +1,249 @@
#include "include/server.h" #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); server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), this, SLOT(clientConnected())); connect(server, SIGNAL(newConnection()), this, SLOT(clientConnected()));
port = p_port; port = p_port;
ws_port = p_ws_port; ws_port = p_ws_port;
player_count = 0; player_count = 0;
} }
void Server::start() void Server::start()
{ {
// TODO: websockets lul // TODO: websockets lul
// Maybe websockets should be handled by a separate intermediate part of the // 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 // 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 // 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 // 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 // be negotiated by sending some extra data over? No idea. I'll wait for
// to read this massive comment and DM me on discord // long to read this massive comment and DM me on discord
// //
// Upon thinking about this a bit more, I realized basically all of the // Upon thinking about this a bit more, I realized basically all of the
// communication only happens via QTcpSocket* pointers. // communication only happens via QTcpSocket* pointers.
// If the Qt WebSocket server gives me QTcpSockets to work with, // 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 // then they can all go into the same object. I doubt this is the case,
if (!server->listen(QHostAddress::Any, port)) { // though
// TODO: signal server start failed if (!server->listen(QHostAddress::Any, port)) {
qDebug() << "Server error:" << server->errorString(); // TODO: signal server start failed
} qDebug() << "Server error:" << server->errorString();
else { }
// TODO: signal server start success else {
qDebug() << "Server listening on" << port; // TODO: signal server start success
} qDebug() << "Server listening on" << port;
}
QFile char_list("characters.txt"); QFile char_list("characters.txt");
char_list.open(QIODevice::ReadOnly | QIODevice::Text); char_list.open(QIODevice::ReadOnly | QIODevice::Text);
while(!char_list.atEnd()) while (!char_list.atEnd()) {
{ characters.append(char_list.readLine().trimmed());
characters.append(char_list.readLine().trimmed()); }
}
// TODO: actually read areas from config // TODO: actually read areas from config
areas.append(new AreaData(characters)); areas.append(new AreaData(characters));
areas[0]->name = "basement lol"; areas[0]->name = "basement lol";
} }
void Server::clientConnected() void Server::clientConnected()
{ {
QTcpSocket *client = server->nextPendingConnection(); QTcpSocket* client = server->nextPendingConnection();
AOClient *ao_client = new AOClient(client->peerAddress()); AOClient* ao_client = new AOClient(client->peerAddress());
clients.insert(client, ao_client); clients.insert(client, ao_client);
connect(client, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); connect(client, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
connect(client, SIGNAL(readyRead()), this, SLOT(clientData())); connect(client, SIGNAL(readyRead()), this, SLOT(clientData()));
AOPacket decryptor("decryptor", {"NOENCRYPT"}); // This is the infamous workaround for tsuserver4 AOPacket decryptor(
// It should disable fantacrypt completely in any client 2.4.3 or newer "decryptor", {"NOENCRYPT"}); // This is the infamous workaround for
client->write(decryptor.toUtf8()); // 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() void Server::clientDisconnected()
{ {
if (QTcpSocket *client = dynamic_cast<QTcpSocket *>(sender())) { if (QTcpSocket* client = dynamic_cast<QTcpSocket*>(sender())) {
qDebug() << client->peerAddress() << "disconnected"; qDebug() << client->peerAddress() << "disconnected";
AOClient* ao_client = clients.value(client); AOClient* ao_client = clients.value(client);
if (ao_client->joined) if (ao_client->joined)
player_count--; player_count--;
areas.value(ao_client->current_area)->characters_taken[ao_client->current_char] = false; areas.value(ao_client->current_area)
->characters_taken[ao_client->current_char] = false;
delete ao_client; delete ao_client;
clients.remove(client); clients.remove(client);
} }
} }
void Server::clientData() void Server::clientData()
{ {
if (QTcpSocket *client = dynamic_cast<QTcpSocket *>(sender())) { if (QTcpSocket* client = dynamic_cast<QTcpSocket*>(sender())) {
QString data = QString::fromUtf8(client->readAll()); QString data = QString::fromUtf8(client->readAll());
// qDebug() << "From" << client->peerAddress() << ":" << data; // qDebug() << "From" << client->peerAddress() << ":" << data;
if (is_partial) { if (is_partial) {
data = partial_packet + data; data = partial_packet + data;
} }
if (!data.endsWith("%")) { if (!data.endsWith("%")) {
is_partial = true; is_partial = true;
} }
QStringList all_packets = data.split("%"); QStringList all_packets = data.split("%");
all_packets.removeLast(); // Remove the entry after the last delimiter all_packets.removeLast(); // Remove the entry after the last delimiter
for (QString single_packet : all_packets) { for (QString single_packet : all_packets) {
AOPacket packet(single_packet); AOPacket packet(single_packet);
handlePacket(packet, client); 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 // TODO: like everything here should send a signal
qDebug() << "Received packet:" << packet.header << ":" << packet.contents; qDebug() << "Received packet:" << packet.header << ":" << packet.contents;
AOClient *client = clients.value(socket); AOClient* client = clients.value(socket);
AreaData *area = areas.value(client->current_area); AreaData* area = areas.value(client->current_area);
// Lord forgive me // Lord forgive me
if (packet.header == "HI") { if (packet.header == "HI") {
AOClient *client = clients.value(socket); AOClient* client = clients.value(socket);
client->setHwid(packet.contents[0]); client->setHwid(packet.contents[0]);
AOPacket response("ID", AOPacket response(
{"271828", "akashi", QApplication::applicationVersion()}); "ID", {"271828", "akashi", QApplication::applicationVersion()});
socket->write(response.toUtf8()); 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"));
} }
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); // Full feature list as of AO 2.8.5
AOPacket response_op("OPPASS", {"DEADBEEF"}); // The only ones that are critical to ensuring the server works are
AOPacket response_done("DONE", {}); // "noencryption" and "fastloading"
socket->write(response_cc.toUtf8()); // TODO: make the rest of these user configurable
socket->write(response_op.toUtf8()); QStringList feature_list = {
socket->write(response_done.toUtf8()); "noencryption", "yellowtext", "prezoom",
} "flipping", "customobjections", "fastloading",
else if (packet.header == "PW") { "deskmod", "evidence", "cccc_ic_support",
client->password = packet.contents[0]; "arup", "casing_alserts", "modcall_reason",
} "looping_sfx", "additive", "effects"};
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]; AOPacket response_pn("PN",
bool taken = area->characters_taken.value(char_selected); {QString::number(player_count), max_players});
if(taken || char_selected == "") AOPacket response_fl("FL", feature_list);
return; socket->write(response_pn.toUtf8());
socket->write(response_fl.toUtf8());
if(client->current_char != "") {
area->characters_taken[client->current_char] = false;
} }
else if (packet.header == "askchaa") {
area->characters_taken[char_selected] = true; // TODO: add user configurable content
client->current_char = char_selected; // For testing purposes, we will just send enough to get things working
AOPacket response("SI",
QStringList chars_taken; {QString::number(characters.length()), "0", "1"});
for(QString cur_char : area->characters_taken.keys()) qDebug() << response.toString();
{ socket->write(response.toUtf8());
chars_taken.append(area->characters_taken.value(cur_char) ? QStringLiteral("-1") : QStringLiteral("0"));
} }
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); QStringList chars_taken;
AOPacket response_pv("PV", {"271828", "CID", packet.contents[1]}); for (QString cur_char : area->characters_taken.keys()) {
socket->write(response_pv.toUtf8()); chars_taken.append(area->characters_taken.value(cur_char)
socket->write(response_cc.toUtf8()); ? QStringLiteral("-1")
} : QStringLiteral("0"));
else if (packet.header == "MS") { }
// TODO: validate, validate, validate
broadcast(packet); AOPacket response_cc("CharsCheck", chars_taken);
} AOPacket response_op("OPPASS", {"DEADBEEF"});
else if (packet.header == "CT") { AOPacket response_done("DONE", {});
// TODO: commands socket->write(response_cc.toUtf8());
// TODO: zalgo strip socket->write(response_op.toUtf8());
broadcast(packet); socket->write(response_done.toUtf8());
} }
else if (packet.header == "CH") { else if (packet.header == "PW") {
// Why does this packet exist client->password = packet.contents[0];
AOPacket response("CHECK", {}); }
socket->write(response.toUtf8()); else if (packet.header == "CC") {
} bool argument_ok;
else if (packet.header == "what") { int char_id = packet.contents[1].toInt(&argument_ok);
AOPacket response("CT", if (!argument_ok)
{"Made with love", "by scatterflower and windrammer"}); return;
}
else { QString char_selected = characters[char_id];
qDebug() << "Unimplemented packet:" << packet.header; bool taken = area->characters_taken.value(char_selected);
qDebug() << packet.contents; if (taken || char_selected == "")
} return;
socket->flush();
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) void Server::broadcast(AOPacket packet)
{ {
for (QTcpSocket *client : clients.keys()) { for (QTcpSocket* client : clients.keys()) {
client->write(packet.toUtf8()); client->write(packet.toUtf8());
client->flush(); client->flush();
} }
} }
QTcpSocket *Server::getClient(QString ipid) QTcpSocket* Server::getClient(QString ipid)
{ {
for (QTcpSocket *client : clients.keys()) { for (QTcpSocket* client : clients.keys()) {
if (clients.value(client)->getIpid() == ipid) if (clients.value(client)->getIpid() == ipid)
return client; return client;
} }
return nullptr; return nullptr;
} }