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
BreakBeforeBraces: Stroustrup
IndentWidth: 4
Language: Cpp
PointerAlignment: Left
BreakBeforeBraces: Stroustrup

View File

@ -9,29 +9,30 @@
#include <QTcpSocket>
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

View File

@ -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

View File

@ -6,24 +6,24 @@
#include <QTcpSocket>
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

View File

@ -7,14 +7,14 @@
#include <QStringList>
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

View File

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

View File

@ -5,31 +5,31 @@
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QFile>
#include <QFileInfo>
#include <QSettings>
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

View File

@ -7,44 +7,44 @@
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QMap>
#include <QSettings>
#include <QString>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFile>
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<QTcpSocket *, AOClient *> clients;
QString partial_packet;
bool is_partial;
QMap<QTcpSocket*, AOClient*> clients;
QString partial_packet;
bool is_partial;
int player_count;
QStringList characters;
QVector<AreaData*> areas;
int player_count;
QStringList characters;
QVector<AreaData*> areas;
};
#endif // SERVER_H

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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; }

View File

@ -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();
}

View File

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

View File

@ -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;
}
}

View File

@ -8,48 +8,49 @@
#include <QSettings>
#include <QTranslator>
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();
}

View File

@ -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<QTcpSocket *>(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<QTcpSocket*>(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<QTcpSocket *>(sender())) {
QString data = QString::fromUtf8(client->readAll());
// qDebug() << "From" << client->peerAddress() << ":" << data;
if (QTcpSocket* client = dynamic_cast<QTcpSocket*>(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;
}