Skip to content

Ue launcher #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: ue_launcher
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions SEGSLauncher/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

find_package(Qt5 COMPONENTS Core Quick Multimedia REQUIRED)
find_package(Qt5 COMPONENTS Core Quick Multimedia Network REQUIRED)
set(CMAKE_DEBUG_POSTFIX "d")

set(SEGSLAUNCHER_SOURCES
Expand All @@ -23,7 +23,7 @@ set(SEGSLAUNCHER_SOURCES

add_executable(${PROJECT_NAME} WIN32 ${SEGSLAUNCHER_SOURCES})
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick Qt5::Multimedia jcon_IMP)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick Qt5::Multimedia Qt5::Network jcon_IMP)


#message("Copying required Qt libraries and binaries to output directory....")
Expand Down
3 changes: 3 additions & 0 deletions SEGSLauncher/Launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
#include <QDir>


const QVersionNumber Launcher::m_version = QVersionNumber(0,0,1);

Launcher::Launcher(QObject *parent) : QObject(parent)
{
m_update_channel = "stable";
// Worker thread for getting server status (RPC call)
Worker *worker = new Worker;
worker->moveToThread(&worker_thread);
Expand Down
18 changes: 13 additions & 5 deletions SEGSLauncher/Launcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <QVariantMap>
#include <QJsonObject>
#include <QThread>
#include <QVersionNumber>

class QProcess;
class QNetworkAccessManager;
Expand All @@ -13,8 +14,13 @@ class QNetworkReply;
class Launcher : public QObject
{
Q_OBJECT

// allow qml to access the launcher version QVersionNumber
Q_PROPERTY(QVersionNumber version READ get_launcher_version CONSTANT)
// allow access to the update_channel from qml
Q_PROPERTY(QString update_channel READ update_channel WRITE set_update_channel NOTIFY update_channel_changed)
public:
static QVersionNumber get_launcher_version() { return m_version; }

explicit Launcher(QObject *parent = nullptr);
~Launcher() override;
void fetch_server_status();
Expand All @@ -31,7 +37,9 @@ class Launcher : public QObject
Q_INVOKABLE QVariantMap get_last_used_server();
Q_INVOKABLE QJsonObject get_server_list();
Q_INVOKABLE QJsonObject get_server_information();

// Property helpers
QString update_channel() const { return m_update_channel; }
void set_update_channel(const QString &channel) { m_update_channel = channel; emit update_channel_changed(); }

public slots:
void handle_servers_reply();
Expand All @@ -44,8 +52,10 @@ public slots:
void fetchReleasesFinished();
void getServerStatus();
void serverStatusReady();

void update_channel_changed();
private:
static const QVersionNumber m_version;
QString m_update_channel;
QProcess *m_start_cox;
QProcess *m_start_segsadmin;
QNetworkReply *m_servers_network_reply;
Expand All @@ -58,6 +68,4 @@ public slots:
QString m_server_name;
QThread worker_thread; // Move to Private -- test it
bool m_server_status;


};
114 changes: 98 additions & 16 deletions SEGSLauncher/LauncherSetup.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
#include "LauncherSetup.h"
#include "Launcher.h"

#include <QCryptographicHash>
#include <QDebug>
#include <QFile>
#include <QSettings>
#include <QStandardPaths>
#include <QIODevice>
#include <QProcess>
#include <QUrl>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>

LauncherSetup::LauncherSetup(QObject *parent) : QObject(parent)
{

/*
Launcher version data is stored in a JSON file on the server
The launcher will download the JSON file and compare the version number
The format of the json file is as follows:
{
"version_data": [
{
"version": "1.0.0",
"channel": "stable",
"notes": "Release notes"
}]
"signature": "crypto signature"
}
crypto signature is a signature of the version data content
*/

LauncherSetup::LauncherSetup(QObject *parent) : QObject(parent) {
m_net_manager = new QNetworkAccessManager(this);
connect(m_net_manager, &QNetworkAccessManager::finished, this, &LauncherSetup::version_check_finished);
}

QVariantMap LauncherSetup::read_launcher_settings()
{
void LauncherSetup::prepare_launcher_setup(const QString &channel) {
m_channel = channel;
check_for_new_version();
}

QVariantMap LauncherSetup::read_launcher_settings() {
QVariantMap launcher_settings;
QSettings settings;
settings.beginGroup("LauncherConfig");
Expand All @@ -33,23 +59,79 @@ QVariantMap LauncherSetup::read_launcher_settings()

// TODO: For Debug only remove later
QString settingsPath = settings.fileName();
qDebug()<<"Settings location: " + settingsPath;
qDebug() << "Settings location: " + settingsPath;
//

return launcher_settings;
}


void LauncherSetup::write_launcher_settings(QVariantMap launcher_settings)
{
qDebug()<<launcher_settings;
QString cox_dir_path = QUrl(launcher_settings["cox_dir"].toString()).toLocalFile();
QSettings settings;
settings.beginGroup("LauncherConfig");
settings.setValue("InitialConfig", launcher_settings["initial_config"]);
settings.setValue("CoxDir", cox_dir_path);
settings.endGroup();
void LauncherSetup::write_launcher_settings(QVariantMap launcher_settings) {
qDebug() << launcher_settings;
QString cox_dir_path = QUrl(launcher_settings["cox_dir"].toString()).toLocalFile();
QSettings settings;
settings.beginGroup("LauncherConfig");
settings.setValue("InitialConfig", launcher_settings["initial_config"]);
settings.setValue("CoxDir", cox_dir_path);
settings.endGroup();
}

// download the launcher version file from the server
// verify the downloaded version against the current version
// if the versions are different, emit a signal to the QML
void LauncherSetup::check_for_new_version() {
QUrl url(launcher_version_url);
QNetworkRequest request(url);
m_net_manager->get(request);
}

void LauncherSetup::version_check_finished(QNetworkReply *reply) {
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Error loading version data: " << reply->errorString();
return;
}
qDebug() << "Version data loaded successfully";
QByteArray data = reply->read(1024*64); // 64KB should be enough for the version data
QJsonDocument doc = QJsonDocument::fromJson(data);
if (doc.isNull()) {
qDebug() << "Error parsing version data";
return;
}

QJsonObject obj = doc.object();
if(!obj.contains("version_data") || !obj["version_data"].isArray()) {
qDebug() << "Invalid/missing version data";
return;
}

QJsonArray version_data = obj["version_data"].toArray();
// collect all versions in the channel that are newer than the current version
QVector<QPair<QVersionNumber, QString>> new_versions;
for (const auto &version: version_data) {
QJsonObject ver = version.toObject();
if (ver["channel"].toString() == m_channel) {
QVersionNumber new_version = QVersionNumber::fromString(ver["version"].toString());
if (new_version > Launcher::get_launcher_version())
new_versions.push_back({new_version, ver["notes"].toString()});
}
}
if (!new_versions.empty()) {
std::sort(new_versions.begin(), new_versions.end(),
[](const QPair<QVersionNumber, QString> &a, const QPair<QVersionNumber, QString> &b) {
return a.first > b.first;
});
m_latest_version = new_versions[0].first;
m_changelogs.clear();
for (const auto &ver: new_versions)
m_changelogs.push_back(ver.second);
emit newVersionAvailable(m_latest_version);
}
}

LauncherSetup::~LauncherSetup() {
delete m_net_manager;
}

/**
void LauncherSetup::verify_client_version(QString cox_dir)
{
Expand Down
26 changes: 21 additions & 5 deletions SEGSLauncher/LauncherSetup.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,38 @@

#include <QObject>
#include <QVariantMap>
#include <QVersionNumber>

class QNetworkAccessManager;
class QNetworkReply;

class LauncherSetup : public QObject
{
Q_OBJECT

// make the version and changelogs available to qml
Q_PROPERTY(QVersionNumber latest_version READ get_latest_version NOTIFY newVersionAvailable)
Q_PROPERTY(QStringList changelogs READ get_changelogs NOTIFY newVersionAvailable)
public:
explicit LauncherSetup(QObject *parent = nullptr);
void get_cox_directory();
void verify_client_version();
~LauncherSetup() override;
Q_INVOKABLE void prepare_launcher_setup(const QString &channel);
Q_INVOKABLE QVariantMap read_launcher_settings();
Q_INVOKABLE void write_launcher_settings(QVariantMap launcher_settings);
//Q_INVOKABLE void verify_client_version(QString cox_dir);
Q_INVOKABLE void check_for_new_version();
QVersionNumber get_latest_version() const { return m_latest_version; }
QStringList get_changelogs() const { return m_changelogs; }
signals:

void newVersionAvailable(QVersionNumber version);

public slots:

private slots:
void version_check_finished(QNetworkReply *reply);
private:
constexpr static const char *launcher_version_url = "https://segs.dev/launcher_version.json";
QString m_channel;
QVersionNumber m_latest_version;
QStringList m_changelogs;

QNetworkAccessManager *m_net_manager=nullptr;
};
14 changes: 10 additions & 4 deletions SEGSLauncher/MainWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ Window {

// Set ID's for backend functions
LauncherSetup { id: backend_launcher_setup }
Launcher { id: backend_launcher }
Launcher {
id: backend_launcher
update_channel: "stable"
}

// Load custom fonts

Expand All @@ -46,6 +49,7 @@ Window {
property bool comboBox_server_select_italic: false
property string server_info_text: ""


// Code to enable frameless window to become draggable
MouseArea {
id: dragMouseRegion
Expand Down Expand Up @@ -988,6 +992,7 @@ Window {
onLinkActivated: Qt.openUrlExternally(link)

MouseArea {
id: mouse_area_si
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
Expand Down Expand Up @@ -1155,9 +1160,10 @@ Window {

// When main window loaded, call these functions.
Component.onCompleted: {
media_manager.startup_audio.play()
start_up()

// set the launcher setup channel
backend_launcher_setup.prepare_launcher_setup(backend_launcher.update_channel);
media_manager.startup_audio.play();
start_up();
}

//////////////////////////////////
Expand Down