Skip to content
Merged
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
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
ci:
patterns: ["*"]
commit-message:
prefix: "ci"
10 changes: 7 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
# Create project
project(sdk_launcher
DESCRIPTION "An SDK launcher for Strata Source engine games"
VERSION "0.6.1"
VERSION "0.7.0"
HOMEPAGE_URL "https://github.com/StrataSource/sdk-launcher")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand All @@ -13,8 +13,9 @@ include(CheckIPOSupported)
include(GNUInstallDirs)

# Set up variables
set(PROJECT_NAME_PRETTY "SDK Launcher" CACHE STRING "" FORCE)
set(PROJECT_TARGET_NAME "SDKLauncher" CACHE STRING "" FORCE)
set(PROJECT_NAME_PRETTY "SDK Launcher" CACHE STRING "" FORCE)
set(PROJECT_TARGET_NAME "SDKLauncher" CACHE STRING "" FORCE)
set(PROJECT_ORGANIZATION "Strata Source" CACHE STRING "" FORCE)

# Helper for creating enum options (pick between certain strings)
macro(option_enum)
Expand Down Expand Up @@ -139,12 +140,15 @@ add_executable(${PROJECT_TARGET_NAME} WIN32
"${CMAKE_CURRENT_SOURCE_DIR}/src/Config.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/GameConfig.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/GameConfig.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/LaunchButton.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/LaunchButton.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Main.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/NewModDialog.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/NewModDialog.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/NewP2CEAddonDialog.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/NewP2CEAddonDialog.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Options.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Options.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Steam.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Steam.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp"
Expand Down
2 changes: 1 addition & 1 deletion ext/miniz
12 changes: 7 additions & 5 deletions src/Config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

#include <string_view>

constexpr std::string_view PROJECT_NAME = "${PROJECT_NAME_PRETTY}";
constexpr std::string_view PROJECT_VERSION = "${PROJECT_VERSION}";
constexpr std::string_view PROJECT_HOMEPAGE = "${PROJECT_HOMEPAGE_URL}";
constexpr std::string_view PROJECT_TITLE = "${PROJECT_NAME_PRETTY} v${PROJECT_VERSION}";
constexpr std::string_view PROJECT_DEFAULT_MOD = "${SDK_LAUNCHER_DEFAULT_MOD}";
constexpr std::string_view PROJECT_NAME = "${PROJECT_NAME_PRETTY}";
constexpr std::string_view PROJECT_TARGET_NAME = "${PROJECT_TARGET_NAME}";
constexpr std::string_view PROJECT_ORGANIZATION = "${PROJECT_ORGANIZATION}";
constexpr std::string_view PROJECT_VERSION = "${PROJECT_VERSION}";
constexpr std::string_view PROJECT_HOMEPAGE = "${PROJECT_HOMEPAGE_URL}";
constexpr std::string_view PROJECT_TITLE = "${PROJECT_NAME_PRETTY} v${PROJECT_VERSION}";
constexpr std::string_view PROJECT_DEFAULT_MOD = "${SDK_LAUNCHER_DEFAULT_MOD}";
22 changes: 11 additions & 11 deletions src/GameConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ GameConfig::ActionType GameConfig::actionTypeFromString(const QString& string) {
using enum ActionType;
if (string == "command") {
return COMMAND;
} else if (string == "link") {
}
if (string == "link") {
return LINK;
} else if (string == "directory") {
}
if (string == "directory") {
return DIRECTORY;
}
return INVALID;
Expand Down Expand Up @@ -43,7 +45,7 @@ std::optional<GameConfig> GameConfig::parse(const QString& path) {
return std::nullopt;
}

QJsonDocument configJson = QJsonDocument::fromJson(config.toUtf8());
const QJsonDocument configJson = QJsonDocument::fromJson(config.toUtf8());
if (!configJson.isObject()) {
return std::nullopt;
}
Expand Down Expand Up @@ -81,9 +83,8 @@ std::optional<GameConfig> GameConfig::parse(const QString& path) {
if (!configObject.contains("sections") || !configObject["sections"].isArray()) {
return std::nullopt;
}
QJsonArray sections = configObject["sections"].toArray();

for (const auto& sectionValue : sections) {
for (const auto& sectionValue : configObject["sections"].toArray()) {
if (!sectionValue.isObject()) {
continue;
}
Expand All @@ -96,8 +97,7 @@ std::optional<GameConfig> GameConfig::parse(const QString& path) {
auto& gameConfigSection = gameConfig.sections.emplace_back();
gameConfigSection.name = sectionObject["name"].toString();

auto entries = sectionObject["entries"].toArray();
for (const auto& entryValue : entries) {
for (const auto& entryValue : sectionObject["entries"].toArray()) {
if (!entryValue.isObject()) {
continue;
}
Expand Down Expand Up @@ -125,7 +125,7 @@ std::optional<GameConfig> GameConfig::parse(const QString& path) {
gameConfigSectionEntry.iconOverride = entryObject["icon_override"].toString();
}

auto os = static_cast<unsigned char>((!entryObject.contains("os") || !entryObject["os"].isString()) ? OS::ALL : osFromString(entryObject["os"].toString()));
const auto os = static_cast<unsigned char>((!entryObject.contains("os") || !entryObject["os"].isString()) ? OS::ALL : osFromString(entryObject["os"].toString()));
#if defined(_WIN32)
if (!(os & static_cast<unsigned char>(OS::WINDOWS))) {
gameConfigSection.entries.pop_back();
Expand All @@ -150,9 +150,9 @@ void GameConfig::setVariable(const QString& variable, const QString& replacement
};
setVar(this->gameDefault);
setVar(this->gameIcon);
for (auto& section : this->sections) {
setVar(section.name);
for (auto& entry : section.entries) {
for (auto& [sectionName, entries] : this->sections) {
setVar(sectionName);
for (auto& entry : entries) {
setVar(entry.name);
setVar(entry.action);
for (auto& argument : entry.arguments) {
Expand Down
19 changes: 19 additions & 0 deletions src/LaunchButton.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "LaunchButton.h"

#include "Options.h"

LaunchButton::LaunchButton(QWidget* parent)
: QToolButton(parent) {
QObject::connect(this, &LaunchButton::clicked, this, [this] {
if (Options::get<bool>(BOOL_SINGLE_CLICK_TO_RUN, BOOL_SINGLE_CLICK_TO_RUN_DEFAULT)) {
emit this->launch();
}
});
}

void LaunchButton::mouseDoubleClickEvent(QMouseEvent* event) {
if (!Options::get<bool>(BOOL_SINGLE_CLICK_TO_RUN, BOOL_SINGLE_CLICK_TO_RUN_DEFAULT)) {
emit this->launch();
}
QToolButton::mouseDoubleClickEvent(event);
}
9 changes: 3 additions & 6 deletions src/LaunchButton.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@ class LaunchButton : public QToolButton {
Q_OBJECT;

public:
using QToolButton::QToolButton;
explicit LaunchButton(QWidget* parent = nullptr);

protected:
// Actually incredible Qt doesn't expose this already
void mouseDoubleClickEvent(QMouseEvent*) override {
emit this->doubleClicked();
}
void mouseDoubleClickEvent(QMouseEvent* event) override;

signals:
void doubleClicked();
void launch();
};
2 changes: 1 addition & 1 deletion src/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "Window.h"

int main(int argc, char** argv) {
QCoreApplication::setOrganizationName("Strata Source");
QCoreApplication::setOrganizationName(PROJECT_ORGANIZATION.data());
QCoreApplication::setApplicationName(PROJECT_NAME.data());
QCoreApplication::setApplicationVersion(PROJECT_VERSION.data());

Expand Down
6 changes: 2 additions & 4 deletions src/NewModDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ namespace {
std::filesystem::create_directories(std::filesystem::path{path.toLocal8Bit().constData()}.parent_path());

QFile file{path};
file.open(QIODevice::WriteOnly);
if (!file.isOpen()) {
if (!file.open(QIODevice::WriteOnly)) {
return false;
}
file.write(data);
Expand All @@ -50,8 +49,7 @@ namespace {
}

[[nodiscard]] bool extractZIP(const QByteArray& zip, const QString& outputDir, QWidget* parent) {
mz_zip_archive zipArchive;
std::memset(&zipArchive, 0, sizeof(zipArchive));
mz_zip_archive zipArchive{};

if (!mz_zip_reader_init_mem(&zipArchive, zip.data(), zip.size(), 0)) {
return false;
Expand Down
29 changes: 15 additions & 14 deletions src/NewP2CEAddonDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,17 @@ NewP2CEAddonDialog::NewP2CEAddonDialog(QString gameRoot_, QWidget* parent)
}

// Create directory structure
QDir dir{this->getAddonInstallDir()};
dir.mkpath("maps");
dir.mkpath("materials");
dir.mkpath("models");
dir.mkpath("particles");
dir.mkpath("resource");
dir.mkpath("scenes");
dir.mkpath("scripts");
dir.mkpath("sound");
const QDir dir{this->getAddonInstallDir()};
(void) dir.mkpath("maps");
(void) dir.mkpath("materials");
(void) dir.mkpath("models");
(void) dir.mkpath("particles");
(void) dir.mkpath("resource");
(void) dir.mkpath("scenes");
(void) dir.mkpath("scripts");
(void) dir.mkpath("sound");

// Create addon.kv3
QFile addonKV3{this->getAddonInstallDir() + QDir::separator() + "addon.kv3"};
addonKV3.open(QIODevice::WriteOnly | QIODevice::Text);

static constexpr auto p2ceAddonKV3ContentsBase = R"({
mod = "%1"
description = """
Expand All @@ -105,11 +102,15 @@ NewP2CEAddonDialog::NewP2CEAddonDialog(QString gameRoot_, QWidget* parent)
cover = ""
}
})";
{
QFile addonKV3{this->getAddonInstallDir() + QDir::separator() + "addon.kv3"};
if (addonKV3.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out{&addonKV3};
out << QString{p2ceAddonKV3ContentsBase}.arg(this->addonName->text(), this->addonDesc->toPlainText(), this->addonType->currentText()).toLocal8Bit();
addonKV3.close();
} else {
QMessageBox::critical(this, tr("File Creation Error"), tr("Failed to create addon.kv3 file."));
return;
}
addonKV3.close();

// Create desktop shortcut
if (this->addShortcutOnDesktop->isChecked()) {
Expand Down
2 changes: 1 addition & 1 deletion src/NewP2CEAddonDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class NewP2CEAddonDialog : public QDialog {
Q_OBJECT;

public:
NewP2CEAddonDialog(QString gameRoot_, QWidget* parent = nullptr);
explicit NewP2CEAddonDialog(QString gameRoot_, QWidget* parent = nullptr);

[[nodiscard]] QString getAddonInstallDir() const;

Expand Down
16 changes: 16 additions & 0 deletions src/Options.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "Options.h"

#include "Config.h"

QSettings& Options::get() {
static QSettings s{QString{"%1.ini"}.arg(PROJECT_TARGET_NAME.data()), QSettings::Format::IniFormat};
return s;
}

bool Options::contains(std::string_view key) {
return get().contains(key);
}

void Options::remove(std::string_view key) {
get().remove(key);
}
28 changes: 28 additions & 0 deletions src/Options.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <QSettings>

constexpr std::string_view STR_RECENT_CONFIGS = "str_recent_configs";
constexpr std::string_view STR_GAME_OVERRIDE = "str_game_override";

constexpr std::string_view BOOL_SINGLE_CLICK_TO_RUN = "opt_single_click_to_run";
constexpr bool BOOL_SINGLE_CLICK_TO_RUN_DEFAULT = false;

namespace Options {

[[nodiscard]] QSettings& get();

[[nodiscard]] bool contains(std::string_view key);

template<typename T>
[[nodiscard]] T get(std::string_view key, T value = {}) {
return qvariant_cast<T>(get().value(key, value));
}

void set(std::string_view key, auto value) {
get().setValue(key, value);
}

void remove(std::string_view key);

} // namespace Options
9 changes: 4 additions & 5 deletions src/Steam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace {
}
#else
{
std::filesystem::path home{std::getenv("HOME")};
const std::filesystem::path home{std::getenv("HOME")};
#ifdef __APPLE__
steamLocation = home / "Library" / "Application Support" / "Steam";
#else
Expand All @@ -52,7 +52,7 @@ namespace {

if (!std::filesystem::exists(steamLocation, ec)) {
std::string location;
std::filesystem::path d{"cwd/steamclient64.dll"};
const std::filesystem::path d{"cwd/steamclient64.dll"};
for (const auto& entry : std::filesystem::directory_iterator{"/proc/"}) {
if (std::filesystem::exists(entry / d, ec)) {
ec.clear();
Expand All @@ -66,13 +66,12 @@ namespace {
}
if (location.empty()) {
return "";
} else {
steamLocation = location;
}
steamLocation = location;
}
#endif

if (auto sourceModPath = (steamLocation / "steamapps" / "sourcemods").string(); std::filesystem::exists(sourceModPath, ec)) {
if (const auto sourceModPath = (steamLocation / "steamapps" / "sourcemods").string(); std::filesystem::exists(sourceModPath, ec)) {
return sourceModPath.c_str();
}
return "";
Expand Down
Loading
Loading