Skip to content

Commit 0464843

Browse files
authored
Merge pull request #150 from OpenBrickProtocolFoundation/windows-installer
Add Windows installer
2 parents 1d4c1aa + d03bfa7 commit 0464843

File tree

14 files changed

+551
-55
lines changed

14 files changed

+551
-55
lines changed

.github/workflows/installer.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: Installer CI
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
workflow_dispatch:
8+
9+
jobs:
10+
build:
11+
name: ${{ matrix.config.name }}
12+
runs-on: ${{ matrix.config.os }}-${{ matrix.config.os-version }}
13+
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
config:
18+
- name: Windows MSVC Installer
19+
os: windows
20+
os-version: 2022
21+
msvc: true
22+
buildtype: release
23+
library_type: static
24+
shell: pwsh
25+
defaults:
26+
run:
27+
shell: ${{ matrix.config.shell }}
28+
29+
steps:
30+
- uses: actions/checkout@v4
31+
with:
32+
fetch-depth: "0"
33+
34+
- name: Setup MSVC (Windows)
35+
if: matrix.config.os == 'windows' && matrix.config.msvc == true
36+
uses: TheMrMilchmann/setup-msvc-dev@v3
37+
with:
38+
arch: x64
39+
toolset: 14.39
40+
41+
- name: Setup meson
42+
if: matrix.config.os != 'macos'
43+
run: |
44+
python -m pip install --upgrade pip
45+
pip install meson
46+
47+
- name: Configure
48+
run: meson setup build -Dbuildtype=${{ matrix.config.buildtype }} -Ddefault_library=${{ matrix.config.library_type }} -Dclang_libcpp=${{ ( ( matrix.config.os == 'ubuntu' && matrix.config.use-clang == true && matrix.config.use-clang_stdlib ) || matrix.config.os == 'macos' ) && 'enabled' || 'disabled' }} -Dbuild_installer=true
49+
50+
- name: Build
51+
run: meson compile -C build
52+
53+
- name: Download EnVar plugin for NSIS
54+
uses: carlosperate/download-file-action@v2
55+
with:
56+
file-url: https://nsis.sourceforge.io/mediawiki/images/7/7f/EnVar_plugin.zip
57+
file-name: envar_plugin.zip
58+
location: ${{ github.workspace }}
59+
60+
- name: Extract EnVar plugin
61+
run: 7z x "-oC:/Program Files (x86)/NSIS" "${{ github.workspace }}/envar_plugin.zip"
62+
63+
- name: Build installer (Windows)
64+
run: |
65+
meson compile -C build windows_installer
66+
67+
- name: Upload artifacts - Windows
68+
uses: actions/upload-artifact@v4
69+
if: matrix.config.os == 'windows'
70+
with:
71+
name: ${{ matrix.config.name }}
72+
path: tools/installer/OOPetris Setup.exe

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,4 @@ logs/
8989
/toolchains/
9090
.flatpak-builder/
9191
flatpak-build/
92+
tools/installer/*.exe

assets/icon/icon.ico

21.3 KB
Binary file not shown.

meson.build

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ project(
1414
version: '0.5.5',
1515
)
1616

17+
oopetris_author = 'Coder2k'
18+
oopetris_name = 'OOPetris'
19+
1720
subdir('tools/options')
1821

1922
subdir('tools/dependencies')
@@ -50,7 +53,11 @@ elif meson.is_cross_build() and host_machine.system() == '3ds'
5053
subdir('platforms/3ds')
5154
else
5255

53-
executable(
56+
if host_machine.system() == 'windows'
57+
subdir('platforms/windows')
58+
endif
59+
60+
oopetris_exe = executable(
5461
'oopetris',
5562
main_files,
5663
dependencies: [liboopetris_graphics_dep, graphic_application_deps],
@@ -59,9 +66,10 @@ else
5966
'werror': true,
6067
},
6168
install: true,
69+
win_subsystem: 'windows',
6270
)
6371

64-
executable(
72+
oopetris_recordings_utility_exe = executable(
6573
'oopetris_recordings_utility',
6674
recordings_main_files,
6775
dependencies: liboopetris_recordings_dep,
@@ -70,8 +78,33 @@ else
7078
'werror': true,
7179
},
7280
install: true,
81+
win_subsystem: 'console',
7382
)
7483

84+
if build_installer
85+
if host_machine.system() == 'windows'
86+
87+
makensis = find_program('makensis')
88+
89+
nsis_script = meson.project_source_root() / 'tools' / 'installer' / 'setup.nsi'
90+
91+
run_target(
92+
'windows_installer',
93+
command: [
94+
makensis,
95+
'-DVERSION=' + meson.project_version(),
96+
'-DNAME=' + oopetris_name,
97+
'-DAUTHOR=' + oopetris_author,
98+
'-DPROJECT_SOURCE_DIR=' + meson.project_source_root(),
99+
'-DPROJECT_BUILD_DIR=' + meson.project_build_root(),
100+
nsis_script,
101+
],
102+
depends: [oopetris_exe, oopetris_recordings_utility_exe],
103+
)
104+
105+
endif
106+
endif
107+
75108
endif
76109

77110
if get_option('tests')

platforms/windows/meson.build

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
windows = import('windows')
2+
3+
version_arr = meson.project_version().split('.')
4+
major_version = version_arr[0].to_int()
5+
minor_version = version_arr[1].to_int()
6+
patch_version = version_arr[2].to_int()
7+
8+
rc_conf = configuration_data(
9+
{
10+
'OOPETRIS_VERSION': meson.project_version(),
11+
'OOPETRIS_NAME': oopetris_name,
12+
'OOPETRIS_AUTHOR': oopetris_author,
13+
'OOPETRIS_MAJOR_VERSION': major_version,
14+
'OOPETRIS_MINOR_VERSION': minor_version,
15+
'OOPETRIS_PATCH_VERSION': patch_version,
16+
'PROJECT_SOURCE_DIR': meson.project_source_root().replace('\\', '/'),
17+
},
18+
)
19+
20+
oopetris_win_rc = configure_file(
21+
input: 'oopetris.rc.in',
22+
output: 'oopetris.rc',
23+
configuration: rc_conf,
24+
)
25+
26+
oopetris_resource_windows = windows.compile_resources(oopetris_win_rc)
27+
28+
main_files += oopetris_resource_windows

platforms/windows/oopetris.rc.in

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
#include <winver.h>
3+
4+
VS_VERSION_INFO VERSIONINFO
5+
FILEVERSION @OOPETRIS_MAJOR_VERSION@,@OOPETRIS_MINOR_VERSION@,@OOPETRIS_PATCH_VERSION@,0
6+
PRODUCTVERSION @OOPETRIS_MAJOR_VERSION@,@OOPETRIS_MINOR_VERSION@,@OOPETRIS_PATCH_VERSION@,0
7+
BEGIN
8+
BLOCK "StringFileInfo"
9+
BEGIN
10+
BLOCK "040904B0"
11+
BEGIN
12+
VALUE "FileDescription", "@OOPETRIS_NAME@"
13+
VALUE "FileVersion", "@[email protected]"
14+
VALUE "ProductName", "@OOPETRIS_NAME@"
15+
VALUE "ProductVersion", "@OOPETRIS_VERSION@"
16+
END
17+
END
18+
BLOCK "VarFileInfo"
19+
BEGIN
20+
VALUE "Translation", 0x409, 1200
21+
END
22+
END
23+
24+
#define AppIcon 101
25+
AppIcon ICON "@PROJECT_SOURCE_DIR@/assets/icon/icon.ico"
26+

settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
"rotate_left": "Left",
1111
"rotate_right": "Right"
1212
},
13-
"volume": 0.2
13+
"volume": 0.2,
14+
"discord": false
1415
}

src/application.cpp

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -246,17 +246,6 @@ void Application::render() const {
246246

247247
void Application::initialize() {
248248

249-
#if defined(_HAVE_DISCORD_SDK)
250-
auto discord_instance = DiscordInstance::initialize();
251-
if (not discord_instance.has_value()) {
252-
spdlog::warn("Error initializing the discord instance, it might not be running: {}", discord_instance.error());
253-
} else {
254-
m_discord_instance = std::move(discord_instance.value());
255-
m_discord_instance->after_setup();
256-
}
257-
258-
#endif
259-
260249
try_load_settings();
261250
load_resources();
262251
push_scene(scenes::create_scene(*this, SceneId::MainMenu, ui::FullScreenLayout{ *m_window }));
@@ -268,6 +257,21 @@ void Application::initialize() {
268257
ui::RelativeLayout{ window(), 0.0, 0.0, 0.1, 0.05 }, false
269258
);
270259
#endif
260+
261+
#if defined(_HAVE_DISCORD_SDK)
262+
if (m_settings.discord) {
263+
auto discord_instance = DiscordInstance::initialize();
264+
if (not discord_instance.has_value()) {
265+
spdlog::warn(
266+
"Error initializing the discord instance, it might not be running: {}", discord_instance.error()
267+
);
268+
} else {
269+
m_discord_instance = std::move(discord_instance.value());
270+
m_discord_instance->after_setup();
271+
}
272+
}
273+
274+
#endif
271275
}
272276

273277
void Application::try_load_settings() {
@@ -281,20 +285,23 @@ void Application::try_load_settings() {
281285
spdlog::error("unable to load settings from \"{}\": {}", settings_filename, result.error());
282286
spdlog::warn("applying default settings");
283287
}
288+
289+
// apply settings
290+
m_music_manager.set_volume(m_settings.volume);
284291
}
285292

286293
void Application::load_resources() {
287294
constexpr auto fonts_size = 128;
288-
const std::vector<std::tuple<FontId, std::string>> fonts {
295+
const std::vector<std::tuple<FontId, std::string>> fonts{
289296
#if defined(__3DS__)
290297
//TODO: debug why the other font crashed, not on loading, but on trying to render text!
291-
{ FontId::Default, "LeroyLetteringLightBeta01.ttf" },
298+
{ FontId::Default, "LeroyLetteringLightBeta01.ttf" },
292299
#else
293300
{ FontId::Default, "PressStart2P.ttf" },
294301
#endif
295-
{ FontId::Arial, "arial.ttf" }, { FontId::NotoColorEmoji, "NotoColorEmoji.ttf" }, {
296-
FontId::Symbola, "Symbola.ttf"
297-
}
302+
{ FontId::Arial, "arial.ttf" },
303+
{ FontId::NotoColorEmoji, "NotoColorEmoji.ttf" },
304+
{ FontId::Symbola, "Symbola.ttf" }
298305
};
299306
for (const auto& [font_id, path] : fonts) {
300307
const auto font_path = utils::get_assets_folder() / "fonts" / path;

src/helper/constants.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ namespace constants {
77
#define STRINGIFY(a) STRINGIFY_HELPER_(a) //NOLINT(cppcoreguidelines-macro-usage)
88
#define STRINGIFY_HELPER_(a) #a //NOLINT(cppcoreguidelines-macro-usage)
99

10-
#if !defined(OOPETRIS_VERSION)
11-
#define OOPETRIS_VERSION "Unknown"
10+
#if !defined(OOPETRIS_NAME) || !defined(OOPETRIS_AUTHOR) || !defined(OOPETRIS_VERSION)
11+
#error "not all needed OOPETRIS_* macros defined"
1212
#endif
1313

1414

15-
constexpr auto program_name = StaticString{ "oopetris" };
16-
constexpr auto author = StaticString{ "coder2k" };
15+
constexpr auto program_name = StaticString{ STRINGIFY(OOPETRIS_NAME) };
16+
constexpr auto author = StaticString{ STRINGIFY(OOPETRIS_AUTHOR) };
1717
constexpr auto version = StaticString{ STRINGIFY(OOPETRIS_VERSION) };
1818
constexpr auto music_change_level = 30;
1919
constexpr auto recordings_directory = "recordings";

src/helper/graphic_utils.cpp

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,51 +25,66 @@ std::vector<std::string> utils::supported_features() {
2525
return features;
2626
}
2727

28-
28+
/**
29+
* \brief this returns the directory of the app, it's read and write-able
30+
*/
2931
[[nodiscard]] std::filesystem::path utils::get_root_folder() {
30-
#if defined(__ANDROID__) or defined(BUILD_INSTALLER)
32+
#if defined(__ANDROID__)
3133
// this call also creates the dir (at least tries to) it returns
3234
char* pref_path = SDL_GetPrefPath(constants::author, constants::program_name);
3335
if (!pref_path) {
3436
throw std::runtime_error{ "Failed in getting the Pref Path: " + std::string{ SDL_GetError() } };
3537
}
3638
return std::filesystem::path{ std::string{ pref_path } };
3739
#elif defined(__CONSOLE__)
38-
// this is in the sdcard of the switch, since internal storage is read-only for applications!
40+
// this is in the sdcard of the switch / 3ds , since internal storage is read-only for applications!
3941
return std::filesystem::path{ "." };
40-
41-
#elif defined(FLATPAK_BUILD)
42+
#elif defined(BUILD_INSTALLER)
43+
#if defined(FLATPAK_BUILD)
4244
// this is a read write location in the flatpak build, see https://docs.flatpak.org/en/latest/conventions.html
4345
const char* data_home = std::getenv("XDG_DATA_HOME");
44-
if (data_home == = nullptr) {
46+
if (data_home == nullptr) {
4547
throw std::runtime_error{ "Failed to get flatpak data directory (XDG_DATA_HOME)" };
4648
}
4749

4850
return std::filesystem::path{ data_home };
51+
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
52+
char* pref_path = SDL_GetPrefPath(constants::author, constants::program_name);
53+
if (!pref_path) {
54+
throw std::runtime_error{ "Failed in getting the Pref Path: " + std::string{ SDL_GetError() } };
55+
}
56+
return std::filesystem::path{ pref_path };
57+
#else
58+
#error "unrecognized installer build"
59+
#endif
4960
#else
5061
// this is only used in local build for debugging, when compiling in release mode the path is real path where the app can store many things without interfering with other things (eg. AppData\Roaming\... on Windows or .local/share/... on Linux )
5162
return std::filesystem::path{ "." };
5263
#endif
5364
}
5465

66+
/**
67+
* \brief this returns the directory of the assets, and is read-only
68+
*/
5569
[[nodiscard]] std::filesystem::path utils::get_assets_folder() {
5670
#if defined(__ANDROID__)
5771
return std::filesystem::path{ "" };
5872
#elif defined(__CONSOLE__)
5973
// this is in the internal storage of the nintendo switch, it ios mounted by libnx (runtime switch support library) and filled at compile time with assets (its called ROMFS there)
6074
return std::filesystem::path{ "romfs:/assets" };
6175
#elif defined(BUILD_INSTALLER)
62-
76+
// if you build in BUILD_INSTALLER mode, you have to assure that the data is there e.g. music + fonts!
6377
#if defined(FLATPAK_BUILD)
64-
const char* resource_path = "/app/share/oopetris/";
65-
#else
66-
char* resource_path = SDL_GetPrefPath(constants::author, constants::program_name);
78+
return std::filesystem::path{ "/app/share/oopetris/assets/" };
79+
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
80+
char* resource_path = SDL_GetBasePath();
6781
if (!resource_path) {
68-
throw std::runtime_error{ "Failed in getting the Pref Path: " + std::string{ SDL_GetError() } };
82+
throw std::runtime_error{ "Failed in getting the Base Path: " + std::string{ SDL_GetError() } };
6983
}
70-
// if you build in BUILD_INSTALLER mode, you have to assure that the data is there e.g. music + fonts!
84+
return std::filesystem::path{ resource_path } / "assets";
85+
#else
86+
#error "unrecognized installer build"
7187
#endif
72-
return std::filesystem::path{ std::string{ resource_path } } / "assets";
7388
#else
7489
return std::filesystem::path{ "assets" };
7590
#endif

0 commit comments

Comments
 (0)