Compare commits

..

1153 Commits
1.2.2 ... 5.1

Author SHA1 Message Date
d8044ababe Merge pull request #332 from Scrumplex/chore-bump-5.1 2022-11-01 11:01:49 +01:00
32b526b729 Merge pull request #333 from flowln/fix_atl_packs_post_modpack_update 2022-11-01 11:01:15 +01:00
7f6515dbe4 Merge pull request #329 from flowln/only_safe_workarounds 2022-11-01 11:01:15 +01:00
a39390b8b4 Merge pull request #359 from Chrono-byte/develop 2022-11-01 09:48:13 +01:00
63a3dd1919 Merge pull request #351 from Scrumplex/fix-trash 2022-10-31 22:58:09 +01:00
7a5a4de6ea Merge pull request #354 from Scrumplex/translations-maybe
Improve display names of certain languages
2022-10-31 11:31:47 +01:00
664d4e701e Merge pull request #352 from TheLastRar/Win-setDarkWinTitlebar-10OrGreater 2022-10-31 11:31:47 +01:00
a4ba8d8288 Merge pull request #353 from FayneAldan/accounts-consistency 2022-10-31 01:42:20 +01:00
392bf7a97b Merge pull request #342 from fn2006/prism-svg-fix 2022-10-29 23:11:37 +02:00
34687049b1 Merge pull request #338 from Scrumplex/fix-credits-1 2022-10-29 16:15:58 +02:00
9337ec6706 Merge pull request #173 from Scrumplex/fix-icons 2022-10-29 00:36:15 +02:00
5bcb6962c4 chore: bump version
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-28 21:54:10 +02:00
0617b43190 Merge pull request #322 from DioEgizio/64bit-it 2022-10-28 21:34:59 +02:00
ed28234cfb Merge pull request #319 from Scrumplex/fix-avoid-mr-segfault 2022-10-28 21:34:59 +02:00
9c4455ca03 Merge pull request #301 from DioEgizio/clang-attempt
feat(actions): use clang32 for building on windows
2022-10-28 21:34:59 +02:00
9ec7837275 Merge pull request #318 from TheLastRar/manifest-platform
Fix: Don't specify x86 in manifest
2022-10-28 21:34:59 +02:00
549b5a6488 Merge pull request #231 from tobimori/patch-1 2022-10-28 21:34:59 +02:00
2652f37453 Merge pull request #206 from flowln/changelog_height_fix 2022-10-28 21:34:59 +02:00
0eaff22145 Merge pull request #283 from flowln/fix_abort_on_autosearch 2022-10-28 21:34:59 +02:00
2f5393b9d0 Merge pull request #281 from Scrumplex/fix-nsis-displayname 2022-10-28 21:34:59 +02:00
e28480a8e4 Merge pull request #274 from Protrikk/patch-1 2022-10-28 21:34:59 +02:00
fcef6321fc Merge pull request #228 from bensuperpc/change_cast 2022-10-28 21:34:59 +02:00
35e792c5de Merge pull request #240 from jn64/fix/version-label-width 2022-10-28 21:34:59 +02:00
c08b632b51 Merge pull request #234 from AliceDTRH/fix/dedupejava 2022-10-28 21:34:59 +02:00
cac800bfd8 Merge pull request #233 from jamierocks/atl-fix-aborting-installs 2022-10-28 21:34:59 +02:00
2eb8173951 Merge pull request #224 from jamierocks/atl-abort-close-optional-mods-dialog 2022-10-28 21:34:59 +02:00
75abf2c124 Merge pull request #225 from Scrumplex/fix-segfault-fileresolver 2022-10-28 21:34:59 +02:00
d40a18d6c5 Merge pull request #218 from getchoo/change-jars-path 2022-10-28 21:34:59 +02:00
a74fdc588c Merge pull request #185 from flowln/fix_blocked_mods_crash 2022-10-28 21:34:59 +02:00
25b0ec6eff Merge pull request #147 from Minion3665/enhancement/update-nix-derivation 2022-10-28 21:34:59 +02:00
04e8982d33 Merge pull request #198 from PrismLauncher/renovate/hendrikmuhs-ccache-action-1.x 2022-10-28 21:34:59 +02:00
58bd449db8 Merge pull request #197 from PrismLauncher/renovate/actions-cache-3.x 2022-10-28 21:34:59 +02:00
c984e9b5d6 Merge pull request #202 from Heath123/patch-1 2022-10-28 21:34:59 +02:00
ddd319369a Merge pull request #39 from Sebbl0508/mod_dialog_fontsize 2022-10-28 21:34:59 +02:00
de3c336213 Merge pull request #184 from Chrono-byte/develop 2022-10-28 21:34:59 +02:00
6e94e9bff1 Merge pull request #148 from ZombieNub/prismlauncher-rename 2022-10-28 21:34:59 +02:00
93b8d9e454 Merge pull request #123 from MMK21Hub/patch-1 2022-10-28 21:34:59 +02:00
6d46081864 Merge pull request #100 from TheEvilSkeleton/improve-approachability 2022-10-28 21:34:59 +02:00
41032aaac2 Merge pull request #110 from Scrumplex/fix-nsis-shortcut 2022-10-19 14:28:36 +02:00
4e08f28246 Merge pull request #31 from flowln/who_needs_webview 2022-10-19 14:28:29 +02:00
46c57e120f Merge pull request #27 from flowln/ftb_install_improve 2022-10-19 13:51:35 +02:00
6b52ee61ae Merge pull request #92 from Scrumplex/new-logo 2022-10-19 13:41:56 +02:00
61fbc5a791 refactor: replace with new logo
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-19 13:08:23 +02:00
22365205f9 fix: use display name for NSIS
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-19 12:17:06 +02:00
c6515c1dad Merge pull request #54 from Samisafool/develop 2022-10-19 12:13:13 +02:00
8201d1df02 Rename
Signed-off-by: Samisafool <thenerdiestguy@gmail.com>
2022-10-19 15:02:43 +05:30
ddf168c536 Merge pull request #75 from Gideon9212/develop 2022-10-19 06:27:09 +02:00
c9f81f56e9 Fix banner
Removed boosted URL for plain

Signed-off-by: Gideon9212 <gideon_gallagher@zoho.com>
2022-10-18 18:35:03 -07:00
570264e1e9 Merge branch 'develop' into develop
Signed-off-by: Gideon9212 <gideon_gallagher@zoho.com>
2022-10-18 17:28:42 -07:00
325e58d98c Merge pull request #88 from FayneAldan/multimc-fallback
go all the way up the fork chain!
2022-10-18 19:27:24 -03:00
23a2960aa3 Merge pull request #60 from jitterdev/develop 2022-10-18 18:53:30 -03:00
888a87463e Add fallback for multimc.cfg
Signed-off-by: Fayne Aldan <FayneAldan@gmail.com>
2022-10-18 14:40:34 -06:00
2ebaf46095 Merge pull request #82 from flowln/i_broke_something_again 2022-10-18 22:15:08 +02:00
3a95a3b7c1 fix: don't take item from a possibly empty list
The list gets destroyed when we take the last object, so things explode.
😔

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-18 16:51:42 -03:00
c4edffb388 Update banner
Changed to Join instead of Support server.

Signed-off-by: Gideon9212 <gideon_gallagher@zoho.com>
2022-10-18 12:10:29 -07:00
5eec7cc788 Change discord invite to a banner
To help direct people to support with a big banner.

Signed-off-by: Gideon9212 <gideon_gallagher@zoho.com>
2022-10-18 11:40:23 -07:00
fb4cf0b75d Merge pull request #55 from flowln/config_add_fallback 2022-10-18 19:50:34 +02:00
5584884fe6 Merge pull request #68 from nightsnowlinouo/develop 2022-10-18 19:43:02 +02:00
3bb1068ef0 Merge pull request #59 from CutestNekoAqua/bug-35 2022-10-18 19:26:57 +02:00
b1b85313ae Fix hosted weblate translation website URL
Signed-off-by: 雪鈴 SnowLin <113241163+nightsnowlinouo@users.noreply.github.com>
2022-10-19 01:22:58 +08:00
aec3e7b0fc correct non-proper noun
Signed-off-by: Jitter <64605731+jitterdev@users.noreply.github.com>
2022-10-18 11:14:27 -05:00
243600b75b Merge pull request #61 from pog5/develop 2022-10-18 18:03:34 +02:00
3d89d126d0 PlaceholderMC => PrismLauncher
Small Correction

Signed-off-by: Nightly <62222436+pog5@users.noreply.github.com>
2022-10-18 15:52:32 +00:00
54281e53a1 Update README.md
Signed-off-by: Jitter <64605731+jitterdev@users.noreply.github.com>
2022-10-18 10:35:00 -05:00
6befd2be81 Update README.md
Signed-off-by: Jitter <64605731+jitterdev@users.noreply.github.com>
2022-10-18 10:34:27 -05:00
1f0ca9ed92 Update README.md
Signed-off-by: Jitter <64605731+jitterdev@users.noreply.github.com>
2022-10-18 10:34:11 -05:00
f3db9c3920 Merge pull request #48 from flowln/fix_nbt 2022-10-18 17:31:46 +02:00
83ceb26151 Streamline Button changes to improve source readability. 2022-10-18 17:28:23 +02:00
32cdfb871c fix: add fallback for polymc.cfg
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-18 12:22:42 -03:00
801e7da5ee feat: allow specifying fallbacks to INI files
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-18 12:22:42 -03:00
2cf1ab7ec5 Merge pull request #43 from SSUPII/develop 2022-10-18 11:31:38 -03:00
d049c1afaf chore: update flake
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-18 16:28:30 +02:00
9f45389bc1 Merge pull request #45 from NotNite/update-readme 2022-10-18 11:23:10 -03:00
d875481969 fix: update libnbtplusplus submodule's URL
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-18 11:11:34 -03:00
17a1e1245c Updated HTML tags to Markdown
Signed-off-by: Sergio <42090377+SSUPII@users.noreply.github.com>
2022-10-18 16:04:28 +02:00
06d28c3eec Updated project naming
Signed-off-by: Sergio <42090377+SSUPII@users.noreply.github.com>
2022-10-18 15:57:43 +02:00
684982c25c README: PlaceholderMC -> Prism Launcher
Also cleaned it up a bit to make my Markdown linter happy.
2022-10-18 09:52:36 -04:00
421522a61a Added further clarifications
Signed-off-by: Sergio <42090377+SSUPII@users.noreply.github.com>
2022-10-18 15:52:00 +02:00
f3b29d67f4 Merge branch 'PrismLauncher:develop' into develop 2022-10-18 15:39:29 +02:00
2ee5c6b2a1 Totally skipped a typo
Signed-off-by: Sergio <42090377+SSUPII@users.noreply.github.com>
2022-10-18 15:38:32 +02:00
5083772c6f Fixed markdown errors
Signed-off-by: Sergio <42090377+SSUPII@users.noreply.github.com>
2022-10-18 15:37:11 +02:00
fd51e5df47 Added build instructions for Linux
Added build instructions in the main repository as a temporary reference

Signed-off-by: Sergio <42090377+SSUPII@users.noreply.github.com>
2022-10-18 15:35:40 +02:00
3405fd91c6 Merge pull request #33 from DioEgizio/remove-useless-actions 2022-10-18 15:31:32 +02:00
194822f11e Merge pull request #28 from flowln/fix_copy 2022-10-18 15:27:53 +02:00
98963d4cdf Merge pull request #29 from Scrumplex/feat-clear-metadata 2022-10-18 15:25:56 +02:00
804ef36b20 Merge pull request #26 from Scrumplex/armhf 2022-10-18 15:24:33 +02:00
3c6ff8fddf Merge pull request #36 from DioEgizio/fix-copying 2022-10-18 15:05:31 +02:00
511893d535 update COPYING
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-18 14:47:20 +02:00
e05fe77bfe feat: remove redundant actions from instance toolbar and redundant "instance"s
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-18 14:43:29 +02:00
2b7b9a2abb Merge pull request #25 from PlaceholderMC/fix-data-path
Fix Data path
2022-10-18 14:05:22 +02:00
6db3f68ae1 refactor: use correct data path
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-18 13:58:50 +02:00
3773f2e7a5 Merge pull request #23 from PlaceholderMC/new-cf-key 2022-10-18 13:29:36 +02:00
1f8bffc15a fix: new CurseForge key
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-18 13:24:57 +02:00
afaef4e83b Merge pull request #13 from PlaceholderMC/rebrand 2022-10-18 13:05:24 +02:00
b746f723cb fix: add Prism copyright header
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-18 13:01:32 +02:00
cfaf44f57b fix: add sparkle public key
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-18 12:49:08 +02:00
eed541201e fix: add new MSA client id
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-18 10:37:35 +02:00
a8bcb85f7b fix(actions): change to PrismLauncher
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-18 10:13:44 +02:00
981e9cf290 Merge pull request #14 from leumasme/develop 2022-10-18 13:27:10 +05:30
3ac398ac49 fix: use display name in code
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-18 09:50:27 +02:00
2d0728395f Update README.md discord vanity link 2022-10-18 09:44:50 +02:00
722194405a refactor: initial rebrand
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-18 09:37:59 +02:00
0868a5e534 Merge pull request #11 from AshtakaOOf/temp-readme
More readable README.md :)
2022-10-18 01:42:54 +02:00
a86b9c82ce Update README.md
Signed-off-by: Adrien <66513643+AshtakaOOf@users.noreply.github.com>
2022-10-18 01:38:49 +02:00
f8642548c8 Update README.md
Signed-off-by: Adrien <66513643+AshtakaOOf@users.noreply.github.com>
2022-10-18 01:35:30 +02:00
27873f7ed4 Update README.md
Signed-off-by: Adrien <66513643+AshtakaOOf@users.noreply.github.com>
2022-10-18 01:27:51 +02:00
b3eda6bcbb Merge pull request #5 from AshtakaOOf/AshtakaOOf-readme
Temporary README.md
2022-10-17 23:08:21 +02:00
1c7799e292 Update README.md
Change some stuff temporarily

Signed-off-by: Adrien <66513643+AshtakaOOf@users.noreply.github.com>
2022-10-17 22:53:02 +02:00
aecd158d3c Merge pull request #1208 from DioEgizio/fix-unused-libs
Removes `classparser` and `xz-embedded`
2022-10-16 10:41:43 -03:00
87d35f0d16 fix: remove some unused libs
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-15 20:16:15 +02:00
c089f9b59f Merge pull request #1203 from DioEgizio/macos-legacy 2022-10-15 15:24:30 +02:00
82d7f9f5a4 chore(tests): add test for FS copy with dot folders/files
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-15 09:40:00 -03:00
8bc529be3d fix: include hidden files when copying instances
fixes instance ccopy on linux .-.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-15 09:20:31 -03:00
924c1634d3 Merge pull request #1194 from flowln/fix_opted_out_on_any_filter 2022-10-15 13:18:35 +02:00
03d077e915 fix(nix): add ghc_filesystem dependency
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-15 13:13:56 +02:00
303628bb05 refactor: support system ghc-filesystem
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-15 13:13:38 +02:00
3b92ec8e82 chore: clang-format RuntimeContext
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-15 12:43:15 +02:00
545944cb0d refactor: support armhf
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-15 12:41:16 +02:00
c90a88b6b6 fix: correct ftb legacy too
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-14 12:18:06 -03:00
89e45a61b3 fix: workaround ghc::filesystem bug
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-14 16:45:13 +02:00
2aff7bac4a fix: disable updater on macOS-Legacy
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-14 15:58:16 +02:00
124097d3a5 feat!: use ghc/filesystem in place of std's one if needed
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-14 14:08:48 +02:00
c520faed6d feat: add gulrak/filesystem submodule
... for old macs that don't have std::filesystem in their stdlib.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-14 14:08:42 +02:00
5bdb3703ed fix: stop forcing libc++ on macOS
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-14 14:08:05 +02:00
2901039a48 feat(actions): macOS-Legacy package
still no updater part though

Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-14 14:08:05 +02:00
dfa220ef02 fix: issues with aborts (again)
i hate it

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-13 15:10:35 -03:00
f26be00571 fix: abort search if we're already trying to download a pack
Meaning we don't have to wait for the searches to finish in the
background to finally start the modpack download, when we have already
selected it -_-

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-13 13:49:06 -03:00
83654a193e refactor+fix: Make FTB install task similar to other install tasks
In particular, this changes the order so that the instance gets created
before downloading the mods (like other install tasks), and the mod download
directly puts the files in the staging folder (like the others), instead
of that weird makeCached and copy stuff.

This fixes some issues with modpack downloads from FTB, like creating an
instance with no mods in it.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-13 13:27:52 -03:00
b2a5d8daf4 fix: don't include opted out versions with the 'Any' filter on the MD
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-12 10:26:14 -03:00
19ee736e1d Merge pull request #1190 from TayouVR/merged-launch-button1 2022-10-11 16:21:41 -03:00
fda3f1352e feat: add image support for the news reader :^)
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-11 16:11:08 -03:00
d194b02e28 fix: prevent images overriding content when changing pages
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-11 15:51:54 -03:00
aaba99dc10 Update launcher/ui/MainWindow.cpp
make " Offline" string for profilers translatable

Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
Signed-off-by: Tayou <31988415+TayouVR@users.noreply.github.com>
2022-10-11 14:58:34 +02:00
93a2e0f777 Merge Launch Buttons
Signed-off-by: Tayou <tayou@gmx.net>
2022-10-10 23:23:06 +02:00
71f3c6b461 feat: add clear metadata action
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-10 12:48:25 +02:00
aabcca5059 Merge pull request #1175 from Ozynt/patch-1 2022-10-09 20:20:05 +02:00
7e67fd8c79 Update LaunchController.cpp
Signed-off-by: Ozynt <104643560+Ozynt@users.noreply.github.com>
2022-10-09 13:20:50 +02:00
fecf1ffcb9 Update LaunchController.cpp
Signed-off-by: Ozynt <104643560+Ozynt@users.noreply.github.com>
2022-10-09 13:19:38 +02:00
fafc9cf9ca Merge pull request #1033 from Scrumplex/multi-arch-support 2022-10-08 20:12:40 +02:00
3111e6a721 chore: add missing license headers
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-08 20:12:07 +02:00
e436f471a0 Merge pull request #1177 from DioEgizio/codeql
bye LGTM 👋
2022-10-08 15:04:23 -03:00
28f84902f6 Merge pull request #1185 from DioEgizio/fix-tooltip
Fix outdated 'Disable mod metadata' button's warning message.
2022-10-08 14:34:59 -03:00
ebee50eedc Improve default light and dark themes (#1174) 2022-10-08 14:33:24 -03:00
e0ef09dfe1 Merge pull request #1183 from Scrumplex/fix-capabilities-first-run 2022-10-08 14:29:14 -03:00
d7992ab29d feat: add image support for FTB packs
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-08 14:12:05 -03:00
60f19f305e feat: add image support for modrinth modpack pages
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-08 14:12:03 -03:00
d99976f5d7 fix: make mod and modpack caches separate for Modrinth
This makes it similar to CF mods / modpacks. The mods cache is
maintained with the same name because it most likely has more data it
in, so this commit will affect existing caches as minimally as possible.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-08 14:11:20 -03:00
db158a5735 feat: add image support for mod pages
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-08 14:11:20 -03:00
ea3be17220 feat: add widget for a text browser with image support
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-10-08 14:11:20 -03:00
f26049009e fix: mod updating isn't upcoming anymore :p
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-08 16:20:46 +02:00
787234a53a Merge pull request #1163 from flowln/fix_list_icons 2022-10-08 12:12:38 +02:00
fc3a64056c Merge pull request #1154 from Scrumplex/epic-formatting-codes 2022-10-08 12:12:26 +02:00
6ebc9abb80 fix: update capabilities before first-run wizard
On first run, the condition for the wizard would return, before running
updateCapabilities(). This moves that call up, as its only dependency is
the settings system.

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-10-06 14:46:13 +02:00
80e9eed35a fix: remove old unused lgtm.yml, exclude cpp/fixme-comment
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-04 16:17:57 +02:00
23b3990f99 feat(code scanning): enable security-and-quality query
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-04 16:17:57 +02:00
41276403df feat(actions): add codeql code scanning
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-10-04 16:17:57 +02:00
e3e9e39498 Merge pull request #1171 from vedantmgoyal2009/patch-1 2022-10-02 15:08:59 +02:00
f315025a8d Merge pull request #1167 from Scrumplex/epic-commandline 2022-10-02 00:41:34 +05:30
8e43d97133 Microsoft account only
Signed-off-by: stoltsvensk <104643560+stoltsvensk@users.noreply.github.com>
2022-10-01 16:47:23 +02:00
c97a47dc62 Merge pull request #1172 from Scrumplex/fix-includes 2022-09-30 18:08:45 -03:00
7ccafdc993 fix: add missing includes to fix Qt 6.4 build
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-30 19:56:01 +02:00
0dca9cb6b8 Merge pull request #1162 from Trial97/feature/Replace-toml-library 2022-09-30 19:44:45 +02:00
be3d780720 Update winget.yml
Signed-off-by: Vedant <83997633+vedantmgoyal2009@users.noreply.github.com>
2022-09-30 22:51:47 +05:30
0f59a1dde1 fix(nix): add tomlplusplus
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-26 15:42:45 +02:00
7c6bb80cee fix: move toml++ find call
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-26 13:46:01 +02:00
62841c5b23 fix: pin tomlplusplus to latest release
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-26 13:44:28 +02:00
aad4f8d1f7 fix: update Git modules
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-26 13:44:28 +02:00
11c44c676c fix: remove unused MACOS_HINT
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-26 13:28:46 +02:00
370c3aa598 Merge pull request #894 from flowln/update_from_external_source
epic PR
2022-09-26 08:25:12 -03:00
1cdadafdf8 refactor: use QCommandLineParser instead
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-26 13:21:27 +02:00
dd6f670dec fix: Fixed memory leak
Signed-off-by: timoreo <contact@timoreo.fr>
2022-09-26 11:50:55 +02:00
9ff364b0d3 huge nit: added const refs, everywhere
Signed-off-by: timoreo <contact@timoreo.fr>
2022-09-26 11:50:31 +02:00
58a5331f7b Merge pull request #1164 from Scrumplex/fix-sort-languages 2022-09-25 19:50:55 +02:00
ed261f0af9 Update launcher/minecraft/mod/tasks/LocalModParseTask.cpp
Co-authored-by: flow <flowlnlnln@gmail.com>
Signed-off-by: Alexandru Ionut Tripon <alexandru.tripon97@gmail.com>
2022-09-25 20:38:55 +03:00
c01b475cbf Merge pull request #1165 from ErogigGit/develop 2022-09-25 09:33:29 -03:00
3d4feeec8d DCO Remediation Commit for ErogigGit <eric.hagerstrand@gmail.com>
I, ErogigGit <eric.hagerstrand@gmail.com>, hereby add my Signed-off-by to this commit: 8a4f1c66f83a339d33ab0ba0076d8c1141055067

Signed-off-by: ErogigGit <eric.hagerstrand@gmail.com>
2022-09-24 23:31:30 +02:00
a1800ec23f Prefer the system tomlplusplus
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2022-09-25 00:20:01 +03:00
8a4f1c66f8 Allow double clicking to mark for dowload
Signed-off-by: Erogig <erogigabyte@gmail.com>
2022-09-24 22:37:51 +02:00
b187231b0e fix: sort languages by their name instead of key
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-24 11:53:41 +02:00
60b38de69f fix: fallback for languages without a native name
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-24 11:48:33 +02:00
600c49f7f0 Replaced tomlc99 with tomlplusplus
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2022-09-24 00:10:27 +03:00
e7380e70a3 fix: use placeholder icon when the project has no icon in MR
Projects with no icon return a null icon URL in Modrinth's API.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-23 18:05:58 -03:00
3df8594f19 feat: change project item delegate for modrinth modpacks
more info! \ ^-^/

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-23 16:59:40 -03:00
ee4a829293 fix: remove manual icon resize in ModModel
THis fixes a FIXME, now that we fixed the issue :o

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-23 16:59:40 -03:00
1862f3c124 fix: set icon sizes correctly in ProjectItemDelegate
no more dumb hacks with icons!!

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-23 16:59:40 -03:00
777ab3416f feat: also format resource/texture pack names
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-21 15:00:28 +02:00
ecf5ab75e7 feat: support more formatting codes
also fix some crashes

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-21 14:59:01 +02:00
4f6d964217 fix: don't change groups when updating an instance
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:10 -03:00
06019f01e3 feat: add dialog to ask whether to chaneg instance's name
This prevents custom names from being lost when updating, by only
changing the name if the old instance name constains the old version,
so that we can update it if the user whishes to.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:10 -03:00
ddde885084 fix: show warning in case there's no old index when updating
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:10 -03:00
be8c6f218c refactor: setAbortStatus -> setAbortable
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:10 -03:00
9eb35ea7c8 fix: don't load specific settings for managed pack info
This avoids loading all settings for all instances when searching for
one with a specific managed pack name.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:10 -03:00
d2fdbec41d fix: move file deletion to the end of the instance update
This makes it harder for problems in the updating process to affect the
current instance. Network issues, for instance, will no longer put the
instance in an invalid state.

Still, a possible improvement to this would be passing that logic to
InstanceStaging instead, to be handled with the instance commiting
directly. However, as it is now, the code would become very spaguetti-y,
and given that the override operation in the commiting could also put
the instance into an invalid state, it seems to me that, in order to
fully error-proof this, we would need to do a copy operation on the
whole instance, in order to modify the copy, and only in the end
override everything an once with a rename. That also has the possibility
of corrupting the instance if done without super care, however, so I
think we may need to instead create an automatic backup system, with an
undo command of sorts, or something like that. This doesn't seem very
trivial though, so it'll probably need to wait until another PR. In the
meantime, the user is advised to always backup their instances before
doing this kind of action, as always.

What a long commit message o.O

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:09 -03:00
2dd372600c fix: some abort-related issues
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:09 -03:00
eda6cf11ef feat(ui): improve info dialog before updating an instance
Adds a 'Cancel' option, and add a note about doing a backup before
updating.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:09 -03:00
68facd6b93 fix(ui): hook up abort status signal in ProgressDialog
Now we have a visual indication on when tasks are abortable!

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:09 -03:00
87002fb8f8 fix: hook up setAbortStatus in instance import tasks
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:09 -03:00
6a50fa35ec feat: add canAbort() status change in Task
By now, it's a recurring pattern of wanting to restrict aborting in
certain situations. This avoids further code duplication, and adds a
signal that external users can hook up to to respond to such change.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:09 -03:00
6541570969 fix: simplify abort handling and add missing emits
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:09 -03:00
4b0ceea894 fix: correctly set managed pack fields in CF pack
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:09 -03:00
8c0816c166 feat: add override awareness to CF modpack updating
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:08 -03:00
be769d07f1 fix: correctly set all managed pack fields in Modrinth pack
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:08 -03:00
3a9d58e31c feat: add override handling in modrinth pack update
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:08 -03:00
7024acac06 feat: add override helper functions
These help us keep track of relevant metadata information about
overrides, so that we know what they are when we update a pack.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:08 -03:00
6131346e2f refactor: change the way instance names are handled
While working on pack updating, instance naming always gets in the way,
since we need both way of respecting the user's name choice, and a
standarized way of getting the original pack name / version.

This tries to circunvent such problems by abstracting away the naming
schema into it's own struct, holding both the original name / version,
and the user-defined name, so that everyone can be happy and world peace
can be achieved! (at least that's what i'd hope :c).

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:08 -03:00
eed73c9078 refactor: clean up InstanceImportTask a bit
Also removes a divide by two in the download progress
(why was it there???)

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:08 -03:00
795d6f35ee feat: add curseforge modpack updating
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:08 -03:00
ebd46705d5 refactor: move creation of CF file download task to a separate function
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:08 -03:00
72d2ca234e refactor: move flame modpack import to separate file
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:07 -03:00
2246c3359b refactor: add throw_on_blocked arg to Flame file parse
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:07 -03:00
242fb156a2 feat: add 'getFiles' by fileIds route in Flame API
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:07 -03:00
208ed73e59 feat: add early modrinth pack updating
Still some FIXMEs and TODOs to consider, but the general thing is here!

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:36:06 -03:00
4441b37338 refactor: move modrinth modpack import to separate file
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:32:36 -03:00
941d75824a refactor: add instance creation abstraction and move vanilla
This is so that 1. Code is more cleanly separated, and 2. Allows to more
easily add instance updating :)

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:32:36 -03:00
ec9ddc4f22 chore: add helper function for copying managed pack data between insts.
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-20 18:32:36 -03:00
98b6f90172 fix: add more legacy architectures
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 16:01:08 +02:00
7e280de361 refactor: drop 64-bit check
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 16:01:08 +02:00
7bd8bd13fe feat: support multiarch system classifiers
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 16:01:06 +02:00
09e85e948c refactor: introduce RuntimeContext
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 15:59:43 +02:00
9ec1c00887 fix: register JavaRealArchitecture for MinecraftInstance
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 15:58:56 +02:00
c6bcb6228b Merge pull request #1108 from Scrumplex/better_texture_packs 2022-09-20 13:28:33 +02:00
a24d589845 fix: ensure all resource folders exist
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 10:39:05 +02:00
ebbcc9f6da fix: actually render color codes for texture packs
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 10:26:15 +02:00
23fc453fae fix: comments and naming of texture pack stuff
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 10:26:15 +02:00
aad6f74db6 fix: tests
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 10:26:15 +02:00
07dcefabcb feat: add texture pack parsing
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-20 10:26:15 +02:00
40c68595d7 Merge pull request #1150 from flowln/fix_crash_on_game_quit 2022-09-20 09:41:59 +05:30
fe9a4fece4 Merge pull request #1142 from flowln/better_fs 2022-09-20 09:00:19 +05:30
098327f128 Merge pull request #903 from jopejoe1/demo-launch 2022-09-18 14:41:25 +02:00
0873b8d304 fix: prevent container detaching in ResourceFolderModel
and use const accessors whenever we can!

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-16 20:12:31 -03:00
c9eb584ac8 fix: prevent deletes by shared pointer accidental creation
This fixes the launcher crashing when opening the game :iea:

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-16 20:12:30 -03:00
10493bd44a fix: move newly allocated resources to the main thread
This avoids them getting deleted when the worker thread exits, due to
thread affinity on the created thread.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-16 20:12:30 -03:00
9e35230467 fix: memory leak when getting mods from the mods folder
friendly reminder to always delete your news.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-16 20:12:30 -03:00
81e326571b fix: enable demo launch only on supported instances
e.g. >= 1.3.1 instances

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-15 19:27:42 -03:00
1b2a7de4e2 fix: show 'demo' instead of 'offline' in log when in demo mode
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-15 18:44:18 -03:00
11216d200c change: move demo action to "Play offline" menu
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-15 18:44:18 -03:00
777be6a48d Add 'Ctrl+Alt+O' Shortcut to launch demo instance.
Signed-off-by: jopejoe1 <johannes@joens.email>
2022-09-15 18:44:18 -03:00
5765a1fdf1 fix: allow demo for older versions
We were not propagating the '--demo' flag in the legacy launcher,
unconditionally setting the 'demo' parameter to false.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-15 18:44:18 -03:00
29dcb9d274 Added Launch Demo button.
Signed-off-by: jopejoe1 <johannes@joens.email>
2022-09-15 18:44:18 -03:00
8674ac4f68 Merge pull request #1146 from Scrumplex/fix-launch-rd 2022-09-15 17:55:08 -03:00
684b8f24f3 fix: allow starting rd- versions
Using `Collections.emptyList()` doesn't allow us to later append stuff
into that list. Use an empty `ArrayList` instead.

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-15 09:29:48 +02:00
1ca2be0039 Merge pull request #982 from DavidoTek/windarkmode2 2022-09-14 13:17:17 +02:00
8c41ff68f7 chore(actions)!: bump macOS required version to 10.15
This is needed for std::filesystem support in macOS's libc.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-12 18:41:13 -03:00
931d6c280a chore(tests): add test for copy operation with blacklist
I almost 💀 because no tests used this x.x

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-12 13:12:55 -03:00
ee0fb2d0e0 fix: use std::wstring for Windows filenames
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-12 13:07:24 -03:00
c496ad1237 chore: make DirNameFromString add normal duplicate identifier
Wrap the number in parenthesis to be similar to other software.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-12 13:07:24 -03:00
277fa21f5f refactor: remove Win32 'crap' in FileSystem
We should use std::filesystem symlink and hardlink functions instead.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-12 13:07:23 -03:00
1cf949226e refactor: use std::filesystem for overrides
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-12 13:07:23 -03:00
be3fae6511 refactor: use std::filesystem for path deletion
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-12 13:07:23 -03:00
5932f36285 refactor: use std::filesystem for file copy
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-12 13:07:23 -03:00
30abb65368 Merge pull request #1133 from Scrumplex/refactor-tests
Move tests to a separate folder, to fix issues and improve maintenance
2022-09-12 12:57:55 -03:00
64a06b5ed6 Merge pull request #1123 from flowln/fix_abort_inst 2022-09-12 17:11:19 +05:30
69d18f17a5 fix(actions, win): only copy openssl libs on qt5 builds (#1130) 2022-09-12 07:57:18 -03:00
4c7d3a103c refactor: restructure tests
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-11 22:29:01 +02:00
10320bdeb4 Merge pull request #1129 from dada513/metainfo_fix
Fixes FlatHub's image metadata for the 1.4.2 release
2022-09-11 09:39:21 -03:00
4261dcff39 fix meta
Signed-off-by: dada513 <dada513@protonmail.com>
2022-09-11 10:45:42 +02:00
a091245793 fix: emit signals when aborting NetJob
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-10 09:10:16 -03:00
ca282f9fb3 Merge pull request #1117 from flowln/fix_updater
Fix the mod updater not working as intended
2022-09-08 09:28:05 +02:00
7cf2c3be0f fix: start at least one task in ConcurrentTask
This allows us to emit all the necessary stuff when we're finished in
the case of starting a task with no subtasks. In particular, this caused
the mod updater to not work properly :)

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-07 12:11:42 -03:00
f65d506f26 Merge pull request #997 from flowln/fix_major_version_filter 2022-09-07 10:34:50 -03:00
333dbca01e Merge pull request #1105 from flowln/better_resource_packs
Add basic resource pack parsing and fix issues
2022-09-07 08:30:36 -03:00
42eb265624 refactor: create mod pages and filter widget by factory methods
This takes most expensive operations out of the constructors.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-07 08:29:58 -03:00
8a65726e9d fix: use more robust method of finding matches for major version
This uses the proper version list to find all MC versions matching the
major number (_don't say anything about SemVer_ 🔫).

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-07 08:27:53 -03:00
1b0ca47682 Merge pull request #939 from flowln/mod_downloader_improve
Some more UI / UX improvements to the mod downloader!
2022-09-07 08:27:11 -03:00
8e3f5c3305 Merge pull request #966 from flowln/refactor_tasks
Reduce code duplication in tasks, fix some bugs and add some tests
2022-09-07 08:26:28 -03:00
3c0a6987cd Merge pull request #1113 from timoreo22/develop
Fix compilation warning due to uninitiated variables.
2022-09-06 18:50:46 -03:00
e37f70b9f7 Merge pull request #1114 from DioEgizio/bump-installqtaction-v3 2022-09-06 20:36:35 +05:30
03c148ce50 chore: update install-qt-action to v3
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-09-06 15:41:32 +02:00
4817f0312d Fixed up a warning
Signed-off-by: timoreo <contact@timoreo.fr>
2022-09-06 14:32:19 +02:00
b70a82c609 Merge pull request #1111 from PolyMC/revert-1067-classpath-epicness 2022-09-05 20:06:33 +02:00
25d1e0c4e6 Merge pull request #1107 from DioEgizio/smaller-about 2022-09-05 17:52:16 +02:00
8e3356f11a Merge pull request #1034 from Scrumplex/detect-performance-features 2022-09-05 17:45:17 +02:00
1b559c7776 Revert "Move classpath definition into NewLaunch itself"
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-09-05 17:37:10 +02:00
d5583f0f02 make the about dialog smaller
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-09-04 14:32:33 +02:00
bedd3c50b6 fix: improve handling of unrecognized pack formats
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 15:05:23 -03:00
43a7af3f44 fix: removing mods with their metadata as well
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:23 -03:00
9db27c6acc fix: crash when adding resource packs directly in the folder
This fixes an issue in which, when adding a new resource pack externally
to PolyMC, when the resource pack view was open, would crash poly.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:22 -03:00
42c81395b3 fix: race condition on ResourceFolderModel tests
This (hopefully) fixes the race contiditions that sometimes got
triggered in tests.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:22 -03:00
3b13e692d2 feat: move resource pack images to QPixmapCache
This takes care of evicting entries when the cache gets too big for us,
so we can add new entries without much worries.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:22 -03:00
0331f5a1eb feat(tests): add tests for resource pack parsing
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:22 -03:00
8a7e117f6b refactor: move resource pack file parsing utilities to separate namespace
This makes it easier to use that logic in other contexts.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:22 -03:00
9b984cedac feat: add image from pack.png to resource packs
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:22 -03:00
dd9e30b24a feat: add resource icon to InfoFrame
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:21 -03:00
6a93688b2e fix: filtering in regex search in resource packs
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:21 -03:00
3ab17a97a8 fix: sorting by pack format
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:21 -03:00
f21ae66265 feat: add basic resource pack parsing of pack.mcmeta
This parses the pack format ID and the description from the local file,
from both a ZIP and a folder, and hooks it into the model.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:21 -03:00
afa1a5e932 feat: modify InfoFrame and ResourcePackPage to show ResourcePack info
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:21 -03:00
050768c266 feat: add more resource pack info
Adds pack format id and description to ResourcePack, that'll be parsed
from pack.mcmeta.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:21 -03:00
cda2bfc240 feat: allow specifying factory for resources in BasicFolderLoadTask
This allows us to hook our own resource type, that possibly has more
content than the base Resource, to it.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-09-03 13:37:20 -03:00
2f167b1512 Merge pull request #1095 from flowln/ensure_file_path_in_override 2022-09-01 09:54:22 +02:00
ba3ac85356 Merge pull request #1067 from Scrumplex/classpath-epicness
Move classpath definition into NewLaunch itself
2022-08-31 18:28:29 -03:00
ec29cedeb7 Merge pull request #1080 from flowln/eternal_cache
Never invalidate libraries cache entries by time elapsed
2022-08-31 18:28:07 -03:00
064ae49d2b fix: make MultipleOptionsTask inherit directly from SequentialTask
It's not a good idea to have multiple concurrent tasks running on a
sequential thing like this one.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:29:02 -03:00
247f99ce2f feat(test): add more tests to Tasks
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:29:01 -03:00
7b6d269904 refactor: make NetJob inherit from ConcurrentTask as well!
Avoids lots of code duplication

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:29:01 -03:00
87a0482b8b refactor: make MultipleOptionsTask inherit from ConcurrentTask too
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:29:01 -03:00
e899699918 refactor: make SequentialTask inherit from ConcurrentTask
In a way, sequential tasks are just concurrent tasks with only a single
task running concurrently, so we can remove LOTS of duplicated logic :)

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:29:01 -03:00
bdf464e792 fix: abort logic running subsequent tasks anyways some times
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:29:01 -03:00
c410bb4ecb fix: 'succeeded while not running' spam in ConcurrentTask
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:29:01 -03:00
a720bcc637 fix: bogus progress update when the total step progress was zero
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:29:01 -03:00
369a8cdc74 fix: only try to start tasks that are really there
This fixes an annoying issue where concurrent tasks would try to start
multiple tasks even when there was not that many tasks to run in the
first place, causing some amount of log spam.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:29:00 -03:00
3f4e55be4f fix: ensure destination file paths exist when overriding folders
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 16:28:23 -03:00
9171f471ab Merge pull request #1094 from flowln/fix_the_thing
Fix build due to merge without rebase messing things up :p
2022-08-28 16:27:41 -03:00
2186b134a4 fix: Mod type enum -> Resource type enum
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-28 14:47:52 -03:00
f371ec210c Merge pull request #1052 from flowln/resource_model 2022-08-28 16:52:53 +02:00
afcd669d2f Merge pull request #965 from flowln/fat_files_in_memory
Refactor a bit EnsureMetadataTask and calculate hashes in a incremental manner
2022-08-28 11:03:12 +02:00
fbf542d205 Merge pull request #1087 from DioEgizio/fix-ftblegacy-url
fix: fix urls on ftb legacy
2022-08-24 20:37:07 -03:00
13184eb8e9 fix: fix urls on ftb legacy
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-08-24 12:31:38 +02:00
ddf1e1ccee fix: make FML libraries cache eternal
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-21 13:47:49 -03:00
5ac4e73697 fix: make libraries cache eternal
This restores the behavior prior to PR #920.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-21 13:47:49 -03:00
6be59b53f1 feat: add eternal cache entries
Those are entries that don't get stale over time, so we don't invalidate
them if they 'expire'.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-21 13:47:49 -03:00
bb54fec907 Merge pull request #1073 from DioEgizio/update-copying
fix(COPYING): fix COPYING.md by adding some missing copyright notices
2022-08-21 13:09:30 -03:00
0b81b283bf fix: LGTM warnings
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:49:56 -03:00
e2ab2aea32 change: add enable/disable to resources
TIL that zip resource packs, when disabled, actually have the effect of
not showing up in the game at all. Since this can be useful to someone,
I moved the logic for it to the resources.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:49:54 -03:00
c3ceefbafb refactor+fix: add new tests for Resource models and fix issues
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:49:23 -03:00
e7cf9932a9 refactor: simplify Mod structure
No need to keep track of pointers left and right. A single one already
gives enough headaches!

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:48:51 -03:00
0c9d03f5df fix(tests): add timeout on ModFolderModel's tests
If the update never ends, the signal is not emitted and we become stuck
in the event loop forever. So a very lenient timer is added to prevent
that.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:48:01 -03:00
92aa24ae34 fix: don't give shared pointer to obj. external to the model
It causes some weird problems and adds refcounting overhead.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:48:00 -03:00
97a74d5c1f refactor: adapt rest of the codebase to the new resource model
In order to access the ModFolderModel from the ModFolderPage, i created
a new m_model for the correct type, shadowing the m_model of type
ResourceFolderModel. This creates two shared_ptr references to the same object,
but since they will have the same lifetime, it doesn't generate a memory
leak.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:47:58 -03:00
256f8094f5 refactor: make Resource Pack model inherit from ResourceFolderModel
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:47:11 -03:00
1e2f0ab308 refactor: move more tied logic to model and move logic to the resources
This moves the QSortFilterProxyModel to the resource model files,
acessible via a factory method, and moves the sorting and filtering to
the objects themselves, decoupling the code a bit.

This also adds a basic implementation of methods in the
ResourceFolderModel, simplifying the process of constructing a new model
from it.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:47:08 -03:00
af2cf2734d refactor: move things around in the mod model
Makes the method order in the cpp file the same as in the header file.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:46:33 -03:00
ec62d8e973 refactor: move general code from mod model to its own model
This aims to continue decoupling other types of resources (e.g. resource
packs, shader packs, etc) from mods, so that we don't have to
continuously watch our backs for changes to one of them affecting the
others.

To do so, this creates a more general list model for resources, based on
the mods one, that allows you to extend it with functionality for other
resources.

I had to do some template and preprocessor stuff to get around the
QObject limitation of not allowing templated classes, so that's sadge :c

On the other hand, I tried cleaning up most general-purpose code in the
mod model, and added some documentation, because it looks nice :D

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:45:01 -03:00
3225f514f6 refactor: move general info from Mod to Resource
This allows us to create other resources that are not Mods, but can
still share a significant portion of code.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:41:59 -03:00
2d63c86022 feat: make Task a QRunnable
This makes it possible to run a task in another thread.

I added a variable to toggle debug prints because they seem to trigger
an assertion on Qt internals when the task in on another thread. Of
course, this isn't awesome, but can wait until we improve our logging.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-20 10:41:59 -03:00
2dcff83be7 Merge pull request #1035 from Scrumplex/fix-coremods
Make Coremods / Mods seperation more clear
2022-08-20 10:15:50 -03:00
afb9ebcd99 fix: distinguish Coremods
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-20 12:53:13 +02:00
92d7e44525 Merge pull request #878 from flowln/lazy_settings 2022-08-20 12:50:56 +02:00
a517f442ea Merge pull request #1023 from flowln/better_shared_ptr 2022-08-20 12:50:50 +02:00
311758233b Merge pull request #1044 from flowln/better_orphan_fix 2022-08-20 12:50:43 +02:00
6e086eb808 Merge pull request #992 from Scrumplex/refactor-version 2022-08-20 12:50:25 +02:00
7e8644430c Merge pull request #1007 from Gingeh/disable-update-button 2022-08-20 12:50:19 +02:00
70a8f6743a Merge pull request #919 from kumquat-ir/download-all-blocked 2022-08-20 12:50:01 +02:00
69eafd0e11 Merge pull request #1058 from DioEgizio/fix-update-org.polymc.PolyMC.metainfo.xml.in 2022-08-19 20:34:11 +02:00
6b6a095b91 fix(COPYING): fix COPYING.md by adding some missing copyright notices
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-08-19 18:42:26 +02:00
d5a2185030 Merge pull request #1068 from TayouVR/improvedWindowsJavaCheck 2022-08-19 14:26:36 +02:00
26f31e9288 use qEnvironmentVariable instead of qgetenv in JavaUtils
Signed-off-by: Tayou <tayou@gmx.net>
2022-08-18 23:59:35 +02:00
e654e66839 Merge pull request #1049 from flowln/waiting_for_news_-_- 2022-08-18 22:53:41 +02:00
bb4861cf0d check for java installs in PATH on windows
this should find java installs from scoop as well as any other installer, that registers java in the PATH environment variable.

Signed-off-by: Tayou <tayou@gmx.net>
2022-08-18 18:24:32 +02:00
01505910f4 refactor: move classpath definition into NewLaunch itself
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-18 18:14:01 +02:00
ab766a0598 Merge pull request #968 from magneticflux-/utf8-logging
Decode process lines as UTF-8
2022-08-18 10:44:01 +02:00
51c664a678 fix: update org.polymc.PolyMC.metainfo.xml.in to not make flatpak break next release
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-08-15 20:34:56 +02:00
3c4b45c9e7 Use C locale codec for decoding
This should correctly decode multi-byte non-UTF-8 text, such as Windows-936 (Simplified Chinese)

Signed-off-by: Mitchell Skaggs <skaggsm333@gmail.com>
2022-08-13 10:39:05 -05:00
93507a263b fix: hide 'More news...' button if the news aren't loaded yet
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-12 17:41:11 -03:00
1175461030 refactor: switch to new versioning scheme
The new versioning system is based on the versioning system used by the
GNOME Foundation for the GNOME desktop.

We are dropping the "major version" as defined by SemVer and move to a
version number with a most and least significant number.

The most significant number must be incremented, if there are new
features or significant changes since last major release.

Otherwise, the least significant number must be incremented, if there
are only minor changes since the last release. New features or
significant changes mustn't be introduced by a bump of the least
significant number.

If a minor change would introduce small user-facing changes (like a
message-box or slight UI changes), it could still be classified as a
minor change.
At the end of the day, a human shall decide, if a change is minor or
significant, as there is no clear line that would separate a "minor" and
a "significant" change in a GUI-application.

Definitions:

feature: New user-facing functionality
significant change: Something that changes user-facing behavior
minor change: Something that fixes unexpected behavior

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-12 14:22:24 +02:00
2f5e55bea0 fix: only remove orphaned metadata on first opening
This avoids deleting the metadata while one is updating their mods.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-11 13:11:56 -03:00
c375e7b4df Merge pull request #897 from jamierocks/atl-updating-initial 2022-08-11 08:50:05 +02:00
5d188c69ed Merge pull request #1039 from budak7273/fix-world-safety-nag-title-text 2022-08-11 07:33:13 +02:00
6bff7751d0 Merge pull request #909 from txtsd/markdownlint 2022-08-11 07:33:04 +02:00
1a5986abe0 Merge pull request #920 from flowln/metacache_fix 2022-08-11 07:32:43 +02:00
cebac3c10e Make new title strings translatable
Signed-off-by: Robb <computerguy440+gh@gmail.com>
2022-08-10 12:07:24 -05:00
a5da3db966 Merge pull request #1018 from Scrumplex/fix-infinite-auth-loop 2022-08-10 18:14:26 +02:00
cd30f75173 fix: Make world safety nag title text match the action being performed instead of always saying 'Copy World'
Signed-off-by: Robb <computerguy440+gh@gmail.com>
2022-08-09 16:01:21 -05:00
94df4ceb36 Fix use of Qt 5.14 enum
Signed-off-by: Mitchell Skaggs <skaggsm333@gmail.com>
2022-08-09 00:17:53 -05:00
a14476c5fb Replace local 8-bit decoding with UTF-8 decoding
Handles incomplete byte sequences using `QTextDecoder`

Signed-off-by: Mitchell Skaggs <skaggsm333@gmail.com>
2022-08-08 23:54:01 -05:00
d82bb29919 fix: don't apply GameMode/MangoHud, if they aren't supported
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-08 21:19:46 +02:00
33af0c6a7c refactor: don't include mangohud's library path
This could cause issues on some environments. Users should just put
MangoHud libs into global LD_LIBRARY_PATH, just like with any other
library

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-08 21:16:37 +02:00
68f3f98bc3 feat: detect GameMode and MangoHud's presence
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-08 21:16:37 +02:00
f873cd5b1a refactor: store current capabilities
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-08 21:16:37 +02:00
fa8df286d9 chore(ci): Add markdownlint config to ignored paths
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 13:00:57 +05:30
76aa0c434a feat(markdown): Add markdownlint config
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 13:00:57 +05:30
78dc0cfdf3 chore(markdown): MD001 Heading levels should only increment by one level at a time
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 13:00:57 +05:30
9654728bfb chore(markdown): Align inline HTML correctly
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 13:00:57 +05:30
123d1864f4 chore(markdown): MD037 Spaces inside emphasis markers
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 13:00:57 +05:30
96a91e988d chore(markdown): MD010 Hard tabs
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 13:00:56 +05:30
19ecb1701e chore(markdown): MD031 Fenced code blocks should be surrounded by blank lines
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 13:00:56 +05:30
8085b2728d chore(markdown): MD032 Lists should be surrounded by blank lines
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 13:00:56 +05:30
56cad31a36 chore(markdown): MD034 Bare URL used
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 13:00:46 +05:30
3275bc4e93 chore(markdown): MD009 Trailing spaces
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 12:57:30 +05:30
8963378039 chore(markdown): MD007 Unordered list indentation
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 12:57:30 +05:30
c7d435bb7a chore(markdown): MD025 Multiple top-level headings in the same document
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 12:57:11 +05:30
06cc7e4ea0 chore(markdown): MD046 Code block style
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 12:55:11 +05:30
fba20e2cfb chore(markdown): MD040 Fenced code blocks should have a language specified
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 12:55:11 +05:30
358f080c76 chore(markdown): MD012 Multiple consecutive blank lines
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 12:55:11 +05:30
8cea57ff0f chore(markdown): MD022 Headings should be surrounded by blank lines
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-08-06 12:53:50 +05:30
7b27f200b1 fix: don't mutate QHash while iterating over it
Even though it was using a QMutableHashIterator, sometimes it didn't
work quite well, so this is a bit better.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-05 16:30:12 -03:00
f4b207220c fix: add some more nullptr checks / protection
die sigsegv 🔫

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-05 15:10:44 -03:00
d835e1d14e refactor: simplify smart pointers more
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-05 11:38:46 -03:00
75f92de8f8 Merge pull request #1017 from flowln/kill_orphan_metadata
Remove orphaned metadata to avoid problems with auto-updating instances
2022-08-04 12:57:20 -07:00
293c1deee5 Merge pull request #1014 from DioEgizio/downgrade-qt-macos
chore: downgrade to Qt 6.3.0 on macos
2022-08-04 12:56:55 -07:00
4dee05a967 Merge pull request #1006 from DioEgizio/appimage-ubuntu-moment
fix: work around ubuntu 22.04 openssl appimage issues by copying openssl libs
2022-08-04 12:56:38 -07:00
8d6414d74a Merge pull request #1019 from Scrumplex/fix-openbsd-root
Add root path detection on OpenBSD
2022-08-04 21:47:35 +02:00
362ecdb583 refactor+fix: use QSharedPointer for shared_qobject_ptr
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-04 15:33:51 -03:00
058b9f9272 Merge pull request #994 from Scrumplex/fix-winget-releaser
Fix WinGet releaser
2022-08-04 16:20:23 +01:00
355762aa30 fix: emit abort in LaunchController
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-04 10:07:36 +02:00
be4fb65470 fix: Add root path detection on OpenBSD
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-03 21:14:32 +02:00
4ed296bad4 fix: allow user to interrupt launch after 3 tries
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-08-03 20:38:40 +02:00
a8aa862919 Move large condition into a new lambda
Signed-off-by: Gingeh <39150378+Gingeh@users.noreply.github.com>
2022-08-03 16:39:30 +10:00
31ba1de53b fix: remove orphaned metadata to avoid problems with auto-updating insts
Just as my master has taught me. 🔫

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-02 16:15:39 -03:00
bca1fef2b2 chore: downgrade to Qt 6.3.0 on macos
seems to fix some emoji-related issues

Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-08-02 10:59:54 +02:00
f33b31e048 Check for running instance when re-opening the mod folder page and when selecting mods
Signed-off-by: Gingeh <39150378+Gingeh@users.noreply.github.com>
2022-08-02 14:14:45 +10:00
0d10ebb7ca Update launcher/ui/pages/instance/ModFolderPage.h
Co-authored-by: flow <flowlnlnln@gmail.com>
Signed-off-by: Gingeh <39150378+Gingeh@users.noreply.github.com>
2022-08-02 12:50:25 +10:00
4a8abc948e fix: prevent segfault due to callbacks into deleted objects
Since network requests are, for the most part, asynchronous, there's a
chance a request only comes through after the request sender has already
been deleted.

This adds a global (read static) hash table relating models for the mod
downloader to their status (true = alive, false = destroyed). It is a
bit of a hack, but I couldn't come up with a better way of doing this.

To reproduce the issue before this commit: scroll really quickly through
CF mods, to trigger network requests for their versions and description.
Then, in the middle of it close the mod downloader. Sometimes this will
create a crash.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 18:34:15 -03:00
6fd3672618 Merge pull request #1012 from DioEgizio/patch-10
fix: remove iconfix from libraries/README.MD
2022-08-01 20:31:11 +02:00
abd090bd48 fix: remove iconfix from libraries/README.MD
someone forgor (💀) to remove it

Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-08-01 20:21:19 +02:00
bd9140f1f3 Merge pull request #1008 from DioEgizio/qt-version-issue-template
chore: update issue template to ask about Qt version
2022-08-01 18:40:11 +02:00
9d78b2d259 Update .github/ISSUE_TEMPLATE/bug_report.yml
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
Co-authored-by: flow <flowlnlnln@gmail.com>
2022-08-01 14:51:19 +02:00
9c9528838a chore: update issue template to ask about Qt version
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-08-01 14:40:55 +02:00
77b640b76b Disable "Check for Updates" and "Download Mods" while the game is running
Signed-off-by: Gingeh <39150378+Gingeh@users.noreply.github.com>
2022-08-01 20:56:05 +10:00
a8dfe98b1a Disable "Check for Updates" if all mods are removed
Signed-off-by: Gingeh <39150378+Gingeh@users.noreply.github.com>
2022-08-01 20:56:05 +10:00
cee41b87f7 fix(ui): force redraw of mod list when (de)selecting a mod
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:31 -03:00
7a95314e42 feat(ui): remember mod download dialog's geometry
Makes it consistent with other modal dialogs.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:31 -03:00
6aaf1f4f21 feat: lazy-load CF mod descriptions
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:30 -03:00
368a0ddd44 feat: add mod descriptions to CF mods
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:30 -03:00
0808a10b7b feat: cache mod versions
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:30 -03:00
6f052baa94 refactor: use function cb instead of class cb in getVersions
I've discovered even more functional programming! :^)

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:30 -03:00
5bc67d3f6b feat: cache extra mod info (like links and body)
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:30 -03:00
74c6c5cfbc refactor: use function cb instead of class cb in getModInfo
I've discovered functional programming :^)
This makes this route more fit for general use.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:30 -03:00
158b7fd166 feat+refactor: clean up ProgressWidget and add progress indicatior to
mod downloader

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:30 -03:00
c3f647dc96 feat: add (semi) instant searching in mod downloader
It has a delay of 350ms from the last typed character to search, in
order to cache small changes while typing.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:30 -03:00
5936c7b65c change: preserve search term across different mod providers
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:29 -03:00
a8bcd85c93 feat+refactor: add shortcuts to mod downloader and clean up
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:29 -03:00
127b558f95 change: change button names to be more user-friendly
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:29 -03:00
6e9a27f40f feat: display the 'body' of a MR mod on the mod downloader
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:29 -03:00
4a13dbe3bb feat: create delegate for project item views
This allows us to define custom painting for list view items. In
particular, this is applied to the mod downloader, in order to allow
displaying both the mod name and mod description, and settings their
effects (like bold or underline) independent of each other.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:29 -03:00
0f61f5ba03 fix(ui): missing tr() in mod download dialog's title
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-01 07:33:29 -03:00
5f1efbeb67 fix: work around ubuntu 22.04 openssl appimage issues by copying openssl libs
terrible hack but it works™️

Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-08-01 09:57:14 +02:00
9c105914f0 use BlockedModsDialog for ftb packs as well
Signed-off-by: kumquat-ir <66188216+kumquat-ir@users.noreply.github.com>
2022-07-31 15:05:47 -04:00
579582740e Merge remote-tracking branch 'origin/develop' into download-all-blocked
Signed-off-by: kumquat-ir <66188216+kumquat-ir@users.noreply.github.com>
2022-07-31 14:54:50 -04:00
b15544c163 Trash instances instead of deleting (when possible) (#549)
Squashed because of :pofat: commit history
2022-07-30 14:42:33 -03:00
94a63e3859 Merge pull request #941 from Scrumplex/bump-cxx-standard
Bump to C++17
2022-07-30 17:10:59 +01:00
842b7e6c39 use c11 instead
c17 dont work properly with lgtm's build system and c11 is already almost identical to c17 at least in gcc
2022-07-30 15:35:48 +01:00
22f5011451 fix(winget): strictly match non-Legacy setup
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-29 16:25:12 +02:00
74120fe1f3 Merge pull request #699 from Scrumplex/resolve-ftb-mods-cf 2022-07-28 09:43:39 +02:00
b4e8abd0ad feat: win32 enable dark titlebar for dark theme
Signed-off-by: DavidoTek <54072917+DavidoTek@users.noreply.github.com>
2022-07-26 23:25:17 +02:00
336f1f4f50 Merge pull request #974 from flowln/accounts_qt6
Fix adding multiple accounts in Qt6
2022-07-26 16:08:05 -03:00
1c256d8876 Merge pull request #958 from jopejoe1/readme 2022-07-27 00:16:35 +05:30
1ce0f0e7a5 fix: progress dialog going away even if the task was not aborted
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-26 20:33:33 +02:00
fbf1901d86 refactor: shuffle some things around to improve readability
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-26 20:33:33 +02:00
0382f33c46 fix(ui): pump events to show "Copying modpack files..." text
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-26 20:33:33 +02:00
13372f3f99 chore: clean up FTBPackInstallTask a bit and connect missing signals
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-26 20:33:33 +02:00
e741cb7f0a fix: add abort handlign in Flame's FileResolvingTask
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-26 20:33:33 +02:00
fb289c6b17 chore: add license headers
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-26 20:33:29 +02:00
75a7ea55d4 feat: implement mod resolving for FTB
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-26 20:33:10 +02:00
86573a5ccd Merge pull request #961 from flowln/fix_resource_filter 2022-07-26 20:14:18 +02:00
6fe55a79f1 fix: use const qualifier for operator==() and allow other comparisons
This fixes an implicit behavior changed by C++17.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-26 15:11:56 -03:00
1a6cb9ee99 chore: add some debugging prints in AccountList
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-26 15:11:56 -03:00
a495d9eca5 chore: Normalize sentence in readme
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-07-26 22:00:40 +05:30
65a945f968 Merge pull request #956 from flowln/jar_mods_aa
Fix segmentation fault when using jar mods
2022-07-25 06:57:40 +01:00
a9e8ed5087 fix: pump events and do a queued start for concurrent tasks
Heavy workloads can consume a ton of time doing their stuff, and starve
the event loop out of events. This adds an event processing call after
every concurrent task has been completed, to decrease the event loop
stravation on such loads.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-24 17:46:54 -03:00
00520b6a0e feat: add hashing tasks to the sequential task in ModUpdateDialog
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-24 17:46:54 -03:00
e6f2a3893a refactor+feat: improve code separation in ensure metadata
... and avoid calculating the same hash multiple times

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-24 17:46:54 -03:00
24c034ff6a change(libs): use a 4MiB buffer by default in murmur2 hashing
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-24 17:46:54 -03:00
631a93bcd8 refactor: add a HashUtils place for hashing stuff
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-24 17:46:54 -03:00
b1763353ea feat: do incremental calculation of CF's hash
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-24 17:46:53 -03:00
f95bcf45ad feat(libs): add incremental version of murmurhash2 calculation
This does two passes for a given file, which is kinda slow, but I don't
know how else to get the size excluding the filtered ones :<

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-24 17:46:53 -03:00
15ec1abb6a feat: use QIODevice for calcuating the JAR hash on Modrinth
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-24 17:46:53 -03:00
cfda8dbb2b refactor: use QIODevice instead of a whole QByteArray for hash calc.
This allows Qt to do its thing and optimize the data gathering from the
JAR.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-24 17:46:53 -03:00
3aa2003951 fix: filter in external resource pages not working
For some reason, using setFilterFixedString() doesn't seem to update the
QRegularExpression object with a new value, instead leaving it empty. It
updates QRegExp just fine, so maybe that's an Qt bug? o.O

Anyway, using regex in the filter is kinda cool actually :D

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-23 23:50:56 -03:00
0e473f4570 Merge pull request #951 from flowln/performace_tab_fix
Hide the entire performance tab on the instance settings in non-Linux OSes
2022-07-23 18:31:04 -03:00
bfa824ee71 Fix broken url in readme
Signed-off-by: jopejoe1 <johannes@joens.email>
2022-07-23 23:22:39 +02:00
1157436a24 fix: sigsegv when trying to use jar mods
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-23 14:24:24 -03:00
4596e78df0 Merge pull request #952 from Scrumplex/fix-pre-post-launch
Fix variable substitution in pre launch/post exit hooks
2022-07-23 18:06:12 +01:00
813dfbd2d3 fix: hide the entire performance tab on instance settings in non-Linux
"just woke up after a major release has just been made" coding style

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-23 13:29:39 -03:00
ba7dfb360c fix: actually substitute variables in pre/post launch
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-23 17:51:58 +02:00
6aad750fe0 Merge pull request #893 from Scrumplex/refactor-env-handling 2022-07-23 14:08:10 +02:00
5e443ae347 fix(nix): change license to gpl3Only
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-23 14:00:11 +02:00
c65f5f7728 Merge pull request #877 from Scrumplex/refactor-offline-accounts 2022-07-23 13:54:36 +02:00
74b62727af Merge pull request #947 from flowln/unicode_uhh 2022-07-23 13:38:48 +02:00
2e94562f79 fix: treat accounts as offline, if auth servers are down
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-23 12:38:01 +02:00
061ea5648e Merge pull request #922 from DioEgizio/qt6-tarballs
feat(actions): package and deliver qt6 tarballs
2022-07-23 14:18:00 +05:30
439e7bbf4e change: unicode chars for folders and disabled mods in mod list
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-22 17:45:27 -03:00
0f1d51f866 Update .github/workflows/build.yml
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-22 22:11:53 +02:00
75cfaf0672 Merge pull request #938 from Scrumplex/fix-i18n3 2022-07-22 22:45:53 +05:30
ceaa732e5f Merge pull request #932 from Scrumplex/fix-nix 2022-07-22 22:43:57 +05:30
deb2a2bd14 Merge pull request #930 from TheOPtimal/develop 2022-07-22 22:43:00 +05:30
33853b6107 fix: use single-space unicode char for checkmark in mod list
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-22 11:48:08 -03:00
ab6e1b112b change(cache): use cache-specific http headers for their lifetime
This uses the 'Age', 'Cache-Control' and 'Expires' HTTP headers to more
accurately set up the cache lifetime, falling back to a static 1-week
time if they're not present in the response.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-21 19:19:24 -03:00
220e823c8d DCO Remediation Commit for Jacob Gogichaishvili <iakob.gogichaishvili@gmail.com>
I, Jacob Gogichaishvili <iakob.gogichaishvili@gmail.com>, hereby add my Signed-off-by to this commit: 3746a2566d7b0f758a1de7a3f78cb88bd28bb1e5

Signed-off-by: Jacob Gogichaishvili <iakob.gogichaishvili@gmail.com>
2022-07-20 23:27:07 +04:00
c666c3e251 refactor!: bump to C++17 and C17
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-20 14:22:10 +02:00
9cc1773fa7 fix: move HTML code outside of translation
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-20 10:15:21 +02:00
e78c7af715 Merge pull request #936 from Scrumplex/fix-windows-crap-2 2022-07-20 10:07:10 +02:00
b96e76134a fix(nix): switch to LD_LIBRARY_PATH
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-19 18:09:48 +02:00
fd2b206997 fix: support LD_* for OpenBSD
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-19 18:07:58 +02:00
2d53c7c5b2 refactor: filter values in environment variables
Before this change, you had to specify custom LD_* variables using the
prefix GAME_LD_*. Now instead of dropping all LD_* variables by default,
we should just filter them and remove the values we *know* are from our
start script.

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-19 18:07:58 +02:00
28ae5d710e fix: fix translations for mod updater
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-19 18:03:45 +02:00
7a13412ec7 feat(actions): package and deliver qt6 tarballs
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-07-19 17:07:34 +02:00
c86610b917 Merge pull request #934 from virchau13/fix-non-nixos-libraries
fix(nix): only load stdenv.cc.cc.lib on NixOS
2022-07-19 11:28:08 -03:00
502750492c Merge pull request #929 from flowln/dark_theme_dark_font 2022-07-19 11:17:40 +02:00
8fc1653b0c fix: fix Java Checker on Windows, again
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-19 11:12:11 +02:00
6841ebc31d fix(nix): only load stdenv.cc.cc.lib on NixOS
On non-NixOS, launching any external process from Minecraft (e.g.
clicking on links) will fail due to a conflict between the system
libraries and the Nix stdenv.cc.cc.lib. This works around that issue by
only loading stdenv.cc.cc.lib on NixOS.

Signed-off-by: Vir Chaudhury <virchau13@hexular.net>
2022-07-19 09:03:54 +08:00
8757281467 fix(nix): switch to PolyMC libnbtplusplus
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-18 20:34:36 +02:00
20b1723e78 merge origin/develop
Signed-off-by: kumquat-ir <66188216+kumquat-ir@users.noreply.github.com>
2022-07-18 14:05:23 -04:00
be78afeee5 qtcreator moment
Signed-off-by: kumquat-ir <66188216+kumquat-ir@users.noreply.github.com>
2022-07-18 14:03:06 -04:00
3746a2566d Add more Nix meta information 2022-07-18 21:47:26 +04:00
0cb47cf7d7 fix: dark placeholder text in dark background on dark theme
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-18 14:25:00 -03:00
dec81c4f27 Merge pull request #588 from flowln/mod_update
Implement mod updater (😎)
2022-07-18 12:40:25 -03:00
54b335711a fix: raw-pointers and leaks in ModFolderLoadTask
Co-authored-by: timoreo <contact@timoreo.fr>
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:56:23 -03:00
6bb8332b4b fix: bogus returns in EnsureMetadataTask
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:43:12 -03:00
de9e304236 fix: std::list -> QList
Qt6 removed Qlist::toStdList() 😭

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:45 -03:00
650af5eb64 change: use ModStatus as a simple member instead of a pointer
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:44 -03:00
47bdcb6050 feat: make second metadata pass concurrent
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:44 -03:00
58dc3e93d3 fix: clean up execWithTask in Progress Dialog
This prevents weird problems, such as dialogs being non-modal when they
should be!

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:44 -03:00
79b0a16f7a fix: try finding a good height for short changelogs
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:44 -03:00
2b65ee433f fix: changelogs with too much space between lines
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:44 -03:00
001bbef9ee fix: don't use shared_ptr for a background task T_T
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:44 -03:00
c4316e81e6 change: make Mod a QObject used as a pointer
Prevents problems when copying it around!

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:44 -03:00
fac63541a4 fix: work around HoeDown bug(?) in changelog line breaks
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:44 -03:00
dfd6cb29be feat: improve changelog and sort updatable mods
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:44 -03:00
5f75e531e6 fix: handling around disabled mods
Don't update disabled mods to prevent mod duplication. Also, chop
filename in the metadata with a '.disabled'.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:43 -03:00
a7648d60ce fix: don't require non-essential items in mod index
Also adds slug field.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:43 -03:00
52c45c2d32 feat: add some mod api calls
- Get Project: Already existed but required a specific caller type. This
  is more general.
- Get Projects: A single call to multiple of the above

Both providers support these calls.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:43 -03:00
fd6755c93f change: mod metadata improvements
- Use slug instead of name
- Keep temporary status before having local details

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:43 -03:00
a53ee2e35c fix: mod parsing of 'String-fied' version (i.e. OpenBlocks)
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:43 -03:00
4e6978ff6f feat: improve metadata gen. networking and performance
This makes the metadata generation code a lot messier and harder to use,
but there's not really much else that can be done about it while
preserving all it's capabilities :(

At least we now have speed

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:43 -03:00
91a5c4bdcb feat: add metadata get/delete via mod id
This is, in many cases, more reliable than name comparisons, so it's
useful specially in cases where a mod changes name between versions

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:43 -03:00
9a07ede615 fix: filter out opted-out mods in mod downloader
Maintains Pre-Updater behaviour

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:43 -03:00
dfab55112b feat: remove existing mod when updating/redownloading it
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:42 -03:00
1709b47bb7 fix: don't double add mods in mod downloader/updater
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:42 -03:00
2d10c246a8 feat: add update mods to the ui / mod model
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:42 -03:00
6e2869834f feat: add mod update dialog
This subclasses the Review mods dialog to make a "Update review" one.
Also, all the necessary components built until now are put together in a
coherent unity that checks and generates metadata on-the-fly and checks for
mod updates, while giving and receiving feedback to the user.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:42 -03:00
b8b71c7dd2 feat: add mod update check tasks
Those tasks take a list of mods and check on the mod providers for
updates. They assume that the mods have metadata already.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:42 -03:00
c3f6c3dd82 feat: add changelog to mod providers
The Modrinth changelog is fairly straight-forward, as it's given to us
directly with the API call we already did. Flame, on the other hand,
requires us to do another call to get the changelog, so it can introduce
quite a heavy performance impact. This way, we make it optional to get
such changelog.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:42 -03:00
844b245776 feat: add EnsureMetadataTask
This task is responsible for checking if the mod has metadata for a
specific provider, and create it if it doesn't.

In the context of the mod updater, this is not the best architecture,
since we do a single task for each mod. However, this way of structuring
it allows us to use it later on in more diverse scenarios.

This way we decouple this task from the mod updater, trading off some performance
(though that will be mitigated when we have a way of running arbitrary tasks
concurrently).

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:42 -03:00
4bcf8e6975 feat: add api call to flame
Call added:
- Get Fingerprints Matches
- Get Mod File Changelog

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:42 -03:00
0e52112016 feat: add some api calls to modrinth
Calls added:
- Get version from hash
- Get versions from hashes
- Latest version of a project from a hash, loader(s), and game version(s)
- Latest versions of multiple project from hashes, loader(s), and game version(s)

Some of those are not used yet, but may be of use later on, so we have
it if we need it :)

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:41 -03:00
32a9545360 libs: add murmur2 library
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:41 -03:00
9a44c92211 feat: add MultipleOptionsTask
This is a variation of a Sequential Task, in which a subtask failing
will prompt the next one to execute, and a subtask being successful will
stop the task.

This way, this can be used for easily managing fallbacks with tasks. :D

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:41 -03:00
dd6aabf9ab feat: add ChooseProviderDialog
Allows you to prompt the user for choosing a (mod) provider. This should
be fairly independent of the mod updater logic, so it can be used for
other ends later down the road :^)

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:41 -03:00
91776311c7 fix: allow aborting upload tasks
This maintains the same behaviour as the Download task.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:41 -03:00
882c82f82c fix: always update global progress of sequential tasks
Previously, it would not update the global counter if the subTask didn't
update its progress, even though progress was being made.

This also prevents a segmentation fault while aborting the task.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:41 -03:00
43b9db6e45 change: allow deleting mods while preserving their metadata
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:41 -03:00
032ceefa1d feat: add some helping methods to WideBar
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:41 -03:00
05fa266e6b fix: provide default value to is_indexed in ModDownloadTask
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-17 11:33:40 -03:00
56085310cb Merge pull request #913 from Gingeh/cape-without-skin 2022-07-17 09:57:03 +02:00
6a1d611fd1 Restore ScrollMessageBox
Signed-off-by: kumquat-ir <66188216+kumquat-ir@users.noreply.github.com>
2022-07-17 02:40:27 -04:00
c8a72c876d fix: add missing HttpMetaCache entry for CF mods
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-16 21:25:29 -03:00
ec87a8ddfc fix: add expiration time to cache entries
This is to prevent problems where the cache entry would still be used
way after the remote resource got updated. The limit is hardcoded for 1
week, which I think is a reasonable time, but this could be further
tweaked.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-16 21:25:28 -03:00
33e34ebb83 Add "Open All" button to blocked mods dialog
Signed-off-by: kumquat-ir <66188216+kumquat-ir@users.noreply.github.com>
2022-07-16 19:14:54 -04:00
dce435c882 Merge pull request #917 from Scrumplex/fix-translations-2 2022-07-16 22:27:03 +02:00
396b3c3952 fix: add missing full-stop to message
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-16 21:26:23 +02:00
8cf42f4e15 Merge pull request #902 from Scrumplex/fix-unicode-windows 2022-07-16 21:15:55 +02:00
17ea51ce27 fix: fix memory leak on Windows
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-16 20:08:08 +02:00
04818ca626 Merge pull request #914 from DioEgizio/cacheqt 2022-07-16 00:42:44 +05:30
6732b77594 chore(actions): Remove superfluous whitespace
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-07-15 22:40:12 +05:30
3e4346e321 feat(actions): bring back qt caching
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-07-15 10:02:11 +02:00
4dfc01899a Make skin upload optional
Signed-off-by: Gingeh <39150378+Gingeh@users.noreply.github.com>
2022-07-15 12:23:11 +10:00
b0b8ccfd4a Merge pull request #911 from Scrumplex/fix-release-workflow-2 2022-07-14 07:59:34 +02:00
4d35c66af3 fix(actions): fix release workflow
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-13 22:47:55 +02:00
509f7bd018 fix: move time record overrides to BaseInstance
This is needed so that we can show time stats in the UI without having
to load all type-specific settings, which would make all the previous
changes useless :c

This is apparently done with console settings too, so I don't think
there's a problem doing this too :>

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-12 21:15:59 -03:00
42b9b3d72a Merge pull request #905 from DioEgizio/fix-copying 2022-07-12 19:19:09 +05:30
e280f9fe3e chore(COPYING): update COPYING.MD a bit
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-07-12 15:20:26 +02:00
89493a2f1d Merge pull request #904 from virchau13/add-stdenv-lib
fix(nix): add stdenv.cc.cc.lib to GAME_LIBRARY_PATH
2022-07-12 07:47:06 -03:00
e259bffca6 Merge pull request #810 from Scrumplex/refactor-launcher-version
Hide channel from version for tagged commits
2022-07-12 07:46:46 -03:00
ba9164022d fix(nix): add stdenv.cc.cc.lib to GAME_LIBRARY_PATH
Some mods (like DiscordRichPresence) require libstdc++.
This commit adds stdenv.cc.cc.lib to $GAME_LIBRARY_PATH so that these
mods function correctly.

Signed-off-by: Vir Chaudhury <virchau13@hexular.net>
2022-07-12 05:16:32 +08:00
a4672ba00f fix: remove unnecessary code for Windows
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-11 19:09:20 +02:00
c0bf267bae fix: fix unicode issue with JavaChecker on Windows
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-11 18:53:20 +02:00
1a26a53659 Merge pull request #901 from txtsd/scdoc 2022-07-11 14:56:19 +02:00
8f4d7ac655 Merge pull request #678 from Scrumplex/improvements-around-proprietary-services 2022-07-11 14:56:09 +02:00
c5625d8d32 Merge pull request #847 from EliteTK/switch-to-scdoc 2022-07-11 14:47:44 +02:00
548a2a1d64 Merge pull request #900 from DioEgizio/CI/fix
fix(actions): fix ccache on windows
2022-07-11 08:02:27 -03:00
df01a58099 feat(ci): Install scdoc to build manpage
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-07-11 14:30:46 +05:30
ac8ee9f981 Merge pull request #479 from kthchew/feature/sparkle-mac 2022-07-11 09:02:41 +02:00
b1805b70ea fix(actions): fix ccache on windows
Also removes some unnecessary dependencies for the generic Linux package

Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-07-11 08:13:02 +02:00
eae8a2914e Remove use of obsolete method
Fixes Qt 6 build

Signed-off-by: Kenneth Chew <kenneth.c0@protonmail.com>
2022-07-10 19:09:58 -04:00
03429db528 Switch to production Sparkle appcast
DCO Remediation Commit for Kenneth Chew <kenneth.c0@protonmail.com>

I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: 92b913ca3740ea1aa799a69d65dc13d0c3612b87
I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: 7eb61a28be3b66c1016eab434ae93b5d94eb11af
I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: ea4ef1655bdadf04c36768f0f641ca7579f754cf
I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: b5bdfa6c2e9a0eb62e476dd399b82bfa972e0320
I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: f9f46609ee288d8df80dd978f8c619a7e02e4787
I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: 34adcec6165662d6245a55ee0a75c36753061df2
I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: 05cd30ac06b67ebc594773fc7e7ccf110fc336a3
I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: f3c72f4f0888aa16793354890055e17df07084fc
I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: b1f486518e3db19cca8ea9f33eb1d8d1afa247e7
I, Kenneth Chew <kenneth.c0@protonmail.com>, hereby add my Signed-off-by to this commit: 3bc02b9662b84c2ab86b5de1b08b4537177fde90

Signed-off-by: Kenneth Chew <kenneth.c0@protonmail.com>
2022-07-10 18:51:52 -04:00
10f27250ee DCO Remediation Commit for bf560f4
I, Jamie Mansfield <jmansfield@cadixdev.org>, hereby add my
Signed-off-by to this commit: bf560f4594e4c17b493725f1ac98f0becfff5c2e

Signed-off-by: Jamie Mansfield <jmansfield@cadixdev.org>
2022-07-10 19:14:05 +01:00
aed7963d11 DCO Remediation Commit for a7fc23d
I, Jamie Mansfield <jmansfield@cadixdev.org>, hereby add my
Signed-off-by to this commit: a7fc23dd96981b1bc2449b5bf32f1913b45ecbc8

Signed-off-by: Jamie Mansfield <jmansfield@cadixdev.org>
2022-07-10 19:13:34 +01:00
2810413112 DCO Remediation Commit for 9e69b8f
I, Jamie Mansfield <jmansfield@cadixdev.org>, hereby add my
Signed-off-by to this commit: 9e69b8fe1bf8b325f6c386b7578408da4b775177

Signed-off-by: Jamie Mansfield <jmansfield@cadixdev.org>
2022-07-10 19:12:57 +01:00
31fd92e071 DCO Remediation Commit for e0ae631
I, Jamie Mansfield <jmansfield@cadixdev.org>, hereby add my
Signed-off-by to this commit: e0ae631d59103cd32d758dec76e55b3a40b86be2

Signed-off-by: Jamie Mansfield <jmansfield@cadixdev.org>
2022-07-10 19:12:08 +01:00
b3b76d5d56 Merge branch 'develop' into feature/sparkle-mac
# Conflicts:
#	.github/workflows/build.yml
2022-07-10 19:38:30 +02:00
cd948dceae Merge pull request #575 from Scrumplex/qt6 2022-07-10 19:21:01 +02:00
eb33a87ff5 fix: remove TODOs
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 18:11:13 +02:00
bf560f4594 ATLauncher: Move the UI support implementation into it's own class
This will allow it to be used in multiple locations.
2022-07-10 11:27:42 +01:00
d77237ca5d refactor(actions): rename Windows builds
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
211d596fdd refactor(actions): switch to system QuaZip on Windows
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
f464b347b2 fix: install TLS plugins for release builds
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
203c3ec233 refactor(actions): speed up package installations for Windows
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
e2a74dfc30 feat(actions): enable Windows-i686 Qt 6 builds
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
4e99da7b62 refactor: query Qt variables using ECM
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
eb5ed50824 fix: set UNICODE and _UNICODE for Qt 5 builds
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
3b4539de79 chore: update license headers
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
3e4d1c04de fix: include TLS plugins in bundle
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
fdf5748029 feat(actions): use Qt 6 on macOS and AppImage
Co-authored-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
3562e94650 Revert "fix: ignore deprecation again"
We want to see deprecation warnings now

This reverts commit 47d0da2d96bc375410f5d494ac9371d47adf33d5.

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
15c5bbcf22 fix: fix slots for Qt 6
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
c363423718 refactor: fix deprecation up to Qt 6
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:15 +02:00
e58158c3cd feat: add Qt 6 support to CMake
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:19:14 +02:00
ff2cd50bfa refactor: replace QRegExp with QRegularExpression
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:17:52 +02:00
984692dc62 refactor: fix deprecation up to Qt 5.15
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-10 12:17:52 +02:00
a7fc23dd96 ATLauncher: Reset existing directory if required 2022-07-10 11:15:48 +01:00
c1bcbf8c63 Merge pull request #880 from Scrumplex/fix-loader-importance
Make loader components not important
2022-07-10 15:44:17 +05:30
9e69b8fe1b ATLauncher: Parse keeps and deletes from pack manifests 2022-07-10 11:05:11 +01:00
e0ae631d59 ATLauncher: Add modes to install task and display appropriate message
This will display the update/reinstall message for the installation
method currently in use..
2022-07-10 10:55:05 +01:00
3b187b5246 Merge pull request #876 from Scrumplex/revert-updater-stuff
Revert "fix: remove updater if it is not used"
2022-07-10 10:50:03 +02:00
20666763f0 Rewrite polymc.6 in scdoc, build, and install it
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
Signed-off-by: Tomasz Kramkowski <tomasz@kramkow.ski>
2022-07-09 23:25:09 +01:00
f591c87665 Merge pull request #851 from russellbanks/patch-1 2022-07-09 01:16:07 +02:00
e6fe701727 Merge pull request #808 from Scrumplex/fix-lgtm-warnings 2022-07-09 01:10:59 +02:00
35a698ef72 Merge pull request #884 from jopejoe1/ftbuifixed
Updated FTB Classic layout
2022-07-08 16:19:14 -03:00
998271414e Merge pull request #890 from Scrumplex/fix-technic-forge
Fix Technic instances using Forge
2022-07-08 16:18:59 -03:00
1749f25420 Merge pull request #881 from gytis-ivaskevicius/develop 2022-07-08 17:29:12 +02:00
4ab0e70a9a fix(technic): map loader libraries to components properly
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-08 17:28:06 +02:00
08989bde5e Merge pull request #839 from flowln/modrinth_packs_bug_hunt 2022-07-08 16:25:35 +02:00
87cbff391c fix: disable MSA login if it is NOT supported
Co-authored-by: flow <flowlnlnln@gmail.com>
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-08 16:25:03 +02:00
962923bbce chore: add missing license headers
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-08 16:25:03 +02:00
311b081e60 feat: add validation for Flame key and MSA client ID
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-08 16:25:03 +02:00
4103948132 feat: track capabilities of application
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-08 16:25:03 +02:00
906f26698b fix: spelling of CF
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-08 16:25:03 +02:00
8a1a583afe refactor: rename references to CurseForge to Flame
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-08 16:25:03 +02:00
9e19b73ce6 Updated FTB Classic layout
Signed-off-by: jopejoe1 <johannes@joens.email>
2022-07-07 23:18:13 +02:00
e11706d99d Cleanup flake.nix
Signed-off-by: Gytis Ivaskevicius <me@gytis.io>
2022-07-07 19:25:14 +03:00
301b811310 fix: make loader components not important
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-07 09:58:03 +02:00
273cf3d565 feat: lazy-load MinecraftInstance settings
Makes the startup go fast!

vrum

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-06 17:17:54 -03:00
f432cfd73a change: put settings initialization in a separate function
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-06 16:18:09 -03:00
ffa756ccee fix: remove tests for updater
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-06 18:13:51 +02:00
e210a4b244 Revert "fix: remove updater if it is not used"
This reverts commit 2ff0aa09e35eb6910ef0a030ea41f84a1ed95782.

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-06 18:13:51 +02:00
f1902a4471 Merge pull request #794 from Scrumplex/resolve-jars-dynamically 2022-07-06 17:40:09 +02:00
04b865adae Merge pull request #707 from Jan200101/PR/gamemode
Add Performance related settings
2022-07-06 17:11:43 +02:00
00df092a99 chore(readme): Reword and place entry in alphabetical order
Signed-off-by: txtsd <thexerothermicsclerodermoid@gmail.com>
2022-07-06 09:34:17 +02:00
cad581388f Add Performance related settings
Integrates support for Feral Gamemode, discrete GPU support for Mesa and the proprietary Nvidia driver and MangoHud support

Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
2022-07-06 09:34:14 +02:00
e7ed3abb79 Merge pull request #871 from Scrumplex/configure-dco 2022-07-03 18:16:25 +02:00
e5f6dc1b14 fix: aborts when using a Qt build with assertions enabled
Preventing undefined behaviour hooray! :D

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-03 12:44:19 -03:00
145da82cd8 fix: show invalid version even when there's none
Having a blank instead of _anything_ is bad UX. Instead, even when
there's not a valid version (most likely disabled redistribution), we
show a message in the UI, to differentiate from the loading state.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-03 12:43:05 -03:00
64776d6bac feat+fix: cache Flame modpack versions
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-03 12:43:05 -03:00
64d123f524 fix: use better naming for Modrinth pack versions
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-03 12:43:04 -03:00
0ec4ade683 feat+fix: cache versions and extra info in Modrinth packs
When you change a copy thinking you're changing the original data smh

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-03 12:43:04 -03:00
4bfc445cf8 fix: add progress indicator on Flame mod resolution dialog
This code is super :pofat: omg

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-03 12:43:04 -03:00
4232b1cedb fix: don't use uniform sizes in Modrinth modpack viewer
Apparently, when Qt sees an icon with the height smaller than the rest,
with this option set, it will change the height of all other items to be
that one, causing #828.

While we do lose some performance changing this option, the issue is
gone, so :|

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-03 12:43:00 -03:00
474d77ac57 feat: resolve JARs dynamically
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-03 17:31:01 +02:00
3c40355d7c chore(DCO): allow remediation
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-03 17:28:01 +02:00
cbc1aad58d fix: don't assume stable channel, if tag is unset
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-03 17:23:13 +02:00
89a30a47c5 fix: use semver format for build tag
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-03 17:23:13 +02:00
881a5603dc feat: hide channel if git tag is set
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-03 17:23:13 +02:00
68c48b2c8a feat: store git tag in buildconfig
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-03 17:23:13 +02:00
0f9260869b chore: update Git CMake module
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-03 17:23:13 +02:00
412fdb0f7b Merge pull request #870 from Scrumplex/fix-release-build
Fix release builds
2022-07-04 00:25:03 +10:00
81d52b6169 Merge pull request #869 from DarkKirb/nix-ecm
fix: Add extra-cmake-modules to the nix build
2022-07-03 11:07:11 -03:00
278d2169da fix: initialize accountIsOnline to fix build
CMAKE_BUILD_TYPE=Release makes the build fail otherwise.

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-07-03 14:32:31 +02:00
5599b5a337 Merge pull request #855 from Gingeh/account-list 2022-07-03 12:55:36 +02:00
471d6d6031 fix: Add extra-cmake-modules to the nix build
Signed-off-by: Charlotte 🦝 Delenk <lotte@chir.rs>
2022-07-03 10:30:45 +01:00
b90d6b0f26 Merge pull request #857 from Scrumplex/dco
Add Developer's Certificate of Origin (DCO)
2022-07-03 16:23:25 +10:00
cd22da9c62 Merge pull request #864 from ivanpu/uncensored-offline
Don't censor "offline" word when that's the access token
2022-07-02 17:56:04 -03:00
fb75c23f4e Merge pull request #784 from Scrumplex/refactor-cmake
Refactor tests
2022-07-02 17:50:08 -03:00
7f22994f68 Merge pull request #831 from flowln/abort_connections
Add missing connections to the abort signal in some tasks
2022-07-03 01:50:36 +10:00
7aba7b6064 Merge pull request #818 from flowln/tiny_mod_icons
Always scale mod icons to the right size
2022-07-03 01:49:09 +10:00
e32030f364 Merge pull request #860 from kthchew/fix/status-version
Show MC version of instance in status bar
2022-07-03 01:47:27 +10:00
b40619bcbd don't censor offline access token 2022-07-02 18:05:33 +03:00
fe2e1d931f Merge pull request #786 from flowln/concurrent_tasks_slimmed 2022-07-01 20:09:18 +02:00
2e17e78052 Merge pull request #845 from flowln/news_in_launcher 2022-07-01 20:04:06 +02:00
f2fa82fd3c Merge pull request #863 from Scrumplex/fix-braindead-moment
update NewLaunch package name
2022-07-01 19:55:01 +02:00
8cec4b60a6 fix: update NewLaunch package name 2022-07-01 19:50:41 +02:00
bf9888099c Merge pull request #800 from Scrumplex/refactor-newlaunch-package
Rename NewLaunch package
2022-07-01 10:05:07 -03:00
02201631e7 feat: use ConcurrentTask for mod downloads
Way faster :)

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-01 08:34:17 -03:00
8e80b4bfc1 feat: add ConcurrentTask
This tasks (or rather, meta-task) has the ability to run several other
sub tasks concurrently.

Signed-off-by: flow <flowlnlnln@gmail.com>
2022-07-01 08:34:10 -03:00
63dfc0633f Merge pull request #652 from flowln/mod_page 2022-07-01 10:00:36 +02:00
50f1847904 Merge pull request #785 from icelimetea/reformat-javacheck 2022-07-01 10:00:08 +02:00
79840f0fca Remove redundant type name from status bar
The type name is always "Minecraft", so it showed "Minecraft X.X.X (Minecraft)"
2022-06-30 23:02:56 -04:00
06bf7b0f31 Fix Minecraft version not appearing in status bar 2022-06-30 23:02:56 -04:00
dbb63b97bd Merge branch 'PolyMC:develop' into account-list 2022-07-01 10:43:41 +10:00
3039cb5c02 chore: add DCO requirement
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-06-30 16:37:13 +02:00
b5d2570fe2 Change Online status to Ready 2022-06-30 22:17:15 +10:00
5f951e8f21 change: better regex for removing 'The' when sorting mods
Teh :|

Co-authored-by: timoreo22 <timo.oreo34@gmail.com>
2022-06-30 07:04:47 -03:00
286f82cc99 Merge pull request #826 from kthchew/fix/kill-menubar 2022-06-30 11:50:43 +02:00
ed5415aeb8 Merge pull request #837 from DioEgizio/fix-sort-mr 2022-06-30 08:24:51 +02:00
bef79df6bb Disable the refresh button for offline accounts 2022-06-30 09:08:53 +10:00
2edabe0f99 Merge remote-tracking branch 'origin/account-list' into account-list
# Conflicts:
#	launcher/minecraft/auth/AccountData.cpp
2022-06-30 09:00:21 +10:00
91b5f0228d add tr() to offline account name
Co-authored-by: flow <flowlnlnln@gmail.com>
2022-06-30 08:59:41 +10:00
d639da741b add tr() to offline account name
Co-authored-by: flow <flowlnlnln@gmail.com>
2022-06-30 08:49:40 +10:00
84bd5ace6c Move account checkboxes to the profile column (oops) 2022-06-29 19:58:41 +10:00
63589d2ba9 Rename profile column to username and update the tooltip 2022-06-29 18:49:06 +10:00
d6f4ff26b5 Disable skin buttons for offline accounts 2022-06-29 18:46:39 +10:00
b606a2e040 Make the profile and account name columns use all available space 2022-06-29 18:45:36 +10:00
f685139d89 Move the profile name column to the left 2022-06-29 18:43:29 +10:00
68d6ce60a9 Don't show account name for offline accounts 2022-06-29 18:42:01 +10:00
2bba64fe3a Create winget.yml 2022-06-28 12:11:52 +01:00
774ed044fc Merge pull request #827 from kthchew/fix/menubar-separator
Workaround Qt bug to fix menu bar separators on macOS
2022-06-27 01:14:15 +10:00
9cc235cde0 Merge pull request #811 from jn64/fix/window-title
Fix duplicate name in window title
2022-06-27 01:13:58 +10:00
91375e4c6d Merge pull request #834 from DioEgizio/reword-flame-warning
chore(flame): reword warning
2022-06-27 01:12:18 +10:00
0ef8da64e0 Merge pull request #724 from Zetvue/patch-1
* Resize PolyMC logo

Co-authored-by: Tatsuya Noda <topia@clovery.jp>
2022-06-26 08:31:18 -03:00
9ef38171e2 fix: use clicked instead of pressed signal for button clicks
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-06-26 08:10:52 -03:00
455e4de6f3 feat: add news reader dialog
Makes it easier to read about new blog posts! Yay :D
2022-06-25 20:15:16 -03:00
4e319254dd fix: use right name for the content of a News entry 2022-06-25 20:14:27 -03:00
04e8780dd0 fix(modrinth): fix sorting 2022-06-24 10:47:02 +02:00
0fe4384067 Update launcher/ui/pages/modplatform/flame/FlamePage.ui
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-06-23 17:58:54 +02:00
bdfcd0b99e chore(flame): reword warning 2022-06-23 17:06:49 +02:00
5da87d1904 fix: add missing connections to the abort signal
Beginning with efa3fbff39bf0dabebdf1c6330090ee320895a4d, we separated
the failing and the aborting signals, as they can mean different
things in certain contexts. Still, some places are not yet changed to
reflect this modification. This can cause aborting of progress dialogs
to not work, instead making the application hang in an unusable satte.

This goes through some places where it's not hooked up yet, fixing their
behaviour in those kinds of situation.
2022-06-22 20:20:39 -03:00
821edf0f51 Merge pull request #830 from Scrumplex/fix-launchermeta
Replace old reference to launchermeta
2022-06-22 18:12:20 -03:00
04e822acfb fix: remove old reference to launchermeta 2022-06-22 20:47:47 +02:00
c31fce3621 Workaround Qt bug to fix menu bar separators on macOS 2022-06-22 00:34:04 -04:00
5c05cf2206 Disable launch actions in menu bar when last instance is deleted
This caused a crash when the action was selected!
2022-06-21 19:19:55 -04:00
d4e544c62c Separate the kill and launch instance actions 2022-06-21 19:19:55 -04:00
d232248268 Merge pull request #807 from Scrumplex/lgtm-config
Add LGTM config
2022-06-22 01:14:08 +10:00
90025ed45d Merge pull request #812 from jn64/fix/about-labels
Make version labels in About dialog selectable
2022-06-22 01:13:43 +10:00
964151d9c7 Merge pull request #817 from flowln/zip_ensure_path
Don't create unnecessary folders when extracting ZIPs
2022-06-22 01:13:23 +10:00
409c9bf9d2 Merge pull request #778 from Scrumplex/track-real-architecture
Track real CPU architecture for instances
2022-06-22 01:13:10 +10:00
a135c06bcf fix: scale mod icons to the right size 2022-06-21 06:41:56 -03:00
efb1f4abf2 Merge pull request #797 from kthchew/fix/update-shortcut 2022-06-21 11:29:15 +02:00
036a826b3a Merge pull request #788 from kthchew/fix/win-install-version 2022-06-21 11:29:06 +02:00
8d2b66a0fd Merge pull request #715 from Heath123/patch-1 2022-06-21 11:18:37 +02:00
31d6278b31 Merge pull request #729 from OldWorldOrdr/develop
Update bug_report.yml to use latest version as the version suggestion
2022-06-21 01:12:04 +10:00
5558d7eef8 Update bug_report.yml 2022-06-20 11:03:22 -04:00
6103d86a47 Merge branch 'PolyMC:develop' into develop 2022-06-20 11:02:40 -04:00
b8899a534d Merge pull request #633 from Scrumplex/chore-remove-unused-workflows
Remove unused GH Workflows
2022-06-20 11:42:53 -03:00
fa6829a6a1 Set beam cursor on selectable labels 2022-06-20 14:28:38 +08:00
5335540c33 Rename main window 2022-06-20 13:45:36 +08:00
7f62de3854 fix: don't create unnecessary folders when extracting ZIPs 2022-06-19 22:03:02 -03:00
0afa2e92d5 Make GitHub link focusable by keyboard 2022-06-18 22:20:38 +08:00
6d1b166ad7 Make labels selectable
User can copy version/build info easily.
2022-06-18 22:19:23 +08:00
4b6ddfb89b Add version to Qt applicationDisplayName 2022-06-18 20:00:28 +08:00
9ec260619b fix: fix warnings reported by LGTM.com 2022-06-17 16:34:32 +02:00
4c6ac9e4fe chore: add LGTM config 2022-06-17 16:24:06 +02:00
08fc3ea2e0 fix: add classpath exception to launcher library
Signed-off-by: icelimetea <fr3shtea@outlook.com>
2022-06-16 17:58:38 +02:00
03e454b71d Merge pull request #694 from Technous285/develop-1
Add OpenBSD support
2022-06-15 06:32:14 -03:00
c527ea83fb Merge pull request #799 from DioEgizio/fix-oopsie
fix websiteurl in cf modpacks (part 2)
2022-06-15 06:28:09 -03:00
8b9ac63657 chore: update COPYING.md 2022-06-15 10:15:35 +02:00
0ba02f0830 refactor: rename NewLaunch package 2022-06-15 10:05:35 +02:00
1f6cef6f8a fix https://github.com/PolyMC/PolyMC/issues/798 2022-06-15 09:11:23 +02:00
251942323e Deselect desktop shortcut by default
Follows the guidelines at https://docs.microsoft.com/en-us/windows/win32/uxguide/winenv-desktop
2022-06-15 00:46:34 -04:00
8e3efec40f Unselect shortcut installation by default if PolyMC is already installed
This is the same behavior as the `/NoShortcuts` switch.
2022-06-15 00:41:52 -04:00
3d0740f80e fix(cmake): allow disabling tests 2022-06-14 21:42:44 +02:00
707a68cb4f Merge pull request #787 from DioEgizio/macos-12-gha
update macos runner to macos 12
2022-06-14 23:30:41 +05:30
e6b1a1fa76 Merge pull request #716 from flowln/mod_perma_2
Hide index folder on Windows
2022-06-14 23:58:35 +10:00
3e8d450741 Merge pull request #665 from jamierocks/h-managed-packs
PackPlatforms: Record where packs come from
2022-06-14 23:54:44 +10:00
d0881b7420 Merge pull request #731 from Scrumplex/update-readme-macstadium
Add sponsors to README
2022-06-14 23:52:38 +10:00
27239b2dde Merge pull request #634 from flowln/donate_links
More links for CF / Modrinth mods / modpacks
2022-06-14 23:52:00 +10:00
3fbbaddece fix(actions): install extra-cmake-modules 2022-06-14 14:44:49 +02:00
effe46db86 refactor: move away from UnitTest.cmake 2022-06-14 14:44:49 +02:00
ba939c92ec feat(actions): test before packaging 2022-06-14 14:44:49 +02:00
e25cdd9d12 refector: move download action to ExternalResourcesPage 2022-06-14 07:04:31 -03:00
d394235ee0 refactor: Create a more clear hierarchy for some instance pages
Previously, the Shaders, Texture packs and Resource packs tabs had as
parent the ModFolderPage, making it so that making changes only to the
Mods page would require checking the id of the page for the correct one.
This was hackish and error-prone.

Now, those pages all inherit from a single class, ExternalResourcesPage,
that handles the basic behaviour of all of them, while allowing for
individual modification in code.

This is still not a clear separation, since internally, all those
resources are derived from Mods, so for now there's still some awkward
common code :/
2022-06-14 07:04:31 -03:00
349fc4143d Merge pull request #714 from Scrumplex/fix-tests
Fix mod metadata tests
2022-06-13 23:10:35 +02:00
4be9e6a0bc refactor: make is_indexed false by default
Co-authored-by: flow <flowlnlnln@gmail.com>
2022-06-13 22:07:42 +02:00
cb258146c4 Merge pull request #782 from Scrumplex/chore-bump-1.4.0 2022-06-13 22:05:40 +02:00
9f039cef72 Set correct installer properties and uninstall registry keys 2022-06-12 14:21:56 -04:00
d08815bbc1 Merge pull request #759 from flowln/mod_perma_3 2022-06-12 19:17:08 +02:00
c04e38d011 update macos runner to macos 12 2022-06-12 19:13:19 +02:00
794022d399 Merge pull request #783 from Scrumplex/fix-avoid-settings-register-warnings
Avoid re-registering InstanceType
2022-06-12 13:46:46 -03:00
8e43190984 Compile JavaCheck for Java 7 2022-06-12 17:46:40 +01:00
2212a6e40f Merge pull request #679 from kthchew/fix/win-install-version 2022-06-12 18:12:42 +02:00
63b69c0b0c Change formatting of JavaCheck 2022-06-12 16:29:39 +01:00
278219b1d8 fix(installer): use Windows version number format 2022-06-12 16:24:05 +02:00
2ce4ce9064 fix(installer): add version info to installer 2022-06-12 14:52:54 +02:00
4448418b63 fix: segfault when the same mod is present enabled and disabled at once
This maintains the previous behaviour
2022-06-12 09:44:03 -03:00
9f1f37e780 fix: correctly handle disabled mods with metadata
im stupid
2022-06-12 09:25:25 -03:00
40ccd1a469 fix: handling of incomplete mods
(i.e. mods without ModDetails that may have metadata)
2022-06-12 09:25:21 -03:00
a4ef0940ed chore: add license headers 2022-06-12 13:50:58 +02:00
2ff0aa09e3 fix: remove updater if it is not used 2022-06-12 13:39:47 +02:00
32217a774f fix(tests): wait until ModFolderModel has updated 2022-06-12 13:33:17 +02:00
8856c8cd62 refactor(test): fix loading mod metadata setting 2022-06-12 13:33:17 +02:00
e843b8e188 fix(test): fix packwiz test 2022-06-12 13:33:17 +02:00
c4f2e3a955 Merge pull request #771 from flowln/modrinth_multiple_downloads 2022-06-12 10:50:57 +02:00
91301ec7fe Merge pull request #632 from ryanccn/macos-app-heuristic 2022-06-12 10:46:49 +02:00
13b03e7e50 Update Application.cpp 2022-06-12 11:44:04 +08:00
8a0aa5a0c8 fix: avoid re-registering InstanceType 2022-06-11 23:06:42 +02:00
2bd8e7dca4 Merge pull request #780 from flowln/guo_ext_2 2022-06-11 19:45:51 +02:00
d75571ffa1 Merge pull request #773 from vancez/fix-launch-button 2022-06-11 19:41:02 +02:00
8683d529fc chore: bump version 2022-06-11 19:35:40 +02:00
2ee4b6768d Merge pull request #770 from flowln/technic_links 2022-06-11 19:34:59 +02:00
a9f0a85590 Merge pull request #764 from Scrumplex/fix-compile-flags 2022-06-11 19:34:01 +02:00
37160f973f fix: account for the dequeued url when checking the number of urls
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-06-11 14:31:50 -03:00
9bbf50e864 Merge pull request #720 from icelimetea/fix-legacy-issues 2022-06-11 19:29:59 +02:00
51258ab28c Merge pull request #709 from Scrumplex/fix-instancetypes
Always store InstanceType
2022-06-11 19:29:46 +02:00
29e5a213a5 fix: dequeue first added file in mrpack import
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-06-11 14:19:51 -03:00
2d261607df Merge pull request #732 from MrMelon54/develop 2022-06-11 19:14:26 +02:00
54144154f9 fix: apply client overrides in mrpacks
another oopsie x.x
2022-06-11 13:44:31 -03:00
81daffe68e fix: remove file filter from translation 2022-06-11 14:10:42 +02:00
2ea20a8b29 fix: allow discovering mrpacks in languages without dot 2022-06-11 07:12:59 -03:00
2257c875f5 Merge pull request #708 from ryanccn/custom-user-agent 2022-06-11 10:53:58 +02:00
8a2e8ad953 feat: track real CPU architecture for instances 2022-06-11 10:48:58 +02:00
fa5b1d9978 change slot name 2022-06-10 15:48:18 +08:00
529fb07b42 I changed my mind 2022-06-10 15:18:47 +08:00
4a261cac1a fix: update toolbar when instance state changes 2022-06-10 10:25:13 +08:00
b3c8f9d508 revert: don't check modrinth whitelisted hosts
people didn't seem to like it, and its not required
2022-06-09 19:57:51 -03:00
1b878030aa fix: enable using more than one download url in mrpacks
Kinda, it's ugly and hackish, since we don't have the facilities to
do this properly (yet!)
2022-06-09 19:54:50 -03:00
46e403b20b fix: properly parse mrpacks without the 'env' field
It's optional, so some files may not have it (like most of FO).
2022-06-09 19:53:29 -03:00
1b1f728c58 fix: allow opening external links in technic modpack page 2022-06-09 18:46:19 -03:00
309013efb3 Merge pull request #762 from muscaln/flake
Bump flake lock
2022-06-09 05:58:42 +05:30
705cf6499e Merge pull request #734 from babbaj/extra-jdks
nix: add package argument for extra jdks
2022-06-09 05:57:23 +05:30
f2ed4a92e2 Update README.md
Co-authored-by: Tatsuya Noda <topia@clovery.jp>
2022-06-08 15:55:28 -04:00
0c8ca1b3c0 fix: remove debug CXX flags 2022-06-08 21:04:27 +02:00
6ee5ee496e flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/41cc1d5d9584103be4108c1815c350e07c807036' (2022-05-23)
  → 'github:nixos/nixpkgs/43ecbe7840d155fa933ee8a500fb00dbbc651fc8' (2022-06-08)
2022-06-08 14:32:08 +03:00
7f8aa2099c Make it responsive 2022-06-07 18:58:02 -04:00
1d9797660b QString::locateAwareCompare() is better for human-like sorting 2022-06-07 15:27:57 +01:00
cd0d8a76c5 chore: add sponsors to README 2022-06-07 10:33:09 +02:00
3f1251e78b nix: add package argument for extra jdks 2022-06-06 22:13:10 -04:00
89d4405563 Simplify sorting logic to a single std::sort call 2022-06-06 22:18:19 +01:00
8966364648 Merge pull request #685 from kthchew/fix/technic-quilt
Add Quilt support for Technic modpacks
2022-06-06 18:03:05 -03:00
1c60e9b4fc Add initial sorting function 2022-06-06 21:51:08 +01:00
843c860d98 Update bug_report.yml 2022-06-06 13:52:50 -04:00
6587e39992 Resize PolyMC logo 2022-06-05 18:05:09 -04:00
757fa1410c Update launcher/Application.cpp
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-06-05 23:52:21 +08:00
dd6d8e0002 Make Launcher class to look more like original 2022-06-05 02:43:14 +01:00
cd49406bfe Fix launching process for some legacy Forge versions 2022-06-05 01:18:59 +01:00
7a3acc3249 refactor(ui): use tabs for APIPage 2022-06-04 22:04:36 +02:00
db1c804812 Merge pull request #718 from DioEgizio/revert-unfunny-pr 2022-06-04 21:49:15 +02:00
493d58f358 Merge pull request #719 from RaptaG/patch-1
Capitalization fix in the README
2022-06-04 16:16:15 -03:00
fcd56dddc2 Capitalization fix 2022-06-04 22:08:35 +03:00
91b85f9919 Revert "Merge pull request #315 from txtsd/display_scaling"
This reverts commit fcf728f3b5f4923cc05edfeb45f8340f420669cf.
2022-06-04 17:09:11 +02:00
4cecba8787 make $LAUNCHER_VER actually work 2022-06-04 22:59:57 +08:00
5930acc418 change UI to scroll
let me just say, this does not look right
2022-06-04 22:54:05 +08:00
61d36c1723 Clarify the forking policy a bit more 2022-06-04 15:20:49 +01:00
c2a43c6f40 fix: hide .index folder on Windows 2022-06-04 11:02:59 -03:00
1ab00ca8b2 Merge pull request #426 from flowln/mod_perma
Add on-disk mod metadata information
2022-06-04 13:23:38 +02:00
778baa6dbe fix: always store InstanceType 2022-06-04 11:59:12 +02:00
25ab121e42 feat: custom user-agent 2022-06-04 15:33:17 +08:00
cf4949b4f5 Prepare for Nix 2.7 (#286)
* Prepare for Nix 2.7

* Fix embarassing oopsie
2022-06-03 22:26:46 -03:00
4ca634d229 Merge pull request #701 from jn64/patch-1
Add "mc" keyword to desktop file
2022-06-03 09:30:36 +02:00
ca21b31696 Add "mc" keyword to desktop file
Certain launchers (e.g. GNOME) only search from word boundaries, so typing "mc" doesn't currently match to "PolyMC".
2022-06-03 09:58:57 +08:00
38ff76d2b8 Add OpenBSD support
Adds OpenBSD support.
2022-06-02 02:02:42 +10:00
147bde5294 Merge pull request #692 from glowiak/patch-6 2022-06-01 17:46:12 +02:00
1a004f0c4d Update MCEditTool.cpp 2022-06-01 15:50:43 +02:00
7d21bf15e8 Update UpdateController.cpp 2022-06-01 15:50:02 +02:00
a88ad8025b Merge pull request #682 from istudyatuni/fix-add-account-behaviour 2022-06-01 10:13:35 +02:00
e06bf17d13 Merge branch 'PolyMC:develop' into macos-app-heuristic 2022-06-01 00:12:14 +08:00
04a3669fc4 Merge pull request #687 from PolyMC/LennyMcLennington-patch-1
Change forking policy a bit
2022-05-31 08:22:33 +02:00
795075f90d Update README.md 2022-05-30 23:59:48 +01:00
2727df704f change the wording a bit 2022-05-30 23:52:12 +01:00
8ce8aadd9b fix typo 2022-05-30 23:50:35 +01:00
2999e69f0f Change forking policy a bit
Ask people forking PolyMC to make it clear that their fork is not endorsed by us.
2022-05-30 23:05:29 +01:00
7ac16ed073 Use QStringList instead of QSet<QString>
Co-authored-by: flow <flowlnlnln@gmail.com>
2022-05-30 14:40:20 -04:00
3585e4764b Add Quilt support for Technic modpacks 2022-05-30 14:14:03 -04:00
065e38c6aa Move Windows installer configure to program_info 2022-05-30 12:56:29 -04:00
9054ee18a1 Merge pull request #505 from flowln/improve_download_ux 2022-05-30 13:41:02 +02:00
9d8b95107d fix: do not show the "profile select" dialog if the user refused to add an account 2022-05-30 13:33:07 +03:00
8731c86d0d Use CMake for Windows installer branding
As a side effect, fixes an issue where the installer wrote the incorrect version to the registry.
2022-05-29 19:50:44 -04:00
d7fad4bd04 Merge pull request #677 from timoreo22/fix-modrinth-link
Fix modrinth search filters
2022-05-29 18:36:03 +02:00
2746251dcd Fix modrinth search filters 2022-05-29 18:23:34 +02:00
73e46e569f Merge pull request #662 from Scrumplex/chore-bump-1.3.1 2022-05-29 17:05:02 +02:00
4f0f74d201 Merge pull request #675 from muscaln/nix
Nix updates
2022-05-29 11:21:47 -03:00
adf1e1982a fix: remove unnecessary translation (#674) 2022-05-29 16:14:01 +02:00
f5405e835e Merge pull request #624 from ryanccn/global-jvm-args
Make global JVM arguments multi-line
2022-05-29 16:10:55 +02:00
85ee7fb3a4 Merge pull request #672 from Scrumplex/fix-ftblegacy-pack-version
fix: add version to Legacy FTB packs
2022-05-29 16:10:43 +02:00
ee00a5d8ee nix: make LTO optional 2022-05-29 17:07:12 +03:00
65d23fc9b9 Merge pull request #671 from Scrumplex/fix-importing-flame-mmc-packs 2022-05-29 15:15:18 +02:00
3448d7cb70 Merge pull request #659 from Scrumplex/fix-apikey-tos
Clarify terms and conditions for API keys
2022-05-29 18:44:32 +05:30
db1abb02d6 Merge pull request #661 from flowln/wow_curseforge_is_being_uncompetitive_im_so_surprised 2022-05-29 14:42:49 +02:00
36d78577e2 Merge pull request #669 from Scrumplex/fix-binary-version-windows
Set version for Windows binaries
2022-05-29 22:37:23 +10:00
20832682ef Update launcher/ui/pages/global/JavaPage.cpp
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-05-29 20:35:57 +08:00
8e6c592ad9 fix: add version to Legacy FTB packs 2022-05-29 14:28:54 +02:00
0b3115997a fix: fix importing Flame/MMC packs 2022-05-29 14:16:13 +02:00
b07c5982e1 fix: set version for Windows binaries 2022-05-29 13:09:13 +02:00
4a0b0d8735 Merge pull request #653 from muscaln/nix 2022-05-29 13:08:56 +02:00
7b9f67f4b4 Merge pull request #667 from DioEgizio/patch-7 2022-05-29 13:07:25 +02:00
577f17c916 remove vista support from the manifest
we don't support qt <5.12 anymore anyways
2022-05-29 09:45:20 +02:00
d4c1d62781 Update launcher/ui/pages/global/JavaPage.cpp
Co-authored-by: Kenneth Chew <79120643+kthchew@users.noreply.github.com>
2022-05-29 12:15:20 +08:00
80da1f1bb9 ATLauncher: Use ATLauncher rather than FTB in error messages 2022-05-29 00:04:28 +01:00
febdb85f96 ModpacksCH: Use ModpacksCH rather than FTB in error messages 2022-05-29 00:04:28 +01:00
96b76c8f5c ModpacksCH: Make packs managed when installing 2022-05-29 00:04:27 +01:00
411bf3be03 ATLauncher: Make packs managed when installing 2022-05-29 00:04:27 +01:00
a98b6663e1 ATLauncher: Pass the full pack name through to the install task 2022-05-29 00:04:27 +01:00
e7f35e6ca3 API: Add settings to support managed packs
Managed packs means an installation of a modpack through a modpack
provider. Managed packs track their origins (pack platform, name, id),
so that in future features can exist around this - such as updating, and
reinstalling.
2022-05-29 00:04:26 +01:00
f0ec165d42 feat: add warning of non-whitelisted URLs instead of a hard fail
Based on people's votes on Discord :^)
2022-05-28 18:04:16 -03:00
abd240468e clean up validateDownloadUrl 2022-05-28 17:11:55 -03:00
b5e00027d1 change: add 'gitlab.com' to whitelisted Modrinth modpack urls 2022-05-28 17:01:58 -03:00
1698554024 debug: add non-translated debug logging for 'non-whitelisted url' fails 2022-05-28 17:01:57 -03:00
f4604bbf79 change: update whitelisted hosts in Modrinth modpacks 2022-05-28 17:01:52 -03:00
699ad316f0 Rework curseforge download (#611)
* Use the bulk endpoint on mod resolution for faster download
* Search on modrinth for api blocked mods
* Display a dialog for manually downloading blocked mods
2022-05-28 21:53:12 +02:00
fcbe233fdb Merge pull request #651 from Scrumplex/fix-mnemonic-apipage
Fix mnemonics in APIPage
2022-05-28 15:46:38 +02:00
4af8a9ed2d Merge pull request #650 from flowln/modrinth_icons
Fix modpack icon importing with non-standard icon paths
2022-05-28 15:45:26 +02:00
80627b4f89 chore: bump version 2022-05-28 15:42:54 +02:00
83078cd49a Merge pull request #657 from JJL772/fix/misc-fixes
Fix crash when aborting instance import
2022-05-28 15:38:36 +02:00
53e0d13142 Merge pull request #625 from ryanccn/light-macos-icon
Use light background macOS icon
2022-05-28 15:36:26 +02:00
85901082a2 Merge pull request #639 from Scrumplex/fix-prio-modpack-formats
Prefer stricter modpack formats during import
2022-05-28 15:36:18 +02:00
f19e27e875 Merge pull request #629 from kthchew/feature/desktop-shortcut
Add desktop shortcut to Windows installer
2022-05-28 15:36:12 +02:00
c864046cee Merge pull request #623 from ryanccn/clang-format
Add a .clang-format
2022-05-28 15:36:01 +02:00
2d68235e55 Merge branch 'develop' into global-jvm-args 2022-05-28 21:15:19 +08:00
2be8100e7c Merge branch 'develop' into global-jvm-args 2022-05-28 21:15:00 +08:00
ab3e2562db fix: clarify terms and conditions for API keys 2022-05-28 13:52:22 +02:00
123d6c72e4 nix: fix nix-build 2022-05-28 11:32:16 +03:00
0ea2135aa5 nix: initial support for qt6 2022-05-28 11:32:13 +03:00
48e20cb5f7 Fix crash when aborting instance import
Also turned a loop var into a reference to avoid copies on each iteration
2022-05-27 16:41:57 -07:00
0ffe0b6894 nix: move files to nix/ 2022-05-27 22:56:42 +03:00
338156500b nix: override msa id via cmake flag 2022-05-27 22:56:42 +03:00
bfd9bd43c9 flake.lock: update
• Updated input 'flake-compat':
    'github:edolstra/flake-compat/64a525ee38886ab9028e6f61790de0832aa3ef03' (2022-03-25)
  → 'github:edolstra/flake-compat/b4a34015c698c7793d592d66adbab377907a2be8' (2022-04-19)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/30d3d79b7d3607d56546dd2a6b49e156ba0ec634' (2022-03-25)
  → 'github:nixos/nixpkgs/41cc1d5d9584103be4108c1815c350e07c807036' (2022-05-23)
• Removed input 'quazip'
2022-05-27 22:56:42 +03:00
283e50e670 nix: use nixpkgs's quazip 2022-05-27 22:56:40 +03:00
6fb5bb6a5e fix: fix mnemonics in APIPage 2022-05-27 14:50:06 +02:00
5d3bef32ca fix: use absolute path when installing icons 2022-05-27 09:15:32 -03:00
3ff26d5cfe Merge pull request #642 from ryanccn/metaserver-show-default
Show default metaserver in settings
2022-05-26 20:09:07 -03:00
88c1e504b0 Merge pull request #618 from DioEgizio/patch-6
fix appimage not having imageformats
2022-05-26 20:03:03 -03:00
0263677e1f fix: prefer stricter modpack formats during import
Flame modpacks use "manifest.json" as their only characteristic for
identification. Some modpacks might have other files called
"manifest.json", which is why we should prefer modpack formats that have
a stricter structure.
2022-05-26 22:41:20 +02:00
940455f81c Merge pull request #645 from PolyMC/revert-609-feature/fix-blocked-modpacks 2022-05-26 19:20:39 +02:00
f541ea659c better new icon 2022-05-26 18:16:32 +08:00
938cae1130 revert: remove CurseForge workaround for packs too
Partial revert. Handles missing download URLs.
2022-05-25 23:14:13 +02:00
7f73e57c67 Merge pull request #630 from jamierocks/h-atl-depends 2022-05-25 14:52:34 +02:00
e50ec31351 fix 2022-05-25 14:44:47 +08:00
a28fa219d7 fix indent width 2022-05-25 14:21:09 +08:00
8a1ba03bcb show default metaserver 2022-05-25 11:46:15 +08:00
f8e7fb3d48 fix: better handle corner case 2022-05-24 20:27:25 -03:00
e8b7e70ec9 Merge pull request #637 from byquanton/patch-1 2022-05-24 20:53:19 +02:00
67c5aa0be9 Update org.polymc.PolyMC.metainfo.xml.in
Should fix Flatpak/Flathub build
2022-05-24 17:44:23 +02:00
e644380160 feat: add links to curseforge modpacks 2022-05-24 12:27:32 -03:00
c5eb6fe6fb feat: add links for curseforge mods
NOT DOWNLOAD LINKS! (someone would ask it i'm sure :p)
2022-05-24 12:14:08 -03:00
ae2ef324f2 feat: add remaining links to modrinth mods 2022-05-24 11:58:11 -03:00
d0337da8ea feat: add remaining links to modrinth modpacks 2022-05-24 11:52:27 -03:00
17b30b2ae2 clean up .clang-format 2022-05-24 22:37:00 +08:00
5e17d53c7f fix: missing tr() and update donate message 2022-05-24 11:11:40 -03:00
22e0527502 feat: add donate info to modrinth modpacks 2022-05-24 09:46:58 -03:00
ca3c6c5e8a feat: add donate links for modrinth mods 2022-05-24 09:38:48 -03:00
4bd30f5e72 chore: remove unused GH Workflows 2022-05-24 14:17:44 +02:00
3cc26b15a1 Merge pull request #631 from kthchew/fix/quazip-warn 2022-05-24 10:25:04 +02:00
9673dac22b add more #ifdefs 2022-05-24 16:18:02 +08:00
0426149580 standard macOS app behavior 2022-05-24 13:35:01 +08:00
fce5c57548 Silence CMake QuaZip not found warnings
These are expected most of the time, and thus just noise.
2022-05-23 17:27:35 -04:00
4ee5264e24 ATLauncher: Delete files from configs if they conflict with a mod 2022-05-23 21:44:01 +01:00
101ca60b2b ATLauncher: Handle extra arguments depends 2022-05-23 20:57:15 +01:00
f28a0aa666 ATLauncher: Handle main class depends 2022-05-23 20:57:14 +01:00
997bf91442 Add desktop shortcut to Windows installer 2022-05-23 14:15:49 -04:00
5a1de15332 fix: use a more robust method of finding metadata indexes
Often times, mods can have their name in different forms, changing one
letter to caps or the other way (e.g. JourneyMaps -> Journeymaps).
This makes it possible to find those as well, which is not perfect by
any means, but should suffice for the majority of cases.
2022-05-23 14:58:15 -03:00
42f8ec5b14 fix: do modrinth changes on flame too
Also fix a dumb moment
2022-05-23 14:58:14 -03:00
2fc1b99911 chore: add license headers
Prevents a massive inload of Scrumplex ditto's :)

I didn't add it to every file modified in this PR because the other
changes are pretty minor, and would explode the diff of the PR. I hope
that's not a problem O_O
2022-05-23 14:58:14 -03:00
3a923060ce fix: use correct hash_type when creating metadata
also fix: wrong parameter name in LocalModUpdateTask's constructor
also fix: correct hash_format in CF
2022-05-23 14:58:14 -03:00
0985adfd74 change: support newest changes with packwiz regarding CF 2022-05-23 14:58:08 -03:00
59d628208b feat: allow trying to use multiple hash types 2022-05-23 14:43:31 -03:00
5c5699bba5 refactor: move individual pack version parsing to its own function 2022-05-23 14:43:31 -03:00
67e0214fa5 fix: don't try to delete mods multiple times
Shows a more helpful message if there's a parsing error when reading the
index file.

Also fixes a clazy warning with using the `.data()` method in a
temporary QByteArray object.
2022-05-23 14:43:10 -03:00
e17b6804a7 fix: implement PR suggestions
Some stylistic changes, and get hashes from the mod providers when
building the metadata.
2022-05-23 14:43:09 -03:00
96e36f0604 refactor: make mod metadata presence (or lack of) easier to find out 2022-05-23 14:43:09 -03:00
a99858c64d refactor: move code out of ModIndex.h
Now it's in ModIndex.cpp
2022-05-23 14:43:07 -03:00
ba50765c30 tidy: apply clang-tidy to some files
Mostly the ones created in this PR + Mod.h / Mod.cpp / ModDetails.h
2022-05-23 14:42:28 -03:00
d7f6b36990 test+fix: add basic tests and fix issues with it 2022-05-23 14:42:28 -03:00
4439666e67 feat: allow disabling mod metadata usage 2022-05-23 14:42:28 -03:00
23febc6d94 feat: cache metadata in ModDetails
Allows for more easy access to the metadata by outside entities
2022-05-23 14:42:28 -03:00
fab4a7a602 refactor: abstract metadata handling and clarify names 2022-05-23 14:42:28 -03:00
092d2f8917 feat: add support for converting builtin -> packwiz mod formats
Also adds more documentation.
2022-05-23 14:42:28 -03:00
e9fb566c07 refactor: remove unused mod info and organize some stuff 2022-05-23 14:42:27 -03:00
5a34e8fd7c refactor: move mod tasks to their own subfolder
Makes the launcher/minecraft/mod/ folder a little more organized.
2022-05-23 14:42:27 -03:00
fcfb2cfc3d feat: use mod metadata for getting mod information
For now this doesn't mean much, but it will help when we need data
exclusive from the metadata, such as addon id and mod provider.

Also removes the metadata when the mod is deleted, and make the Mod.h
file a little more pleasing to look at :)
2022-05-23 14:42:27 -03:00
e93b9560b5 feat: add method to delete mod metadata
Also moves indexDir setting from LocalModUpdateTask -> ModFolderModel
2022-05-23 14:42:27 -03:00
8e4438b375 feat: add parser for current impl of packwiz mod.toml
This reads a local mod.toml file and extract information from it. Using
C libs in C++ is kind of a pain tho :(
2022-05-23 14:42:27 -03:00
eaa5ce4467 feat(ui): adapt SequentialTask to nested SequentialTasks 2022-05-23 14:42:27 -03:00
c86c719e1a feat: add mod index updating to ModDownloadTask
This makes ModDownloadTask into a SequentialTask with 2 subtasks:
Downloading the mod files and updating the index with the new
information.

The index updating is done first so that, in the future, we
can prompt the user before download if, for instance, we discover
there's another version already installed.
2022-05-23 14:42:27 -03:00
b30b88716e feat: add very early mod.toml packwiz support
Also use it as a on-disk format for storing mod metadata. This will be
used later on to make better mod managment.
2022-05-23 14:42:22 -03:00
c3e6b1aa8a use light bigsur icon 2022-05-23 18:40:46 +08:00
6d0ea13f97 make JVM args PlainTextEdit 2022-05-23 16:52:12 +08:00
dca4ea5cea Merge pull request #621 from Scrumplex/remove-curseforge-workarounds 2022-05-23 10:47:30 +02:00
be1e2c07ec Merge pull request #622 from Scrumplex/chore-bump-1.3.0
Bump version to 1.3.0
2022-05-23 08:44:56 +05:30
2a0018e730 add a .clang-format 2022-05-23 08:29:30 +08:00
ac4497a1f2 Merge pull request #605 from jamierocks/h-atl-improv
ATLauncher: Various work to improve the platform support
2022-05-22 20:09:13 -03:00
d72c75db23 chore: bump version 2022-05-22 22:56:52 +02:00
6821a45b7f Merge pull request #620 from Scrumplex/update-cxxflags 2022-05-22 22:55:04 +02:00
f24cdd6564 Merge pull request #425 from dada513/dynamic_meta 2022-05-22 22:47:00 +02:00
cb69869836 revert: remove CurseForge workaround
We have been asked by CurseForge to remove this workaround as it
violates their terms of service. This is just a partial revert, as the
UI changes were otherwise unrelated.

This reverts commit 92e8aaf36f72b7527322add169b253d0698939d0, reversing
changes made to 88a93945d4c9a11bf53016133335d359b819585e.
2022-05-22 22:07:03 +02:00
0b85051a23 fix: more generous optimizations for debug builds 2022-05-22 21:41:41 +02:00
f2e2053134 feat: add trailing slash to meta URL if it is missing 2022-05-22 21:36:31 +02:00
b181f4bc30 fix: improve spacing in APIPage 2022-05-22 21:36:30 +02:00
f00dbdc215 Make Metaserver changable in settings
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
Co-authored-by: flow <flowlnlnln@gmail.com>
2022-05-22 21:35:20 +02:00
309dcc82ca Revert "fix: temporarily ignore stringop-overflow warning"
This reverts commit 90007e2d9d4f63cfc9dc73888af34a17657b5102.
2022-05-22 20:57:52 +02:00
0922a7f410 refactor: use -O2 for release and -O1 for debug builds 2022-05-22 20:50:37 +02:00
7d91db607f Merge pull request #554 from PolyMC/more_paste_services 2022-05-22 20:49:11 +02:00
2be583ad4d Merge branch 'PolyMC:develop' into patch-6 2022-05-22 20:03:10 +02:00
efcba698ac Merge pull request #616 from Scrumplex/fix-windows-crap
fix: temporarily ignore stringop-overflow warning
2022-05-22 18:43:31 +02:00
b191291737 Merge pull request #577 from PolyMC/fix/toolbar_🦀_fix 2022-05-22 18:11:00 +02:00
c988b4d213 fix appimage not having imageformats
fixes stuff like the iris icon
2022-05-22 17:26:27 +02:00
90007e2d9d fix: temporarily ignore stringop-overflow warning 2022-05-22 16:13:30 +02:00
29ef1e2c4b Merge pull request #597 from Scrumplex/refactor-modloader-modapi 2022-05-22 13:17:53 +02:00
fbe84f9e47 Merge pull request #614 from txtsd/ccache_release_fix
Avoid invoking ccache on Release builds
2022-05-22 16:16:14 +05:30
b036d95bab Merge pull request #576 from kthchew/feature/win-installer
Create Windows installer
2022-05-22 12:26:43 +02:00
bfffcb3910 fix(workflow): Avoid invoking ccache on Release builds 2022-05-22 13:42:33 +05:30
3bc02b9662 Fix Sparkle signing step 2022-05-21 13:23:02 -04:00
bc450e4cee Merge pull request #612 from DioEgizio/update-cf-logo-real
change cf icon to a more fancy one
2022-05-21 09:53:31 -07:00
de02deac98 Make if statement condition more readable
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-05-21 17:30:54 +01:00
e2ad3b0183 Add migration wizard, fix migration from custom paste instance
- Very basic wizard just to allow the user to choose whether to keep
  their old paste settings or use the new default settings.

- People who used custom 0x0 instances would just be kept on those
  settings and won't see the wizard.
2022-05-21 17:30:19 +01:00
caf6d02728 Change paste settings and add copyright headers
- There's now a notice reminding people to change the base URL if they
  had a custom base URL and change the paste type (that was something I
  personally had problems with when I was testing, so a reminder was
  helpful for me).

- Broke down some of the long lines on APIPage.cpp to be more readable.

- Added copyright headers where they were missing.

- Changed the paste service display names to the names they are more
  commonly known by.

- Changed the default hastebin base URL to https://hst.sh due to the
  acquisition of https://hastebin.com by Toptal.
2022-05-21 17:30:09 +01:00
35f71f5793 Support paste.gg, hastebin, and mclo.gs 2022-05-21 17:28:22 +01:00
b2a89ee4b9 change cf icon to a more fancy one
taken from QuiltMC/art in the emoji folder, so it's licensed under CC0
2022-05-21 17:49:52 +02:00
b84d52be3d ATLauncher: Display warnings when selecting optional mods 2022-05-21 15:20:38 +01:00
305973c0e7 ATLauncher: Display install messages if applicable 2022-05-21 15:19:55 +01:00
7c251efc47 ATLauncher: Display mod colours in optional mod dialog 2022-05-21 15:18:50 +01:00
166f872712 fix: various issues with ProgressDialog and SequentialTasks
- Fix aborting sequential tasks
- Fix displaying wrong number of tasks concluded
- Fix text cutting when the URL is too big
2022-05-21 08:36:36 -03:00
8f2c485c92 feat(ui): make selected mods in downloader bold with underline
Makes it easier to find which mods are selected in case you want to
change those.
2022-05-21 08:04:26 -03:00
613f2fc447 feat: allow deselecting mods from the mod confirmation dialog
This adds a checkbox to each mod on the dialog that shows up when
confirming the mods to download, so you can deselect some of those if
you want to.
2022-05-21 08:02:27 -03:00
9a0d6124f3 Merge pull request #609 from timoreo22/feature/fix-blocked-modpacks 2022-05-21 12:22:45 +02:00
2646ae29f0 Merge pull request #520 from icelimetea/refactor-java-launcher-v2 2022-05-21 12:06:45 +02:00
b4707f46ad Merge pull request #500 from flowln/net_refactor
Refactor a little the code in `launcher/net/` files
2022-05-21 12:06:34 +02:00
482e049ac7 Merge pull request #606 from jamierocks/h-launch-version 2022-05-21 11:43:19 +02:00
c04adf7452 Do the url trick on initial modpack download too 2022-05-21 08:31:07 +02:00
92e8aaf36f Merge pull request #608 from timoreo22/feature/curseforge-fix
Very Temporary Fix for curseforge
2022-05-21 06:34:43 +02:00
b1f486518e Use GitHub Actions to get signature for Sparkle
Requires a secret called `SPARKLE_ED25519_KEY`, in the format of a private key file
2022-05-21 00:32:14 -04:00
3cab0e69f1 Fix default install location 2022-05-20 17:23:11 -04:00
1ec7878c07 Add /NoShortcuts parameter for Windows installer 2022-05-20 17:22:30 -04:00
cdd83c279c Remove portable option in Windows installer 2022-05-20 17:12:08 -04:00
12cadf3af0 Add /NoUninstaller parameter for Windows installer 2022-05-20 17:09:42 -04:00
2bc6da038d Add installer to release workflow 2022-05-20 17:09:26 -04:00
3b4b34b369 fix(ui): make CF and MR modpack dialogs more consistent 2022-05-20 22:48:42 +02:00
6542f5f15a Apply suggestions 2022-05-20 22:06:36 +02:00
30b56dbcbd Port temp fix to mods too 2022-05-20 22:00:38 +02:00
cbc8c1aed6 Use consistent naming scheme
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-05-20 15:56:13 -04:00
6afe59e76b Very Temporary Fix for curseforge 2022-05-20 21:19:19 +02:00
88a93945d4 Merge pull request #607 from dada513/curse_set 2022-05-20 20:41:42 +02:00
2847cefff7 Add cursefrog key override 2022-05-20 19:56:27 +02:00
96f16069a9 Launch: Apply the Minecraft version correctly
It was previously using a deprecated field.
2022-05-20 18:47:11 +01:00
188c5aaa35 Launch: Match Vanilla launcher version string behaviour
This removes a means of profiling users.
2022-05-20 18:43:47 +01:00
f5f59203a2 ATLauncher: Reduce boilerplate code for fetching versions 2022-05-20 18:05:58 +01:00
c329730de8 ATLauncher: Install LiteLoader as a component where possible 2022-05-20 18:03:32 +01:00
97a83c9b7a ATLauncher: Avoid downloading Forge twice for older packs
This resolves a quirk where Forge would still be downloaded for use as
a jarmod, even when we detected Forge as a component.
2022-05-20 17:58:00 +01:00
1e6df7eec0 Merge pull request #592 from flowln/technic
Use empty string when version is null in the Technic pack manifest
2022-05-20 10:56:42 +02:00
f3c72f4f08 Actually install the full Sparkle.framework
CMake's `fixup_bundle` did not copy everything in the framework, which caused the app to crash when updating. Oops.
2022-05-19 20:22:45 -04:00
05cd30ac06 Refactor code, create abstract class ExternalUpdater
(Hopefully) this makes implementing updaters using external libraries easier on other platforms. To implement an updater on a new platform, create a new class that implements the pure virtual methods from `ExternalUpdater` and add code in the `UpdateChecker` initializer to initialize the new class.
2022-05-19 15:16:37 -04:00
34adcec616 Add functionality to (Sparkle) updater settings on macOS
Also remove a debug line I accidentally left in
2022-05-19 15:16:37 -04:00
f9f46609ee Use my public key and appcast URL for testing purposes
This is for testing the PR only. If merged, this must be removed.
2022-05-19 15:16:37 -04:00
b5bdfa6c2e Implement automatic and manual updates on macOS 2022-05-19 15:16:37 -04:00
ea4ef1655b Create SparkleUpdater class for access from Qt/C++
To actually get automatic updates going, all that needs to happen is that `SparkleUpdater` needs to be initialized.

The rest of the functions can be connected to elements in the UI.
2022-05-19 15:16:37 -04:00
7eb61a28be Add build options for Sparkle updater
Two new build options are added:

`MAC_SPARKLE_PUB_KEY`: the public key used to verify the signatures of the appcast
`MAC_SPARKLE_APPCAST_URL`: the URL where the `appcast.xml` is located

If the updater should be disabled on macOS, set either of these to an empty string.
2022-05-19 15:16:37 -04:00
92b913ca37 Add Sparkle Updater framework to macOS build 2022-05-19 15:16:37 -04:00
3806f23b02 Merge pull request #594 from Scrumplex/fix-support-split-natives
Support Mojang's new split natives
2022-05-19 17:42:17 +02:00
36045a8b0a chore: improve readability
Co-authored-by: flow <thiagodonato300@gmail.com>
2022-05-19 12:37:20 +02:00
943090db98 refactor: allow tracking multiple mod loaders 2022-05-19 08:49:27 +02:00
77caaca50d fix: only consider enabled mod loaders 2022-05-19 08:09:37 +02:00
f66e0fa0e8 fix: support split natives
Mojang introduced a new structure for natives, notably for LWJGL.
Now instead of using the `natives` structure of the version format, Mojang
chose to create a seperate library entry for each platform, which uses
the `rules` structure to specify the platform. These new split natives
carry the same groupId and artifactId, as the main library, but have an
additional classifier, like `natives-linux`.

When comparing GradleSpecifiers we don't look at the classifier, so when
the launcher sees an artifact called `org.lwjgl:lwjgl:3.3.1` and right
after that an artifact called `org.lwjgl:lwjgl:3.3.1:natives-linux`, it
will treat it as "already added" and forget it.

This change will include the classifier in that comparison.
2022-05-18 22:51:15 +02:00
441075f610 fix: version field in technic pack manifest being null
Sometimes, the version field, that is supposed to be a string, was a
null instead. Inspecting other entries, seems like the default for not
having a version should be "", so I made it like that in case the
version was null.

I hope this fixes the issue :^)
2022-05-18 17:17:16 -03:00
b2878dca1d Merge pull request #590 from DioEgizio/fix-qmj-over-fmj
fix(quilt) always prefer qmj over fmj
2022-05-18 19:18:18 +02:00
b883ce5c51 Merge pull request #127 from Scrumplex/refactor-bump-qt5.12 2022-05-18 15:47:17 +02:00
127dfadc6c fix(quilt) always prefer qmj over fmj
this fixes Quilt-only mods like ok zoomer showing wrong metadata
2022-05-18 14:33:58 +02:00
ff9f3cb31f fix conflicts with develop 2022-05-17 18:25:08 -03:00
a21bd41580 fix: ignore deprecation again 2022-05-17 22:25:50 +02:00
8e9f1bcf18 fix: remove unnecessary Qt version checks 2022-05-17 22:25:50 +02:00
4b06fc5323 chore!: drop support for Qt <5.12
BREAKING CHANGE: If there are references to stuff that's deprecated as
of Qt 5.12, the compilation will fail. This means that support for
versions below 5.12 is hereby dropped
2022-05-17 22:25:50 +02:00
cc27bb3231 fix(updater): remove Windows version check
Qt 5.12 doesn't support anything older than Windows 7 anyway, so we
can't really check if we are on an older platform.
2022-05-17 22:25:50 +02:00
c1700054f4 fix: replace deprecated stuff as of Qt 5.12 2022-05-17 22:25:50 +02:00
cc13310083 Merge pull request #565 from Scrumplex/modrinth-packs
Initial Modrinth modpack support
2022-05-17 16:09:22 +02:00
1012912272 Merge pull request #567 from Scrumplex/quilt-metadata
Support `quilt.mod.json` metadata
2022-05-17 16:08:59 +02:00
edbd90a4e6 fix: update links for Quilt metadata format 2022-05-17 15:17:20 +02:00
ddc3b5eb0b Update launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
Co-authored-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2022-05-17 15:14:53 +02:00
17bbfe8d89 fix: virtual signal in Task.h 2022-05-17 06:47:00 -03:00
96deb5b09d chore: remove copyright from files i didnt mess with
This is what happens when you auto-pilot stuff xdd
2022-05-17 06:36:30 -03:00
9b387d73e5 Merge pull request #529 from flowln/vertical_toolbar
Set right orientation for instance toolbar when moving it around
2022-05-17 12:14:34 +05:30
c02a6780b0 Merge pull request #540 from kthchew/fix/executable-screenshot
Show "executable" screenshots in the screenshot manager
2022-05-17 10:59:55 +05:30
85ec9d95a4 Support installer languages other than English 2022-05-16 19:28:04 -04:00
6dfec4db40 Fix toolbar disappearing in a certain circumstance. 2022-05-17 00:21:57 +01:00
2e9d7f5c3d fix: mod skipping between pages and remove dead code 2022-05-16 19:17:37 -03:00
696a711e39 fix: missed change to metacache entry lookup 2022-05-16 19:10:31 -03:00
887246a66b fix: typo and useless code 2022-05-16 17:09:14 -03:00
2993318d19 Remove admin requirement (no multi-user install option) 2022-05-16 15:29:37 -04:00
2b52cf01f5 Build Windows installer 2022-05-16 15:23:32 -04:00
cd9e0e0cc0 fix: use own metacache base for modrinth icons 2022-05-16 20:17:19 +02:00
f66598db8a Merge pull request #564 from flowln/cf_icon 2022-05-16 20:06:59 +02:00
cf5c752dda Merge pull request #568 from kthchew/fix/mac-steam-overlay 2022-05-16 20:06:34 +02:00
a6d2c5e181 fix: better hack for icons that cant be natively scaled to 48x48 2022-05-16 14:35:01 -03:00
82760f4b91 fix: import modrinth packs with weird overrides structure
Probably because of Packwiz limitations, or an space optimizer that did
this :)
2022-05-16 12:11:50 -03:00
62e099ace5 feat: better handling of optional mods
This disables the optional mods by default and tell the user about it.
Pretty hackish, but a better solution would involve the modrinth
metadata to have the mod names...

Also sorry for the diffs, my clangd went rogue x.x
2022-05-15 22:16:52 -03:00
e92b7bd25e change: switch to modrinth production servers 2022-05-15 21:50:42 -03:00
e7bb3b2776 fix: macos compilation
i forgor macos is cringe with static arrays 💀

edit: WHY DONT MAC LET ME USE STD::ARRAY ;----;
2022-05-15 21:18:29 -03:00
ec3c882a44 change: add alpha note to modrinth page 2022-05-15 20:52:57 -03:00
66ce5a4a2d fix: pack sorting and other search parameters 2022-05-15 20:45:27 -03:00
a110d445ac feat: support quilt.mod.json metadata 2022-05-15 23:00:09 +02:00
a67f3131e7 Merge pull request #560 from kthchew/feature/close-pmc-override
Add instance overrides for miscellaneous settings
2022-05-15 17:40:53 -03:00
7f305aad1b Add Allow DYLD Environment Variables Entitlement to macOS build
This allows the Steam overlay to be injected into Minecraft.
2022-05-15 16:34:53 -04:00
80908efdcb Fix indentation of macOS resources 2022-05-15 16:33:52 -04:00
e5d0097116 Merge pull request #531 from Ozynt/patch-1
Remove reference to legacy Minecraft accounts
2022-05-15 22:18:34 +02:00
6d78ea5a45 Merge pull request #539 from kthchew/fix/translation-switch
Fix untranslated strings after changing language
2022-05-15 17:11:21 -03:00
550d6a6a9b Merge pull request #547 from kthchew/feature/hidden-temp 2022-05-15 21:54:46 +02:00
9be8160bf2 Merge pull request #546 from kthchew/feature/scrollable-accounts 2022-05-15 21:43:34 +02:00
3070565fa3 Merge pull request #545 from DioEgizio/patch-4 2022-05-15 21:42:51 +02:00
7194bb1b81 fix: validate whitelisted download urls 2022-05-15 16:06:49 -03:00
78cf0c73c8 fix: always show project url, if available 2022-05-15 20:38:27 +02:00
4adc61bda9 change: update modrinth icon
Updates to the version at https://github.com/modrinth/docs/blob/master/static/img/logo.svg
2022-05-15 11:26:15 -03:00
93e0041d0e change: use modrinth icon as default on modrinth packs 2022-05-15 11:09:45 -03:00
682a7fb6ba feat: add version of Modrinth modpack to instance name 2022-05-15 13:36:55 +02:00
5f2398fe59 chore: license headers 2 2022-05-15 08:26:34 -03:00
3abf466632 chore: add/update license headers 2022-05-15 13:20:05 +02:00
4bb429a0fb change: use build variables for the modrinth API URLs
Make it more consistent with the others
2022-05-15 07:43:02 -03:00
4a0e4fdb85 fix: add author page url 2022-05-15 07:15:56 -03:00
a43f882d48 feat: add support for Quilt Loader in Modrinth packs 2022-05-15 12:06:01 +02:00
9731e06728 fix: fix build on Qt 5.12 2022-05-15 11:49:27 +02:00
8e764fc8fb Merge pull request #4 from flowln/modrinth_pack 2022-05-15 11:48:09 +02:00
4745ed2818 fix: choose valid download url even if it's not the primary one
It seems to be possible to have modpack versions that have to primary
file. In those cases, we pick a valid one "at random".
2022-05-14 22:50:04 -03:00
49de5d9b07 change: list what file types can be entered in the importer 2022-05-14 22:04:40 -03:00
365cc198ba refactor: some random improvements 2022-05-14 21:50:54 -03:00
9899a0e098 fix: Have the URL be the project URL itself
(I think, doesn't seem to work for the waffle though, probably because
of the staging API :/)
2022-05-14 21:47:35 -03:00
5ea8cec16f fix: make all modrinth modpacks have the same icon size 2022-05-14 21:29:48 -03:00
9dd70ca9ae fix: download icon as well when importing modrinth modpacks 2022-05-14 20:26:20 -03:00
4fda35b466 feat: add modrinth pack downloading
Things that don't work / work poorly (there's more for sure but those
are the evident ones):
    - Icons are broken in the import dialog
    - No way to search for private packs
    - Icons are not downloaded when downloading a mod
    - No support for multiple download URLs
    - Probably a lot more...
2022-05-14 20:19:26 -03:00
31988f0529 fix: adapt upstream Modrinth code to our codebase 2022-05-14 20:27:45 +02:00
db03846358 Add support for importing Modrinth packs from files 2022-05-14 20:01:09 +02:00
c6b3eccbdf refactor: rename Modrinth classes to ModrinthMod 2022-05-14 20:00:54 +02:00
3f259eb97a Refactor script parsing 2022-05-14 16:48:14 +01:00
fac0b027b3 Fix the license header 2022-05-14 16:46:57 +01:00
84b962f256 fix: Handle icons with a dot in their names
E.g. some FTB modpacks.
Also fixes an issue with the name viewing on the Icon Chooser dialog
when the name was too big.
2022-05-13 17:21:35 -03:00
123ed5bd2e Merge pull request #519 from Scrumplex/cleanup-cmake
Remove in-tree CMake modules where possible
2022-05-13 22:05:04 +02:00
c3336251e0 Add the license header to EntryPoint 2022-05-13 18:10:11 +01:00
c054d0f329 Add the license header to LauncherFactory 2022-05-13 17:21:35 +01:00
8dd68580a6 Merge pull request #528 from flowln/guo_ext 2022-05-13 18:17:40 +02:00
067484a6a8 Fix formatting 2022-05-13 16:59:00 +01:00
c83e16aba4 Merge pull request #553 from DioEgizio/add-version-PolyMC
chore: add version of polymc area in bug report template
2022-05-13 14:42:26 +02:00
d85fc456a9 Merge pull request #557 from PolyMC/ZekeSmith-cf-api 2022-05-13 13:36:36 +02:00
dd2b324d8f chore: add license header to remaining files
Also remove some unused imports
2022-05-12 18:11:55 -03:00
0bce08d30f chore: add polymc license headers to launcher/net files 2022-05-12 18:11:55 -03:00
57d65177c8 fix: abort and fail logic in tasks
Also sets up correctly the status connections
2022-05-12 18:11:55 -03:00
040ee919e5 refactor: more net cleanup
This runs clang-tidy on some other files in launcher/net/.

This also makes use of some JSON wrappers in HttpMetaCache, instead of
using the Qt stuff directly.

Lastly, this removes useless null checks (crashes don't occur because of
this, but because of concurrent usage / free of the QByteArray pointer),
and fix a fixme in Download.h
2022-05-12 18:11:55 -03:00
efa3fbff39 refactor: remove some superfluous signals
Since now we're inheriting from Task, some signals can be reused.
2022-05-12 18:11:55 -03:00
8c8eabf7ac refactor: organize a little more the code in launcher/net/
This also reduces some code duplication by using some Task logic in
NetAction.
2022-05-12 18:11:49 -03:00
3aea639fe4 Add UI for miscellaneous instance setting overrides 2022-05-12 17:11:06 -04:00
046f1e6e58 Add instance overrides for miscellaneous settings 2022-05-12 17:08:06 -04:00
37e8f495b4 CurseForge API Key update to PolyMC key
Use the key CurseForge provided me to use for PolyMC

*pr done on mobile if someone could test that would be great*
2022-05-12 23:39:48 +10:00
512d7b07d0 chore: add version of polymc area in bug report template 2022-05-11 15:18:07 +02:00
527fa7ba9c Hide temporary directory in instances folder 2022-05-09 18:34:47 -04:00
288e7bc9c5 Make profile menu scrollable 2022-05-09 15:37:56 -04:00
649b8ac7c6 Merge pull request #537 from PolyMC/stable
Merge stable into develop
2022-05-09 18:06:56 +02:00
96b2758169 fix websiteurl in curseforge modpacks 2022-05-09 17:42:17 +02:00
40e0252d7d Show "executable" screenshots in the screenshot manager
Since the readable/writable filter was removed to do this, extra code was added to enable/disable certain buttons based on whether the screenshot is readable or writable.
2022-05-09 00:54:47 -04:00
5171d99fe5 Retranslate playtime text immediately when language is changed 2022-05-08 23:42:37 -04:00
ea9d61c21c Retranslate account actions after switching language 2022-05-08 23:19:23 -04:00
bdd2d57808 This makes more sense 2022-05-08 11:19:53 +02:00
29a53d7e95 fix: always have the instance toolbar be vertical
This overrides the orientation set automatically by Qt when we start
moving the toolbar around.
2022-05-07 20:44:44 -03:00
2fbb7be23b fix: filter based on MIME type instead of plaintext suffix
Suffixes are unreliable in different locales, while MIME types are more
standarized.
2022-05-07 20:16:55 -03:00
f7f39854f8 Merge pull request #495 from ryanccn/big-sur-icon 2022-05-05 14:29:04 +02:00
113528e1f2 Make line count check more lenient 2022-05-05 07:20:33 +01:00
6bffa06063 Fix typo 2022-05-05 07:16:16 +01:00
dcc41ef885 Improve mpticket file parsing code 2022-05-05 07:14:32 +01:00
e909cc363d add big sur-style icon 2022-05-05 08:10:36 +08:00
9a87ae575e More minor fixes 2022-05-03 03:19:26 +01:00
860a7af679 Fix method access modifier 2022-05-03 00:53:22 +01:00
4fdb21b414 Compile with Java 7 in mind 2022-05-03 00:27:14 +01:00
eeb5297284 Use only Java 7 features (in order to deal with #515) 2022-05-03 00:25:26 +01:00
8de63b60b1 Refactor some parts of NewLaunch (part 2) 2022-05-02 22:36:55 +01:00
0b38d878a1 fix: remove in-tree CMake modules where possible 2022-05-02 16:27:15 +02:00
d29720fbce Merge pull request #518 from timoreo22/develop
Fix nightly.link pr comment
2022-05-02 12:23:00 +02:00
0556ae4749 Merge pull request #503 from txtsd/mnemonics_fix
Fix mnemonics that didn't parse
2022-05-02 11:19:30 +02:00
1a86f72690 Fix nightly.link pr comment 2022-05-02 11:13:46 +02:00
25d380f051 Merge pull request #510 from txtsd/ccache_gha
CI Speedup [1/3]: Use ccache to speed up CI builds
2022-05-02 10:47:28 +02:00
546d394868 Merge pull request #475 from Scrumplex/fix-hide-all-tokens
Hide all tokens for non-Debug builds for log and logfiles
2022-05-02 10:45:58 +02:00
8110040f86 Merge pull request #511 from dada513/hide_java_wizard
add hide java wizard toggle
2022-05-01 08:48:37 +02:00
239e4adf29 refactor(workflow): Only use ccache on Debug builds 2022-05-01 00:34:37 +05:30
5662d41062 Update launcher/ui/pages/global/JavaPage.ui
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-04-30 16:20:05 +02:00
1e03ef484d Update launcher/ui/pages/global/JavaPage.ui
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-04-30 16:14:48 +02:00
1d95f10090 Merge pull request #489 from kthchew/fix/old-mac-cleanup 2022-04-30 15:54:10 +02:00
6768768373 Remove symlink 2022-04-30 15:22:31 +02:00
dac801c8ac add hide java wizard toggle 2022-04-30 15:19:57 +02:00
ece5ca52b2 feat(workflow): Use ccache 2022-04-30 17:26:34 +05:30
3205d9e9da Merge pull request #492 from DioEgizio/appimage-fix 2022-04-29 09:10:32 +02:00
b931dc0f93 fix(mnemonics): Add missing buddies to labels
Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-04-29 01:30:47 +05:30
efe4e7df06 fix some appimage issues building with qt 5.15.2
some users are having weird scaling issues since we're using qt 5.12.8 for the appimage
2022-04-28 18:17:02 +02:00
b94f70ea96 Merge pull request #498 from ryanccn/polymc-instance-icon
Add PolyMC icon as instance icon
2022-04-28 07:18:57 +02:00
bd946c78f3 Merge pull request #486 from icelimetea/refactor-java-launcher
Refactor some parts of NewLaunch
2022-04-28 07:18:39 +02:00
a507907443 Merge pull request #477 from flowln/iconfix_static
Always build iconfix as static library
2022-04-28 07:18:22 +02:00
0507b56bed feat: add PolyMC icon as instance icon 2022-04-27 20:30:50 +08:00
ac405aa564 Remove old macOS data migration code 2022-04-25 19:57:47 -04:00
aad7c63282 Merge pull request #482 from TheCodex6824/mojang-auth-fix 2022-04-25 21:55:00 +02:00
1ff459d995 Use suggested error handling 2022-04-25 14:08:27 -04:00
52454ca77b Merge pull request #480 from dschemp/develop 2022-04-25 14:26:10 +02:00
884f772362 Clarify exception messages 2022-04-25 11:22:56 +01:00
bc06571dba Merge pull request #478 from Scrumplex/update-readme 2022-04-25 11:21:21 +02:00
1e8ad3d979 Merge pull request #408 from jamierocks/atl-share-codes 2022-04-25 11:21:10 +02:00
b0a469baab Use java.util.logging instead of custom logging 2022-04-24 15:10:35 +01:00
c968c1be78 Refactor some parts of NewLaunch 2022-04-24 14:45:01 +01:00
a0bafa4952 Re-add base64 decode option for Qt versions that support it 2022-04-23 11:11:55 -04:00
e56f0db11b Remove base64 decode option that was added in Qt 5.15 2022-04-23 10:32:52 -04:00
8bcbe07c87 Fix Mojang auth failing due to Mojang rejecting requests to the profile endpoint 2022-04-22 23:39:38 -04:00
ba9059c7c8 ATLauncher: Replace usage of QPushButton::pressed with ::clicked 2022-04-22 20:37:55 +01:00
45783c1661 ATLauncher: Support using share codes 2022-04-22 20:37:55 +01:00
71777e7a6f added and fixed some Mnemonics in MainWindow 2022-04-22 00:31:03 +02:00
c86ec0bd36 added: Mnemonics for Settings/APIs 2022-04-22 00:23:36 +02:00
08b1b2669a added: Mnemonics for Settings/Accounts 2022-04-22 00:22:50 +02:00
94a655b055 added: Mnemonics for Settings/External Tools 2022-04-22 00:20:54 +02:00
717067e9eb added: Mnemonics for Settings/Proxy 2022-04-22 00:19:54 +02:00
5a5797d914 added: Mnemonics for Settings/Custom Commands 2022-04-22 00:18:39 +02:00
75826aca13 added: Mnemonics for Settings/Java 2022-04-22 00:16:11 +02:00
f52b7c030f added: Mnemonics for Settings/Minecraft+ 2022-04-22 00:14:24 +02:00
c1386bcb04 added: Mnemonics for Settings/Launcher 2022-04-22 00:12:20 +02:00
234a9e48e9 chore: add FUNDING 2022-04-21 22:53:45 +02:00
908e6364c9 fix: update README 2022-04-21 22:52:05 +02:00
3ec511010f fix: Build iconfix as static library
On CI we build using the bundled Quazip, and automatically set
-DBUILD_STATIC_LIBS to true, so it build iconfix statically as well.

However, since we recently added support for using the system quazip,
this flag is not set anymore, and PolyMC fails to run because iconfix
neither is statically linked, nor it creates a .so file for dynamic
linking.

Since most other libs are built statically, we should make this one
static as well. Maybe we should consider allowing for dynamic linking of
libs now that quazip is not much of an issue anymore. :^)
2022-04-21 09:34:44 -03:00
b3e1691c01 fix: hide LauncherLoginStep tokens for non-Debug builds 2022-04-20 18:33:33 +02:00
664 changed files with 30222 additions and 23563 deletions

16
.clang-format Normal file
View File

@ -0,0 +1,16 @@
---
Language: Cpp
BasedOnStyle: Chromium
IndentWidth: 4
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AllowShortIfStatementsOnASingleLine: false
BraceWrapping:
AfterFunction: true
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBraces: Custom
BreakConstructorInitializers: BeforeComma
ColumnLimit: 140
Cpp11BracedListStyle: false

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
open_collective: polymc

View File

@ -23,6 +23,20 @@ body:
- macOS
- Linux
- Other
- type: textarea
attributes:
label: Version of PolyMC
description: The version of PolyMC used in the bug report.
placeholder: PolyMC 1.4.1
validations:
required: true
- type: textarea
attributes:
label: Version of Qt
description: The version of Qt used in the bug report. You can find it in Help -> About PolyMC -> About Qt.
placeholder: Qt 6.3.0
validations:
required: true
- type: textarea
attributes:
label: Description of bug

3
.github/codeql/codeql-config.yml vendored Normal file
View File

@ -0,0 +1,3 @@
query-filters:
- exclude:
id: cpp/fixme-comment

2
.github/dco.yml vendored Normal file
View File

@ -0,0 +1,2 @@
allowRemediationCommits:
individual: true

View File

@ -1,19 +0,0 @@
name: Backport PR to stable
on:
pull_request:
branches: [ develop ]
types: [ closed ]
jobs:
release_pull_request:
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'backport')
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Backport PR by cherry-pick-ing
uses: Nathanmalnoury/gh-backport-action@master
with:
pr_branch: 'stable'
github_token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -7,6 +7,10 @@ on:
description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
type: string
default: Debug
secrets:
SPARKLE_ED25519_KEY:
description: Private key for signing Sparkle updates
required: false
jobs:
build:
@ -16,20 +20,39 @@ jobs:
include:
- os: ubuntu-20.04
qt_ver: 5
- os: ubuntu-20.04
appimage: true
qt_ver: 6
qt_host: linux
qt_version: '6.2.4'
qt_modules: 'qt5compat qtimageformats'
- os: windows-2022
name: "Windows-i686"
msystem: mingw32
name: "Windows-Legacy"
msystem: clang32
qt_ver: 5
- os: windows-2022
name: "Windows-x86_64"
msystem: mingw64
name: "Windows"
msystem: clang64
qt_ver: 6
- os: macos-11
- os: macos-12
name: macOS
macosx_deployment_target: 10.15
qt_ver: 6
qt_host: mac
qt_version: '6.3.0'
qt_modules: 'qt5compat qtimageformats'
- os: macos-12
name: macOS-Legacy
macosx_deployment_target: 10.13
qt_ver: 5
qt_host: mac
qt_version: '5.15.2'
qt_modules: ''
runs-on: ${{ matrix.os }}
@ -39,6 +62,7 @@ jobs:
INSTALL_PORTABLE_DIR: "install-portable"
INSTALL_APPIMAGE_DIR: "install-appdir"
BUILD_DIR: "build"
CCACHE_VAR: ""
steps:
##
@ -49,6 +73,14 @@ jobs:
with:
submodules: 'true'
- name: Initialize CodeQL
if: runner.os == 'Linux' && matrix.qt_ver == 6
uses: github/codeql-action/init@v2
with:
config-file: ./.github/codeql/codeql-config.yml
queries: security-and-quality
languages: cpp, java
- name: 'Setup MSYS2'
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
@ -57,11 +89,49 @@ jobs:
update: true
install: >-
git
mingw-w64-x86_64-binutils
pacboy: >-
toolchain:p
cmake:p
extra-cmake-modules:p
ninja:p
qt5:p
qt${{ matrix.qt_ver }}-base:p
qt${{ matrix.qt_ver }}-svg:p
qt${{ matrix.qt_ver }}-imageformats:p
quazip-qt${{ matrix.qt_ver }}:p
ccache:p
${{ matrix.qt_ver == 6 && 'qt6-5compat:p' || '' }}
- name: Setup ccache
if: runner.os != 'Windows' && inputs.build_type == 'Debug'
uses: hendrikmuhs/ccache-action@v1.2.3
with:
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
- name: Setup ccache (Windows)
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
shell: msys2 {0}
run: |
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
ccache --set-config=max_size='500M'
ccache --set-config=compression=true
ccache -p # Show config
ccache -z # Zero stats
- name: Use ccache on Debug builds only
if: inputs.build_type == 'Debug'
shell: bash
run: |
echo "CCACHE_VAR=ccache" >> $GITHUB_ENV
- name: Retrieve ccache cache (Windows)
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
uses: actions/cache@v3.0.11
with:
path: '${{ github.workspace }}\.ccache'
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
restore-keys: |
${{ matrix.os }}-qt${{ matrix.qt_ver }}
- name: Set short version
shell: bash
@ -69,25 +139,36 @@ jobs:
ver_short=`git rev-parse --short HEAD`
echo "VERSION=$ver_short" >> $GITHUB_ENV
- name: Install Qt (macOS)
if: runner.os == 'macOS'
run: |
brew update
brew install qt@5 ninja
- name: Update Qt (AppImage)
if: runner.os == 'Linux' && matrix.appimage == true
run: |
sudo add-apt-repository ppa:savoury1/qt-5-15
- name: Install Qt (Linux)
- name: Install Dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get -y update
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 ninja-build
sudo apt-get -y install ninja-build extra-cmake-modules scdoc
- name: Install Dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew update
brew install ninja extra-cmake-modules
- name: Install Qt (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 6
run: |
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
- name: Install Qt (macOS and AppImage)
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS'
uses: jurplel/install-qt-action@v3
with:
version: ${{ matrix.qt_version }}
host: ${{ matrix.qt_host }}
target: 'desktop'
modules: ${{ matrix.qt_modules }}
cache: true
cache-key-prefix: ${{ matrix.qt_host }}-${{ matrix.qt_version }}-"${{ matrix.qt_modules }}"-qt_cache
- name: Prepare AppImage (Linux)
if: runner.os == 'Linux' && matrix.appimage == true
if: runner.os == 'Linux' && matrix.qt_ver != 5
run: |
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage"
@ -100,20 +181,25 @@ jobs:
##
- name: Configure CMake (macOS)
if: runner.os == 'macOS'
if: runner.os == 'macOS' && matrix.qt_ver == 6
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DQt5_DIR=/usr/local/opt/qt@5 -DCMAKE_PREFIX_PATH=/usr/local/opt/qt@5 -DLauncher_BUILD_PLATFORM=macOS -G Ninja
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
- name: Configure CMake (macOS-Legacy)
if: runner.os == 'macOS' && matrix.qt_ver == 5
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja
- name: Configure CMake (Windows)
if: runner.os == 'Windows'
shell: msys2 {0}
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -G Ninja
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -G Ninja
- name: Configure CMake (Linux)
if: runner.os == 'Linux'
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=Linux -G Ninja
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=Linux -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -G Ninja
##
# BUILD
@ -130,6 +216,29 @@ jobs:
run: |
cmake --build ${{ env.BUILD_DIR }}
##
# TEST
##
- name: Test
if: runner.os != 'Windows'
run: |
ctest --test-dir build --output-on-failure
- name: Test (Windows)
if: runner.os == 'Windows'
shell: msys2 {0}
run: |
ctest --test-dir build --output-on-failure
##
# CODE SCAN
##
- name: Perform CodeQL Analysis
if: runner.os == 'Linux' && matrix.qt_ver == 6
uses: github/codeql-action/analyze@v2
##
# PACKAGE BUILDS
##
@ -140,9 +249,29 @@ jobs:
cmake --install ${{ env.BUILD_DIR }}
cd ${{ env.INSTALL_DIR }}
chmod +x "PolyMC.app/Contents/MacOS/polymc"
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PolyMC.app/Contents/MacOS/polymc"
tar -czf ../PolyMC.tar.gz *
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
mv "PrismLauncher.app" "Prism Launcher.app"
tar -czf ../PrismLauncher.tar.gz *
- name: Make Sparkle signature (macOS)
if: matrix.name == 'macOS'
run: |
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
brew install openssl@3
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.tar.gz -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
rm ed25519-priv.pem
cat >> $GITHUB_STEP_SUMMARY << EOF
### Artifact Information :information_source:
- :memo: Sparkle Signature (ed25519): \`$signature\`
EOF
else
cat >> $GITHUB_STEP_SUMMARY << EOF
### Artifact Information :information_source:
- :warning: Sparkle Signature (ed25519): No private key available (likely a pull request or fork)
EOF
fi
- name: Package (Windows)
if: runner.os == 'Windows'
@ -151,10 +280,8 @@ jobs:
cmake --install ${{ env.BUILD_DIR }}
cd ${{ env.INSTALL_DIR }}
if [ "${{ matrix.msystem }}" == "mingw32" ]; then
cp /mingw32/bin/libcrypto-1_1.dll /mingw32/bin/libssl-1_1.dll ./
elif [ "${{ matrix.msystem }}" == "mingw64" ]; then
cp /mingw64/bin/libcrypto-1_1-x64.dll /mingw64/bin/libssl-1_1-x64.dll ./
if [ "${{ matrix.qt_ver }}" == "5" ]; then
cp /clang32/bin/libcrypto-1_1.dll /clang32/bin/libssl-1_1.dll ./
fi
- name: Package (Windows, portable)
@ -164,39 +291,51 @@ jobs:
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
- name: Package (Windows, installer)
if: runner.os == 'Windows'
run: |
cd ${{ env.INSTALL_DIR }}
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
- name: Package (Linux)
if: runner.os == 'Linux' && matrix.appimage != true
if: runner.os == 'Linux'
run: |
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }}
cd ${{ env.INSTALL_DIR }}
tar --owner root --group root -czf ../PolyMC.tar.gz *
tar --owner root --group root -czf ../PrismLauncher.tar.gz *
- name: Package (Linux, portable)
if: runner.os == 'Linux' && matrix.appimage != true
if: runner.os == 'Linux'
run: |
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
cd ${{ env.INSTALL_PORTABLE_DIR }}
tar -czf ../PolyMC-portable.tar.gz *
tar -czf ../PrismLauncher-portable.tar.gz *
- name: Package AppImage (Linux)
if: runner.os == 'Linux' && matrix.appimage == true
if: runner.os == 'Linux' && matrix.qt_ver != 5
shell: bash
run: |
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
export OUTPUT="PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
export OUTPUT="PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
chmod +x linuxdeploy-*.AppImage
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-{8,17}-openjdk
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
cp -r ${{ github.workspace }}/JREs/jre8/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk
cp -r ${{ github.workspace }}/JREs/jre17/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk
cp -r /home/runner/work/PrismLauncher/Qt/${{ matrix.qt_version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}//usr/lib/
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib"
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64/server"
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64"
@ -204,7 +343,7 @@ jobs:
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib"
export LD_LIBRARY_PATH
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.polymc.PolyMC.svg
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.prismlauncher.PrismLauncher.svg
##
# UPLOAD BUILDS
@ -214,42 +353,63 @@ jobs:
if: runner.os == 'macOS'
uses: actions/upload-artifact@v3
with:
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: PolyMC.tar.gz
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher.tar.gz
- name: Upload binary zip (Windows)
if: runner.os == 'Windows'
uses: actions/upload-artifact@v3
with:
name: PolyMC-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: ${{ env.INSTALL_DIR }}/**
- name: Upload binary zip (Windows, portable)
if: runner.os == 'Windows'
uses: actions/upload-artifact@v3
with:
name: PolyMC-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
- name: Upload binary tarball (Linux)
if: runner.os == 'Linux' && matrix.appimage != true
- name: Upload installer (Windows)
if: runner.os == 'Windows'
uses: actions/upload-artifact@v3
with:
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: PolyMC.tar.gz
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-Setup.exe
- name: Upload binary tarball (Linux, portable)
if: runner.os == 'Linux' && matrix.appimage != true
- name: Upload binary tarball (Linux, Qt 5)
if: runner.os == 'Linux' && matrix.qt_ver != 6
uses: actions/upload-artifact@v3
with:
name: PolyMC-${{ runner.os }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: PolyMC-portable.tar.gz
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher.tar.gz
- name: Upload binary tarball (Linux, portable, Qt 5)
if: runner.os == 'Linux' && matrix.qt_ver != 6
uses: actions/upload-artifact@v3
with:
name: PrismLauncher-${{ runner.os }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-portable.tar.gz
- name: Upload binary tarball (Linux, Qt 6)
if: runner.os == 'Linux' && matrix.qt_ver !=5
uses: actions/upload-artifact@v3
with:
name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher.tar.gz
- name: Upload binary tarball (Linux, portable, Qt 6)
if: runner.os == 'Linux' && matrix.qt_ver != 5
uses: actions/upload-artifact@v3
with:
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-portable.tar.gz
- name: Upload AppImage (Linux)
if: runner.os == 'Linux' && matrix.appimage == true
if: runner.os == 'Linux' && matrix.qt_ver != 5
uses: actions/upload-artifact@v3
with:
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
path: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage

View File

@ -1,61 +0,0 @@
name: Comment on pull request
on:
workflow_run:
workflows: ['Test workflow with upload']
types: [completed]
jobs:
pr_comment:
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v5
with:
# This snippet is public-domain, taken from
# https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml
script: |
async function upsertComment(owner, repo, issue_number, purpose, body) {
const {data: comments} = await github.rest.issues.listComments(
{owner, repo, issue_number});
const marker = `<!-- bot: ${purpose} -->`;
body = marker + "\n" + body;
const existing = comments.filter((c) => c.body.includes(marker));
if (existing.length > 0) {
const last = existing[existing.length - 1];
core.info(`Updating comment ${last.id}`);
await github.rest.issues.updateComment({
owner, repo,
body,
comment_id: last.id,
});
} else {
core.info(`Creating a comment in issue / PR #${issue_number}`);
await github.rest.issues.createComment({issue_number, body, owner, repo});
}
}
const {owner, repo} = context.repo;
const run_id = ${{github.event.workflow_run.id}};
const pull_requests = ${{ toJSON(github.event.workflow_run.pull_requests) }};
if (!pull_requests.length) {
return core.error("This workflow doesn't match any pull requests!");
}
const artifacts = await github.paginate(
github.rest.actions.listWorkflowRunArtifacts, {owner, repo, run_id});
if (!artifacts.length) {
return core.error(`No artifacts found`);
}
let body = `Download the artifacts for this pull request:\n`;
for (const art of artifacts) {
body += `\n* [${art.name}.zip](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
}
core.info("Review thread message body:", body);
for (const pr of pull_requests) {
await upsertComment(owner, repo, pr.number,
"nightly-link", body);
}

View File

@ -11,6 +11,7 @@ on:
- '**.nix'
- 'packages/**'
- '.github/ISSUE_TEMPLATE/**'
- '.markdownlint**'
pull_request:
paths-ignore:
- '**.md'
@ -19,6 +20,7 @@ on:
- '**.nix'
- 'packages/**'
- '.github/ISSUE_TEMPLATE/**'
- '.markdownlint**'
workflow_dispatch:
jobs:
@ -28,3 +30,5 @@ jobs:
uses: ./.github/workflows/build.yml
with:
build_type: Debug
secrets:
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}

View File

@ -12,6 +12,8 @@ jobs:
uses: ./.github/workflows/build.yml
with:
build_type: Release
secrets:
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
create_release:
needs: build_release
@ -23,7 +25,7 @@ jobs:
uses: actions/checkout@v3
with:
submodules: 'true'
path: 'PolyMC-source'
path: 'PrismLauncher-source'
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Grab and store version
@ -32,21 +34,27 @@ jobs:
echo "VERSION=$tag_name" >> $GITHUB_ENV
- name: Package artifacts properly
run: |
mv ${{ github.workspace }}/PolyMC-source PolyMC-${{ env.VERSION }}
mv PolyMC-Linux-Portable*/PolyMC-portable.tar.gz PolyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
mv PolyMC-Linux*/PolyMC.tar.gz PolyMC-Linux-${{ env.VERSION }}.tar.gz
mv PolyMC-*.AppImage/PolyMC-*.AppImage PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
mv PolyMC-macOS*/PolyMC.tar.gz PolyMC-macOS-${{ env.VERSION }}.tar.gz
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }}
mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
mv PrismLauncher-Linux-Qt6*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
mv PrismLauncher-Linux-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
mv PrismLauncher-Linux*/PrismLauncher.tar.gz PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
mv PrismLauncher-macOS-Legacy*/PrismLauncher.tar.gz PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
mv PrismLauncher-macOS*/PrismLauncher.tar.gz PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
tar -czf PolyMC-${{ env.VERSION }}.tar.gz PolyMC-${{ env.VERSION }}
tar -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
for d in PolyMC-Windows-*; do
for d in PrismLauncher-Windows-*; do
cd "${d}" || continue
ARCH="$(echo -n ${d} | cut -d '-' -f 3)"
LEGACY="$(echo -n ${d} | grep -o Legacy || true)"
INST="$(echo -n ${d} | grep -o Setup || true)"
PORT="$(echo -n ${d} | grep -o Portable || true)"
NAME="PolyMC-Windows-${ARCH}"
NAME="PrismLauncher-Windows"
test -z "${LEGACY}" || NAME="${NAME}-Legacy"
test -z "${PORT}" || NAME="${NAME}-Portable"
zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
test -z "${INST}" || mv PrismLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe
test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
cd ..
done
@ -57,16 +65,21 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
name: PolyMC ${{ env.VERSION }}
name: Prism Launcher ${{ env.VERSION }}
draft: true
prerelease: false
files: |
PolyMC-Linux-${{ env.VERSION }}.tar.gz
PolyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
PolyMC-Windows-i686-${{ env.VERSION }}.zip
PolyMC-Windows-i686-Portable-${{ env.VERSION }}.zip
PolyMC-Windows-x86_64-${{ env.VERSION }}.zip
PolyMC-Windows-x86_64-Portable-${{ env.VERSION }}.zip
PolyMC-macOS-${{ env.VERSION }}.tar.gz
PolyMC-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
PrismLauncher-Windows-Legacy-${{ env.VERSION }}.zip
PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
PrismLauncher-Windows-Legacy-Portable-${{ env.VERSION }}.zip
PrismLauncher-Windows-Legacy-Setup-${{ env.VERSION }}.exe
PrismLauncher-Windows-${{ env.VERSION }}.zip
PrismLauncher-Windows-Portable-${{ env.VERSION }}.zip
PrismLauncher-Windows-Setup-${{ env.VERSION }}.exe
PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
PrismLauncher-${{ env.VERSION }}.tar.gz

15
.github/workflows/winget.yml vendored Normal file
View File

@ -0,0 +1,15 @@
name: Publish to WinGet
on:
release:
types: [released]
jobs:
publish:
runs-on: windows-latest
steps:
- uses: vedantmgoyal2009/winget-releaser@v1
with:
identifier: PrismLauncher.PrismLauncher
version: ${{ github.event.release.tag_name }}
installers-regex: 'PrismLauncher-Windows-Setup-.+\.exe$'
token: ${{ secrets.WINGET_TOKEN }}

1
.gitignore vendored
View File

@ -15,7 +15,6 @@ CMakeLists.txt.user.*
/.settings
/.idea
/.vscode
.clang-format
cmake-build-*/
Debug

14
.gitmodules vendored
View File

@ -1,8 +1,12 @@
[submodule "depends/libnbtplusplus"]
path = libraries/libnbtplusplus
url = https://github.com/PolyMC/libnbtplusplus.git
pushurl = git@github.com:PolyMC/libnbtplusplus.git
[submodule "libraries/quazip"]
path = libraries/quazip
url = https://github.com/stachenov/quazip.git
[submodule "libraries/tomlplusplus"]
path = libraries/tomlplusplus
url = https://github.com/marzer/tomlplusplus.git
[submodule "libraries/filesystem"]
path = libraries/filesystem
url = https://github.com/gulrak/filesystem
[submodule "libraries/libnbtplusplus"]
path = libraries/libnbtplusplus
url = https://github.com/PrismLauncher/libnbtplusplus.git

12
.markdownlint.yaml Normal file
View File

@ -0,0 +1,12 @@
# MD013/line-length - Line length
MD013: false
# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content
MD024:
siblings-only: true
# MD033/no-inline-html Inline HTML
MD033: false
# MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading
MD041: false

2
.markdownlintignore Normal file
View File

@ -0,0 +1,2 @@
libraries/nbtplusplus
libraries/quazip

View File

@ -1,5 +1,53 @@
# Build Instructions
Build instructions are available on [the website](https://polymc.org/wiki/development/build-instructions/).
Full build instructions will be available on [the website](https://prismlauncher.org/wiki/development/build-instructions/).
If you would like to contribute or fix an issue with the Build instructions you will be able to do so [here](https://github.com/PrismLauncher/website/blob/master/src/wiki/development/build-instructions.md).
## Getting the source
Clone the source code using git, and grab all the submodules. This is generic for all platforms you want to build on.
```
git clone --recursive https://github.com/PrismLauncher/PrismLauncher
cd PrismLauncher
```
## Linux
This guide will mostly mention dependant packages by their Debian naming and commands are done by a user in the sudoers file.
### Dependencies
- A C++ compiler capable of building C++17 code (can be found in the package `build-essential`).
- Qt Development tools 5.12 or newer (on Debian 11 or Debian-based distributions, `qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5`).
- `cmake` 3.15 or newer.
- `extra-cmake-modules`.
- zlib (`zlib1g-dev` on Debian 11 or Debian-based distributions).
- Java Development Kit (Java JDK) (`openjdk-17-jdk` on Debian 11 or Debian-based distributions).
- Mesa GL headers (`libgl1-mesa-dev` on Debian 11 or Debian-based distributions).
- (Optional) `scdoc` to generate man pages.
In conclusion, to check if all you need is installed (including optional):
```
sudo apt install build-essential qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 cmake extra-cmake-modules zlib1g-dev openjdk-17-jdk libgl1-mesa-dev scdoc
```
### Compiling
#### Building and installing on the system
This is usually the suggested way to build the client.
```
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="/usr" -DENABLE_LTO=ON
cmake --build build -j$(nproc)
sudo cmake --install build
```
#### Building a portable binary
```
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=install
cmake --build build -j$(nproc)
cmake --install build
cmake --install build --component portable
```
If you would like to contribute or fix an issue with the Build instructions you can do so [here](https://github.com/PolyMC/polymc.github.io/blob/master/src/wiki/development/build-instructions.md).

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.9.4)
cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip
if(WIN32)
# In Qt 5.1+ we have our own main() function, don't autolink to qtmain on Windows
@ -6,14 +6,12 @@ if(WIN32)
endif()
project(Launcher)
include(CTest)
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
if(IS_IN_SOURCE_BUILD)
message(FATAL_ERROR "You are building the Launcher in-source. Please separate the build tree from the source tree.")
endif()
##################################### Set CMake options #####################################
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
@ -31,18 +29,19 @@ set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/jars)
######## Set compiler flags ########
set(CMAKE_CXX_STANDARD_REQUIRED true)
set(CMAKE_C_STANDARD_REQUIRED true)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)
include(GenerateExportHeader)
set(CMAKE_CXX_FLAGS " -Wall -pedantic -Werror -Wno-deprecated-declarations -D_GLIBCXX_USE_CXX11_ABI=0 -fstack-protector-strong --param=ssp-buffer-size=4 -O3 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS}")
if(UNIX AND APPLE)
set(CMAKE_CXX_FLAGS " -stdlib=libc++ ${CMAKE_CXX_FLAGS}")
endif()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror=return-type")
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
# Fix build with Qt 5.13
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
# set CXXFLAGS for build targets
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
option(ENABLE_LTO "Enable Link Time Optimization" off)
if(ENABLE_LTO)
@ -59,20 +58,30 @@ if(ENABLE_LTO)
endif()
endif()
option(BUILD_TESTING "Build the testing tree." ON)
find_package(ECM REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH "${ECM_MODULE_PATH};${CMAKE_MODULE_PATH}")
include(CTest)
include(ECMAddTests)
if(BUILD_TESTING)
enable_testing()
endif()
##################################### Set Application options #####################################
######## Set URLs ########
set(Launcher_NEWS_RSS_URL "https://polymc.org/feed/feed.xml" CACHE STRING "URL to fetch PolyMC's news RSS feed from.")
set(Launcher_NEWS_OPEN_URL "https://polymc.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
set(Launcher_HELP_URL "https://polymc.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
######## Set version numbers ########
set(Launcher_VERSION_MAJOR 1)
set(Launcher_VERSION_MINOR 2)
set(Launcher_VERSION_HOTFIX 2)
set(Launcher_VERSION_MAJOR 5)
set(Launcher_VERSION_MINOR 1)
# Build number
set(Launcher_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},0,0")
# Build platform.
set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.")
@ -81,89 +90,117 @@ set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the plat
set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.")
# The metadata server
set(Launcher_META_URL "https://meta.polymc.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
set(Launcher_META_URL "https://meta.prismlauncher.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
# Imgur API Client ID
set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can get from Imgur when you register an application")
# MSA Client ID
set(Launcher_MSA_CLIENT_ID "549033b2-1532-4d4e-ae77-1bbaa46f9d74" CACHE STRING "Client ID you can get from Microsoft Identity Platform when you register an application")
# CurseForge API Key
# CHANGE THIS IF YOU FORK THIS PROJECT!
set(Launcher_CURSEFORGE_API_KEY "$2a$10$iR1RdPDG95FWdILZbHuoMOlV4vL4eckBx7QPZR6SVZmliEb9ZQplu" CACHE STRING "CurseForge API Key")
# Bug tracker URL
set(Launcher_BUG_TRACKER_URL "https://github.com/PolyMC/PolyMC/issues" CACHE STRING "URL for the bug tracker.")
set(Launcher_BUG_TRACKER_URL "https://github.com/PrismLauncher/PrismLauncher/issues" CACHE STRING "URL for the bug tracker.")
# Translations Platform URL
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/polymc/polymc/" CACHE STRING "URL for the translations platform.")
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/prismlauncher/launcher/" CACHE STRING "URL for the translations platform.")
# Matrix Space
set(Launcher_MATRIX_URL "https://matrix.to/#/#polymc:matrix.org" CACHE STRING "URL to the Matrix Space")
set(Launcher_MATRIX_URL "https://matrix.to/#/#prismlauncher:matrix.org" CACHE STRING "URL to the Matrix Space")
# Discord URL
set(Launcher_DISCORD_URL "https://discord.gg/Z52pwxWCHP" CACHE STRING "URL for the Discord guild.")
set(Launcher_DISCORD_URL "https://discord.gg/prismlauncher" CACHE STRING "URL for the Discord guild.")
# Subreddit URL
set(Launcher_SUBREDDIT_URL "https://www.reddit.com/r/PolyMCLauncher/" CACHE STRING "URL for the subreddit.")
set(Launcher_SUBREDDIT_URL "https://www.reddit.com/r/PrismLauncher/" CACHE STRING "URL for the subreddit.")
# Builds
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
set(Launcher_QT_VERSION_MAJOR "5" CACHE STRING "Major Qt version to build against")
# API Keys
# NOTE: These API keys are here for convenience. If you rebrand this software or intend to break the terms of service
# of these platforms, please change these API keys beforehand.
# Be aware that if you were to use these API keys for malicious purposes they might get revoked, which might cause
# breakage to thousands of users.
# If you don't plan to use these features of this software, you can just remove these values.
# By using this key in your builds you accept the terms of use laid down in
# https://docs.microsoft.com/en-us/legal/microsoft-identity-platform/terms-of-use
set(Launcher_MSA_CLIENT_ID "c36a9fb6-4f2a-41ff-90bd-ae7cc92031eb" CACHE STRING "Client ID you can get from Microsoft Identity Platform when you register an application")
# By using this key in your builds you accept the terms and conditions laid down in
# https://support.curseforge.com/en/support/solutions/articles/9000207405-curse-forge-3rd-party-api-terms-and-conditions
# NOTE: CurseForge requires you to change this if you make any kind of derivative work.
# This key was issued specifically for Prism Launcher
set(Launcher_CURSEFORGE_API_KEY "$2a$10$wuAJuNZuted3NORVmpgUC.m8sI.pv1tOPKZyBgLFGjxFp/br0lZCC" CACHE STRING "API key for the CurseForge platform")
#### Check the current Git commit and branch
include(GetGitRevisionDescription)
git_get_exact_tag(Launcher_GIT_TAG)
get_git_head_revision(Launcher_GIT_REFSPEC Launcher_GIT_COMMIT)
message(STATUS "Git commit: ${Launcher_GIT_COMMIT}")
message(STATUS "Git tag: ${Launcher_GIT_TAG}")
message(STATUS "Git refspec: ${Launcher_GIT_REFSPEC}")
set(Launcher_RELEASE_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
string(TIMESTAMP TODAY "%Y-%m-%d")
set(Launcher_RELEASE_TIMESTAMP "${TODAY}")
#### Custom target to just print the version.
add_custom_target(version echo "Version: ${Launcher_RELEASE_VERSION_NAME}")
add_custom_target(tcversion echo "\\#\\#teamcity[setParameter name=\\'env.LAUNCHER_VERSION\\' value=\\'${Launcher_RELEASE_VERSION_NAME}\\']")
set(Launcher_BUILD_TIMESTAMP "${TODAY}")
################################ 3rd Party Libs ################################
# Find the required Qt parts
include(QtVersionlessBackport)
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
set(QT_VERSION_MAJOR 5)
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml)
if(NOT Launcher_FORCE_BUNDLED_LIBS)
find_package(QuaZip-Qt5 1.3)
find_package(QuaZip-Qt5 1.3 QUIET)
endif()
if (NOT QuaZip-Qt5_FOUND)
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
set(FORCE_BUNDLED_QUAZIP 1)
endif()
# Qt 6 sets these by default. Notably causes Windows APIs to use UNICODE strings.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
set(QT_VERSION_MAJOR 6)
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml Core5Compat)
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
if(NOT Launcher_FORCE_BUNDLED_LIBS)
find_package(QuaZip-Qt6 1.3 QUIET)
endif()
if (NOT QuaZip-Qt6_FOUND)
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
set(FORCE_BUNDLED_QUAZIP 1)
endif()
else()
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
endif()
# The Qt5 cmake files don't provide its install paths, so ask qmake.
include(QMakeQuery)
query_qmake(QT_INSTALL_PLUGINS QT_PLUGINS_DIR)
query_qmake(QT_INSTALL_IMPORTS QT_IMPORTS_DIR)
query_qmake(QT_INSTALL_LIBS QT_LIBS_DIR)
query_qmake(QT_INSTALL_LIBEXECS QT_LIBEXECS_DIR)
query_qmake(QT_HOST_DATA QT_DATA_DIR)
include(ECMQueryQt)
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
ecm_query_qt(QT_DATA_DIR QT_HOST_DATA)
set(QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs)
# NOTE: Qt 6 already sets this by default
if (Qt5_POSITION_INDEPENDENT_CODE)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
if(NOT Launcher_FORCE_BUNDLED_LIBS)
# Find toml++
find_package(tomlplusplus 3.2.0 QUIET)
# Find ghc_filesystem
find_package(ghc_filesystem QUIET)
endif()
####################################### Program Info #######################################
set(Launcher_APP_BINARY_NAME "polymc" CACHE STRING "Name of the Launcher binary")
set(Launcher_APP_BINARY_NAME "prismlauncher" CACHE STRING "Name of the Launcher binary")
add_subdirectory(program_info)
####################################### Install layout #######################################
@ -177,6 +214,7 @@ if(UNIX AND APPLE)
set(BINARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
set(LIBRARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
set(PLUGIN_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
set(FRAMEWORK_DEST_DIR "${Launcher_Name}.app/Contents/Frameworks")
set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources")
set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars")
@ -184,17 +222,23 @@ if(UNIX AND APPLE)
set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.app")
# Mac bundle settings
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}")
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.polymc.${Launcher_Name}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_DisplayName}")
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_DisplayName}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.prismlauncher.${Launcher_Name}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2021-2022 ${Launcher_Copyright}")
set(MACOSX_BUNDLE_COPYRIGHT "© 2022 ${Launcher_Copyright_Mac}")
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=")
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml")
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.1.0/Sparkle-2.1.0.tar.xz" CACHE STRING "URL to Sparkle release archive")
set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive")
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
# directories to look for dependencies
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${MACOSX_SPARKLE_DIR})
# install as bundle
set(INSTALL_BUNDLE "full")
@ -205,7 +249,7 @@ if(UNIX AND APPLE)
elseif(UNIX)
set(BINARY_DEST_DIR "bin")
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
set(JARS_DEST_DIR "share/jars")
set(JARS_DEST_DIR "share/${Launcher_APP_BINARY_NAME}")
set(LAUNCHER_DESKTOP_DEST_DIR "share/applications" CACHE STRING "Path to the desktop file directory")
set(LAUNCHER_METAINFO_DEST_DIR "share/metainfo" CACHE STRING "Path to the metainfo directory")
set(LAUNCHER_ICON_DEST_DIR "share/icons/hicolor/scalable/apps" CACHE STRING "Path to the scalable icon directory")
@ -217,13 +261,13 @@ elseif(UNIX)
# Set RPATH
SET(Launcher_BINARY_RPATH "$ORIGIN/")
# jars path is determined on runtime, relative to "Application root path", generally /usr or the root of the portable bundle
set(Launcher_APP_BINARY_DEFS "-DLAUNCHER_JARS_LOCATION=${JARS_DEST_DIR}")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${LAUNCHER_DESKTOP_DEST_DIR})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${LAUNCHER_METAINFO_DEST_DIR})
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION ${LAUNCHER_ICON_DEST_DIR})
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_ManPage} DESTINATION ${LAUNCHER_MAN_DEST_DIR} RENAME "${Launcher_APP_BINARY_NAME}.6")
if(Launcher_ManPage)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION ${LAUNCHER_MAN_DEST_DIR})
endif()
# Install basic runner script if component "portable" is selected
configure_file(launcher/Launcher.in "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" @ONLY)
@ -262,7 +306,6 @@ add_subdirectory(libraries/systeminfo) # system information library
add_subdirectory(libraries/hoedown) # markdown parser
add_subdirectory(libraries/launcher) # java based launcher part for Minecraft
add_subdirectory(libraries/javacheck) # java compatibility checker
add_subdirectory(libraries/xz-embedded) # xz compression
if (FORCE_BUNDLED_QUAZIP)
message(STATUS "Using bundled QuaZip")
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
@ -272,16 +315,31 @@ else()
message(STATUS "Using system QuaZip")
endif()
add_subdirectory(libraries/rainbow) # Qt extension for colors
add_subdirectory(libraries/iconfix) # fork of Qt's QIcon loader
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
add_subdirectory(libraries/classparser) # class parser library
add_subdirectory(libraries/optional-bare)
add_subdirectory(libraries/tomlc99) # toml parser
if(NOT tomlplusplus_FOUND)
message(STATUS "Using bundled tomlplusplus")
add_subdirectory(libraries/tomlplusplus) # toml parser
else()
message(STATUS "Using system tomlplusplus")
endif()
add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much
add_subdirectory(libraries/gamemode)
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
if (NOT ghc_filesystem_FOUND)
message(STATUS "Using bundled ghc_filesystem")
set(GHC_FILESYSTEM_WITH_INSTALL OFF) # Workaround ghc::filesystem bug
add_subdirectory(libraries/filesystem) # Implementation of std::filesystem for old C++, for usage in old macOS
add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
else()
message(STATUS "Using system ghc_filesystem")
endif()
############################### Built Artifacts ###############################
add_subdirectory(buildconfig)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
# NOTE: this must always be last to appease the CMake deity of quirky install command evaluation order.
add_subdirectory(launcher)

View File

@ -1,4 +1,5 @@
# Contributor Covenant Code of Conduct
This is a modified version of the Contributor Covenant.
See commit history to see our changes.
@ -62,7 +63,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement via email at
[polymc-enforcement@scrumplex.net](mailto:polymc-enforcement@scrumplex.net) (Email
[coc@scrumplex.net](mailto:coc@scrumplex.net) (Email
address subject to change).
All complaints will be reviewed and investigated promptly and fairly.
@ -133,4 +134,3 @@ For answers to common questions about this code of conduct, see the FAQ at
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

63
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,63 @@
# Contributions Guidelines
## Code formatting
Try to follow the existing formatting.
If there is no existing formatting, you may use `clang-format` with our included `.clang-format` configuration.
In general, in order of importance:
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
- Prefer readability over dogma.
- Keep to the existing formatting.
- Indent with 4 space unless it's in a submodule.
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
## Signing your work
In an effort to ensure that the code you contribute is actually compatible with the licenses in this codebase, we require you to sign-off all your contributions.
This can be done by appending `-s` to your `git commit` call, or by manually appending the following text to your commit message:
```
<commit message>
Signed-off-by: Author name <Author email>
```
By signing off your work, you agree to the terms below:
```
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
These terms will be enforced once you create a pull request, and you will be informed automatically if any of your commits aren't signed-off by you.
As a bonus, you can also [cryptographically sign your commits][gh-signing-commits] and enable [vigilant mode][gh-vigilant-mode] on GitHub.
[gh-signing-commits]: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits
[gh-vigilant-mode]: https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits

View File

@ -1,64 +1,121 @@
# PolyMC
## Prism Launcher
Copyright (C) 2012-2021 MultiMC Contributors
Copyright (C) 2021-2022 PolyMC Contributors
Prism Launcher - Minecraft Launcher
Copyright (C) 2022 Prism Launcher Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
# Launcher (https://github.com/MultiMC/Launcher)
Copyright 2012-2021 MultiMC Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
This file incorporates work covered by the following copyright and
permission notice:
http://www.apache.org/licenses/LICENSE-2.0
Copyright 2013-2021 MultiMC Contributors
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
# MinGW runtime (Windows)
http://www.apache.org/licenses/LICENSE-2.0
Copyright (c) 2012 MinGW.org project
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
## PolyMC
The above copyright notice, this permission notice and the below disclaimer
shall be included in all copies or substantial portions of the Software.
PolyMC - Minecraft Launcher
Copyright (C) 2021-2022 PolyMC Contributors
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3.
# Qt 5
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
Contact: http://www.qt-project.org/legal
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Licensed under LGPL v2.1
This file incorporates work covered by the following copyright and
permission notice:
# libnbt++
Copyright 2013-2021 MultiMC Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
## MinGW-w64 runtime (Windows)
Copyright (c) 2009, 2010, 2011, 2012, 2013 by the mingw-w64 project
This license has been certified as open source. It has also been designated
as GPL compatible by the Free Software Foundation (FSF).
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions in source code must retain the accompanying copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the accompanying
copyright notice, this list of conditions, and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
3. Names of the copyright holders must not be used to endorse or promote
products derived from this software without prior written permission
from the copyright holders.
4. The right to distribute this software or to use it for any purpose does
not give you the right to use Servicemarks (sm) or Trademarks (tm) of
the copyright holders. Use of them is covered by separate agreement
with the copyright holders.
5. If any files are modified, you must cause the modified files to carry
prominent notices stating that you changed the files and the date of
any change.
Disclaimer
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt.
## Qt 5/6
Copyright (C) 2022 The Qt Company Ltd and other contributors.
Contact: https://www.qt.io/licensing
Licensed under LGPL v3
## libnbt++
libnbt++ - A library for the Minecraft Named Binary Tag format.
Copyright (C) 2013, 2015 ljfa-ag
@ -76,7 +133,7 @@
You should have received a copy of the GNU Lesser General Public License
along with libnbt++. If not, see <http://www.gnu.org/licenses/>.
# rainbow (KGuiAddons)
## rainbow (KGuiAddons)
Copyright (C) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
Copyright (C) 2007 Olaf Schmidt <ojschmidt@kde.org>
@ -99,7 +156,7 @@
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
# Hoedown
## Hoedown
Copyright (c) 2008, Natacha Porté
Copyright (c) 2011, Vicent Martí
@ -117,7 +174,7 @@
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# Batch icon set
## Batch icon set
You are free to use Batch (the "icon set") or any part thereof (the "icons")
in any personal, open-source or commercial work without obligation of payment
@ -133,7 +190,7 @@
PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THE USE OF THE ICONS,
EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
# Material Design Icons
## Material Design Icons
Copyright (c) 2014, Austin Andrews (http://materialdesignicons.com/),
with Reserved Font Name Material Design Icons.
@ -144,76 +201,82 @@
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
# Quazip
## Quazip
Copyright (C) 2005-2011 Sergey A. Tachenov
Copyright (C) 2005-2021 Sergey A. Tachenov
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
The QuaZip library is licensed under the GNU Lesser General Public
License V2.1 plus a static linking exception.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
General Public License for more details.
The original ZIP/UNZIP package (MiniZip) is copyrighted by Gilles
Vollant and contributors, see quazip/(un)zip.h files for details.
Basically it's the zlib license.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
STATIC LINKING EXCEPTION
The copyright holders give you permission to link this library with
independent modules to produce an executable, regardless of the license
terms of these independent modules, and to copy and distribute the
resulting executable under terms of your choice, provided that you also
meet, for each linked independent module, the terms and conditions of
the license of that module. An independent module is a module which is
not derived from or based on this library. If you modify this library,
you must extend this exception to your version of the library.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant, see
quazip/(un)zip.h files for details, basically it's zlib license.
## launcher (`libraries/launcher`)
# xz-minidec
PolyMC - Minecraft Launcher
Copyright (C) 2021-2022 PolyMC Contributors
XZ decompressor
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3.
Authors: Lasse Collin <lasse.collin@tukaani.org>
Igor Pavlov <http://7-zip.org/>
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This file has been put into the public domain.
You can do whatever you want with this file.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
# ColumnResizer
As a special exception, the copyright holders of this library give
you permission to link this library with independent modules to
produce an executable, regardless of the license terms of these
independent modules, and to copy and distribute the resulting
executable under terms of your choice, provided that you also meet,
for each linked independent module, the terms and conditions of the
license of that module. An independent module is a module which is
not derived from or based on this library. If you modify this
library, you may extend this exception to your version of the
library, but you are not obliged to do so. If you do not wish to do
so, delete this exception statement from your version.
Copyright (c) 2011-2016 Aurélien Gâteau and contributors.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
All rights reserved.
This file incorporates work covered by the following copyright and
permission notice:
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the
disclaimer below) provided that the following conditions are met:
Copyright 2013-2021 MultiMC Contributors
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.
http://www.apache.org/licenses/LICENSE-2.0
* The name of the contributors may not be used to endorse or
promote products derived from this software without specific prior
written permission.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# lionshead
## lionshead
Code has been taken from https://github.com/natefoo/lionshead and loosely
translated to C++ laced with Qt.
@ -240,60 +303,26 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# optional-bare
Code from https://github.com/martinmoene/optional-bare/
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
# tomlc99
## tomlplusplus
MIT License
Copyright (c) 2017 CK Tan
https://github.com/cktan/tomlc99
Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# O2 (Katabasis fork)
## O2 (Katabasis fork)
Copyright (c) 2012, Akos Polster
All rights reserved.
@ -318,3 +347,54 @@
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## Gamemode
Copyright (c) 2017-2022, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Feral Interactive nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
## gulrak/filesystem
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,88 +1,29 @@
<p align="center">
<img src="./program_info/polymc-header-black.svg#gh-light-mode-only" alt="PolyMC logo"/>
<img src="./program_info/polymc-header.svg#gh-dark-mode-only" alt="PolyMC logo"/>
<img src="./program_info/org.prismlauncher.PrismLauncher.logo.svg#gh-light-mode-only" alt="Prism Launcher logo" width="50%"/>
<img src="./program_info/org.prismlauncher.PrismLauncher.logo-darkmode.svg#gh-dark-mode-only" alt="Prism Launcher logo" width="50%"/>
</p>
<br>
PolyMC is a custom launcher for Minecraft that focuses on predictability, long term stability and simplicity.
Prism Launcher is a custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.
This is a **fork** of the MultiMC Launcher and not endorsed by MultiMC. The PolyMC community felt that the maintainer was not acting in the spirit of Free Software so this fork was made.
<br>
We are working on a website and other media, for more info we have a [Discord server](https://discord.gg/prismlauncher).
# Installation
## Installation
- All downloads and instructions for PolyMC can be found [here](https://polymc.org/download/)
- Last build status: https://github.com/PolyMC/PolyMC/actions
- All downloads and instructions for Prism Launcher will soon be available.
- Last build status can be found [here](https://github.com/PrismLauncher/PrismLauncher/actions).
### Development Builds
## Development Builds
There are development builds available [here](https://github.com/PrismLauncher/PrismLauncher/actions). These have debug information in the binaries, so their file sizes are relatively larger.
There are per-commit development builds available [here](https://github.com/PolyMC/PolyMC/actions). These have debug information in the binaries, so their file sizes are relatively larger.
Portable builds are provided for AppImage on Linux, Windows, and macOS.
For Debian and Arch, you can use these packages for the latest development versions:
[![polymc-git](https://img.shields.io/badge/aur-polymc--git-blue)](https://aur.archlinux.org/packages/polymc-git/)
[![polymc-git](https://img.shields.io/badge/mpr-polymc--git-orange)](https://mpr.makedeb.org/packages/polymc-git)
For flatpak, you can use [flathub-beta](https://discourse.flathub.org/t/how-to-use-flathub-beta/2111)
## Help & Support
# Help & Support
Feel free to create an issue if you need help. However, you might find it easier to ask in the Discord server.
[![Join the Discord Server](https://discordapp.com/api/guilds/1031648380885147709/widget.png?style=banner3)](https://discord.gg/hX4g537UNE)
[![PolyMC Discord](https://img.shields.io/discord/923671181020766230?label=PolyMC%20Discord)](https://discord.gg/xq7fxrgtMP)
For people who don't want to use Discord, we have a Matrix Space which is bridged to the Discord server:
## License
[![PolyMC Space](https://img.shields.io/matrix/polymc:matrix.org?label=PolyMC%20space)](https://matrix.to/#/#polymc:matrix.org)
If there are any issues with the space or you are using a client that does not support the feature here are the individual rooms:
[![Development](https://img.shields.io/matrix/polymc-development:matrix.org?label=PolyMC%20Development)](https://matrix.to/#/#polymc-development:matrix.org)
[![Discussion](https://img.shields.io/matrix/polymc-discussion:matrix.org?label=PolyMC%20Discussion)](https://matrix.to/#/#polymc-discussion:matrix.org)
[![Github](https://img.shields.io/matrix/polymc-github:matrix.org?label=PolyMC%20Github)](https://matrix.to/#/#polymc-github:matrix.org)
[![Maintainers](https://img.shields.io/matrix/polymc-maintainers:matrix.org?label=PolyMC%20Maintainers)](https://matrix.to/#/#polymc-maintainers:matrix.org)
[![News](https://img.shields.io/matrix/polymc-news:matrix.org?label=PolyMC%20News)](https://matrix.to/#/#polymc-news:matrix.org)
[![Offtopic](https://img.shields.io/matrix/polymc-offtopic:matrix.org?label=PolyMC%20Offtopic)](https://matrix.to/#/#polymc-offtopic:matrix.org)
[![Support](https://img.shields.io/matrix/polymc-support:matrix.org?label=PolyMC%20Support)](https://matrix.to/#/#polymc-support:matrix.org)
[![Voice](https://img.shields.io/matrix/polymc-voice:matrix.org?label=PolyMC%20Voice)](https://matrix.to/#/#polymc-voice:matrix.org)
we also have a subreddit you can post your issues and suggestions on:
[r/PolyMCLauncher](https://www.reddit.com/r/PolyMCLauncher/)
# Development
If you want to contribute to PolyMC you might find it useful to join our Discord Server or Matrix Space.
## Building
If you want to build PolyMC yourself, check [Build Instructions](https://polymc.org/wiki/development/build-instructions/) for build instructions.
## Code formatting
Just follow the existing formatting.
In general, in order of importance:
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
- Prefer readability over dogma.
- Keep to the existing formatting.
- Indent with 4 space unless it's in a submodule.
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
## Translations
The translation effort for PolyMC is hosted on [Weblate](https://hosted.weblate.org/projects/polymc/polymc/) and information about translating PolyMC is available at https://github.com/PolyMC/Translations
## Download information
To modify download information or change packaging information send a pull request or issue to the website [Here](https://github.com/PolyMC/polymc.github.io/blob/master/src/download.md)
## Forking/Redistributing/Custom builds policy
Do whatever you want, we don't care. Just follow the license. If you have any questions about this feel free to ask in an issue.
All launcher code is available under the GPL-3 license.
[Source for the website](https://github.com/PolyMC/polymc.github.io) is hosted under the AGPL-3 License.
The logo and related assets are under the CC BY-SA 4.0 license.
All launcher code is available under the GPL-3.0-only license.

View File

@ -42,12 +42,14 @@ Config::Config()
{
// Name and copyright
LAUNCHER_NAME = "@Launcher_Name@";
LAUNCHER_APP_BINARY_NAME = "@Launcher_APP_BINARY_NAME@";
LAUNCHER_DISPLAYNAME = "@Launcher_DisplayName@";
LAUNCHER_COPYRIGHT = "@Launcher_Copyright@";
LAUNCHER_DOMAIN = "@Launcher_Domain@";
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
LAUNCHER_GIT = "@Launcher_Git@";
LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
USER_AGENT = "@Launcher_UserAgent@";
USER_AGENT_UNCACHED = USER_AGENT + " (Uncached)";
@ -55,23 +57,36 @@ Config::Config()
// Version information
VERSION_MAJOR = @Launcher_VERSION_MAJOR@;
VERSION_MINOR = @Launcher_VERSION_MINOR@;
VERSION_HOTFIX = @Launcher_VERSION_HOTFIX@;
VERSION_BUILD = @Launcher_VERSION_BUILD@;
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
BUILD_DATE = "@Launcher_BUILD_TIMESTAMP@";
UPDATER_BASE = "@Launcher_UPDATER_BASE@";
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND"))
MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@";
MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@";
if (BUILD_PLATFORM == "macOS" && !MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty())
{
VERSION_CHANNEL = QStringLiteral("stable");
UPDATER_ENABLED = true;
}
else if(GIT_REFSPEC.startsWith("refs/heads/"))
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
GIT_TAG = "@Launcher_GIT_TAG@";
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
// Assume that builds outside of Git repos are "stable"
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND")
|| GIT_TAG == QStringLiteral("GITDIR-NOTFOUND"))
{
GIT_REFSPEC = "refs/heads/stable";
GIT_TAG = versionString();
}
if (GIT_REFSPEC.startsWith("refs/heads/"))
{
VERSION_CHANNEL = GIT_REFSPEC;
VERSION_CHANNEL.remove("refs/heads/");
if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty() && VERSION_BUILD >= 0) {
if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty()) {
UPDATER_ENABLED = true;
}
}
@ -81,16 +96,15 @@ Config::Config()
}
else
{
VERSION_CHANNEL = QObject::tr("unknown");
VERSION_CHANNEL = "unknown";
}
VERSION_STR = "@Launcher_VERSION_STRING@";
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
HELP_URL = "@Launcher_HELP_URL@";
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
CURSEFORGE_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
META_URL = "@Launcher_META_URL@";
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
@ -100,20 +114,19 @@ Config::Config()
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
}
QString Config::versionString() const
{
return QString("%1.%2").arg(VERSION_MAJOR).arg(VERSION_MINOR);
}
QString Config::printableVersionString() const
{
QString vstr = QString("%1.%2.%3").arg(QString::number(VERSION_MAJOR), QString::number(VERSION_MINOR), QString::number(VERSION_HOTFIX));
QString vstr = versionString();
// If the build is not a main release, append the channel
if(VERSION_CHANNEL != "stable")
if(VERSION_CHANNEL != "stable" && GIT_TAG != vstr)
{
vstr += "-" + VERSION_CHANNEL;
}
// if a build number is set, also add it to the end
if(VERSION_BUILD >= 0)
{
vstr += "-" + QString::number(VERSION_BUILD);
}
return vstr;
}

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
@ -43,21 +44,19 @@ class Config {
public:
Config();
QString LAUNCHER_NAME;
QString LAUNCHER_APP_BINARY_NAME;
QString LAUNCHER_DISPLAYNAME;
QString LAUNCHER_COPYRIGHT;
QString LAUNCHER_DOMAIN;
QString LAUNCHER_CONFIGFILE;
QString LAUNCHER_GIT;
QString LAUNCHER_DESKTOPFILENAME;
QString LAUNCHER_SVGFILENAME;
/// The major version number.
int VERSION_MAJOR;
/// The minor version number.
int VERSION_MINOR;
/// The hotfix number.
int VERSION_HOTFIX;
/// The build number.
int VERSION_BUILD;
/**
* The version channel
@ -70,9 +69,18 @@ class Config {
/// A short string identifying this build's platform. For example, "lin64" or "win32".
QString BUILD_PLATFORM;
/// A string containing the build timestamp
QString BUILD_DATE;
/// URL for the updater's channel
QString UPDATER_BASE;
/// The public key used to sign releases for the Sparkle updater appcast
QString MAC_SPARKLE_PUB_KEY;
/// URL for the Sparkle updater's appcast
QString MAC_SPARKLE_APPCAST_URL;
/// User-Agent to use.
QString USER_AGENT;
@ -82,12 +90,12 @@ class Config {
/// The git commit hash of this build
QString GIT_COMMIT;
/// The git tag of this build
QString GIT_TAG;
/// The git refspec of this build
QString GIT_REFSPEC;
/// This is printed on start to standard output
QString VERSION_STR;
/**
* This is used to fetch the news RSS feed.
* It defaults in CMakeLists.txt to "https://multimc.org/rss.xml"
@ -117,7 +125,7 @@ class Config {
/**
* Client API key for CurseForge
*/
QString CURSEFORGE_API_KEY;
QString FLAME_API_KEY;
/**
* Metadata repository URL prefix
@ -134,14 +142,15 @@ class Config {
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
QString AUTH_BASE = "https://authserver.mojang.com/";
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
QString FMLLIBS_BASE_URL = "https://files.polymc.org/fmllibs/";
QString TRANSLATIONS_BASE_URL = "https://i18n.polymc.org/";
QString FMLLIBS_BASE_URL = "https://files.prismlauncher.org/fmllibs/"; // FIXME: move into CMakeLists
QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/"; // FIXME: move into CMakeLists
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
QString LEGACY_FTB_CDN_BASE_URL = "https://dist.creeper.host/FTB2/";
QString ATL_DOWNLOAD_SERVER_URL = "https://download.nodecdn.net/containers/atl/";
QString ATL_API_BASE_URL = "https://api.atlauncher.com/v1/";
QString TECHNIC_API_BASE_URL = "https://api.technicpack.net/";
/**
@ -149,6 +158,10 @@ class Config {
*/
QString TECHNIC_API_BUILD = "multimc";
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
QString versionString() const;
/**
* \brief Converts the Version to a string.
* \return The version number in string format (major.minor.revision.build).

View File

@ -7,5 +7,5 @@ add_library(BuildConfig STATIC
${CMAKE_CURRENT_BINARY_DIR}/BuildConfig.cpp
)
target_link_libraries(BuildConfig Qt5::Core)
target_link_libraries(BuildConfig Qt${QT_VERSION_MAJOR}::Core)
target_include_directories(BuildConfig PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")

View File

@ -1,786 +0,0 @@
# - Functions to help assemble a standalone bundle application.
# A collection of CMake utility functions useful for dealing with .app
# bundles on the Mac and bundle-like directories on any OS.
#
# The following functions are provided by this module:
# fixup_bundle
# copy_and_fixup_bundle
# verify_app
# get_bundle_main_executable
# get_dotapp_dir
# get_bundle_and_executable
# get_bundle_all_executables
# get_item_key
# clear_bundle_keys
# set_bundle_key_values
# get_bundle_keys
# copy_resolved_item_into_bundle
# copy_resolved_framework_into_bundle
# fixup_bundle_item
# verify_bundle_prerequisites
# verify_bundle_symlinks
# Requires CMake 2.6 or greater because it uses function, break and
# PARENT_SCOPE. Also depends on GetPrerequisites.cmake.
#
# FIXUP_BUNDLE(<app> <libs> <dirs>)
# Fix up a bundle in-place and make it standalone, such that it can be
# drag-n-drop copied to another machine and run on that machine as long as all
# of the system libraries are compatible.
#
# If you pass plugins to fixup_bundle as the libs parameter, you should install
# them or copy them into the bundle before calling fixup_bundle. The "libs"
# parameter is a list of libraries that must be fixed up, but that cannot be
# determined by otool output analysis. (i.e., plugins)
#
# Gather all the keys for all the executables and libraries in a bundle, and
# then, for each key, copy each prerequisite into the bundle. Then fix each one
# up according to its own list of prerequisites.
#
# Then clear all the keys and call verify_app on the final bundle to ensure
# that it is truly standalone.
#
# COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>)
# Makes a copy of the bundle <src> at location <dst> and then fixes up the
# new copied bundle in-place at <dst>...
#
# VERIFY_APP(<app>)
# Verifies that an application <app> appears valid based on running analysis
# tools on it. Calls "message(FATAL_ERROR" if the application is not verified.
#
# GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>)
# The result will be the full path name of the bundle's main executable file
# or an "error:" prefixed string if it could not be determined.
#
# GET_DOTAPP_DIR(<exe> <dotapp_dir_var>)
# Returns the nearest parent dir whose name ends with ".app" given the full
# path to an executable. If there is no such parent dir, then simply return
# the dir containing the executable.
#
# The returned directory may or may not exist.
#
# GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>)
# Takes either a ".app" directory name or the name of an executable
# nested inside a ".app" directory and returns the path to the ".app"
# directory in <bundle_var> and the path to its main executable in
# <executable_var>
#
# GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>)
# Scans the given bundle recursively for all executable files and accumulates
# them into a variable.
#
# GET_ITEM_KEY(<item> <key_var>)
# Given a file (item) name, generate a key that should be unique considering
# the set of libraries that need copying or fixing up to make a bundle
# standalone. This is essentially the file name including extension with "."
# replaced by "_"
#
# This key is used as a prefix for CMake variables so that we can associate a
# set of variables with a given item based on its key.
#
# CLEAR_BUNDLE_KEYS(<keys_var>)
# Loop over the list of keys, clearing all the variables associated with each
# key. After the loop, clear the list of keys itself.
#
# Caller of get_bundle_keys should call clear_bundle_keys when done with list
# of keys.
#
# SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs>
# <copyflag>)
# Add a key to the list (if necessary) for the given item. If added,
# also set all the variables associated with that key.
#
# GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>)
# Loop over all the executable and library files within the bundle (and given
# as extra <libs>) and accumulate a list of keys representing them. Set
# values associated with each key such that we can loop over all of them and
# copy prerequisite libs into the bundle and then do appropriate
# install_name_tool fixups.
#
# COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
# Copy a resolved item into the bundle if necessary. Copy is not necessary if
# the resolved_item is "the same as" the resolved_embedded_item.
#
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
# Copy a resolved framework into the bundle if necessary. Copy is not necessary
# if the resolved_item is "the same as" the resolved_embedded_item.
#
# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want full
# frameworks embedded in your bundles, set BU_COPY_FULL_FRAMEWORK_CONTENTS to
# ON before calling fixup_bundle. By default,
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework dylib itself plus
# the framework Resources directory.
#
# FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>)
# Get the direct/non-system prerequisites of the resolved embedded item. For
# each prerequisite, change the way it is referenced to the value of the
# _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely changing to
# an "@executable_path" style reference.)
#
# This function requires that the resolved_embedded_item be "inside" the bundle
# already. In other words, if you pass plugins to fixup_bundle as the libs
# parameter, you should install them or copy them into the bundle before
# calling fixup_bundle. The "libs" parameter is a list of libraries that must
# be fixed up, but that cannot be determined by otool output analysis. (i.e.,
# plugins)
#
# Also, change the id of the item being fixed up to its own _EMBEDDED_ITEM
# value.
#
# Accumulate changes in a local variable and make *one* call to
# install_name_tool at the end of the function with all the changes at once.
#
# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be
# marked writable before install_name_tool tries to change them.
#
# VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>)
# Verifies that the sum of all prerequisites of all files inside the bundle
# are contained within the bundle or are "system" libraries, presumed to exist
# everywhere.
#
# VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>)
# Verifies that any symlinks found in the bundle point to other files that are
# already also in the bundle... Anything that points to an external file causes
# this function to fail the verification.
#=============================================================================
# Copyright 2008-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# The functions defined in this file depend on the get_prerequisites function
# (and possibly others) found in:
#
get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
include("${BundleUtilities_cmake_dir}/GetPrerequisites.cmake")
function(get_bundle_main_executable bundle result_var)
set(result "error: '${bundle}/Contents/Info.plist' file does not exist")
if(EXISTS "${bundle}/Contents/Info.plist")
set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file")
set(line_is_main_executable 0)
set(bundle_executable "")
# Read Info.plist as a list of lines:
#
set(eol_char "E")
file(READ "${bundle}/Contents/Info.plist" info_plist)
string(REGEX REPLACE ";" "\\\\;" info_plist "${info_plist}")
string(REGEX REPLACE "\n" "${eol_char};" info_plist "${info_plist}")
# Scan the lines for "<key>CFBundleExecutable</key>" - the line after that
# is the name of the main executable.
#
foreach(line ${info_plist})
if(line_is_main_executable)
string(REGEX REPLACE "^.*<string>(.*)</string>.*$" "\\1" bundle_executable "${line}")
break()
endif()
if(line MATCHES "^.*<key>CFBundleExecutable</key>.*$")
set(line_is_main_executable 1)
endif()
endforeach()
if(NOT "${bundle_executable}" STREQUAL "")
if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}")
set(result "${bundle}/Contents/MacOS/${bundle_executable}")
else()
# Ultimate goal:
# If not in "Contents/MacOS" then scan the bundle for matching files. If
# there is only one executable file that matches, then use it, otherwise
# it's an error...
#
#file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}")
# But for now, pragmatically, it's an error. Expect the main executable
# for the bundle to be in Contents/MacOS, it's an error if it's not:
#
set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist")
endif()
endif()
else()
#
# More inclusive technique... (This one would work on Windows and Linux
# too, if a developer followed the typical Mac bundle naming convention...)
#
# If there is no Info.plist file, try to find an executable with the same
# base name as the .app directory:
#
endif()
set(${result_var} "${result}" PARENT_SCOPE)
endfunction()
function(get_dotapp_dir exe dotapp_dir_var)
set(s "${exe}")
if(s MATCHES "^.*/.*\\.app/.*$")
# If there is a ".app" parent directory,
# ascend until we hit it:
# (typical of a Mac bundle executable)
#
set(done 0)
while(NOT ${done})
get_filename_component(snamewe "${s}" NAME_WE)
get_filename_component(sname "${s}" NAME)
get_filename_component(sdir "${s}" PATH)
set(s "${sdir}")
if(sname MATCHES "\\.app$")
set(done 1)
set(dotapp_dir "${sdir}/${sname}")
endif()
endwhile()
else()
# Otherwise use a directory containing the exe
# (typical of a non-bundle executable on Mac, Windows or Linux)
#
is_file_executable("${s}" is_executable)
if(is_executable)
get_filename_component(sdir "${s}" PATH)
set(dotapp_dir "${sdir}")
else()
set(dotapp_dir "${s}")
endif()
endif()
set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE)
endfunction()
function(get_bundle_and_executable app bundle_var executable_var valid_var)
set(valid 0)
if(EXISTS "${app}")
# Is it a directory ending in .app?
if(IS_DIRECTORY "${app}")
if(app MATCHES "\\.app$")
get_bundle_main_executable("${app}" executable)
if(EXISTS "${app}" AND EXISTS "${executable}")
set(${bundle_var} "${app}" PARENT_SCOPE)
set(${executable_var} "${executable}" PARENT_SCOPE)
set(valid 1)
#message(STATUS "info: handled .app directory case...")
else()
message(STATUS "warning: *NOT* handled - .app directory case...")
endif()
else()
message(STATUS "warning: *NOT* handled - directory but not .app case...")
endif()
else()
# Is it an executable file?
is_file_executable("${app}" is_executable)
if(is_executable)
get_dotapp_dir("${app}" dotapp_dir)
if(EXISTS "${dotapp_dir}")
set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE)
set(${executable_var} "${app}" PARENT_SCOPE)
set(valid 1)
#message(STATUS "info: handled executable file in .app dir case...")
else()
get_filename_component(app_dir "${app}" PATH)
set(${bundle_var} "${app_dir}" PARENT_SCOPE)
set(${executable_var} "${app}" PARENT_SCOPE)
set(valid 1)
#message(STATUS "info: handled executable file in any dir case...")
endif()
else()
message(STATUS "warning: *NOT* handled - not .app dir, not executable file...")
endif()
endif()
else()
message(STATUS "warning: *NOT* handled - directory/file ${app} does not exist...")
endif()
if(NOT valid)
set(${bundle_var} "error: not a bundle" PARENT_SCOPE)
set(${executable_var} "error: not a bundle" PARENT_SCOPE)
endif()
set(${valid_var} ${valid} PARENT_SCOPE)
endfunction()
function(get_bundle_all_executables bundle exes_var)
set(exes "")
file(GLOB_RECURSE file_list "${bundle}/*")
foreach(f ${file_list})
is_file_executable("${f}" is_executable)
if(is_executable)
set(exes ${exes} "${f}")
endif()
endforeach()
set(${exes_var} "${exes}" PARENT_SCOPE)
endfunction()
function(get_item_key item key_var)
get_filename_component(item_name "${item}" NAME)
if(WIN32)
string(TOLOWER "${item_name}" item_name)
endif()
string(REGEX REPLACE "\\." "_" ${key_var} "${item_name}")
set(${key_var} ${${key_var}} PARENT_SCOPE)
endfunction()
function(clear_bundle_keys keys_var)
foreach(key ${${keys_var}})
set(${key}_ITEM PARENT_SCOPE)
set(${key}_RESOLVED_ITEM PARENT_SCOPE)
set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE)
set(${key}_EMBEDDED_ITEM PARENT_SCOPE)
set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE)
set(${key}_COPYFLAG PARENT_SCOPE)
endforeach()
set(${keys_var} PARENT_SCOPE)
endfunction()
function(set_bundle_key_values keys_var context item exepath dirs copyflag)
get_filename_component(item_name "${item}" NAME)
get_item_key("${item}" key)
list(LENGTH ${keys_var} length_before)
gp_append_unique(${keys_var} "${key}")
list(LENGTH ${keys_var} length_after)
if(NOT length_before EQUAL length_after)
gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item)
gp_item_default_embedded_path("${item}" default_embedded_path)
if(item MATCHES "[^/]+\\.framework/")
# For frameworks, construct the name under the embedded path from the
# opening "${item_name}.framework/" to the closing "/${item_name}":
#
string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}")
else()
# For other items, just use the same name as the original, but in the
# embedded path:
#
set(embedded_item "${default_embedded_path}/${item_name}")
endif()
# Replace @executable_path and resolve ".." references:
#
string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}")
get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE)
# *But* -- if we are not copying, then force resolved_embedded_item to be
# the same as resolved_item. In the case of multiple executables in the
# original bundle, using the default_embedded_path results in looking for
# the resolved executable next to the main bundle executable. This is here
# so that exes in the other sibling directories (like "bin") get fixed up
# properly...
#
if(NOT copyflag)
set(resolved_embedded_item "${resolved_item}")
endif()
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
set(${key}_ITEM "${item}" PARENT_SCOPE)
set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE)
set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE)
set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE)
set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE)
set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE)
else()
#message("warning: item key '${key}' already in the list, subsequent references assumed identical to first")
endif()
endfunction()
function(get_bundle_keys app libs dirs keys_var)
set(${keys_var} PARENT_SCOPE)
get_bundle_and_executable("${app}" bundle executable valid)
if(valid)
# Always use the exepath of the main bundle executable for @executable_path
# replacements:
#
get_filename_component(exepath "${executable}" PATH)
# But do fixups on all executables in the bundle:
#
get_bundle_all_executables("${bundle}" exes)
# For each extra lib, accumulate a key as well and then also accumulate
# any of its prerequisites. (Extra libs are typically dynamically loaded
# plugins: libraries that are prerequisites for full runtime functionality
# but that do not show up in otool -L output...)
#
foreach(lib ${libs})
set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0)
set(prereqs "")
get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}")
foreach(pr ${prereqs})
set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1)
endforeach()
endforeach()
# For each executable found in the bundle, accumulate keys as we go.
# The list of keys should be complete when all prerequisites of all
# binaries in the bundle have been analyzed.
#
foreach(exe ${exes})
# Add the exe itself to the keys:
#
set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0)
# Add each prerequisite to the keys:
#
set(prereqs "")
get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}")
foreach(pr ${prereqs})
set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1)
endforeach()
endforeach()
# Propagate values to caller's scope:
#
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
foreach(key ${${keys_var}})
set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE)
set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE)
set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE)
set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE)
set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE)
set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE)
endforeach()
endif()
endfunction()
function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
if(WIN32)
# ignore case on Windows
string(TOLOWER "${resolved_item}" resolved_item_compare)
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
else()
set(resolved_item_compare "${resolved_item}")
set(resolved_embedded_item_compare "${resolved_embedded_item}")
endif()
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
else()
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
if(UNIX AND NOT APPLE)
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
endif()
endif()
endfunction()
function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item)
if(WIN32)
# ignore case on Windows
string(TOLOWER "${resolved_item}" resolved_item_compare)
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
else()
set(resolved_item_compare "${resolved_item}")
set(resolved_embedded_item_compare "${resolved_embedded_item}")
endif()
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
else()
if(BU_COPY_FULL_FRAMEWORK_CONTENTS)
# Full Framework (everything):
get_filename_component(resolved_dir "${resolved_item}" PATH)
get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE)
get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH)
get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE)
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}")
else()
# Framework lib itself:
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
# Plus Resources, if they exist:
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}")
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}")
if(EXISTS "${resolved_resources}")
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}")
endif()
endif()
if(UNIX AND NOT APPLE)
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
endif()
endif()
endfunction()
function(fixup_bundle_item resolved_embedded_item exepath dirs)
# This item's key is "ikey":
#
get_item_key("${resolved_embedded_item}" ikey)
# Ensure the item is "inside the .app bundle" -- it should not be fixed up if
# it is not in the .app bundle... Otherwise, we'll modify files in the build
# tree, or in other varied locations around the file system, with our call to
# install_name_tool. Make sure that doesn't happen here:
#
get_dotapp_dir("${exepath}" exe_dotapp_dir)
string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length)
string(LENGTH "${resolved_embedded_item}" resolved_embedded_item_length)
set(path_too_short 0)
set(is_embedded 0)
if(${resolved_embedded_item_length} LESS ${exe_dotapp_dir_length})
set(path_too_short 1)
endif()
if(NOT path_too_short)
string(SUBSTRING "${resolved_embedded_item}" 0 ${exe_dotapp_dir_length} item_substring)
if("${exe_dotapp_dir}/" STREQUAL "${item_substring}")
set(is_embedded 1)
endif()
endif()
if(NOT is_embedded)
message(" exe_dotapp_dir/='${exe_dotapp_dir}/'")
message(" item_substring='${item_substring}'")
message(" resolved_embedded_item='${resolved_embedded_item}'")
message("")
message("Install or copy the item into the bundle before calling fixup_bundle.")
message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?")
message("")
message(FATAL_ERROR "cannot fixup an item that is not in the bundle...")
endif()
set(prereqs "")
get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}")
set(changes "")
foreach(pr ${prereqs})
# Each referenced item's key is "rkey" in the loop:
#
get_item_key("${pr}" rkey)
if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "")
set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}")
else()
message("warning: unexpected reference to '${pr}'")
endif()
endforeach()
if(BU_CHMOD_BUNDLE_ITEMS)
execute_process(COMMAND chmod u+w "${resolved_embedded_item}")
endif()
# Change this item's id and all of its references in one call
# to install_name_tool:
#
execute_process(COMMAND install_name_tool
${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}"
)
endfunction()
function(fixup_bundle app libs dirs)
message(STATUS "fixup_bundle")
message(STATUS " app='${app}'")
message(STATUS " libs='${libs}'")
message(STATUS " dirs='${dirs}'")
get_bundle_and_executable("${app}" bundle executable valid)
if(valid)
get_filename_component(exepath "${executable}" PATH)
message(STATUS "fixup_bundle: preparing...")
get_bundle_keys("${app}" "${libs}" "${dirs}" keys)
message(STATUS "fixup_bundle: copying...")
list(LENGTH keys n)
math(EXPR n ${n}*2)
set(i 0)
foreach(key ${keys})
math(EXPR i ${i}+1)
if(${${key}_COPYFLAG})
message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'")
else()
message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'")
endif()
set(show_status 0)
if(show_status)
message(STATUS "key='${key}'")
message(STATUS "item='${${key}_ITEM}'")
message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'")
message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'")
message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'")
message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'")
message(STATUS "copyflag='${${key}_COPYFLAG}'")
message(STATUS "")
endif()
if(${${key}_COPYFLAG})
set(item "${${key}_ITEM}")
if(item MATCHES "[^/]+\\.framework/")
copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}"
"${${key}_RESOLVED_EMBEDDED_ITEM}")
else()
copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}"
"${${key}_RESOLVED_EMBEDDED_ITEM}")
endif()
endif()
endforeach()
message(STATUS "fixup_bundle: fixing...")
foreach(key ${keys})
math(EXPR i ${i}+1)
if(APPLE)
message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'")
fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}")
else()
message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'")
endif()
endforeach()
message(STATUS "fixup_bundle: cleaning up...")
clear_bundle_keys(keys)
message(STATUS "fixup_bundle: verifying...")
verify_app("${app}")
else()
message(SEND_ERROR "error: fixup_bundle: not a valid bundle")
endif()
message(STATUS "fixup_bundle: done")
endfunction()
function(copy_and_fixup_bundle src dst libs dirs)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}")
fixup_bundle("${dst}" "${libs}" "${dirs}")
endfunction()
function(verify_bundle_prerequisites bundle result_var info_var)
set(result 1)
set(info "")
set(count 0)
get_bundle_main_executable("${bundle}" main_bundle_exe)
file(GLOB_RECURSE file_list "${bundle}/*")
foreach(f ${file_list})
is_file_executable("${f}" is_executable)
if(is_executable)
get_filename_component(exepath "${f}" PATH)
math(EXPR count "${count} + 1")
message(STATUS "executable file ${count}: ${f}")
set(prereqs "")
get_prerequisites("${f}" prereqs 1 1 "${exepath}" "")
# On the Mac,
# "embedded" and "system" prerequisites are fine... anything else means
# the bundle's prerequisites are not verified (i.e., the bundle is not
# really "standalone")
#
# On Windows (and others? Linux/Unix/...?)
# "local" and "system" prereqs are fine...
#
set(external_prereqs "")
foreach(p ${prereqs})
set(p_type "")
gp_file_type("${f}" "${p}" p_type)
if(APPLE)
if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system")
set(external_prereqs ${external_prereqs} "${p}")
endif()
else()
if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system")
set(external_prereqs ${external_prereqs} "${p}")
endif()
endif()
endforeach()
if(external_prereqs)
# Found non-system/somehow-unacceptable prerequisites:
set(result 0)
set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n")
endif()
endif()
endforeach()
if(result)
set(info "Verified ${count} executable files in '${bundle}'")
endif()
set(${result_var} "${result}" PARENT_SCOPE)
set(${info_var} "${info}" PARENT_SCOPE)
endfunction()
function(verify_bundle_symlinks bundle result_var info_var)
set(result 1)
set(info "")
set(count 0)
# TODO: implement this function for real...
# Right now, it is just a stub that verifies unconditionally...
set(${result_var} "${result}" PARENT_SCOPE)
set(${info_var} "${info}" PARENT_SCOPE)
endfunction()
function(verify_app app)
set(verified 0)
set(info "")
get_bundle_and_executable("${app}" bundle executable valid)
message(STATUS "===========================================================================")
message(STATUS "Analyzing app='${app}'")
message(STATUS "bundle='${bundle}'")
message(STATUS "executable='${executable}'")
message(STATUS "valid='${valid}'")
# Verify that the bundle does not have any "external" prerequisites:
#
verify_bundle_prerequisites("${bundle}" verified info)
message(STATUS "verified='${verified}'")
message(STATUS "info='${info}'")
message(STATUS "")
if(verified)
# Verify that the bundle does not have any symlinks to external files:
#
verify_bundle_symlinks("${bundle}" verified info)
message(STATUS "verified='${verified}'")
message(STATUS "info='${info}'")
message(STATUS "")
endif()
if(NOT verified)
message(FATAL_ERROR "error: verify_app failed")
endif()
endfunction()

100
cmake/ECMQueryQt.cmake Normal file
View File

@ -0,0 +1,100 @@
# SPDX-FileCopyrightText: 2014 Rohan Garg <rohan16garg@gmail.com>
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2014-2016 Aleix Pol <aleixpol@kde.org>
# SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
# SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samir78@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause
#[=======================================================================[.rst:
ECMQueryQt
---------------
This module can be used to query the installation paths used by Qt.
For Qt5 this uses ``qmake``, and for Qt6 this used ``qtpaths`` (the latter has built-in
support to query the paths of a target platform when cross-compiling).
This module defines the following function:
::
ecm_query_qt(<result_variable> <qt_variable> [TRY])
Passing ``TRY`` will result in the method not making the build fail if the executable
used for querying has not been found, but instead simply print a warning message and
return an empty string.
Example usage:
.. code-block:: cmake
include(ECMQueryQt)
ecm_query_qt(bin_dir QT_INSTALL_BINS)
If the call succeeds ``${bin_dir}`` will be set to ``<prefix>/path/to/bin/dir`` (e.g.
``/usr/lib64/qt/bin/``).
Since: 5.93
#]=======================================================================]
include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
include(CheckLanguage)
check_language(CXX)
if (CMAKE_CXX_COMPILER)
# Enable the CXX language to let CMake look for config files in library dirs.
# See: https://gitlab.kitware.com/cmake/cmake/-/issues/23266
enable_language(CXX)
endif()
if (QT_MAJOR_VERSION STREQUAL "5")
# QUIET to accommodate the TRY option
find_package(Qt${QT_MAJOR_VERSION}Core QUIET)
if(TARGET Qt5::qmake)
get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
set(QUERY_EXECUTABLE ${_qmake_executable_default}
CACHE FILEPATH "Location of the Qt5 qmake executable")
set(_exec_name_text "Qt5 qmake")
set(_cli_option "-query")
endif()
elseif(QT_MAJOR_VERSION STREQUAL "6")
# QUIET to accommodate the TRY option
find_package(Qt6 COMPONENTS CoreTools QUIET CONFIG)
if (TARGET Qt6::qtpaths)
get_target_property(_qtpaths_executable Qt6::qtpaths LOCATION)
set(QUERY_EXECUTABLE ${_qtpaths_executable}
CACHE FILEPATH "Location of the Qt6 qtpaths executable")
set(_exec_name_text "Qt6 qtpaths")
set(_cli_option "--query")
endif()
endif()
function(ecm_query_qt result_variable qt_variable)
set(options TRY)
set(oneValueArgs)
set(multiValueArgs)
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT QUERY_EXECUTABLE)
if(ARGS_TRY)
set(${result_variable} "" PARENT_SCOPE)
message(STATUS "No ${_exec_name_text} executable found. Can't check ${qt_variable}")
return()
else()
message(FATAL_ERROR "No ${_exec_name_text} executable found. Can't check ${qt_variable} as required")
endif()
endif()
execute_process(
COMMAND ${QUERY_EXECUTABLE} ${_cli_option} "${qt_variable}"
RESULT_VARIABLE return_code
OUTPUT_VARIABLE output
)
if(return_code EQUAL 0)
string(STRIP "${output}" output)
file(TO_CMAKE_PATH "${output}" output_path)
set(${result_variable} "${output_path}" PARENT_SCOPE)
else()
message(WARNING "Failed call: ${_command} \"${qt_variable}\"")
message(FATAL_ERROR "${_exec_name_text} call failed: ${return_code}")
endif()
endfunction()

View File

@ -3,7 +3,7 @@
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
#
# Returns the refspec and sha hash of the current head revision
#
@ -12,20 +12,33 @@
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the working tree (--dirty option),
# and adjusting the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# git_local_changes(<var>)
#
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
# Uses the return code of "git diff-index --quiet HEAD --".
# Does not regard untracked files.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Copyright 2009-2013, Iowa State University.
# Copyright 2013-2020, Ryan Pavlik
# Copyright 2013-2020, Contributors
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
@ -39,45 +52,124 @@ set(__get_git_revision_description YES)
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
function(get_git_head_revision _refspecvar _hashvar)
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
# Function _git_find_closest_git_dir finds the next closest .git directory
# that is part of any directory in the path defined by _start_dir.
# The result is returned in the parent scope variable whose name is passed
# as variable _git_dir_var. If no .git directory can be found, the
# function returns an empty string via _git_dir_var.
#
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
# neither foo nor bar contain a file/directory .git. This wil return
# C:/bla/.git
#
function(_git_find_closest_git_dir _start_dir _git_dir_var)
set(cur_dir "${_start_dir}")
set(git_dir "${_start_dir}/.git")
while(NOT EXISTS "${git_dir}")
# .git dir not found, search parent directories
set(git_previous_parent "${cur_dir}")
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
if(cur_dir STREQUAL git_previous_parent)
# We have reached the root directory, we are not in git
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_git_dir_var}
""
PARENT_SCOPE)
return()
endif()
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
set(git_dir "${cur_dir}/.git")
endwhile()
# check if this is a submodule
set(${_git_dir_var}
"${git_dir}"
PARENT_SCOPE)
endfunction()
function(get_git_head_revision _refspecvar _hashvar)
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
else()
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
endif()
if(NOT "${GIT_DIR}" STREQUAL "")
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
"${GIT_DIR}")
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
# We've gone above the CMake root dir.
set(GIT_DIR "")
endif()
endif()
if("${GIT_DIR}" STREQUAL "")
set(${_refspecvar}
"GITDIR-NOTFOUND"
PARENT_SCOPE)
set(${_hashvar}
"GITDIR-NOTFOUND"
PARENT_SCOPE)
return()
endif()
# Check if the current source dir is a git submodule or a worktree.
# In both cases .git is a file instead of a directory.
#
if(NOT IS_DIRECTORY ${GIT_DIR})
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
# The following git command will return a non empty string that
# points to the super project working tree if the current
# source dir is inside a git submodule.
# Otherwise the command will return an empty string.
#
execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse
--show-superproject-working-tree
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT "${out}" STREQUAL "")
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
${submodule})
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
ABSOLUTE)
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
else()
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
file(READ ${GIT_DIR} worktree_ref)
# The .git directory contains a path to the worktree information directory
# inside the parent git repo of the worktree.
#
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
${worktree_ref})
string(STRIP ${git_worktree_dir} git_worktree_dir)
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
endif()
else()
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${GIT_DIR}/HEAD")
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake"
@ONLY)
"${GIT_DATA}/grabRef.cmake" @ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
set(${_refspecvar}
"${HEAD_REF}"
PARENT_SCOPE)
set(${_hashvar}
"${HEAD_HASH}"
PARENT_SCOPE)
endfunction()
function(git_describe _var)
@ -86,45 +178,107 @@ function(git_describe _var)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
set(${_var}
"HEAD-HASH-NOTFOUND"
PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} "${out}" PARENT_SCOPE)
set(${_var}
"${out}"
PARENT_SCOPE)
endfunction()
function(git_describe_working_tree _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
if(NOT GIT_FOUND)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var}
"${out}"
PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
set(${_var}
"${out}"
PARENT_SCOPE)
endfunction()
function(git_local_changes _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var}
"HEAD-HASH-NOTFOUND"
PARENT_SCOPE)
return()
endif()
execute_process(
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(res EQUAL 0)
set(${_var}
"CLEAN"
PARENT_SCOPE)
else()
set(${_var}
"DIRTY"
PARENT_SCOPE)
endif()
endfunction()

View File

@ -8,10 +8,12 @@
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Copyright 2009-2012, Iowa State University
# Copyright 2011-2015, Contributors
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
# SPDX-License-Identifier: BSL-1.0
set(HEAD_HASH)
@ -19,23 +21,23 @@ file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
endif()
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()

View File

@ -1,902 +0,0 @@
# - Functions to analyze and list executable file prerequisites.
# This module provides functions to list the .dll, .dylib or .so
# files that an executable or shared library file depends on. (Its
# prerequisites.)
#
# It uses various tools to obtain the list of required shared library files:
# dumpbin (Windows)
# objdump (MinGW on Windows)
# ldd (Linux/Unix)
# otool (Mac OSX)
# The following functions are provided by this module:
# get_prerequisites
# list_prerequisites
# list_prerequisites_by_glob
# gp_append_unique
# is_file_executable
# gp_item_default_embedded_path
# (projects can override with gp_item_default_embedded_path_override)
# gp_resolve_item
# (projects can override with gp_resolve_item_override)
# gp_resolved_file_type
# (projects can override with gp_resolved_file_type_override)
# gp_file_type
# Requires CMake 2.6 or greater because it uses function, break, return and
# PARENT_SCOPE.
#
# GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
# <exepath> <dirs>)
# Get the list of shared library files required by <target>. The list in
# the variable named <prerequisites_var> should be empty on first entry to
# this function. On exit, <prerequisites_var> will contain the list of
# required shared library files.
#
# <target> is the full path to an executable file. <prerequisites_var> is the
# name of a CMake variable to contain the results. <exclude_system> must be 0
# or 1 indicating whether to include or exclude "system" prerequisites. If
# <recurse> is set to 1 all prerequisites will be found recursively, if set to
# 0 only direct prerequisites are listed. <exepath> is the path to the top
# level executable used for @executable_path replacment on the Mac. <dirs> is
# a list of paths where libraries might be found: these paths are searched
# first when a target without any path info is given. Then standard system
# locations are also searched: PATH, Framework locations, /usr/lib...
#
# LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]])
# Print a message listing the prerequisites of <target>.
#
# <target> is the name of a shared library or executable target or the full
# path to a shared library or executable file. If <recurse> is set to 1 all
# prerequisites will be found recursively, if set to 0 only direct
# prerequisites are listed. <exclude_system> must be 0 or 1 indicating whether
# to include or exclude "system" prerequisites. With <verbose> set to 0 only
# the full path names of the prerequisites are printed, set to 1 extra
# informatin will be displayed.
#
# LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>)
# Print the prerequisites of shared library and executable files matching a
# globbing pattern. <glob_arg> is GLOB or GLOB_RECURSE and <glob_exp> is a
# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve
# a list of matching files. If a matching file is executable, its prerequisites
# are listed.
#
# Any additional (optional) arguments provided are passed along as the
# optional arguments to the list_prerequisites calls.
#
# GP_APPEND_UNIQUE(<list_var> <value>)
# Append <value> to the list variable <list_var> only if the value is not
# already in the list.
#
# IS_FILE_EXECUTABLE(<file> <result_var>)
# Return 1 in <result_var> if <file> is a binary executable, 0 otherwise.
#
# GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>)
# Return the path that others should refer to the item by when the item
# is embedded inside a bundle.
#
# Override on a per-project basis by providing a project-specific
# gp_item_default_embedded_path_override function.
#
# GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>)
# Resolve an item into an existing full path file.
#
# Override on a per-project basis by providing a project-specific
# gp_resolve_item_override function.
#
# GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>)
# Return the type of <file> with respect to <original_file>. String
# describing type of prerequisite is returned in variable named <type_var>.
#
# Use <exepath> and <dirs> if necessary to resolve non-absolute <file>
# values -- but only for non-embedded items.
#
# Possible types are:
# system
# local
# embedded
# other
# Override on a per-project basis by providing a project-specific
# gp_resolved_file_type_override function.
#
# GP_FILE_TYPE(<original_file> <file> <type_var>)
# Return the type of <file> with respect to <original_file>. String
# describing type of prerequisite is returned in variable named <type_var>.
#
# Possible types are:
# system
# local
# embedded
# other
#=============================================================================
# Copyright 2008-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
function(gp_append_unique list_var value)
set(contains 0)
foreach(item ${${list_var}})
if("${item}" STREQUAL "${value}")
set(contains 1)
break()
endif()
endforeach()
if(NOT contains)
set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
endif()
endfunction()
function(is_file_executable file result_var)
#
# A file is not executable until proven otherwise:
#
set(${result_var} 0 PARENT_SCOPE)
get_filename_component(file_full "${file}" ABSOLUTE)
string(TOLOWER "${file_full}" file_full_lower)
# If file name ends in .exe on Windows, *assume* executable:
#
if(WIN32 AND NOT UNIX)
if("${file_full_lower}" MATCHES "\\.exe$")
set(${result_var} 1 PARENT_SCOPE)
return()
endif()
# A clause could be added here that uses output or return value of dumpbin
# to determine ${result_var}. In 99%+? practical cases, the exe name
# match will be sufficient...
#
endif()
# Use the information returned from the Unix shell command "file" to
# determine if ${file_full} should be considered an executable file...
#
# If the file command's output contains "executable" and does *not* contain
# "text" then it is likely an executable suitable for prerequisite analysis
# via the get_prerequisites macro.
#
if(UNIX)
if(NOT file_cmd)
find_program(file_cmd "file")
mark_as_advanced(file_cmd)
endif()
if(file_cmd)
execute_process(COMMAND "${file_cmd}" "${file_full}"
OUTPUT_VARIABLE file_ov
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Replace the name of the file in the output with a placeholder token
# (the string " _file_full_ ") so that just in case the path name of
# the file contains the word "text" or "executable" we are not fooled
# into thinking "the wrong thing" because the file name matches the
# other 'file' command output we are looking for...
#
string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
string(TOLOWER "${file_ov}" file_ov)
#message(STATUS "file_ov='${file_ov}'")
if("${file_ov}" MATCHES "executable")
#message(STATUS "executable!")
if("${file_ov}" MATCHES "text")
#message(STATUS "but text, so *not* a binary executable!")
else()
set(${result_var} 1 PARENT_SCOPE)
return()
endif()
endif()
# Also detect position independent executables on Linux,
# where "file" gives "shared object ... (uses shared libraries)"
if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)")
set(${result_var} 1 PARENT_SCOPE)
return()
endif()
# "file" version 5.22 does not print "(used shared libraries)"
# but uses "interpreter"
if("${file_ov}" MATCHES "shared object.*interpreter")
set(${result_var} 1 PARENT_SCOPE)
return()
endif()
else()
message(STATUS "warning: No 'file' command, skipping execute_process...")
endif()
endif()
endfunction()
function(gp_item_default_embedded_path item default_embedded_path_var)
# On Windows and Linux, "embed" prerequisites in the same directory
# as the executable by default:
#
set(path "@executable_path")
set(overridden 0)
# On the Mac, relative to the executable depending on the type
# of the thing we are embedding:
#
if(APPLE)
#
# The assumption here is that all executables in the bundle will be
# in same-level-directories inside the bundle. The parent directory
# of an executable inside the bundle should be MacOS or a sibling of
# MacOS and all embedded paths returned from here will begin with
# "@executable_path/../" and will work from all executables in all
# such same-level-directories inside the bundle.
#
# By default, embed things right next to the main bundle executable:
#
set(path "@executable_path/../../Contents/MacOS")
# Embed .dylibs right next to the main bundle executable:
#
if(item MATCHES "\\.dylib$")
set(path "@executable_path/../MacOS")
set(overridden 1)
endif()
# Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS):
#
if(NOT overridden)
if(item MATCHES "[^/]+\\.framework/")
set(path "@executable_path/../Frameworks")
set(overridden 1)
endif()
endif()
endif()
# Provide a hook so that projects can override the default embedded location
# of any given library by whatever logic they choose:
#
if(COMMAND gp_item_default_embedded_path_override)
gp_item_default_embedded_path_override("${item}" path)
endif()
set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
endfunction()
function(gp_resolve_item context item exepath dirs resolved_item_var)
set(resolved 0)
set(resolved_item "${item}")
# Is it already resolved?
#
if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
set(resolved 1)
endif()
if(NOT resolved)
if(item MATCHES "@executable_path")
#
# @executable_path references are assumed relative to exepath
#
string(REPLACE "@executable_path" "${exepath}" ri "${item}")
get_filename_component(ri "${ri}" ABSOLUTE)
if(EXISTS "${ri}")
#message(STATUS "info: embedded item exists (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
else()
message(STATUS "warning: embedded item does not exist '${ri}'")
endif()
endif()
endif()
if(NOT resolved)
if(item MATCHES "@loader_path")
#
# @loader_path references are assumed relative to the
# PATH of the given "context" (presumably another library)
#
get_filename_component(contextpath "${context}" PATH)
string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
get_filename_component(ri "${ri}" ABSOLUTE)
if(EXISTS "${ri}")
#message(STATUS "info: embedded item exists (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
else()
message(STATUS "warning: embedded item does not exist '${ri}'")
endif()
endif()
endif()
if(NOT resolved)
if(item MATCHES "@rpath")
#
# @rpath references are relative to the paths built into the binaries with -rpath
# We handle this case like we do for other Unixes
#
string(REPLACE "@rpath/" "" norpath_item "${item}")
set(ri "ri-NOTFOUND")
find_file(ri "${norpath_item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
if(ri)
#message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
set(ri "ri-NOTFOUND")
endif()
endif()
endif()
if(NOT resolved)
set(ri "ri-NOTFOUND")
find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
if(ri)
#message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
set(ri "ri-NOTFOUND")
endif()
endif()
if(NOT resolved)
if(item MATCHES "[^/]+\\.framework/")
set(fw "fw-NOTFOUND")
find_file(fw "${item}"
"~/Library/Frameworks"
"/Library/Frameworks"
"/System/Library/Frameworks"
)
if(fw)
#message(STATUS "info: 'find_file' found framework (${fw})")
set(resolved 1)
set(resolved_item "${fw}")
set(fw "fw-NOTFOUND")
endif()
endif()
endif()
# Using find_program on Windows will find dll files that are in the PATH.
# (Converting simple file names into full path names if found.)
#
if(WIN32 AND NOT UNIX)
if(NOT resolved)
set(ri "ri-NOTFOUND")
find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH)
find_program(ri "${item}" PATHS "${exepath};${dirs}")
if(ri)
#message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
set(ri "ri-NOTFOUND")
endif()
endif()
endif()
# Provide a hook so that projects can override item resolution
# by whatever logic they choose:
#
if(COMMAND gp_resolve_item_override)
gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
endif()
if(NOT resolved)
message(STATUS "
warning: cannot resolve item '${item}'
possible problems:
need more directories?
need to use InstallRequiredSystemLibraries?
run in install tree instead of build tree?
")
# message(STATUS "
#******************************************************************************
#warning: cannot resolve item '${item}'
#
# possible problems:
# need more directories?
# need to use InstallRequiredSystemLibraries?
# run in install tree instead of build tree?
#
# context='${context}'
# item='${item}'
# exepath='${exepath}'
# dirs='${dirs}'
# resolved_item_var='${resolved_item_var}'
#******************************************************************************
#")
endif()
set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
endfunction()
function(gp_resolved_file_type original_file file exepath dirs type_var)
#message(STATUS "**")
if(NOT IS_ABSOLUTE "${original_file}")
message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
endif()
set(is_embedded 0)
set(is_local 0)
set(is_system 0)
set(resolved_file "${file}")
if("${file}" MATCHES "^@(executable|loader)_path")
set(is_embedded 1)
endif()
if(NOT is_embedded)
if(NOT IS_ABSOLUTE "${file}")
gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file)
endif()
string(TOLOWER "${original_file}" original_lower)
string(TOLOWER "${resolved_file}" lower)
if(UNIX)
if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
set(is_system 1)
endif()
endif()
if(APPLE)
if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
set(is_system 1)
endif()
endif()
if(WIN32)
string(TOLOWER "$ENV{SystemRoot}" sysroot)
string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}")
string(TOLOWER "$ENV{windir}" windir)
string(REGEX REPLACE "\\\\" "/" windir "${windir}")
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
set(is_system 1)
endif()
if(UNIX)
# if cygwin, we can get the properly formed windows paths from cygpath
find_program(CYGPATH_EXECUTABLE cygpath)
if(CYGPATH_EXECUTABLE)
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W
OUTPUT_VARIABLE env_windir
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S
OUTPUT_VARIABLE env_sysdir
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(TOLOWER "${env_windir}" windir)
string(TOLOWER "${env_sysdir}" sysroot)
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
set(is_system 1)
endif()
endif()
endif()
endif()
if(NOT is_system)
get_filename_component(original_path "${original_lower}" PATH)
get_filename_component(path "${lower}" PATH)
if("${original_path}" STREQUAL "${path}")
set(is_local 1)
else()
string(LENGTH "${original_path}/" original_length)
string(LENGTH "${lower}" path_length)
if(${path_length} GREATER ${original_length})
string(SUBSTRING "${lower}" 0 ${original_length} path)
if("${original_path}/" STREQUAL "${path}")
set(is_embedded 1)
endif()
endif()
endif()
endif()
endif()
# Return type string based on computed booleans:
#
set(type "other")
if(is_system)
set(type "system")
elseif(is_embedded)
set(type "embedded")
elseif(is_local)
set(type "local")
endif()
#message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
#message(STATUS " type: '${type}'")
if(NOT is_embedded)
if(NOT IS_ABSOLUTE "${resolved_file}")
if(lower MATCHES "^msvc[^/]+dll" AND is_system)
message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
else()
message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
endif()
endif()
endif()
# Provide a hook so that projects can override the decision on whether a
# library belongs to the system or not by whatever logic they choose:
#
if(COMMAND gp_resolved_file_type_override)
gp_resolved_file_type_override("${resolved_file}" type)
endif()
set(${type_var} "${type}" PARENT_SCOPE)
#message(STATUS "**")
endfunction()
function(gp_file_type original_file file type_var)
if(NOT IS_ABSOLUTE "${original_file}")
message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
endif()
get_filename_component(exepath "${original_file}" PATH)
set(type "")
gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
set(${type_var} "${type}" PARENT_SCOPE)
endfunction()
function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
set(verbose 0)
set(eol_char "E")
if(NOT IS_ABSOLUTE "${target}")
message("warning: target '${target}' is not absolute...")
endif()
if(NOT EXISTS "${target}")
message("warning: target '${target}' does not exist...")
endif()
set(gp_cmd_paths ${gp_cmd_paths}
"C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
"C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
"C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
"C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
"C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
"C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
"/usr/local/bin"
"/usr/bin"
)
# <setup-gp_tool-vars>
#
# Try to choose the right tool by default. Caller can set gp_tool prior to
# calling this function to force using a different tool.
#
if("${gp_tool}" STREQUAL "")
set(gp_tool "ldd")
if(APPLE)
set(gp_tool "otool")
endif()
if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har!
find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths})
if(gp_dumpbin)
set(gp_tool "dumpbin")
else() # Try harder. Maybe we're on MinGW
set(gp_tool "objdump")
endif()
endif()
endif()
find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
if(NOT gp_cmd)
message(FATAL_ERROR "FATAL ERROR: could not find '${gp_tool}' - cannot analyze prerequisites!")
return()
endif()
set(gp_tool_known 0)
if("${gp_tool}" STREQUAL "ldd")
set(gp_cmd_args "")
set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$")
set(gp_regex_error "not found${eol_char}$")
set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$")
set(gp_regex_cmp_count 1)
set(gp_tool_known 1)
endif()
if("${gp_tool}" STREQUAL "otool")
set(gp_cmd_args "-L")
set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
set(gp_regex_error "")
set(gp_regex_fallback "")
set(gp_regex_cmp_count 3)
set(gp_tool_known 1)
endif()
if("${gp_tool}" STREQUAL "dumpbin")
set(gp_cmd_args "/dependents")
set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
set(gp_regex_error "")
set(gp_regex_fallback "")
set(gp_regex_cmp_count 1)
set(gp_tool_known 1)
endif()
if("${gp_tool}" STREQUAL "objdump")
set(gp_cmd_args "-p")
set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$")
set(gp_regex_error "")
set(gp_regex_fallback "")
set(gp_regex_cmp_count 1)
set(gp_tool_known 1)
endif()
if(NOT gp_tool_known)
message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.")
return()
endif()
if("${gp_tool}" STREQUAL "dumpbin")
# When running dumpbin, it also needs the "Common7/IDE" directory in the
# PATH. It will already be in the PATH if being run from a Visual Studio
# command prompt. Add it to the PATH here in case we are running from a
# different command prompt.
#
get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
# Use cmake paths as a user may have a PATH element ending with a backslash.
# This will escape the list delimiter and create havoc!
if(EXISTS "${gp_cmd_dlls_dir}")
# only add to the path if it is not already in the path
set(gp_found_cmd_dlls_dir 0)
file(TO_CMAKE_PATH "$ENV{PATH}" env_path)
foreach(gp_env_path_element ${env_path})
if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}")
set(gp_found_cmd_dlls_dir 1)
endif()
endforeach()
if(NOT gp_found_cmd_dlls_dir)
file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir)
set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
endif()
endif()
endif()
#
# </setup-gp_tool-vars>
if("${gp_tool}" STREQUAL "ldd")
set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
foreach(dir ${exepath} ${dirs})
set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}")
endforeach()
endif()
# Track new prerequisites at each new level of recursion. Start with an
# empty list at each level:
#
set(unseen_prereqs)
# Run gp_cmd on the target:
#
execute_process(
COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
OUTPUT_VARIABLE gp_cmd_ov
)
if("${gp_tool}" STREQUAL "ldd")
set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
endif()
if(verbose)
message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
message(STATUS "</RawOutput>")
endif()
get_filename_component(target_dir "${target}" PATH)
# Convert to a list of lines:
#
string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}")
string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}")
# check for install id and remove it from list, since otool -L can include a
# reference to itself
set(gp_install_id)
if("${gp_tool}" STREQUAL "otool")
execute_process(
COMMAND otool -D ${target}
OUTPUT_VARIABLE gp_install_id_ov
)
# second line is install name
string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
if(gp_install_id)
# trim
string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}")
#message("INSTALL ID is \"${gp_install_id}\"")
endif()
endif()
# Analyze each line for file names that match the regular expression:
#
foreach(candidate ${candidates})
if("${candidate}" MATCHES "${gp_regex}")
# Extract information from each candidate:
if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}")
string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}")
else()
string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
endif()
if(gp_regex_cmp_count GREATER 1)
string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
endif()
if(gp_regex_cmp_count GREATER 2)
string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
endif()
# Use the raw_item as the list entries returned by this function. Use the
# gp_resolve_item function to resolve it to an actual full path file if
# necessary.
#
set(item "${raw_item}")
# Add each item unless it is excluded:
#
set(add_item 1)
if("${item}" STREQUAL "${gp_install_id}")
set(add_item 0)
endif()
if(add_item AND ${exclude_system})
set(type "")
gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type)
if("${type}" STREQUAL "system")
set(add_item 0)
endif()
endif()
if(add_item)
list(LENGTH ${prerequisites_var} list_length_before_append)
gp_append_unique(${prerequisites_var} "${item}")
list(LENGTH ${prerequisites_var} list_length_after_append)
if(${recurse})
# If item was really added, this is the first time we have seen it.
# Add it to unseen_prereqs so that we can recursively add *its*
# prerequisites...
#
# But first: resolve its name to an absolute full path name such
# that the analysis tools can simply accept it as input.
#
if(NOT list_length_before_append EQUAL list_length_after_append)
gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item)
set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
endif()
endif()
endif()
else()
if(verbose)
message(STATUS "ignoring non-matching line: '${candidate}'")
endif()
endif()
endforeach()
list(LENGTH ${prerequisites_var} prerequisites_var_length)
if(prerequisites_var_length GREATER 0)
list(SORT ${prerequisites_var})
endif()
if(${recurse})
set(more_inputs ${unseen_prereqs})
foreach(input ${more_inputs})
get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}")
endforeach()
endif()
set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
endfunction()
function(list_prerequisites target)
if("${ARGV1}" STREQUAL "")
set(all 1)
else()
set(all "${ARGV1}")
endif()
if("${ARGV2}" STREQUAL "")
set(exclude_system 0)
else()
set(exclude_system "${ARGV2}")
endif()
if("${ARGV3}" STREQUAL "")
set(verbose 0)
else()
set(verbose "${ARGV3}")
endif()
set(count 0)
set(count_str "")
set(print_count "${verbose}")
set(print_prerequisite_type "${verbose}")
set(print_target "${verbose}")
set(type_str "")
get_filename_component(exepath "${target}" PATH)
set(prereqs "")
get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
if(print_target)
message(STATUS "File '${target}' depends on:")
endif()
foreach(d ${prereqs})
math(EXPR count "${count} + 1")
if(print_count)
set(count_str "${count}. ")
endif()
if(print_prerequisite_type)
gp_file_type("${target}" "${d}" type)
set(type_str " (${type})")
endif()
message(STATUS "${count_str}${d}${type_str}")
endforeach()
endfunction()
function(list_prerequisites_by_glob glob_arg glob_exp)
message(STATUS "=============================================================================")
message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
message(STATUS "")
file(${glob_arg} file_list ${glob_exp})
foreach(f ${file_list})
is_file_executable("${f}" is_f_executable)
if(is_f_executable)
message(STATUS "=============================================================================")
list_prerequisites("${f}" ${ARGN})
message(STATUS "")
endif()
endforeach()
endfunction()

View File

@ -2,10 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSCameraUsageDescription</key>
<string>A Minecraft mod wants to access your camera.</string>
<key>NSMicrophoneUsageDescription</key>
<string>A Minecraft mod wants to access your microphone.</string>
<key>NSCameraUsageDescription</key>
<string>A Minecraft mod wants to access your camera.</string>
<key>NSMicrophoneUsageDescription</key>
<string>A Minecraft mod wants to access your microphone.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
@ -40,5 +40,9 @@
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>SUPublicEDKey</key>
<string>${MACOSX_SPARKLE_UPDATE_PUBLIC_KEY}</string>
<key>SUFeedURL</key>
<string>${MACOSX_SPARKLE_UPDATE_FEED_URL}</string>
</dict>
</plist>

View File

@ -1,14 +0,0 @@
if(__QMAKEQUERY_CMAKE__)
return()
endif()
set(__QMAKEQUERY_CMAKE__ TRUE)
get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION)
function(QUERY_QMAKE VAR RESULT)
exec_program(${QMAKE_EXECUTABLE} ARGS "-query ${VAR}" RETURN_VALUE return_code OUTPUT_VARIABLE output )
if(NOT return_code)
file(TO_CMAKE_PATH "${output}" output)
set(${RESULT} ${output} PARENT_SCOPE)
endif(NOT return_code)
endfunction(QUERY_QMAKE)

View File

@ -0,0 +1,38 @@
#.rst:
# QtVersionOption
# ---------------
#
# Adds a build option to select the major Qt version if necessary,
# that is, if the major Qt version has not yet been determined otherwise
# (e.g. by a corresponding find_package() call).
#
# This module is typically included by other modules requiring knowledge
# about the major Qt version.
#
# ``QT_MAJOR_VERSION`` is defined to either be "5" or "6".
#
#
# Since 5.82.0.
#=============================================================================
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
if (DEFINED QT_MAJOR_VERSION)
return()
endif()
if (TARGET Qt5::Core)
set(QT_MAJOR_VERSION 5)
elseif (TARGET Qt6::Core)
set(QT_MAJOR_VERSION 6)
else()
option(BUILD_WITH_QT6 "Build against Qt 6" OFF)
if (BUILD_WITH_QT6)
set(QT_MAJOR_VERSION 6)
else()
set(QT_MAJOR_VERSION 5)
endif()
endif()

View File

@ -0,0 +1,97 @@
#=============================================================================
# Copyright 2005-2011 Kitware, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the name of Kitware, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
# From Qt5CoreMacros.cmake
function(qt_generate_moc)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_generate_moc(${ARGV})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_generate_moc(${ARGV})
endif()
endfunction()
function(qt_wrap_cpp outfiles)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_wrap_cpp("${outfiles}" ${ARGN})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_wrap_cpp("${outfiles}" ${ARGN})
endif()
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()
function(qt_add_binary_resources)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_add_binary_resources(${ARGV})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_add_binary_resources(${ARGV})
endif()
endfunction()
function(qt_add_resources outfiles)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_add_resources("${outfiles}" ${ARGN})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_add_resources("${outfiles}" ${ARGN})
endif()
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()
function(qt_add_big_resources outfiles)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_add_big_resources(${outfiles} ${ARGN})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_add_big_resources(${outfiles} ${ARGN})
endif()
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()
function(qt_import_plugins)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_import_plugins(${ARGV})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_import_plugins(${ARGV})
endif()
endfunction()
# From Qt5WidgetsMacros.cmake
function(qt_wrap_ui outfiles)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_wrap_ui("${outfiles}" ${ARGN})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_wrap_ui("${outfiles}" ${ARGN})
endif()
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()

View File

@ -1,50 +0,0 @@
find_package(Qt5Test REQUIRED)
set(TEST_RESOURCE_PATH ${CMAKE_CURRENT_LIST_DIR})
message(${TEST_RESOURCE_PATH})
function(add_unit_test name)
if(BUILD_TESTING)
set(options "")
set(oneValueArgs DATA)
set(multiValueArgs SOURCES LIBS)
cmake_parse_arguments(OPT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
if(WIN32)
add_executable(${name}_test ${OPT_SOURCES} ${TEST_RESOURCE_PATH}/UnitTest/test.rc)
else()
add_executable(${name}_test ${OPT_SOURCES})
endif()
if(NOT "${OPT_DATA}" STREQUAL "")
set(TEST_DATA_PATH "${CMAKE_CURRENT_BINARY_DIR}/data")
set(TEST_DATA_PATH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${OPT_DATA}")
message("From ${TEST_DATA_PATH_SRC} to ${TEST_DATA_PATH}")
string(REGEX REPLACE "[/\\:]" "_" DATA_TARGET_NAME "${TEST_DATA_PATH_SRC}")
if(UNIX)
# on unix we get the third / from the filename
set(TEST_DATA_URL "file://${TEST_DATA_PATH}")
else()
# we don't on windows, so we have to add it ourselves
set(TEST_DATA_URL "file:///${TEST_DATA_PATH}")
endif()
if(NOT TARGET "${DATA_TARGET_NAME}")
add_custom_target(${DATA_TARGET_NAME})
add_dependencies(${name}_test ${DATA_TARGET_NAME})
add_custom_command(
TARGET ${DATA_TARGET_NAME}
COMMAND ${CMAKE_COMMAND} "-DTEST_DATA_URL=${TEST_DATA_URL}" -DSOURCE=${TEST_DATA_PATH_SRC} -DDESTINATION=${TEST_DATA_PATH} -P ${TEST_RESOURCE_PATH}/UnitTest/generate_test_data.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
endif()
endif()
target_link_libraries(${name}_test Qt5::Test ${OPT_LIBS})
target_include_directories(${name}_test PRIVATE "${TEST_RESOURCE_PATH}/UnitTest/")
add_test(NAME ${name} COMMAND ${name}_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
endfunction()

View File

@ -1,28 +0,0 @@
#pragma once
#include <QFile>
#include <QCoreApplication>
#include <QTest>
#include <QDir>
#define expandstr(s) expandstr2(s)
#define expandstr2(s) #s
class TestsInternal
{
public:
static QByteArray readFile(const QString &fileName)
{
QFile f(fileName);
f.open(QFile::ReadOnly);
return f.readAll();
}
static QString readFileUtf8(const QString &fileName)
{
return QString::fromUtf8(readFile(fileName));
}
};
#define GET_TEST_FILE(file) TestsInternal::readFile(QFINDTESTDATA(file))
#define GET_TEST_FILE_UTF8(file) TestsInternal::readFileUtf8(QFINDTESTDATA(file))

View File

@ -1,23 +0,0 @@
# Copy files from source directory to destination directory, substituting any
# variables. Create destination directory if it does not exist.
function(configure_files srcDir destDir)
make_directory(${destDir})
file(GLOB templateFiles RELATIVE ${srcDir} ${srcDir}/*)
foreach(templateFile ${templateFiles})
set(srcTemplatePath ${srcDir}/${templateFile})
if(NOT IS_DIRECTORY ${srcTemplatePath})
configure_file(
${srcTemplatePath}
${destDir}/${templateFile}
@ONLY
NEWLINE_STYLE LF
)
else()
configure_files("${srcTemplatePath}" "${destDir}/${templateFile}")
endif()
endforeach()
endfunction()
configure_files(${SOURCE} ${DESTINATION})

View File

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity name="Launcher.Test.0" type="win32" version="5.0.0.0" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
<description>Custom Minecraft launcher for managing multiple installs.</description>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--The ID below indicates app support for Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!--The ID below indicates app support for Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!--The ID below indicates app support for Windows Developer Preview / Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
</assembly>

View File

@ -1,28 +0,0 @@
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
1 RT_MANIFEST "test.manifest"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000004b0"
BEGIN
VALUE "CompanyName", "MultiMC & PolyMC Contributors"
VALUE "FileDescription", "Testcase"
VALUE "FileVersion", "1.0.0.0"
VALUE "ProductName", "Launcher Testcase"
VALUE "ProductVersion", "5"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0000, 0x04b0 // Unicode
END
END

View File

@ -1,881 +0,0 @@
# - Use Module for Java
# This file provides functions for Java. It is assumed that FindJava.cmake
# has already been loaded. See FindJava.cmake for information on how to
# load Java into your CMake project.
#
# add_jar(TARGET_NAME SRC1 SRC2 .. SRCN RCS1 RCS2 .. RCSN)
#
# This command creates a <TARGET_NAME>.jar. It compiles the given source
# files (SRC) and adds the given resource files (RCS) to the jar file.
# If only resource files are given then just a jar file is created.
#
# Additional instructions:
# To add compile flags to the target you can set these flags with
# the following variable:
#
# set(CMAKE_JAVA_COMPILE_FLAGS -nowarn)
#
# To add a path or a jar file to the class path you can do this
# with the CMAKE_JAVA_INCLUDE_PATH variable.
#
# set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar)
#
# To use a different output name for the target you can set it with:
#
# set(CMAKE_JAVA_TARGET_OUTPUT_NAME shibboleet.jar)
# add_jar(foobar foobar.java)
#
# To use a different output directory than CMAKE_CURRENT_BINARY_DIR
# you can set it with:
#
# set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin)
#
# To define an entry point in your jar you can set it with:
#
# set(CMAKE_JAVA_JAR_ENTRY_POINT com/examples/MyProject/Main)
#
# To add a VERSION to the target output name you can set it using
# CMAKE_JAVA_TARGET_VERSION. This will create a jar file with the name
# shibboleet-1.0.0.jar and will create a symlink shibboleet.jar
# pointing to the jar with the version information.
#
# set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
# add_jar(shibboleet shibbotleet.java)
#
# If the target is a JNI library, utilize the following commands to
# create a JNI symbolic link:
#
# set(CMAKE_JNI_TARGET TRUE)
# set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
# add_jar(shibboleet shibbotleet.java)
# install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet)
# install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR})
#
# If a single target needs to produce more than one jar from its
# java source code, to prevent the accumulation of duplicate class
# files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior
# to calling the add_jar() function:
#
# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo)
# add_jar(foo foo.java)
#
# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar)
# add_jar(bar bar.java)
#
# Target Properties:
# The add_jar() functions sets some target properties. You can get these
# properties with the
# get_property(TARGET <target_name> PROPERTY <propery_name>)
# command.
#
# INSTALL_FILES The files which should be installed. This is used by
# install_jar().
# JNI_SYMLINK The JNI symlink which should be installed.
# This is used by install_jni_symlink().
# JAR_FILE The location of the jar file so that you can include
# it.
# CLASS_DIR The directory where the class files can be found. For
# example to use them with javah.
#
# find_jar(<VAR>
# name | NAMES name1 [name2 ...]
# [PATHS path1 [path2 ... ENV var]]
# [VERSIONS version1 [version2]]
# [DOC "cache documentation string"]
# )
#
# This command is used to find a full path to the named jar. A cache
# entry named by <VAR> is created to stor the result of this command. If
# the full path to a jar is found the result is stored in the variable
# and the search will not repeated unless the variable is cleared. If
# nothing is found, the result will be <VAR>-NOTFOUND, and the search
# will be attempted again next time find_jar is invoked with the same
# variable.
# The name of the full path to a file that is searched for is specified
# by the names listed after NAMES argument. Additional search locations
# can be specified after the PATHS argument. If you require special a
# version of a jar file you can specify it with the VERSIONS argument.
# The argument after DOC will be used for the documentation string in
# the cache.
#
# install_jar(TARGET_NAME DESTINATION)
#
# This command installs the TARGET_NAME files to the given DESTINATION.
# It should be called in the same scope as add_jar() or it will fail.
#
# install_jni_symlink(TARGET_NAME DESTINATION)
#
# This command installs the TARGET_NAME JNI symlinks to the given
# DESTINATION. It should be called in the same scope as add_jar()
# or it will fail.
#
# create_javadoc(<VAR>
# PACKAGES pkg1 [pkg2 ...]
# [SOURCEPATH <sourcepath>]
# [CLASSPATH <classpath>]
# [INSTALLPATH <install path>]
# [DOCTITLE "the documentation title"]
# [WINDOWTITLE "the title of the document"]
# [AUTHOR TRUE|FALSE]
# [USE TRUE|FALSE]
# [VERSION TRUE|FALSE]
# )
#
# Create java documentation based on files or packages. For more
# details please read the javadoc manpage.
#
# There are two main signatures for create_javadoc. The first
# signature works with package names on a path with source files:
#
# Example:
# create_javadoc(my_example_doc
# PACKAGES com.exmaple.foo com.example.bar
# SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}"
# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
# WINDOWTITLE "My example"
# DOCTITLE "<h1>My example</h1>"
# AUTHOR TRUE
# USE TRUE
# VERSION TRUE
# )
#
# The second signature for create_javadoc works on a given list of
# files.
#
# create_javadoc(<VAR>
# FILES file1 [file2 ...]
# [CLASSPATH <classpath>]
# [INSTALLPATH <install path>]
# [DOCTITLE "the documentation title"]
# [WINDOWTITLE "the title of the document"]
# [AUTHOR TRUE|FALSE]
# [USE TRUE|FALSE]
# [VERSION TRUE|FALSE]
# )
#
# Example:
# create_javadoc(my_example_doc
# FILES ${example_SRCS}
# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
# WINDOWTITLE "My example"
# DOCTITLE "<h1>My example</h1>"
# AUTHOR TRUE
# USE TRUE
# VERSION TRUE
# )
#
# Both signatures share most of the options. These options are the
# same as what you can find in the javadoc manpage. Please look at
# the manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and
# VERSION.
#
# The documentation will be by default installed to
#
# ${CMAKE_INSTALL_PREFIX}/share/javadoc/<VAR>
#
# if you don't set the INSTALLPATH.
#
#=============================================================================
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
# Copyright 2010 Ben Boeckel <ben.boeckel@kitware.com>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
function (__java_copy_file src dest comment)
add_custom_command(
OUTPUT ${dest}
COMMAND cmake -E copy_if_different
ARGS ${src}
${dest}
DEPENDS ${src}
COMMENT ${comment})
endfunction (__java_copy_file src dest comment)
# define helper scripts
set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake)
set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake)
function(add_jar _TARGET_NAME)
set(_JAVA_SOURCE_FILES ${ARGN})
if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif(NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
if (CMAKE_JAVA_JAR_ENTRY_POINT)
set(_ENTRY_POINT_OPTION e)
set(_ENTRY_POINT_VALUE ${CMAKE_JAVA_JAR_ENTRY_POINT})
endif (CMAKE_JAVA_JAR_ENTRY_POINT)
if (LIBRARY_OUTPUT_PATH)
set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH})
else (LIBRARY_OUTPUT_PATH)
set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR})
endif (LIBRARY_OUTPUT_PATH)
set(CMAKE_JAVA_INCLUDE_PATH
${CMAKE_JAVA_INCLUDE_PATH}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_JAVA_OBJECT_OUTPUT_PATH}
${CMAKE_JAVA_LIBRARY_OUTPUT_PATH}
)
if (WIN32 AND NOT CYGWIN AND NOT CMAKE_CROSSCOMPILING)
set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";")
else ()
set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":")
endif()
foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH})
set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}")
endforeach(JAVA_INCLUDE_DIR)
set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir")
set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar")
if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION)
set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
elseif (CMAKE_JAVA_TARGET_VERSION)
set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar")
elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME)
set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
endif (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION)
# reset
set(CMAKE_JAVA_TARGET_OUTPUT_NAME)
set(_JAVA_CLASS_FILES)
set(_JAVA_COMPILE_FILES)
set(_JAVA_DEPENDS)
set(_JAVA_RESOURCE_FILES)
foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES})
get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT)
get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE)
get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH)
get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE)
file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR} ${_JAVA_FULL})
file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL})
string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN)
string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN)
if (${_BIN_LEN} LESS ${_SRC_LEN})
set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH})
else (${_BIN_LEN} LESS ${_SRC_LEN})
set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH})
endif (${_BIN_LEN} LESS ${_SRC_LEN})
get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH)
if (_JAVA_EXT MATCHES ".java")
list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE})
set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class")
set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE})
elseif (_JAVA_EXT MATCHES ".jar"
OR _JAVA_EXT MATCHES ".war"
OR _JAVA_EXT MATCHES ".ear"
OR _JAVA_EXT MATCHES ".sar")
list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_SOURCE_FILE})
elseif (_JAVA_EXT STREQUAL "")
list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH})
list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}})
else (_JAVA_EXT MATCHES ".java")
__java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE}
${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE}
"Copying ${_JAVA_SOURCE_FILE} to the build directory")
list(APPEND _JAVA_RESOURCE_FILES ${_JAVA_SOURCE_FILE})
endif (_JAVA_EXT MATCHES ".java")
endforeach(_JAVA_SOURCE_FILE)
# create an empty java_class_filelist
if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist)
file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "")
endif()
if (_JAVA_COMPILE_FILES)
# Compile the java files and create a list of class files
add_custom_command(
# NOTE: this command generates an artificial dependency file
OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
COMMAND ${Java_JAVAC_EXECUTABLE}
${CMAKE_JAVA_COMPILE_FLAGS}
-classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}"
-d ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
${_JAVA_COMPILE_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
DEPENDS ${_JAVA_COMPILE_FILES}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Building Java objects for ${_TARGET_NAME}.jar"
)
add_custom_command(
OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
COMMAND ${CMAKE_COMMAND}
-DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
-DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}"
-P ${_JAVA_CLASS_FILELIST_SCRIPT}
DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
endif (_JAVA_COMPILE_FILES)
# create the jar file
set(_JAVA_JAR_OUTPUT_PATH
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME})
if (CMAKE_JNI_TARGET)
add_custom_command(
OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
COMMAND ${Java_JAR_EXECUTABLE}
-cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
${_JAVA_RESOURCE_FILES} @java_class_filelist
COMMAND ${CMAKE_COMMAND}
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
-P ${_JAVA_SYMLINK_SCRIPT}
COMMAND ${CMAKE_COMMAND}
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH}
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
-P ${_JAVA_SYMLINK_SCRIPT}
DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
)
else ()
add_custom_command(
OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
COMMAND ${Java_JAR_EXECUTABLE}
-cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
${_JAVA_RESOURCE_FILES} @java_class_filelist
COMMAND ${CMAKE_COMMAND}
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
-P ${_JAVA_SYMLINK_SCRIPT}
WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
)
endif (CMAKE_JNI_TARGET)
# Add the target and make sure we have the latest resource files.
add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH})
set_property(
TARGET
${_TARGET_NAME}
PROPERTY
INSTALL_FILES
${_JAVA_JAR_OUTPUT_PATH}
)
if (_JAVA_TARGET_OUTPUT_LINK)
set_property(
TARGET
${_TARGET_NAME}
PROPERTY
INSTALL_FILES
${_JAVA_JAR_OUTPUT_PATH}
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
)
if (CMAKE_JNI_TARGET)
set_property(
TARGET
${_TARGET_NAME}
PROPERTY
JNI_SYMLINK
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
)
endif (CMAKE_JNI_TARGET)
endif (_JAVA_TARGET_OUTPUT_LINK)
set_property(
TARGET
${_TARGET_NAME}
PROPERTY
JAR_FILE
${_JAVA_JAR_OUTPUT_PATH}
)
set_property(
TARGET
${_TARGET_NAME}
PROPERTY
CLASSDIR
${CMAKE_JAVA_CLASS_OUTPUT_PATH}
)
endfunction(add_jar)
function(INSTALL_JAR _TARGET_NAME _DESTINATION)
get_property(__FILES
TARGET
${_TARGET_NAME}
PROPERTY
INSTALL_FILES
)
if (__FILES)
install(
FILES
${__FILES}
DESTINATION
${_DESTINATION}
)
else (__FILES)
message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
endif (__FILES)
endfunction(INSTALL_JAR _TARGET_NAME _DESTINATION)
function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
get_property(__SYMLINK
TARGET
${_TARGET_NAME}
PROPERTY
JNI_SYMLINK
)
if (__SYMLINK)
install(
FILES
${__SYMLINK}
DESTINATION
${_DESTINATION}
)
else (__SYMLINK)
message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
endif (__SYMLINK)
endfunction(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
function (find_jar VARIABLE)
set(_jar_names)
set(_jar_files)
set(_jar_versions)
set(_jar_paths
/usr/share/java/
/usr/local/share/java/
${Java_JAR_PATHS})
set(_jar_doc "NOTSET")
set(_state "name")
foreach (arg ${ARGN})
if (${_state} STREQUAL "name")
if (${arg} STREQUAL "VERSIONS")
set(_state "versions")
elseif (${arg} STREQUAL "NAMES")
set(_state "names")
elseif (${arg} STREQUAL "PATHS")
set(_state "paths")
elseif (${arg} STREQUAL "DOC")
set(_state "doc")
else (${arg} STREQUAL "NAMES")
set(_jar_names ${arg})
if (_jar_doc STREQUAL "NOTSET")
set(_jar_doc "Finding ${arg} jar")
endif (_jar_doc STREQUAL "NOTSET")
endif (${arg} STREQUAL "VERSIONS")
elseif (${_state} STREQUAL "versions")
if (${arg} STREQUAL "NAMES")
set(_state "names")
elseif (${arg} STREQUAL "PATHS")
set(_state "paths")
elseif (${arg} STREQUAL "DOC")
set(_state "doc")
else (${arg} STREQUAL "NAMES")
set(_jar_versions ${_jar_versions} ${arg})
endif (${arg} STREQUAL "NAMES")
elseif (${_state} STREQUAL "names")
if (${arg} STREQUAL "VERSIONS")
set(_state "versions")
elseif (${arg} STREQUAL "PATHS")
set(_state "paths")
elseif (${arg} STREQUAL "DOC")
set(_state "doc")
else (${arg} STREQUAL "VERSIONS")
set(_jar_names ${_jar_names} ${arg})
if (_jar_doc STREQUAL "NOTSET")
set(_jar_doc "Finding ${arg} jar")
endif (_jar_doc STREQUAL "NOTSET")
endif (${arg} STREQUAL "VERSIONS")
elseif (${_state} STREQUAL "paths")
if (${arg} STREQUAL "VERSIONS")
set(_state "versions")
elseif (${arg} STREQUAL "NAMES")
set(_state "names")
elseif (${arg} STREQUAL "DOC")
set(_state "doc")
else (${arg} STREQUAL "VERSIONS")
set(_jar_paths ${_jar_paths} ${arg})
endif (${arg} STREQUAL "VERSIONS")
elseif (${_state} STREQUAL "doc")
if (${arg} STREQUAL "VERSIONS")
set(_state "versions")
elseif (${arg} STREQUAL "NAMES")
set(_state "names")
elseif (${arg} STREQUAL "PATHS")
set(_state "paths")
else (${arg} STREQUAL "VERSIONS")
set(_jar_doc ${arg})
endif (${arg} STREQUAL "VERSIONS")
endif (${_state} STREQUAL "name")
endforeach (arg ${ARGN})
if (NOT _jar_names)
message(FATAL_ERROR "find_jar: No name to search for given")
endif (NOT _jar_names)
foreach (jar_name ${_jar_names})
foreach (version ${_jar_versions})
set(_jar_files ${_jar_files} ${jar_name}-${version}.jar)
endforeach (version ${_jar_versions})
set(_jar_files ${_jar_files} ${jar_name}.jar)
endforeach (jar_name ${_jar_names})
find_file(${VARIABLE}
NAMES ${_jar_files}
PATHS ${_jar_paths}
DOC ${_jar_doc}
NO_DEFAULT_PATH)
endfunction (find_jar VARIABLE)
function(create_javadoc _target)
set(_javadoc_packages)
set(_javadoc_files)
set(_javadoc_sourcepath)
set(_javadoc_classpath)
set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc")
set(_javadoc_doctitle)
set(_javadoc_windowtitle)
set(_javadoc_author FALSE)
set(_javadoc_version FALSE)
set(_javadoc_use FALSE)
set(_state "package")
foreach (arg ${ARGN})
if (${_state} STREQUAL "package")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "CLASSPATH")
set(_state "classpath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
set(_javadoc_packages ${arg})
set(_state "packages")
endif ()
elseif (${_state} STREQUAL "packages")
if (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "CLASSPATH")
set(_state "classpath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
list(APPEND _javadoc_packages ${arg})
endif ()
elseif (${_state} STREQUAL "files")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "CLASSPATH")
set(_state "classpath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
list(APPEND _javadoc_files ${arg})
endif ()
elseif (${_state} STREQUAL "sourcepath")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "CLASSPATH")
set(_state "classpath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
list(APPEND _javadoc_sourcepath ${arg})
endif ()
elseif (${_state} STREQUAL "classpath")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
list(APPEND _javadoc_classpath ${arg})
endif ()
elseif (${_state} STREQUAL "installpath")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
set(_javadoc_installpath ${arg})
endif ()
elseif (${_state} STREQUAL "doctitle")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "CLASSPATH")
set(_state "classpath")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
set(_javadoc_doctitle ${arg})
endif ()
elseif (${_state} STREQUAL "windowtitle")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "CLASSPATH")
set(_state "classpath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
set(_javadoc_windowtitle ${arg})
endif ()
elseif (${_state} STREQUAL "author")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "CLASSPATH")
set(_state "classpath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
set(_javadoc_author ${arg})
endif ()
elseif (${_state} STREQUAL "use")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "CLASSPATH")
set(_state "classpath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
set(_javadoc_use ${arg})
endif ()
elseif (${_state} STREQUAL "version")
if (${arg} STREQUAL "PACKAGES")
set(_state "packages")
elseif (${arg} STREQUAL "FILES")
set(_state "files")
elseif (${arg} STREQUAL "SOURCEPATH")
set(_state "sourcepath")
elseif (${arg} STREQUAL "CLASSPATH")
set(_state "classpath")
elseif (${arg} STREQUAL "INSTALLPATH")
set(_state "installpath")
elseif (${arg} STREQUAL "DOCTITLE")
set(_state "doctitle")
elseif (${arg} STREQUAL "WINDOWTITLE")
set(_state "windowtitle")
elseif (${arg} STREQUAL "AUTHOR")
set(_state "author")
elseif (${arg} STREQUAL "USE")
set(_state "use")
elseif (${arg} STREQUAL "VERSION")
set(_state "version")
else ()
set(_javadoc_version ${arg})
endif ()
endif (${_state} STREQUAL "package")
endforeach (arg ${ARGN})
set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target})
set(_javadoc_options -d ${_javadoc_builddir})
if (_javadoc_sourcepath)
set(_start TRUE)
foreach(_path ${_javadoc_sourcepath})
if (_start)
set(_sourcepath ${_path})
set(_start FALSE)
else (_start)
set(_sourcepath ${_sourcepath}:${_path})
endif (_start)
endforeach(_path ${_javadoc_sourcepath})
set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath})
endif (_javadoc_sourcepath)
if (_javadoc_classpath)
set(_start TRUE)
foreach(_path ${_javadoc_classpath})
if (_start)
set(_classpath ${_path})
set(_start FALSE)
else (_start)
set(_classpath ${_classpath}:${_path})
endif (_start)
endforeach(_path ${_javadoc_classpath})
set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}")
endif (_javadoc_classpath)
if (_javadoc_doctitle)
set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}')
endif (_javadoc_doctitle)
if (_javadoc_windowtitle)
set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}')
endif (_javadoc_windowtitle)
if (_javadoc_author)
set(_javadoc_options ${_javadoc_options} -author)
endif (_javadoc_author)
if (_javadoc_use)
set(_javadoc_options ${_javadoc_options} -use)
endif (_javadoc_use)
if (_javadoc_version)
set(_javadoc_options ${_javadoc_options} -version)
endif (_javadoc_version)
add_custom_target(${_target}_javadoc ALL
COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options}
${_javadoc_files}
${_javadoc_packages}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
install(
DIRECTORY ${_javadoc_builddir}
DESTINATION ${_javadoc_installpath}
)
endfunction(create_javadoc)

View File

@ -1,52 +0,0 @@
#
# This script create a list of compiled Java class files to be added to a
# jar file. This avoids including cmake files which get created in the
# binary directory.
#
#=============================================================================
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
if (CMAKE_JAVA_CLASS_OUTPUT_PATH)
if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
set(_JAVA_GLOBBED_FILES)
if (CMAKE_JAR_CLASSES_PREFIX)
foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}")
file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class")
if (_JAVA_GLOBBED_TMP_FILES)
list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES})
endif (_JAVA_GLOBBED_TMP_FILES)
endforeach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
else()
file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class")
endif (CMAKE_JAR_CLASSES_PREFIX)
set(_JAVA_CLASS_FILES)
# file(GLOB_RECURSE foo RELATIVE) is broken so we need this.
foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE})
set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n)
endforeach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
# write to file
file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES})
else (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
message(SEND_ERROR "FATAL: Java class output path doesn't exist")
endif (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
else (CMAKE_JAVA_CLASS_OUTPUT_PATH)
message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH")
endif (CMAKE_JAVA_CLASS_OUTPUT_PATH)

View File

@ -1,32 +0,0 @@
#
# Helper script for UseJava.cmake
#
#=============================================================================
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
if (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
if (_JAVA_TARGET_OUTPUT_NAME)
find_program(LN_EXECUTABLE
NAMES
ln
)
execute_process(
COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}"
WORKING_DIRECTORY ${_JAVA_TARGET_DIR}
)
else (_JAVA_TARGET_OUTPUT_NAME)
message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME")
endif (_JAVA_TARGET_OUTPUT_NAME)
endif (UNIX AND _JAVA_TARGET_OUTPUT_LINK)

View File

@ -1 +1 @@
(import packages/nix/flake-compat.nix).defaultNix
(import nix/flake-compat.nix).defaultNix

56
flake.lock generated
View File

@ -3,11 +3,11 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1648199409,
"narHash": "sha256-JwPKdC2PoVBkG6E+eWw3j6BMR6sL3COpYWfif7RVb8Y=",
"lastModified": 1650374568,
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "64a525ee38886ab9028e6f61790de0832aa3ef03",
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
"type": "github"
},
"original": {
@ -19,26 +19,26 @@
"libnbtplusplus": {
"flake": false,
"locked": {
"lastModified": 1591558203,
"narHash": "sha256-QgvNvaoFflCXEPCCFBCeZvYTpuiwScBG7EosUgFwFNQ=",
"owner": "multimc",
"lastModified": 1650031308,
"narHash": "sha256-TvVOjkUobYJD9itQYueELJX3wmecvEdCbJ0FinW2mL4=",
"owner": "PrismLauncher",
"repo": "libnbtplusplus",
"rev": "dc72a20b7efd304d12af2025223fad07b4b78464",
"rev": "2203af7eeb48c45398139b583615134efd8d407f",
"type": "github"
},
"original": {
"owner": "multimc",
"owner": "PrismLauncher",
"repo": "libnbtplusplus",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1648219316,
"narHash": "sha256-Ctij+dOi0ZZIfX5eMhgwugfvB+WZSrvVNAyAuANOsnQ=",
"lastModified": 1666057921,
"narHash": "sha256-VpQqtXdj6G7cH//SvoprjR7XT3KS7p+tCVebGK1N6tE=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "30d3d79b7d3607d56546dd2a6b49e156ba0ec634",
"rev": "88eab1e431cabd0ed621428d8b40d425a07af39f",
"type": "github"
},
"original": {
@ -48,28 +48,28 @@
"type": "github"
}
},
"quazip": {
"flake": false,
"locked": {
"lastModified": 1643049383,
"narHash": "sha256-LcJY6yd6GyeL7X5MP4L94diceM1TYespWByliBsjK98=",
"owner": "stachenov",
"repo": "quazip",
"rev": "09ec1d10c6d627f895109b21728dda000cbfa7d1",
"type": "github"
},
"original": {
"owner": "stachenov",
"repo": "quazip",
"type": "github"
}
},
"root": {
"inputs": {
"flake-compat": "flake-compat",
"libnbtplusplus": "libnbtplusplus",
"nixpkgs": "nixpkgs",
"quazip": "quazip"
"tomlplusplus": "tomlplusplus"
}
},
"tomlplusplus": {
"flake": false,
"locked": {
"lastModified": 1666091090,
"narHash": "sha256-djpMCFPvkJcfynV8WnsYdtwLq+J7jpV1iM4C6TojiyM=",
"owner": "marzer",
"repo": "tomlplusplus",
"rev": "1e4a3833d013aee08f58c5b31c69f709afc69f73",
"type": "github"
},
"original": {
"owner": "marzer",
"repo": "tomlplusplus",
"type": "github"
}
}
},

View File

@ -4,31 +4,35 @@
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
libnbtplusplus = { url = "github:multimc/libnbtplusplus"; flake = false; };
quazip = { url = "github:stachenov/quazip"; flake = false; };
libnbtplusplus = { url = "github:PrismLauncher/libnbtplusplus"; flake = false; };
tomlplusplus = { url = "github:marzer/tomlplusplus"; flake = false; };
};
outputs = { self, nixpkgs, libnbtplusplus, quazip, ... }:
outputs = { self, nixpkgs, libnbtplusplus, tomlplusplus, ... }:
let
# Generate a user-friendly version number.
# User-friendly version number.
version = builtins.substring 0 8 self.lastModifiedDate;
# System types to support (qtbase is currently broken for "aarch64-darwin")
# Supported systems (qtbase is currently broken for "aarch64-darwin")
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" ];
# Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'.
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
# Nixpkgs instantiated for supported system types.
# Nixpkgs instantiated for supported systems.
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
packagesFn = pkgs: rec {
prismlauncher = pkgs.libsForQt5.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
prismlauncher-qt6 = pkgs.qt6Packages.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
};
in
{
packages = forAllSystems (system: { polymc = pkgs.${system}.libsForQt5.callPackage ./packages/nix/polymc { inherit version self quazip libnbtplusplus; }; });
defaultPackage = forAllSystems (system: self.packages.${system}.polymc);
packages = forAllSystems (system:
let packages = packagesFn pkgs.${system}; in
packages // { default = packages.prismlauncher; }
);
apps = forAllSystems (system: { polymc = { type = "app"; program = "${self.defaultPackage.${system}}/bin/polymc"; }; });
defaultApp = forAllSystems (system: self.apps.${system}.polymc);
overlay = final: prev: { polymc = self.defaultPackage.${final.system}; };
overlay = final: packagesFn;
};
}

View File

@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -36,6 +37,7 @@
#include "Application.h"
#include "BuildConfig.h"
#include "net/PasteUpload.h"
#include "ui/MainWindow.h"
#include "ui/InstanceWindow.h"
@ -58,9 +60,15 @@
#include "ui/themes/BrightTheme.h"
#include "ui/themes/CustomTheme.h"
#ifdef Q_OS_WIN
#include "ui/WinDarkmode.h"
#include <versionhelpers.h>
#endif
#include "ui/setupwizard/SetupWizard.h"
#include "ui/setupwizard/LanguageWizardPage.h"
#include "ui/setupwizard/JavaWizardPage.h"
#include "ui/setupwizard/PasteWizardPage.h"
#include "ui/dialogs/CustomMessageBox.h"
@ -71,6 +79,7 @@
#include <iostream>
#include <QAccessible>
#include <QCommandLineParser>
#include <QDir>
#include <QFileInfo>
#include <QNetworkAccessManager>
@ -81,6 +90,7 @@
#include <QDebug>
#include <QStyleFactory>
#include <QWindow>
#include <QIcon>
#include "InstanceList.h"
@ -96,20 +106,23 @@
#include "tools/JVisualVM.h"
#include "tools/MCEditTool.h"
#include <xdgicon.h>
#include "settings/INISettingsObject.h"
#include "settings/Setting.h"
#include "translations/TranslationsModel.h"
#include "meta/Index.h"
#include <Commandline.h>
#include <FileSystem.h>
#include <DesktopServices.h>
#include <LocalPeer.h>
#include <sys.h>
#ifdef Q_OS_LINUX
#include <dlfcn.h>
#include "gamemode_client.h"
#endif
#if defined Q_OS_WIN32
#ifndef WIN32_LEAN_AND_MEAN
@ -124,12 +137,6 @@
static const QLatin1String liveCheckFile("live.check");
using namespace Commandline;
#define MACOS_HINT "If you are on macOS Sierra, you might have to move the app to your /Applications or ~/Applications folder. "\
"This usually fixes the problem and you can move the application elsewhere afterwards.\n"\
"\n"
namespace {
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
@ -221,91 +228,36 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
setOrganizationName(BuildConfig.LAUNCHER_NAME);
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
setApplicationName(BuildConfig.LAUNCHER_NAME);
setApplicationDisplayName(BuildConfig.LAUNCHER_DISPLAYNAME);
setApplicationDisplayName(QString("%1 %2").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString()));
setApplicationVersion(BuildConfig.printableVersionString());
#if (QT_VERSION >= QT_VERSION_CHECK(5,7,0))
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
#endif
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
startTime = QDateTime::currentDateTime();
// Don't quit on hiding the last window
this->setQuitOnLastWindowClosed(false);
// Commandline parsing
QHash<QString, QVariant> args;
{
Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
QCommandLineParser parser;
parser.setApplicationDescription(BuildConfig.LAUNCHER_DISPLAYNAME);
// --help
parser.addSwitch("help");
parser.addShortOpt("help", 'h');
parser.addDocumentation("help", "Display this help and exit.");
// --version
parser.addSwitch("version");
parser.addShortOpt("version", 'V');
parser.addDocumentation("version", "Display program version and exit.");
// --dir
parser.addOption("dir");
parser.addShortOpt("dir", 'd');
parser.addDocumentation("dir", "Use the supplied folder as application root instead of the binary location (use '.' for current)");
// --launch
parser.addOption("launch");
parser.addShortOpt("launch", 'l');
parser.addDocumentation("launch", "Launch the specified instance (by instance ID)");
// --server
parser.addOption("server");
parser.addShortOpt("server", 's');
parser.addDocumentation("server", "Join the specified server on launch (only valid in combination with --launch)");
// --profile
parser.addOption("profile");
parser.addShortOpt("profile", 'a');
parser.addDocumentation("profile", "Use the account specified by its profile name (only valid in combination with --launch)");
// --alive
parser.addSwitch("alive");
parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after the launcher starts");
// --import
parser.addOption("import");
parser.addShortOpt("import", 'I');
parser.addDocumentation("import", "Import instance from specified zip (local path or URL)");
parser.addOptions({
{{"d", "dir"}, "Use a custom path as application root (use '.' for current directory)", "directory"},
{{"l", "launch"}, "Launch the specified instance (by instance ID)", "instance"},
{{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
{{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
{"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
{{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"}
});
parser.addHelpOption();
parser.addVersionOption();
// parse the arguments
try
{
args = parser.parse(arguments());
}
catch (const ParsingError &e)
{
std::cerr << "CommandLineError: " << e.what() << std::endl;
if(argc > 0)
std::cerr << "Try '" << argv[0] << " -h' to get help on command line parameters."
<< std::endl;
m_status = Application::Failed;
return;
}
parser.process(arguments());
// display help and exit
if (args["help"].toBool())
{
std::cout << qPrintable(parser.compileHelp(arguments()[0]));
m_status = Application::Succeeded;
return;
}
// display version and exit
if (args["version"].toBool())
{
std::cout << "Version " << BuildConfig.printableVersionString().toStdString() << std::endl;
std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
m_status = Application::Succeeded;
return;
}
}
m_instanceIdToLaunch = args["launch"].toString();
m_serverToJoin = args["server"].toString();
m_profileToUse = args["profile"].toString();
m_liveCheck = args["alive"].toBool();
m_zipToImport = args["import"].toUrl();
m_instanceIdToLaunch = parser.value("launch");
m_serverToJoin = parser.value("server");
m_profileToUse = parser.value("profile");
m_liveCheck = parser.isSet("alive");
m_zipToImport = parser.value("import");
// error if --launch is missing with --server or --profile
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
@ -320,7 +272,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
{
// Root path is used for updates and portable data
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
QDir foo(FS::PathCombine(binPath, "..")); // typically portable-root or /usr
m_rootPath = foo.absolutePath();
#elif defined(Q_OS_WIN32)
@ -331,16 +283,12 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
// on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
FS::updateTimestamp(m_rootPath);
#endif
#ifdef LAUNCHER_JARS_LOCATION
m_jarsPath = TOSTRING(LAUNCHER_JARS_LOCATION);
#endif
}
QString adjustedBy;
QString dataPath;
// change folder
QString dirParam = args["dir"].toString();
QString dirParam = parser.value("dir");
if (!dirParam.isEmpty())
{
// the dir param. it makes multimc data path point to whatever the user specified
@ -354,6 +302,12 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
dataPath = foo.absolutePath();
adjustedBy = "Persistent data path";
QDir polymcData(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "PolyMC"));
if (polymcData.exists()) {
dataPath = polymcData.absolutePath();
adjustedBy = "PolyMC data path";
}
#ifdef Q_OS_LINUX
// TODO: this should be removed in a future version
// TODO: provide a migration path similar to macOS migration
@ -379,9 +333,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
QString(
"The launcher data folder could not be created.\n"
"\n"
#if defined(Q_OS_MAC)
MACOS_HINT
#endif
"Make sure you have the right permissions to the launcher data folder and any folder needed to access it.\n"
"(%1)\n"
"\n"
@ -397,9 +348,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
QString(
"The launcher data folder could not be opened.\n"
"\n"
#if defined(Q_OS_MAC)
MACOS_HINT
#endif
"Make sure you have the right permissions to the launcher data folder.\n"
"(%1)\n"
"\n"
@ -409,69 +357,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
return;
}
#if defined(Q_OS_MAC)
// move user data to new location if on macOS and it still exists in Contents/MacOS
QDir fi(applicationDirPath());
QString originalData = fi.absolutePath();
// if the config file exists in Contents/MacOS, then user data is still there and needs to moved
if (QFileInfo::exists(FS::PathCombine(originalData, BuildConfig.LAUNCHER_CONFIGFILE)))
{
if (!QFileInfo::exists(FS::PathCombine(originalData, "dontmovemacdata")))
{
QMessageBox::StandardButton askMoveDialogue;
askMoveDialogue = QMessageBox::question(
nullptr,
BuildConfig.LAUNCHER_DISPLAYNAME,
"Would you like to move application data to a new data location? It will improve the launcher's performance, but if you switch to older versions it will look like instances have disappeared. If you select no, you can migrate later in settings. You should select yes unless you're commonly switching between different versions (eg. develop and stable).",
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes
);
if (askMoveDialogue == QMessageBox::Yes)
{
qDebug() << "On macOS and found config file in old location, moving user data...";
QDir dir;
QStringList dataFiles {
"*.log", // Launcher log files: ${Launcher_Name}-@.log
"accounts.json",
"accounts",
"assets",
"cache",
"icons",
"instances",
"libraries",
"meta",
"metacache",
"mods",
BuildConfig.LAUNCHER_CONFIGFILE,
"themes",
"translations"
};
QDirIterator files(originalData, dataFiles);
while (files.hasNext()) {
QString filePath(files.next());
QString fileName(files.fileName());
if (!dir.rename(filePath, FS::PathCombine(dataPath, fileName)))
{
qWarning() << "Failed to move " << fileName;
}
}
}
else
{
dataPath = originalData;
QDir::setCurrent(dataPath);
QFile file(originalData + "/dontmovemacdata");
file.open(QIODevice::WriteOnly);
}
}
else
{
dataPath = originalData;
QDir::setCurrent(dataPath);
}
}
#endif
/*
* Establish the mechanism for communication with an already running PolyMC that uses the same data path.
* If there is one, tell it what the user actually wanted to do and exit.
@ -543,9 +428,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
QString(
"The launcher couldn't create a log file - the data folder is not writable.\n"
"\n"
#if defined(Q_OS_MAC)
MACOS_HINT
#endif
"Make sure you have write permissions to the data folder.\n"
"(%1)\n"
"\n"
@ -607,8 +489,10 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
// Initialize application settings
{
m_settings.reset(new INISettingsObject(BuildConfig.LAUNCHER_CONFIGFILE, this));
// Provide a fallback for migration from PolyMC
m_settings.reset(new INISettingsObject({ BuildConfig.LAUNCHER_CONFIGFILE, "polymc.cfg", "multimc.cfg" }, this));
// Updates
// Multiple channels are separated by spaces
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
m_settings->registerSetting("AutoUpdate", true);
@ -686,16 +570,23 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("JavaPath", "");
m_settings->registerSetting("JavaTimestamp", 0);
m_settings->registerSetting("JavaArchitecture", "");
m_settings->registerSetting("JavaRealArchitecture", "");
m_settings->registerSetting("JavaVersion", "");
m_settings->registerSetting("JavaVendor", "");
m_settings->registerSetting("LastHostname", "");
m_settings->registerSetting("JvmArgs", "");
m_settings->registerSetting("IgnoreJavaCompatibility", false);
m_settings->registerSetting("IgnoreJavaWizard", false);
// Native library workarounds
m_settings->registerSetting("UseNativeOpenAL", false);
m_settings->registerSetting("UseNativeGLFW", false);
// Peformance related options
m_settings->registerSetting("EnableFeralGamemode", false);
m_settings->registerSetting("EnableMangoHud", false);
m_settings->registerSetting("UseDiscreteGpu", false);
// Game time
m_settings->registerSetting("ShowGameTime", true);
m_settings->registerSetting("ShowGlobalGameTime", true);
@ -704,6 +595,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
// Minecraft launch method
m_settings->registerSetting("MCLaunchMethod", "LauncherPart");
// Minecraft mods
m_settings->registerSetting("ModMetadataDisabled", false);
// Minecraft offline player name
m_settings->registerSetting("LastOfflinePlayerName", "");
@ -735,15 +629,55 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("UpdateDialogGeometry", "");
// pastebin URL
m_settings->registerSetting("PastebinURL", "https://0x0.st");
m_settings->registerSetting("ModDownloadGeometry", "");
// HACK: This code feels so stupid is there a less stupid way of doing this?
{
m_settings->registerSetting("PastebinURL", "");
m_settings->registerSetting("PastebinType", PasteUpload::PasteType::Mclogs);
m_settings->registerSetting("PastebinCustomAPIBase", "");
QString pastebinURL = m_settings->get("PastebinURL").toString();
bool userHadDefaultPastebin = pastebinURL == "https://0x0.st";
if (!pastebinURL.isEmpty() && !userHadDefaultPastebin)
{
m_settings->set("PastebinType", PasteUpload::PasteType::NullPointer);
m_settings->set("PastebinCustomAPIBase", pastebinURL);
m_settings->reset("PastebinURL");
}
bool ok;
int pasteType = m_settings->get("PastebinType").toInt(&ok);
// If PastebinType is invalid then reset the related settings.
if (!ok || !(PasteUpload::PasteType::First <= pasteType && pasteType <= PasteUpload::PasteType::Last))
{
m_settings->reset("PastebinType");
m_settings->reset("PastebinCustomAPIBase");
}
}
// meta URL
m_settings->registerSetting("MetaURLOverride", "");
m_settings->registerSetting("CloseAfterLaunch", false);
m_settings->registerSetting("QuitAfterGameStop", false);
// Custom MSA credentials
// Custom Microsoft Authentication Client ID
m_settings->registerSetting("MSAClientIDOverride", "");
// Custom Flame API Key
{
m_settings->registerSetting("CFKeyOverride", "");
m_settings->registerSetting("FlameKeyOverride", "");
QString flameKey = m_settings->get("CFKeyOverride").toString();
if (!flameKey.isEmpty())
m_settings->set("FlameKeyOverride", flameKey);
m_settings->reset("CFKeyOverride");
}
m_settings->registerSetting("UserAgentOverride", "");
// Init page provider
{
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
@ -791,7 +725,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
auto platform = getIdealPlatform(BuildConfig.BUILD_PLATFORM);
auto channelUrl = BuildConfig.UPDATER_BASE + platform + "/channels.json";
qDebug() << "Initializing updater with platform: " << platform << " -- " << channelUrl;
m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL));
qDebug() << "<> Updater started.";
}
@ -881,6 +815,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath());
m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath());
m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
m_metacache->addBase("FlameMods", QDir("cache/FlameMods").absolutePath());
m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath());
m_metacache->addBase("ModrinthModpacks", QDir("cache/ModrinthModpacks").absolutePath());
m_metacache->addBase("root", QDir::currentPath());
m_metacache->addBase("translations", QDir("translations").absolutePath());
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
@ -905,6 +842,12 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_mcedit.reset(new MCEditTool(m_settings));
}
#ifdef Q_OS_MACOS
connect(this, &Application::clickedOnDock, [this]() {
this->showMainWindow();
});
#endif
connect(this, &Application::aboutToQuit, [this](){
if(m_instances)
{
@ -925,10 +868,13 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
qDebug() << "<> Application theme set.";
}
updateCapabilities();
if(createSetupWizard())
{
return;
}
performMainStartupAction();
}
@ -936,6 +882,10 @@ bool Application::createSetupWizard()
{
bool javaRequired = [&]()
{
bool ignoreJavaWizard = m_settings->get("IgnoreJavaWizard").toBool();
if(ignoreJavaWizard) {
return false;
}
QString currentHostName = QHostInfo::localHostName();
QString oldHostName = settings()->get("LastHostname").toString();
if (currentHostName != oldHostName)
@ -957,7 +907,8 @@ bool Application::createSetupWizard()
return true;
return false;
}();
bool wizardRequired = javaRequired || languageRequired;
bool pasteInterventionRequired = settings()->get("PastebinURL") != "";
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired;
if(wizardRequired)
{
@ -966,10 +917,16 @@ bool Application::createSetupWizard()
{
m_setupWizard->addPage(new LanguageWizardPage(m_setupWizard));
}
if (javaRequired)
{
m_setupWizard->addPage(new JavaWizardPage(m_setupWizard));
}
if (pasteInterventionRequired)
{
m_setupWizard->addPage(new PasteWizardPage(m_setupWizard));
}
connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished);
m_setupWizard->show();
return true;
@ -977,6 +934,21 @@ bool Application::createSetupWizard()
return false;
}
bool Application::event(QEvent* event) {
#ifdef Q_OS_MACOS
if (event->type() == QEvent::ApplicationStateChange) {
auto ev = static_cast<QApplicationStateChangeEvent*>(event);
if (m_prevAppState == Qt::ApplicationActive
&& ev->applicationState() == Qt::ApplicationActive) {
emit clickedOnDock();
}
m_prevAppState = ev->applicationState();
}
#endif
return QApplication::event(event);
}
void Application::setupWizardFinished(int status)
{
qDebug() << "Wizard result =" << status;
@ -1011,7 +983,7 @@ void Application::performMainStartupAction()
qDebug() << " Launching with account" << m_profileToUse;
}
launch(inst, true, nullptr, serverToJoin, accountToUse);
launch(inst, true, false, nullptr, serverToJoin, accountToUse);
return;
}
}
@ -1115,6 +1087,7 @@ void Application::messageReceived(const QByteArray& message)
launch(
instance,
true,
false,
nullptr,
serverObject,
accountObject
@ -1152,15 +1125,6 @@ std::vector<ITheme *> Application::getValidApplicationThemes()
return ret;
}
bool Application::isFlatpak()
{
#ifdef Q_OS_LINUX
return QFile::exists("/.flatpak-info");
#else
return false;
#endif
}
void Application::setApplicationTheme(const QString& name, bool initial)
{
auto systemPalette = qApp->palette();
@ -1169,6 +1133,15 @@ void Application::setApplicationTheme(const QString& name, bool initial)
{
auto & theme = (*themeIter).second;
theme->apply(initial);
#ifdef Q_OS_WIN
if (m_mainWindow && IsWindows10OrGreater()) {
if (QString::compare(theme->id(), "dark") == 0) {
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
} else {
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
}
}
#endif
}
else
{
@ -1178,15 +1151,15 @@ void Application::setApplicationTheme(const QString& name, bool initial)
void Application::setIconTheme(const QString& name)
{
XdgIcon::setThemeName(name);
QIcon::setThemeName(name);
}
QIcon Application::getThemedIcon(const QString& name)
{
if(name == "logo") {
return QIcon(":/org.polymc.PolyMC.svg");
return QIcon(":/" + BuildConfig.LAUNCHER_SVGFILENAME);
}
return XdgIcon::fromTheme(name);
return QIcon::fromTheme(name);
}
bool Application::openJsonEditor(const QString &filename)
@ -1206,6 +1179,7 @@ bool Application::openJsonEditor(const QString &filename)
bool Application::launch(
InstancePtr instance,
bool online,
bool demo,
BaseProfilerFactory *profiler,
MinecraftServerTargetPtr serverToJoin,
MinecraftAccountPtr accountToUse
@ -1229,6 +1203,7 @@ bool Application::launch(
controller.reset(new LaunchController());
controller->setInstance(instance);
controller->setOnline(online);
controller->setDemo(demo);
controller->setProfiler(profiler);
controller->setServerToJoin(serverToJoin);
controller->setAccountToUse(accountToUse);
@ -1242,6 +1217,9 @@ bool Application::launch(
}
connect(controller.get(), &LaunchController::succeeded, this, &Application::controllerSucceeded);
connect(controller.get(), &LaunchController::failed, this, &Application::controllerFailed);
connect(controller.get(), &LaunchController::aborted, this, [this] {
controllerFailed(tr("Aborted"));
});
addRunningInstance();
controller->start();
return true;
@ -1396,6 +1374,16 @@ MainWindow* Application::showMainWindow(bool minimized)
m_mainWindow = new MainWindow();
m_mainWindow->restoreState(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowState").toByteArray()));
m_mainWindow->restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowGeometry").toByteArray()));
#ifdef Q_OS_WIN
if (IsWindows10OrGreater())
{
if (QString::compare(settings()->get("ApplicationTheme").toString(), "dark") == 0) {
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
} else {
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
}
}
#endif
if(minimized)
{
m_mainWindow->showMinimized();
@ -1548,13 +1536,48 @@ shared_qobject_ptr<Meta::Index> Application::metadataIndex()
return m_metadataIndex;
}
QString Application::getJarsPath()
void Application::updateCapabilities()
{
if(m_jarsPath.isEmpty())
m_capabilities = None;
if (!getMSAClientID().isEmpty())
m_capabilities |= SupportsMSA;
if (!getFlameAPIKey().isEmpty())
m_capabilities |= SupportsFlame;
#ifdef Q_OS_LINUX
if (gamemode_query_status() >= 0)
m_capabilities |= SupportsGameMode;
{
return FS::PathCombine(QCoreApplication::applicationDirPath(), "jars");
void *dummy = dlopen("libMangoHud_dlsym.so", RTLD_LAZY);
// try normal variant as well
if (dummy == NULL)
dummy = dlopen("libMangoHud.so", RTLD_LAZY);
if (dummy != NULL) {
dlclose(dummy);
m_capabilities |= SupportsMangoHud;
}
}
return FS::PathCombine(m_rootPath, m_jarsPath);
#endif
}
QString Application::getJarPath(QString jarFile)
{
QStringList potentialPaths = {
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
FS::PathCombine(m_rootPath, "share/" + BuildConfig.LAUNCHER_APP_BINARY_NAME),
#endif
FS::PathCombine(m_rootPath, "jars"),
FS::PathCombine(applicationDirPath(), "jars")
};
for(QString p : potentialPaths)
{
QString jarPath = FS::PathCombine(p, jarFile);
if (QFileInfo(jarPath).isFile())
return jarPath;
}
return {};
}
QString Application::getMSAClientID()
@ -1566,3 +1589,34 @@ QString Application::getMSAClientID()
return BuildConfig.MSA_CLIENT_ID;
}
QString Application::getFlameAPIKey()
{
QString keyOverride = m_settings->get("FlameKeyOverride").toString();
if (!keyOverride.isEmpty()) {
return keyOverride;
}
return BuildConfig.FLAME_API_KEY;
}
QString Application::getUserAgent()
{
QString uaOverride = m_settings->get("UserAgentOverride").toString();
if (!uaOverride.isEmpty()) {
return uaOverride.replace("$LAUNCHER_VER", BuildConfig.printableVersionString());
}
return BuildConfig.USER_AGENT;
}
QString Application::getUserAgentUncached()
{
QString uaOverride = m_settings->get("UserAgentOverride").toString();
if (!uaOverride.isEmpty()) {
uaOverride += " (Uncached)";
return uaOverride.replace("$LAUNCHER_VER", BuildConfig.printableVersionString());
}
return BuildConfig.USER_AGENT_UNCACHED;
}

View File

@ -90,10 +90,22 @@ public:
Initialized
};
enum Capability {
None = 0,
SupportsMSA = 1 << 0,
SupportsFlame = 1 << 1,
SupportsGameMode = 1 << 2,
SupportsMangoHud = 1 << 3,
};
Q_DECLARE_FLAGS(Capabilities, Capability)
public:
Application(int &argc, char **argv);
virtual ~Application();
bool event(QEvent* event) override;
std::shared_ptr<SettingsObject> settings() const {
return m_settings;
}
@ -104,8 +116,6 @@ public:
QIcon getThemedIcon(const QString& name);
bool isFlatpak();
void setIconTheme(const QString& name);
std::vector<ITheme *> getValidApplicationThemes();
@ -152,15 +162,28 @@ public:
shared_qobject_ptr<Meta::Index> metadataIndex();
QString getJarsPath();
void updateCapabilities();
/*!
* Finds and returns the full path to a jar file.
* Returns a null-string if it could not be found.
*/
QString getJarPath(QString jarFile);
QString getMSAClientID();
QString getFlameAPIKey();
QString getUserAgent();
QString getUserAgentUncached();
/// this is the root of the 'installation'. Used for automatic updates
const QString &root() {
return m_rootPath;
}
const Capabilities capabilities() {
return m_capabilities;
}
/*!
* Opens a json file using either a system default editor, or, if not empty, the editor
* specified in the settings
@ -180,10 +203,15 @@ signals:
void globalSettingsAboutToOpen();
void globalSettingsClosed();
#ifdef Q_OS_MACOS
void clickedOnDock();
#endif
public slots:
bool launch(
InstancePtr instance,
bool online = true,
bool demo = false,
BaseProfilerFactory *profiler = nullptr,
MinecraftServerTargetPtr serverToJoin = nullptr,
MinecraftAccountPtr accountToUse = nullptr
@ -229,13 +257,17 @@ private:
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
std::map<QString, std::unique_ptr<ITheme>> m_themes;
std::unique_ptr<MCEditTool> m_mcedit;
QString m_jarsPath;
QSet<QString> m_features;
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
QString m_rootPath;
Status m_status = Application::StartingUp;
Capabilities m_capabilities;
#ifdef Q_OS_MACOS
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
#endif
#if defined Q_OS_WIN32
// used on Windows to attach the standard IO streams

View File

@ -1,11 +1,47 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ApplicationMessage.h"
#include <QJsonDocument>
#include <QJsonObject>
#include "Json.h"
void ApplicationMessage::parse(const QByteArray & input) {
auto doc = QJsonDocument::fromBinaryData(input);
auto root = doc.object();
auto doc = Json::requireDocument(input, "ApplicationMessage");
auto root = Json::requireObject(doc, "ApplicationMessage");
command = root.value("command").toString();
args.clear();
@ -25,7 +61,5 @@ QByteArray ApplicationMessage::serialize() {
}
root.insert("args", outArgs);
QJsonDocument out;
out.setObject(root);
return out.toBinaryData();
return Json::toText(root);
}

View File

@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -38,6 +39,7 @@
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include <QRegularExpression>
#include "settings/INISettingsObject.h"
#include "settings/Setting.h"
@ -51,15 +53,26 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
: QObject()
{
m_settings = settings;
m_global_settings = globalSettings;
m_rootDir = rootDir;
m_settings->registerSetting("name", "Unnamed Instance");
m_settings->registerSetting("iconKey", "default");
m_settings->registerSetting("notes", "");
m_settings->registerSetting("lastLaunchTime", 0);
m_settings->registerSetting("totalTimePlayed", 0);
m_settings->registerSetting("lastTimePlayed", 0);
m_settings->registerSetting("InstanceType", "OneSix");
// Game time override
auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride);
m_settings->registerOverride(globalSettings->getSetting("RecordGameTime"), gameTimeOverride);
// NOTE: Sometimees InstanceType is already registered, as it was used to identify the type of
// a locally stored instance
if (!m_settings->getSetting("InstanceType"))
m_settings->registerSetting("InstanceType", "");
// Custom Commands
auto commandSetting = m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false);
@ -76,6 +89,14 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleMaxLines"), nullptr);
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleOverflowStop"), nullptr);
// Managed Packs
m_settings->registerSetting("ManagedPack", false);
m_settings->registerSetting("ManagedPackType", "");
m_settings->registerSetting("ManagedPackID", "");
m_settings->registerSetting("ManagedPackName", "");
m_settings->registerSetting("ManagedPackVersionID", "");
m_settings->registerSetting("ManagedPackVersionName", "");
}
QString BaseInstance::getPreLaunchCommand()
@ -93,9 +114,59 @@ QString BaseInstance::getPostExitCommand()
return settings()->get("PostExitCommand").toString();
}
bool BaseInstance::isManagedPack() const
{
return m_settings->get("ManagedPack").toBool();
}
QString BaseInstance::getManagedPackType() const
{
return m_settings->get("ManagedPackType").toString();
}
QString BaseInstance::getManagedPackID() const
{
return m_settings->get("ManagedPackID").toString();
}
QString BaseInstance::getManagedPackName() const
{
return m_settings->get("ManagedPackName").toString();
}
QString BaseInstance::getManagedPackVersionID() const
{
return m_settings->get("ManagedPackVersionID").toString();
}
QString BaseInstance::getManagedPackVersionName() const
{
return m_settings->get("ManagedPackVersionName").toString();
}
void BaseInstance::setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version)
{
m_settings->set("ManagedPack", true);
m_settings->set("ManagedPackType", type);
m_settings->set("ManagedPackID", id);
m_settings->set("ManagedPackName", name);
m_settings->set("ManagedPackVersionID", versionId);
m_settings->set("ManagedPackVersionName", version);
}
void BaseInstance::copyManagedPack(BaseInstance& other)
{
m_settings->set("ManagedPack", other.isManagedPack());
m_settings->set("ManagedPackType", other.getManagedPackType());
m_settings->set("ManagedPackID", other.getManagedPackID());
m_settings->set("ManagedPackName", other.getManagedPackName());
m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID());
m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName());
}
int BaseInstance::getConsoleMaxLines() const
{
auto lineSetting = settings()->getSetting("ConsoleMaxLines");
auto lineSetting = m_settings->getSetting("ConsoleMaxLines");
bool conversionOk = false;
int maxLines = lineSetting->get().toInt(&conversionOk);
if(!conversionOk)
@ -108,7 +179,7 @@ int BaseInstance::getConsoleMaxLines() const
bool BaseInstance::shouldStopOnConsoleOverflow() const
{
return settings()->get("ConsoleOverflowStop").toBool();
return m_settings->get("ConsoleOverflowStop").toBool();
}
void BaseInstance::iconUpdated(QString key)
@ -183,7 +254,7 @@ void BaseInstance::setRunning(bool running)
int64_t BaseInstance::totalTimePlayed() const
{
qint64 current = settings()->get("totalTimePlayed").toLongLong();
qint64 current = m_settings->get("totalTimePlayed").toLongLong();
if(m_isRunning)
{
QDateTime timeNow = QDateTime::currentDateTime();
@ -199,7 +270,7 @@ int64_t BaseInstance::lastTimePlayed() const
QDateTime timeNow = QDateTime::currentDateTime();
return m_timeStarted.secsTo(timeNow);
}
return settings()->get("lastTimePlayed").toLongLong();
return m_settings->get("lastTimePlayed").toLongLong();
}
void BaseInstance::resetTimePlayed()
@ -218,8 +289,10 @@ QString BaseInstance::instanceRoot() const
return m_rootDir;
}
SettingsObjectPtr BaseInstance::settings() const
SettingsObjectPtr BaseInstance::settings()
{
loadSpecificSettings();
return m_settings;
}
@ -282,11 +355,11 @@ QString BaseInstance::name() const
QString BaseInstance::windowTitle() const
{
return BuildConfig.LAUNCHER_NAME + ": " + name().replace(QRegExp("[ \n\r\t]+"), " ");
return BuildConfig.LAUNCHER_DISPLAYNAME + ": " + name().replace(QRegularExpression("\\s+"), " ");
}
// FIXME: why is this here? move it to MinecraftInstance!!!
QStringList BaseInstance::extraArguments() const
QStringList BaseInstance::extraArguments()
{
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
}
@ -295,3 +368,8 @@ shared_qobject_ptr<LaunchTask> BaseInstance::getLaunchTask()
{
return m_launchProcess;
}
void BaseInstance::updateRuntimeContext()
{
// NOOP
}

View File

@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -53,6 +54,7 @@
#include "net/Mode.h"
#include "minecraft/launch/MinecraftServerTarget.h"
#include "RuntimeContext.h"
class QDir;
class Task;
@ -139,13 +141,22 @@ public:
QString getPostExitCommand();
QString getWrapperCommand();
bool isManagedPack() const;
QString getManagedPackType() const;
QString getManagedPackID() const;
QString getManagedPackName() const;
QString getManagedPackVersionID() const;
QString getManagedPackVersionName() const;
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
void copyManagedPack(BaseInstance& other);
/// guess log level from a line of game log
virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level)
{
return level;
};
virtual QStringList extraArguments() const;
virtual QStringList extraArguments();
/// Traits. Normally inside the version, depends on instance implementation.
virtual QSet <QString> traits() const = 0;
@ -161,9 +172,18 @@ public:
/*!
* \brief Gets this instance's settings object.
* This settings object stores instance-specific settings.
*
* Note that this method is not const.
* It may call loadSpecificSettings() to ensure those are loaded.
*
* \return A pointer to this instance's settings object.
*/
virtual SettingsObjectPtr settings() const;
virtual SettingsObjectPtr settings();
/*!
* \brief Loads settings specific to an instance type if they're not already loaded.
*/
virtual void loadSpecificSettings() = 0;
/// returns a valid update task
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
@ -179,6 +199,7 @@ public:
* Create envrironment variables for running the instance
*/
virtual QProcessEnvironment createEnvironment() = 0;
virtual QProcessEnvironment createLaunchEnvironment() = 0;
/*!
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'
@ -196,10 +217,16 @@ public:
virtual QString instanceConfigFolder() const = 0;
/// get variables this instance exports
virtual QMap<QString, QString> getVariables() const = 0;
virtual QMap<QString, QString> getVariables() = 0;
virtual QString typeName() const = 0;
void updateRuntimeContext();
RuntimeContext runtimeContext() const
{
return m_runtimeContext;
}
bool hasVersionBroken() const
{
return m_hasBrokenVersion;
@ -258,6 +285,11 @@ public:
protected:
void changeStatus(Status newStatus);
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); };
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
signals:
/*!
* \brief Signal emitted when properties relevant to the instance view change
@ -280,12 +312,17 @@ protected: /* data */
bool m_isRunning = false;
shared_qobject_ptr<LaunchTask> m_launchProcess;
QDateTime m_timeStarted;
RuntimeContext m_runtimeContext;
private: /* data */
Status m_status = Status::Present;
bool m_crashed = false;
bool m_hasUpdate = false;
bool m_hasBrokenVersion = false;
SettingsObjectWeakPtr m_global_settings;
bool m_specific_settings_loaded = false;
};
Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>)

View File

@ -1,16 +1,36 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* http://www.apache.org/licenses/LICENSE-2.0
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "BaseVersionList.h"
@ -51,7 +71,7 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const
switch (role)
{
case VersionPointerRole:
return qVariantFromValue(version);
return QVariant::fromValue(version);
case VersionRole:
return version->name();

View File

@ -4,8 +4,6 @@ project(application)
######## Sources and headers ########
include (UnitTest)
set(CORE_SOURCES
# LOGIC - Base classes and infrastructure
BaseInstaller.h
@ -28,6 +26,7 @@ set(CORE_SOURCES
MMCZip.cpp
MMCStrings.h
MMCStrings.cpp
RuntimeContext.h
# Basic instance manipulation tasks (derived from InstanceTask)
InstanceCreationTask.h
@ -90,17 +89,6 @@ set(CORE_SOURCES
MMCTime.cpp
)
add_unit_test(FileSystem
SOURCES FileSystem_test.cpp
LIBS Launcher_logic
DATA testdata
)
add_unit_test(GZip
SOURCES GZip_test.cpp
LIBS Launcher_logic
)
set(PATHMATCHER_SOURCES
# Path matchers
pathmatcher/FSTreeMatcher.h
@ -124,10 +112,13 @@ set(NET_SOURCES
net/NetAction.h
net/NetJob.cpp
net/NetJob.h
net/NetUtils.h
net/PasteUpload.cpp
net/PasteUpload.h
net/Sink.h
net/Validator.h
net/Upload.cpp
net/Upload.h
)
# Game launch logic
@ -162,19 +153,13 @@ set(UPDATE_SOURCES
updater/UpdateChecker.cpp
updater/DownloadTask.h
updater/DownloadTask.cpp
updater/ExternalUpdater.h
)
add_unit_test(UpdateChecker
SOURCES updater/UpdateChecker_test.cpp
LIBS Launcher_logic
DATA updater/testdata
)
add_unit_test(DownloadTask
SOURCES updater/DownloadTask_test.cpp
LIBS Launcher_logic
DATA updater/testdata
)
set(MAC_UPDATE_SOURCES
updater/MacSparkleUpdater.h
updater/MacSparkleUpdater.mm
)
# Backend for the news bar... there's usually no news.
set(NEWS_SOURCES
@ -304,8 +289,6 @@ set(MINECRAFT_SOURCES
minecraft/Rule.h
minecraft/OneSixVersionFormat.cpp
minecraft/OneSixVersionFormat.h
minecraft/OpSys.cpp
minecraft/OpSys.h
minecraft/ParseUtils.cpp
minecraft/ParseUtils.h
minecraft/ProfileUtils.cpp
@ -313,6 +296,8 @@ set(MINECRAFT_SOURCES
minecraft/Library.cpp
minecraft/Library.h
minecraft/MojangDownloadInfo.h
minecraft/VanillaInstanceCreationTask.cpp
minecraft/VanillaInstanceCreationTask.h
minecraft/VersionFile.cpp
minecraft/VersionFile.h
minecraft/VersionFilterData.h
@ -322,19 +307,36 @@ set(MINECRAFT_SOURCES
minecraft/WorldList.h
minecraft/WorldList.cpp
minecraft/mod/MetadataHandler.h
minecraft/mod/Mod.h
minecraft/mod/Mod.cpp
minecraft/mod/ModDetails.h
minecraft/mod/ModFolderModel.h
minecraft/mod/ModFolderModel.cpp
minecraft/mod/ModFolderLoadTask.h
minecraft/mod/ModFolderLoadTask.cpp
minecraft/mod/LocalModParseTask.h
minecraft/mod/LocalModParseTask.cpp
minecraft/mod/Resource.h
minecraft/mod/Resource.cpp
minecraft/mod/ResourceFolderModel.h
minecraft/mod/ResourceFolderModel.cpp
minecraft/mod/ResourcePack.h
minecraft/mod/ResourcePack.cpp
minecraft/mod/ResourcePackFolderModel.h
minecraft/mod/ResourcePackFolderModel.cpp
minecraft/mod/TexturePack.h
minecraft/mod/TexturePack.cpp
minecraft/mod/TexturePackFolderModel.h
minecraft/mod/TexturePackFolderModel.cpp
minecraft/mod/ShaderPackFolderModel.h
minecraft/mod/tasks/BasicFolderLoadTask.h
minecraft/mod/tasks/ModFolderLoadTask.h
minecraft/mod/tasks/ModFolderLoadTask.cpp
minecraft/mod/tasks/LocalModParseTask.h
minecraft/mod/tasks/LocalModParseTask.cpp
minecraft/mod/tasks/LocalModUpdateTask.h
minecraft/mod/tasks/LocalModUpdateTask.cpp
minecraft/mod/tasks/LocalResourcePackParseTask.h
minecraft/mod/tasks/LocalResourcePackParseTask.cpp
minecraft/mod/tasks/LocalTexturePackParseTask.h
minecraft/mod/tasks/LocalTexturePackParseTask.cpp
# Assets
minecraft/AssetsUtils.h
@ -352,52 +354,6 @@ set(MINECRAFT_SOURCES
mojang/PackageManifest.cpp
minecraft/Agent.h)
add_unit_test(GradleSpecifier
SOURCES minecraft/GradleSpecifier_test.cpp
LIBS Launcher_logic
)
if(BUILD_TESTING)
add_executable(PackageManifest
mojang/PackageManifest_test.cpp
)
target_link_libraries(PackageManifest
Launcher_logic
Qt5::Test
)
target_include_directories(PackageManifest
PRIVATE ../cmake/UnitTest/
)
add_test(
NAME PackageManifest
COMMAND PackageManifest
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
endif()
add_unit_test(MojangVersionFormat
SOURCES minecraft/MojangVersionFormat_test.cpp
LIBS Launcher_logic
DATA minecraft/testdata
)
add_unit_test(Library
SOURCES minecraft/Library_test.cpp
LIBS Launcher_logic
)
# FIXME: shares data with FileSystem test
add_unit_test(ModFolderModel
SOURCES minecraft/mod/ModFolderModel_test.cpp
DATA testdata
LIBS Launcher_logic
)
add_unit_test(ParseUtils
SOURCES minecraft/ParseUtils_test.cpp
LIBS Launcher_logic
)
# the screenshots feature
set(SCREENSHOTS_SOURCES
screenshots/Screenshot.h
@ -411,15 +367,14 @@ set(TASKS_SOURCES
# Tasks
tasks/Task.h
tasks/Task.cpp
tasks/ConcurrentTask.h
tasks/ConcurrentTask.cpp
tasks/SequentialTask.h
tasks/SequentialTask.cpp
tasks/MultipleOptionsTask.h
tasks/MultipleOptionsTask.cpp
)
add_unit_test(Task
SOURCES tasks/Task_test.cpp
LIBS Launcher_logic
)
set(SETTINGS_SOURCES
# Settings
settings/INIFile.cpp
@ -436,11 +391,6 @@ set(SETTINGS_SOURCES
settings/SettingsObject.h
)
add_unit_test(INIFile
SOURCES settings/INIFile_test.cpp
LIBS Launcher_logic
)
set(JAVA_SOURCES
java/JavaChecker.h
java/JavaChecker.cpp
@ -456,11 +406,6 @@ set(JAVA_SOURCES
java/JavaVersion.cpp
)
add_unit_test(JavaVersion
SOURCES java/JavaVersion_test.cpp
LIBS Launcher_logic
)
set(TRANSLATIONS_SOURCES
translations/TranslationsModel.h
translations/TranslationsModel.cpp
@ -497,13 +442,26 @@ set(META_SOURCES
)
set(API_SOURCES
modplatform/ModIndex.h
modplatform/ModIndex.cpp
modplatform/ModAPI.h
modplatform/EnsureMetadataTask.h
modplatform/EnsureMetadataTask.cpp
modplatform/CheckUpdateTask.h
modplatform/flame/FlameAPI.h
modplatform/flame/FlameAPI.cpp
modplatform/modrinth/ModrinthAPI.h
modplatform/modrinth/ModrinthAPI.cpp
modplatform/helpers/NetworkModAPI.h
modplatform/helpers/NetworkModAPI.cpp
modplatform/helpers/HashUtils.h
modplatform/helpers/HashUtils.cpp
modplatform/helpers/OverrideUtils.h
modplatform/helpers/OverrideUtils.cpp
)
set(FTB_SOURCES
@ -527,11 +485,21 @@ set(FLAME_SOURCES
modplatform/flame/PackManifest.cpp
modplatform/flame/FileResolvingTask.h
modplatform/flame/FileResolvingTask.cpp
modplatform/flame/FlameCheckUpdate.cpp
modplatform/flame/FlameCheckUpdate.h
modplatform/flame/FlameInstanceCreationTask.h
modplatform/flame/FlameInstanceCreationTask.cpp
)
set(MODRINTH_SOURCES
modplatform/modrinth/ModrinthPackIndex.cpp
modplatform/modrinth/ModrinthPackIndex.h
modplatform/modrinth/ModrinthPackManifest.cpp
modplatform/modrinth/ModrinthPackManifest.h
modplatform/modrinth/ModrinthCheckUpdate.cpp
modplatform/modrinth/ModrinthCheckUpdate.h
modplatform/modrinth/ModrinthInstanceCreationTask.cpp
modplatform/modrinth/ModrinthInstanceCreationTask.h
)
set(MODPACKSCH_SOURCES
@ -541,6 +509,12 @@ set(MODPACKSCH_SOURCES
modplatform/modpacksch/FTBPackManifest.cpp
)
set(PACKWIZ_SOURCES
modplatform/packwiz/Packwiz.h
modplatform/packwiz/Packwiz.cpp
)
set(TECHNIC_SOURCES
modplatform/technic/SingleZipPackInstallTask.h
modplatform/technic/SingleZipPackInstallTask.cpp
@ -559,13 +533,10 @@ set(ATLAUNCHER_SOURCES
modplatform/atlauncher/ATLPackInstallTask.h
modplatform/atlauncher/ATLPackManifest.cpp
modplatform/atlauncher/ATLPackManifest.h
modplatform/atlauncher/ATLShareCode.cpp
modplatform/atlauncher/ATLShareCode.h
)
add_unit_test(Index
SOURCES meta/Index_test.cpp
LIBS Launcher_logic
)
################################ COMPILE ################################
# we need zlib
@ -592,10 +563,15 @@ set(LOGIC_SOURCES
${FLAME_SOURCES}
${MODRINTH_SOURCES}
${MODPACKSCH_SOURCES}
${PACKWIZ_SOURCES}
${TECHNIC_SOURCES}
${ATLAUNCHER_SOURCES}
)
if(APPLE)
set (LOGIC_SOURCES ${LOGIC_SOURCES} ${MAC_UPDATE_SOURCES})
endif()
SET(LAUNCHER_SOURCES
# Application base
Application.h
@ -657,6 +633,8 @@ SET(LAUNCHER_SOURCES
ui/setupwizard/JavaWizardPage.h
ui/setupwizard/LanguageWizardPage.cpp
ui/setupwizard/LanguageWizardPage.h
ui/setupwizard/PasteWizardPage.cpp
ui/setupwizard/PasteWizardPage.h
# GUI - themes
ui/themes/FusionTheme.cpp
@ -689,6 +667,8 @@ SET(LAUNCHER_SOURCES
ui/pages/BasePageProvider.h
# GUI - instance pages
ui/pages/instance/ExternalResourcesPage.cpp
ui/pages/instance/ExternalResourcesPage.h
ui/pages/instance/GameOptionsPage.cpp
ui/pages/instance/GameOptionsPage.h
ui/pages/instance/VersionPage.cpp
@ -750,6 +730,8 @@ SET(LAUNCHER_SOURCES
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h
ui/pages/modplatform/atlauncher/AtlPage.cpp
ui/pages/modplatform/atlauncher/AtlPage.h
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.cpp
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.h
ui/pages/modplatform/ftb/FtbFilterModel.cpp
ui/pages/modplatform/ftb/FtbFilterModel.h
@ -772,6 +754,11 @@ SET(LAUNCHER_SOURCES
ui/pages/modplatform/flame/FlameModPage.cpp
ui/pages/modplatform/flame/FlameModPage.h
ui/pages/modplatform/modrinth/ModrinthPage.cpp
ui/pages/modplatform/modrinth/ModrinthPage.h
ui/pages/modplatform/modrinth/ModrinthModel.cpp
ui/pages/modplatform/modrinth/ModrinthModel.h
ui/pages/modplatform/technic/TechnicModel.cpp
ui/pages/modplatform/technic/TechnicModel.h
ui/pages/modplatform/technic/TechnicPage.cpp
@ -780,10 +767,10 @@ SET(LAUNCHER_SOURCES
ui/pages/modplatform/ImportPage.cpp
ui/pages/modplatform/ImportPage.h
ui/pages/modplatform/modrinth/ModrinthModel.cpp
ui/pages/modplatform/modrinth/ModrinthModel.h
ui/pages/modplatform/modrinth/ModrinthPage.cpp
ui/pages/modplatform/modrinth/ModrinthPage.h
ui/pages/modplatform/modrinth/ModrinthModModel.cpp
ui/pages/modplatform/modrinth/ModrinthModModel.h
ui/pages/modplatform/modrinth/ModrinthModPage.cpp
ui/pages/modplatform/modrinth/ModrinthModPage.h
# GUI - dialogs
ui/dialogs/AboutDialog.cpp
@ -812,6 +799,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/NewComponentDialog.h
ui/dialogs/NewInstanceDialog.cpp
ui/dialogs/NewInstanceDialog.h
ui/dialogs/NewsDialog.cpp
ui/dialogs/NewsDialog.h
ui/pagedialog/PageDialog.cpp
ui/pagedialog/PageDialog.h
ui/dialogs/ProgressDialog.cpp
@ -826,6 +815,14 @@ SET(LAUNCHER_SOURCES
ui/dialogs/SkinUploadDialog.h
ui/dialogs/ModDownloadDialog.cpp
ui/dialogs/ModDownloadDialog.h
ui/dialogs/ScrollMessageBox.cpp
ui/dialogs/ScrollMessageBox.h
ui/dialogs/BlockedModsDialog.cpp
ui/dialogs/BlockedModsDialog.h
ui/dialogs/ChooseProviderDialog.h
ui/dialogs/ChooseProviderDialog.cpp
ui/dialogs/ModUpdateDialog.cpp
ui/dialogs/ModUpdateDialog.h
# GUI - widgets
ui/widgets/Common.cpp
@ -848,8 +845,8 @@ SET(LAUNCHER_SOURCES
ui/widgets/LineSeparator.h
ui/widgets/LogView.cpp
ui/widgets/LogView.h
ui/widgets/MCModInfoFrame.cpp
ui/widgets/MCModInfoFrame.h
ui/widgets/InfoFrame.cpp
ui/widgets/InfoFrame.h
ui/widgets/ModFilterWidget.cpp
ui/widgets/ModFilterWidget.h
ui/widgets/ModListView.cpp
@ -857,6 +854,12 @@ SET(LAUNCHER_SOURCES
ui/widgets/PageContainer.cpp
ui/widgets/PageContainer.h
ui/widgets/PageContainer_p.h
ui/widgets/ProjectDescriptionPage.h
ui/widgets/ProjectDescriptionPage.cpp
ui/widgets/VariableSizedImageObject.h
ui/widgets/VariableSizedImageObject.cpp
ui/widgets/ProjectItem.h
ui/widgets/ProjectItem.cpp
ui/widgets/VersionListView.cpp
ui/widgets/VersionListView.h
ui/widgets/VersionSelectWidget.cpp
@ -880,7 +883,18 @@ SET(LAUNCHER_SOURCES
ui/instanceview/VisualGroup.h
)
qt5_wrap_ui(LAUNCHER_UI
if(WIN32)
set(LAUNCHER_SOURCES
${LAUNCHER_SOURCES}
# GUI - dark titlebar for Windows 10/11
ui/WinDarkmode.h
ui/WinDarkmode.cpp
)
endif()
qt_wrap_ui(LAUNCHER_UI
ui/setupwizard/PasteWizardPage.ui
ui/pages/global/AccountListPage.ui
ui/pages/global/JavaPage.ui
ui/pages/global/LauncherPage.ui
@ -888,7 +902,7 @@ qt5_wrap_ui(LAUNCHER_UI
ui/pages/global/ProxyPage.ui
ui/pages/global/MinecraftPage.ui
ui/pages/global/ExternalToolsPage.ui
ui/pages/instance/ModFolderPage.ui
ui/pages/instance/ExternalResourcesPage.ui
ui/pages/instance/NotesPage.ui
ui/pages/instance/LogPage.ui
ui/pages/instance/ServersPage.ui
@ -906,10 +920,11 @@ qt5_wrap_ui(LAUNCHER_UI
ui/pages/modplatform/legacy_ftb/Page.ui
ui/pages/modplatform/ImportPage.ui
ui/pages/modplatform/ftb/FtbPage.ui
ui/pages/modplatform/modrinth/ModrinthPage.ui
ui/pages/modplatform/technic/TechnicPage.ui
ui/widgets/InstanceCardWidget.ui
ui/widgets/CustomCommands.ui
ui/widgets/MCModInfoFrame.ui
ui/widgets/InfoFrame.ui
ui/widgets/ModFilterWidget.ui
ui/dialogs/CopyInstanceDialog.ui
ui/dialogs/ProfileSetupDialog.ui
@ -917,6 +932,7 @@ qt5_wrap_ui(LAUNCHER_UI
ui/dialogs/NewInstanceDialog.ui
ui/dialogs/UpdateDialog.ui
ui/dialogs/NewComponentDialog.ui
ui/dialogs/NewsDialog.ui
ui/dialogs/ProfileSelectDialog.ui
ui/dialogs/SkinUploadDialog.ui
ui/dialogs/ExportInstanceDialog.ui
@ -927,9 +943,12 @@ qt5_wrap_ui(LAUNCHER_UI
ui/dialogs/LoginDialog.ui
ui/dialogs/EditAccountDialog.ui
ui/dialogs/ReviewMessageBox.ui
ui/dialogs/ScrollMessageBox.ui
ui/dialogs/BlockedModsDialog.ui
ui/dialogs/ChooseProviderDialog.ui
)
qt5_add_resources(LAUNCHER_RESOURCES
qt_add_resources(LAUNCHER_RESOURCES
resources/backgrounds/backgrounds.qrc
resources/multimc/multimc.qrc
resources/pe_dark/pe_dark.qrc
@ -945,35 +964,61 @@ qt5_add_resources(LAUNCHER_RESOURCES
######## Windows resource files ########
if(WIN32)
set(LAUNCHER_RCS ../${Launcher_Branding_WindowsRC})
set(LAUNCHER_RCS ${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_WindowsRC})
endif()
# Add executable
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(Launcher_logic
systeminfo
Launcher_classparser
Launcher_murmur2
nbt++
${ZLIB_LIBRARIES}
optional-bare
tomlc99
tomlplusplus::tomlplusplus
BuildConfig
Katabasis
Qt${QT_VERSION_MAJOR}::Widgets
ghcFilesystem::ghc_filesystem
)
if (UNIX AND NOT CYGWIN AND NOT APPLE)
target_link_libraries(Launcher_logic
gamemode
)
endif()
target_link_libraries(Launcher_logic
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Xml
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Concurrent
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
${Launcher_QT_LIBS}
)
target_link_libraries(Launcher_logic
Qt5::Core
Qt5::Xml
Qt5::Network
Qt5::Concurrent
Qt5::Gui
)
target_link_libraries(Launcher_logic
Launcher_iconfix
QuaZip::QuaZip
hoedown
LocalPeer
Launcher_rainbow
)
if(APPLE)
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
target_link_libraries(Launcher_logic
"-framework AppKit"
"-framework Carbon"
"-framework Foundation"
"-framework ApplicationServices"
)
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
endif()
target_link_libraries(Launcher_logic)
@ -996,8 +1041,16 @@ install(TARGETS ${Launcher_Name}
BUNDLE DESTINATION "." COMPONENT Runtime
LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime
)
if (UNIX AND APPLE)
# Add Sparkle updater
# It has to be copied here instead of just allowing fixup_bundle to install it, otherwise essential parts of
# the framework aren't installed
install(DIRECTORY ${MACOSX_SPARKLE_DIR}/Sparkle.framework DESTINATION ${FRAMEWORK_DEST_DIR} USE_SOURCE_PERMISSIONS)
endif()
#### The bundle mess! ####
# Bundle utilities are used to complete the portable packages - they add all the libraries that would otherwise be missing on the target system.
# NOTE: it seems that this absolutely has to be here, and nowhere else.
@ -1038,6 +1091,14 @@ if(INSTALL_BUNDLE STREQUAL "full")
COMPONENT Runtime
)
endif()
# TLS plugins (Qt 6 only)
if(EXISTS "${QT_PLUGINS_DIR}/tls")
install(
DIRECTORY "${QT_PLUGINS_DIR}/tls"
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
)
endif()
else()
# Image formats
install(
@ -1080,6 +1141,16 @@ if(INSTALL_BUNDLE STREQUAL "full")
REGEX "\\.dSYM" EXCLUDE
)
endif()
# TLS plugins (Qt 6 only)
if(EXISTS "${QT_PLUGINS_DIR}/tls")
install(
DIRECTORY "${QT_PLUGINS_DIR}/tls"
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
REGEX "_debug\\." EXCLUDE
REGEX "\\.dSYM" EXCLUDE
)
endif()
endif()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"

View File

@ -1,18 +1,38 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* http://www.apache.org/licenses/LICENSE-2.0
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Commandline.h"
@ -47,7 +67,7 @@ QStringList splitArgs(QString args)
if (cchar == '\\')
escape = true;
else if (cchar == inquotes)
inquotes = 0;
inquotes = QChar::Null;
else
current += cchar;
// otherwise
@ -72,412 +92,4 @@ QStringList splitArgs(QString args)
argv << current;
return argv;
}
Parser::Parser(FlagStyle::Enum flagStyle, ArgumentStyle::Enum argStyle)
{
m_flagStyle = flagStyle;
m_argStyle = argStyle;
}
// styles setter/getter
void Parser::setArgumentStyle(ArgumentStyle::Enum style)
{
m_argStyle = style;
}
ArgumentStyle::Enum Parser::argumentStyle()
{
return m_argStyle;
}
void Parser::setFlagStyle(FlagStyle::Enum style)
{
m_flagStyle = style;
}
FlagStyle::Enum Parser::flagStyle()
{
return m_flagStyle;
}
// setup methods
void Parser::addSwitch(QString name, bool def)
{
if (m_params.contains(name))
throw "Name not unique";
OptionDef *param = new OptionDef;
param->type = otSwitch;
param->name = name;
param->metavar = QString("<%1>").arg(name);
param->def = def;
m_options[name] = param;
m_params[name] = (CommonDef *)param;
m_optionList.append(param);
}
void Parser::addOption(QString name, QVariant def)
{
if (m_params.contains(name))
throw "Name not unique";
OptionDef *param = new OptionDef;
param->type = otOption;
param->name = name;
param->metavar = QString("<%1>").arg(name);
param->def = def;
m_options[name] = param;
m_params[name] = (CommonDef *)param;
m_optionList.append(param);
}
void Parser::addArgument(QString name, bool required, QVariant def)
{
if (m_params.contains(name))
throw "Name not unique";
PositionalDef *param = new PositionalDef;
param->name = name;
param->def = def;
param->required = required;
param->metavar = name;
m_positionals.append(param);
m_params[name] = (CommonDef *)param;
}
void Parser::addDocumentation(QString name, QString doc, QString metavar)
{
if (!m_params.contains(name))
throw "Name does not exist";
CommonDef *param = m_params[name];
param->doc = doc;
if (!metavar.isNull())
param->metavar = metavar;
}
void Parser::addShortOpt(QString name, QChar flag)
{
if (!m_params.contains(name))
throw "Name does not exist";
if (!m_options.contains(name))
throw "Name is not an Option or Swtich";
OptionDef *param = m_options[name];
m_flags[flag] = param;
param->flag = flag;
}
// help methods
QString Parser::compileHelp(QString progName, int helpIndent, bool useFlags)
{
QStringList help;
help << compileUsage(progName, useFlags) << "\r\n";
// positionals
if (!m_positionals.isEmpty())
{
help << "\r\n";
help << "Positional arguments:\r\n";
QListIterator<PositionalDef *> it2(m_positionals);
while (it2.hasNext())
{
PositionalDef *param = it2.next();
help << " " << param->metavar;
help << " " << QString(helpIndent - param->metavar.length() - 1, ' ');
help << param->doc << "\r\n";
}
}
// Options
if (!m_optionList.isEmpty())
{
help << "\r\n";
QString optPrefix, flagPrefix;
getPrefix(optPrefix, flagPrefix);
help << "Options & Switches:\r\n";
QListIterator<OptionDef *> it(m_optionList);
while (it.hasNext())
{
OptionDef *option = it.next();
help << " ";
int nameLength = optPrefix.length() + option->name.length();
if (!option->flag.isNull())
{
nameLength += 3 + flagPrefix.length();
help << flagPrefix << option->flag << ", ";
}
help << optPrefix << option->name;
if (option->type == otOption)
{
QString arg = QString("%1%2").arg(
((m_argStyle == ArgumentStyle::Equals) ? "=" : " "), option->metavar);
nameLength += arg.length();
help << arg;
}
help << " " << QString(helpIndent - nameLength - 1, ' ');
help << option->doc << "\r\n";
}
}
return help.join("");
}
QString Parser::compileUsage(QString progName, bool useFlags)
{
QStringList usage;
usage << "Usage: " << progName;
QString optPrefix, flagPrefix;
getPrefix(optPrefix, flagPrefix);
// options
QListIterator<OptionDef *> it(m_optionList);
while (it.hasNext())
{
OptionDef *option = it.next();
usage << " [";
if (!option->flag.isNull() && useFlags)
usage << flagPrefix << option->flag;
else
usage << optPrefix << option->name;
if (option->type == otOption)
usage << ((m_argStyle == ArgumentStyle::Equals) ? "=" : " ") << option->metavar;
usage << "]";
}
// arguments
QListIterator<PositionalDef *> it2(m_positionals);
while (it2.hasNext())
{
PositionalDef *param = it2.next();
usage << " " << (param->required ? "<" : "[");
usage << param->metavar;
usage << (param->required ? ">" : "]");
}
return usage.join("");
}
// parsing
QHash<QString, QVariant> Parser::parse(QStringList argv)
{
QHash<QString, QVariant> map;
QStringListIterator it(argv);
QString programName = it.next();
QString optionPrefix;
QString flagPrefix;
QListIterator<PositionalDef *> positionals(m_positionals);
QStringList expecting;
getPrefix(optionPrefix, flagPrefix);
while (it.hasNext())
{
QString arg = it.next();
if (!expecting.isEmpty())
// we were expecting an argument
{
QString name = expecting.first();
/*
if (map.contains(name))
throw ParsingError(
QString("Option %2%1 was given multiple times").arg(name, optionPrefix));
*/
map[name] = QVariant(arg);
expecting.removeFirst();
continue;
}
if (arg.startsWith(optionPrefix))
// we have an option
{
// qDebug("Found option %s", qPrintable(arg));
QString name = arg.mid(optionPrefix.length());
QString equals;
if ((m_argStyle == ArgumentStyle::Equals ||
m_argStyle == ArgumentStyle::SpaceAndEquals) &&
name.contains("="))
{
int i = name.indexOf("=");
equals = name.mid(i + 1);
name = name.left(i);
}
if (m_options.contains(name))
{
/*
if (map.contains(name))
throw ParsingError(QString("Option %2%1 was given multiple times")
.arg(name, optionPrefix));
*/
OptionDef *option = m_options[name];
if (option->type == otSwitch)
map[name] = true;
else // if (option->type == otOption)
{
if (m_argStyle == ArgumentStyle::Space)
expecting.append(name);
else if (!equals.isNull())
map[name] = equals;
else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
expecting.append(name);
else
throw ParsingError(QString("Option %2%1 reqires an argument.")
.arg(name, optionPrefix));
}
continue;
}
throw ParsingError(QString("Unknown Option %2%1").arg(name, optionPrefix));
}
if (arg.startsWith(flagPrefix))
// we have (a) flag(s)
{
// qDebug("Found flags %s", qPrintable(arg));
QString flags = arg.mid(flagPrefix.length());
QString equals;
if ((m_argStyle == ArgumentStyle::Equals ||
m_argStyle == ArgumentStyle::SpaceAndEquals) &&
flags.contains("="))
{
int i = flags.indexOf("=");
equals = flags.mid(i + 1);
flags = flags.left(i);
}
for (int i = 0; i < flags.length(); i++)
{
QChar flag = flags.at(i);
if (!m_flags.contains(flag))
throw ParsingError(QString("Unknown flag %2%1").arg(flag, flagPrefix));
OptionDef *option = m_flags[flag];
/*
if (map.contains(option->name))
throw ParsingError(QString("Option %2%1 was given multiple times")
.arg(option->name, optionPrefix));
*/
if (option->type == otSwitch)
map[option->name] = true;
else // if (option->type == otOption)
{
if (m_argStyle == ArgumentStyle::Space)
expecting.append(option->name);
else if (!equals.isNull())
if (i == flags.length() - 1)
map[option->name] = equals;
else
throw ParsingError(QString("Flag %4%2 of Argument-requiring Option "
"%1 not last flag in %4%3")
.arg(option->name, flag, flags, flagPrefix));
else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
expecting.append(option->name);
else
throw ParsingError(QString("Option %1 reqires an argument. (flag %3%2)")
.arg(option->name, flag, flagPrefix));
}
}
continue;
}
// must be a positional argument
if (!positionals.hasNext())
throw ParsingError(QString("Don't know what to do with '%1'").arg(arg));
PositionalDef *param = positionals.next();
map[param->name] = arg;
}
// check if we're missing something
if (!expecting.isEmpty())
throw ParsingError(QString("Was still expecting arguments for %2%1").arg(
expecting.join(QString(", ") + optionPrefix), optionPrefix));
while (positionals.hasNext())
{
PositionalDef *param = positionals.next();
if (param->required)
throw ParsingError(
QString("Missing required positional argument '%1'").arg(param->name));
else
map[param->name] = param->def;
}
// fill out gaps
QListIterator<OptionDef *> iter(m_optionList);
while (iter.hasNext())
{
OptionDef *option = iter.next();
if (!map.contains(option->name))
map[option->name] = option->def;
}
return map;
}
// clear defs
void Parser::clear()
{
m_flags.clear();
m_params.clear();
m_options.clear();
QMutableListIterator<OptionDef *> it(m_optionList);
while (it.hasNext())
{
OptionDef *option = it.next();
it.remove();
delete option;
}
QMutableListIterator<PositionalDef *> it2(m_positionals);
while (it2.hasNext())
{
PositionalDef *arg = it2.next();
it2.remove();
delete arg;
}
}
// Destructor
Parser::~Parser()
{
clear();
}
// getPrefix
void Parser::getPrefix(QString &opt, QString &flag)
{
if (m_flagStyle == FlagStyle::Windows)
opt = flag = "/";
else if (m_flagStyle == FlagStyle::Unix)
opt = flag = "-";
// else if (m_flagStyle == FlagStyle::GNU)
else
{
opt = "--";
flag = "-";
}
}
// ParsingError
ParsingError::ParsingError(const QString &what) : std::runtime_error(what.toStdString())
{
}
}

View File

@ -17,12 +17,7 @@
#pragma once
#include <exception>
#include <stdexcept>
#include <QString>
#include <QVariant>
#include <QHash>
#include <QStringList>
/**
@ -39,212 +34,4 @@ namespace Commandline
* @return a QStringList containing all arguments
*/
QStringList splitArgs(QString args);
/**
* @brief The FlagStyle enum
* Specifies how flags are decorated
*/
namespace FlagStyle
{
enum Enum
{
GNU, /**< --option and -o (GNU Style) */
Unix, /**< -option and -o (Unix Style) */
Windows, /**< /option and /o (Windows Style) */
#ifdef Q_OS_WIN32
Default = Windows
#else
Default = GNU
#endif
};
}
/**
* @brief The ArgumentStyle enum
*/
namespace ArgumentStyle
{
enum Enum
{
Space, /**< --option value */
Equals, /**< --option=value */
SpaceAndEquals, /**< --option[= ]value */
#ifdef Q_OS_WIN32
Default = Equals
#else
Default = SpaceAndEquals
#endif
};
}
/**
* @brief The ParsingError class
*/
class ParsingError : public std::runtime_error
{
public:
ParsingError(const QString &what);
};
/**
* @brief The Parser class
*/
class Parser
{
public:
/**
* @brief Parser constructor
* @param flagStyle the FlagStyle to use in this Parser
* @param argStyle the ArgumentStyle to use in this Parser
*/
Parser(FlagStyle::Enum flagStyle = FlagStyle::Default,
ArgumentStyle::Enum argStyle = ArgumentStyle::Default);
/**
* @brief set the flag style
* @param style
*/
void setFlagStyle(FlagStyle::Enum style);
/**
* @brief get the flag style
* @return
*/
FlagStyle::Enum flagStyle();
/**
* @brief set the argument style
* @param style
*/
void setArgumentStyle(ArgumentStyle::Enum style);
/**
* @brief get the argument style
* @return
*/
ArgumentStyle::Enum argumentStyle();
/**
* @brief define a boolean switch
* @param name the parameter name
* @param def the default value
*/
void addSwitch(QString name, bool def = false);
/**
* @brief define an option that takes an additional argument
* @param name the parameter name
* @param def the default value
*/
void addOption(QString name, QVariant def = QVariant());
/**
* @brief define a positional argument
* @param name the parameter name
* @param required wether this argument is required
* @param def the default value
*/
void addArgument(QString name, bool required = true, QVariant def = QVariant());
/**
* @brief adds a flag to an existing parameter
* @param name the (existing) parameter name
* @param flag the flag character
* @see addSwitch addArgument addOption
* Note: any one parameter can only have one flag
*/
void addShortOpt(QString name, QChar flag);
/**
* @brief adds documentation to a Parameter
* @param name the parameter name
* @param metavar a string to be displayed as placeholder for the value
* @param doc a QString containing the documentation
* Note: on positional arguments, metavar replaces the name as displayed.
* on options , metavar replaces the value placeholder
*/
void addDocumentation(QString name, QString doc, QString metavar = QString());
/**
* @brief generate a help message
* @param progName the program name to use in the help message
* @param helpIndent how much the parameter documentation should be indented
* @param flagsInUsage whether we should use flags instead of options in the usage
* @return a help message
*/
QString compileHelp(QString progName, int helpIndent = 22, bool flagsInUsage = true);
/**
* @brief generate a short usage message
* @param progName the program name to use in the usage message
* @param useFlags whether we should use flags instead of options
* @return a usage message
*/
QString compileUsage(QString progName, bool useFlags = true);
/**
* @brief parse
* @param argv a QStringList containing the program ARGV
* @return a QHash mapping argument names to their values
*/
QHash<QString, QVariant> parse(QStringList argv);
/**
* @brief clear all definitions
*/
void clear();
~Parser();
private:
FlagStyle::Enum m_flagStyle;
ArgumentStyle::Enum m_argStyle;
enum OptionType
{
otSwitch,
otOption
};
// Important: the common part MUST BE COMMON ON ALL THREE structs
struct CommonDef
{
QString name;
QString doc;
QString metavar;
QVariant def;
};
struct OptionDef
{
// common
QString name;
QString doc;
QString metavar;
QVariant def;
// option
OptionType type;
QChar flag;
};
struct PositionalDef
{
// common
QString name;
QString doc;
QString metavar;
QVariant def;
// positional
bool required;
};
QHash<QString, OptionDef *> m_options;
QHash<QChar, OptionDef *> m_flags;
QHash<QString, CommonDef *> m_params;
QList<PositionalDef *> m_positionals;
QList<OptionDef *> m_optionList;
void getPrefix(QString &opt, QString &flag);
};
}

View File

@ -119,7 +119,7 @@ bool openDirectory(const QString &path, bool ensureExists)
return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
};
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
if(!APPLICATION->isFlatpak())
if(!isFlatpak())
{
return IndirectOpen(f);
}
@ -140,7 +140,7 @@ bool openFile(const QString &path)
return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
};
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
if(!APPLICATION->isFlatpak())
if(!isFlatpak())
{
return IndirectOpen(f);
}
@ -158,7 +158,7 @@ bool openFile(const QString &application, const QString &path, const QString &wo
qDebug() << "Opening file" << path << "using" << application;
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
if(!APPLICATION->isFlatpak())
if(!isFlatpak())
{
return IndirectOpen([&]()
{
@ -178,7 +178,7 @@ bool run(const QString &application, const QStringList &args, const QString &wor
{
qDebug() << "Running" << application << "with args" << args.join(' ');
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
if(!APPLICATION->isFlatpak())
if(!isFlatpak())
{
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
return IndirectOpen([&]()
@ -203,7 +203,7 @@ bool openUrl(const QUrl &url)
return QDesktopServices::openUrl(url);
};
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
if(!APPLICATION->isFlatpak())
if(!isFlatpak())
{
return IndirectOpen(f);
}
@ -216,4 +216,13 @@ bool openUrl(const QUrl &url)
#endif
}
bool isFlatpak()
{
#ifdef Q_OS_LINUX
return QFile::exists("/.flatpak-info");
#else
return false;
#endif
}
}

View File

@ -33,4 +33,6 @@ namespace DesktopServices
* Open the URL, most likely in a browser. Maybe.
*/
bool openUrl(const QUrl &url);
bool isFlatpak();
}

View File

@ -1,77 +1,135 @@
// Licensed under the Apache-2.0 license. See README.md for details.
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "FileSystem.h"
#include <QDir>
#include <QFile>
#include <QSaveFile>
#include <QFileInfo>
#include <QDebug>
#include <QUrl>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QSaveFile>
#include <QStandardPaths>
#include <QTextStream>
#include <QUrl>
#include "DesktopServices.h"
#if defined Q_OS_WIN32
#include <windows.h>
#include <string>
#include <sys/utime.h>
#include <winnls.h>
#include <shobjidl.h>
#include <objbase.h>
#include <objidl.h>
#include <shlguid.h>
#include <shlobj.h>
#include <objbase.h>
#include <objidl.h>
#include <shlguid.h>
#include <shlobj.h>
#include <shobjidl.h>
#include <sys/utime.h>
#include <windows.h>
#include <winnls.h>
#include <string>
#else
#include <utime.h>
#include <utime.h>
#endif
// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header
#ifdef __APPLE__
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
#endif // __APPLE__
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#endif // MacOS min version check
#endif // Other OSes version check
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
#if defined Q_OS_WIN32
std::wstring toStdString(QString s)
{
return s.toStdWString();
}
#else
std::string toStdString(QString s)
{
return s.toStdString();
}
#endif
namespace FS {
void ensureExists(const QDir &dir)
void ensureExists(const QDir& dir)
{
if (!QDir().mkpath(dir.absolutePath()))
{
throw FileSystemException("Unable to create folder " + dir.dirName() + " (" +
dir.absolutePath() + ")");
if (!QDir().mkpath(dir.absolutePath())) {
throw FileSystemException("Unable to create folder " + dir.dirName() + " (" + dir.absolutePath() + ")");
}
}
void write(const QString &filename, const QByteArray &data)
void write(const QString& filename, const QByteArray& data)
{
ensureExists(QFileInfo(filename).dir());
QSaveFile file(filename);
if (!file.open(QSaveFile::WriteOnly))
{
throw FileSystemException("Couldn't open " + filename + " for writing: " +
file.errorString());
if (!file.open(QSaveFile::WriteOnly)) {
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
}
if (data.size() != file.write(data))
{
throw FileSystemException("Error writing data to " + filename + ": " +
file.errorString());
if (data.size() != file.write(data)) {
throw FileSystemException("Error writing data to " + filename + ": " + file.errorString());
}
if (!file.commit())
{
throw FileSystemException("Error while committing data to " + filename + ": " +
file.errorString());
if (!file.commit()) {
throw FileSystemException("Error while committing data to " + filename + ": " + file.errorString());
}
}
QByteArray read(const QString &filename)
QByteArray read(const QString& filename)
{
QFile file(filename);
if (!file.open(QFile::ReadOnly))
{
throw FileSystemException("Unable to open " + filename + " for reading: " +
file.errorString());
if (!file.open(QFile::ReadOnly)) {
throw FileSystemException("Unable to open " + filename + " for reading: " + file.errorString());
}
const qint64 size = file.size();
QByteArray data(int(size), 0);
const qint64 ret = file.read(data.data(), size);
if (ret == -1 || ret != size)
{
throw FileSystemException("Error reading data from " + filename + ": " +
file.errorString());
if (ret == -1 || ret != size) {
throw FileSystemException("Error reading data from " + filename + ": " + file.errorString());
}
return data;
}
@ -105,149 +163,102 @@ bool ensureFolderPathExists(QString foldernamepath)
return success;
}
bool copy::operator()(const QString &offset)
bool copy::operator()(const QString& offset)
{
//NOTE always deep copy on windows. the alternatives are too messy.
#if defined Q_OS_WIN32
using copy_opts = fs::copy_options;
// NOTE always deep copy on windows. the alternatives are too messy.
#if defined Q_OS_WIN32
m_followSymlinks = true;
#endif
#endif
auto src = PathCombine(m_src.absolutePath(), offset);
auto dst = PathCombine(m_dst.absolutePath(), offset);
QFileInfo currentSrc(src);
if (!currentSrc.exists())
return false;
std::error_code err;
if(!m_followSymlinks && currentSrc.isSymLink())
{
qDebug() << "creating symlink" << src << " - " << dst;
if (!ensureFilePathExists(dst))
{
qWarning() << "Cannot create path!";
return false;
fs::copy_options opt = copy_opts::none;
// The default behavior is to follow symlinks
if (!m_followSymlinks)
opt |= copy_opts::copy_symlinks;
// Function that'll do the actual copying
auto copy_file = [&](QString src_path, QString relative_dst_path) {
if (m_blacklist && m_blacklist->matches(relative_dst_path))
return;
auto dst_path = PathCombine(dst, relative_dst_path);
ensureFilePathExists(dst_path);
fs::copy(toStdString(src_path), toStdString(dst_path), opt, err);
if (err) {
qWarning() << "Failed to copy files:" << QString::fromStdString(err.message());
qDebug() << "Source file:" << src_path;
qDebug() << "Destination file:" << dst_path;
}
return QFile::link(currentSrc.symLinkTarget(), dst);
};
// We can't use copy_opts::recursive because we need to take into account the
// blacklisted paths, so we iterate over the source directory, and if there's no blacklist
// match, we copy the file.
QDir src_dir(src);
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
while (source_it.hasNext()) {
auto src_path = source_it.next();
auto relative_path = src_dir.relativeFilePath(src_path);
copy_file(src_path, relative_path);
}
else if(currentSrc.isFile())
{
qDebug() << "copying file" << src << " - " << dst;
if (!ensureFilePathExists(dst))
{
qWarning() << "Cannot create path!";
return false;
}
return QFile::copy(src, dst);
}
else if(currentSrc.isDir())
{
qDebug() << "recursing" << offset;
if (!ensureFolderPathExists(dst))
{
qWarning() << "Cannot create path!";
return false;
}
QDir currentDir(src);
for(auto & f : currentDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System))
{
auto inner_offset = PathCombine(offset, f);
// ignore and skip stuff that matches the blacklist.
if(m_blacklist && m_blacklist->matches(inner_offset))
{
continue;
}
if(!operator()(inner_offset))
{
qWarning() << "Failed to copy" << inner_offset;
return false;
}
}
}
else
{
qCritical() << "Copy ERROR: Unknown filesystem object:" << src;
return false;
}
return true;
// If the root src is not a directory, the previous iterator won't run.
if (!fs::is_directory(toStdString(src)))
copy_file(src, "");
return err.value() == 0;
}
bool deletePath(QString path)
{
bool OK = true;
QFileInfo finfo(path);
if(finfo.isFile()) {
return QFile::remove(path);
std::error_code err;
fs::remove_all(toStdString(path), err);
if (err) {
qWarning() << "Failed to remove files:" << QString::fromStdString(err.message());
}
QDir dir(path);
if (!dir.exists())
{
return OK;
}
auto allEntries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden |
QDir::AllDirs | QDir::Files,
QDir::DirsFirst);
for(auto & info: allEntries)
{
#if defined Q_OS_WIN32
QString nativePath = QDir::toNativeSeparators(info.absoluteFilePath());
auto wString = nativePath.toStdWString();
DWORD dwAttrs = GetFileAttributesW(wString.c_str());
// Windows: check for junctions, reparse points and other nasty things of that sort
if(dwAttrs & FILE_ATTRIBUTE_REPARSE_POINT)
{
if (info.isFile())
{
OK &= QFile::remove(info.absoluteFilePath());
}
else if (info.isDir())
{
OK &= dir.rmdir(info.absoluteFilePath());
}
}
#else
// We do not trust Qt with reparse points, but do trust it with unix symlinks.
if(info.isSymLink())
{
OK &= QFile::remove(info.absoluteFilePath());
}
#endif
else if (info.isDir())
{
OK &= deletePath(info.absoluteFilePath());
}
else if (info.isFile())
{
OK &= QFile::remove(info.absoluteFilePath());
}
else
{
OK = false;
qCritical() << "Delete ERROR: Unknown filesystem object:" << info.absoluteFilePath();
}
}
OK &= dir.rmdir(dir.absolutePath());
return OK;
return err.value() == 0;
}
QString PathCombine(const QString & path1, const QString & path2)
bool trash(QString path, QString *pathInTrash = nullptr)
{
if(!path1.size())
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
return false;
#else
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
if (DesktopServices::isFlatpak())
return false;
return QFile::moveToTrash(path, pathInTrash);
#endif
}
QString PathCombine(const QString& path1, const QString& path2)
{
if (!path1.size())
return path2;
if(!path2.size())
if (!path2.size())
return path1;
return QDir::cleanPath(path1 + QDir::separator() + path2);
}
QString PathCombine(const QString & path1, const QString & path2, const QString & path3)
QString PathCombine(const QString& path1, const QString& path2, const QString& path3)
{
return PathCombine(PathCombine(path1, path2), path3);
}
QString PathCombine(const QString & path1, const QString & path2, const QString & path3, const QString & path4)
QString PathCombine(const QString& path1, const QString& path2, const QString& path3, const QString& path4)
{
return PathCombine(PathCombine(path1, path2, path3), path4);
}
@ -259,17 +270,14 @@ QString AbsolutePath(QString path)
QString ResolveExecutable(QString path)
{
if (path.isEmpty())
{
if (path.isEmpty()) {
return QString();
}
if(!path.contains('/'))
{
if (!path.contains('/')) {
path = QStandardPaths::findExecutable(path);
}
QFileInfo pathInfo(path);
if(!pathInfo.exists() || !pathInfo.isExecutable())
{
if (!pathInfo.exists() || !pathInfo.isExecutable()) {
return QString();
}
return pathInfo.absoluteFilePath();
@ -289,12 +297,9 @@ QString NormalizePath(QString path)
QDir b(path);
QString newAbsolute = b.absolutePath();
if (newAbsolute.startsWith(currentAbsolute))
{
if (newAbsolute.startsWith(currentAbsolute)) {
return a.relativeFilePath(newAbsolute);
}
else
{
} else {
return newAbsolute;
}
}
@ -303,10 +308,8 @@ QString badFilenameChars = "\"\\/?<>:;*|!+\r\n";
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
{
for (int i = 0; i < string.length(); i++)
{
if (badFilenameChars.contains(string[i]))
{
for (int i = 0; i < string.length(); i++) {
if (badFilenameChars.contains(string[i])) {
string[i] = replaceWith;
}
}
@ -318,15 +321,11 @@ QString DirNameFromString(QString string, QString inDir)
int num = 0;
QString baseName = RemoveInvalidFilenameChars(string, '-');
QString dirName;
do
{
if(num == 0)
{
do {
if (num == 0) {
dirName = baseName;
}
else
{
dirName = baseName + QString::number(num);;
} else {
dirName = baseName + "(" + QString::number(num) + ")";
}
// If it's over 9000
@ -345,63 +344,13 @@ bool checkProblemticPathJava(QDir folder)
return pathfoldername.contains("!", Qt::CaseInsensitive);
}
// Win32 crap
#if defined Q_OS_WIN
bool called_coinit = false;
HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args)
{
HRESULT hres;
if (!called_coinit)
{
hres = CoInitialize(NULL);
called_coinit = true;
if (!SUCCEEDED(hres))
{
qWarning("Failed to initialize COM. Error 0x%08lX", hres);
return hres;
}
}
IShellLink *link;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
(LPVOID *)&link);
if (SUCCEEDED(hres))
{
IPersistFile *persistFile;
link->SetPath(targetPath);
link->SetArguments(args);
hres = link->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile);
if (SUCCEEDED(hres))
{
WCHAR wstr[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, linkPath, -1, wstr, MAX_PATH);
hres = persistFile->Save(wstr, TRUE);
persistFile->Release();
}
link->Release();
}
return hres;
}
#endif
QString getDesktopDir()
{
return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
}
// Cross-platform Shortcut creation
bool createShortCut(QString location, QString dest, QStringList args, QString name,
QString icon)
bool createShortCut(QString location, QString dest, QStringList args, QString name, QString icon)
{
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
location = PathCombine(location, name + ".desktop");
@ -426,8 +375,7 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na
stream.flush();
f.close();
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup |
QFileDevice::ExeOther);
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
return true;
#elif defined Q_OS_WIN
@ -454,4 +402,26 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na
return false;
#endif
}
bool overrideFolder(QString overwritten_path, QString override_path)
{
using copy_opts = fs::copy_options;
if (!FS::ensureFolderPathExists(overwritten_path))
return false;
std::error_code err;
fs::copy_options opt = copy_opts::recursive | copy_opts::overwrite_existing;
// FIXME: hello traveller! Apparently std::copy does NOT overwrite existing files on GNU libstdc++ on Windows?
fs::copy(toStdString(override_path), toStdString(overwritten_path), opt, err);
if (err) {
qCritical() << QString("Failed to apply override from %1 to %2").arg(override_path, overwritten_path);
qCritical() << "Reason:" << QString::fromStdString(err.message());
}
return err.value() == 0;
}
}

View File

@ -1,4 +1,37 @@
// Licensed under the Apache-2.0 license. See README.md for details.
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
@ -8,29 +41,27 @@
#include <QDir>
#include <QFlags>
namespace FS
{
namespace FS {
class FileSystemException : public ::Exception
{
public:
FileSystemException(const QString &message) : Exception(message) {}
class FileSystemException : public ::Exception {
public:
FileSystemException(const QString& message) : Exception(message) {}
};
/**
* write data to a file safely
*/
void write(const QString &filename, const QByteArray &data);
void write(const QString& filename, const QByteArray& data);
/**
* read data from a file safely\
*/
QByteArray read(const QString &filename);
QByteArray read(const QString& filename);
/**
* Update the last changed timestamp of an existing file
*/
bool updateTimestamp(const QString & filename);
bool updateTimestamp(const QString& filename);
/**
* Creates all the folders in a path for the specified path
@ -44,35 +75,31 @@ bool ensureFilePathExists(QString filenamepath);
*/
bool ensureFolderPathExists(QString filenamepath);
class copy
{
public:
copy(const QString & src, const QString & dst)
class copy {
public:
copy(const QString& src, const QString& dst)
{
m_src = src;
m_dst = dst;
m_src.setPath(src);
m_dst.setPath(dst);
}
copy & followSymlinks(const bool follow)
copy& followSymlinks(const bool follow)
{
m_followSymlinks = follow;
return *this;
}
copy & blacklist(const IPathMatcher * filter)
copy& blacklist(const IPathMatcher* filter)
{
m_blacklist = filter;
return *this;
}
bool operator()()
{
return operator()(QString());
}
bool operator()() { return operator()(QString()); }
private:
bool operator()(const QString &offset);
private:
bool operator()(const QString& offset);
private:
private:
bool m_followSymlinks = true;
const IPathMatcher * m_blacklist = nullptr;
const IPathMatcher* m_blacklist = nullptr;
QDir m_src;
QDir m_dst;
};
@ -82,9 +109,14 @@ private:
*/
bool deletePath(QString path);
QString PathCombine(const QString &path1, const QString &path2);
QString PathCombine(const QString &path1, const QString &path2, const QString &path3);
QString PathCombine(const QString &path1, const QString &path2, const QString &path3, const QString &path4);
/**
* Trash a folder / file
*/
bool trash(QString path, QString *pathInTrash);
QString PathCombine(const QString& path1, const QString& path2);
QString PathCombine(const QString& path1, const QString& path2, const QString& path3);
QString PathCombine(const QString& path1, const QString& path2, const QString& path3, const QString& path4);
QString AbsolutePath(QString path);
@ -120,8 +152,7 @@ bool checkProblemticPathJava(QDir folder);
// Get the Directory representing the User's Desktop
QString getDesktopDir();
// Create a shortcut at *location*, pointing to *dest* called with the arguments *args*
// call it *name* and assign it the icon *icon*
// return true if operation succeeded
bool createShortCut(QString location, QString dest, QStringList args, QString name, QString iconLocation);
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
// Equivalent to doing QDir::rename, but allowing for overrides
bool overrideFolder(QString overwritten_path, QString override_path);
}

View File

@ -1,3 +1,38 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "GZip.h"
#include <zlib.h>
#include <QByteArray>
@ -37,7 +72,7 @@ bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedByte
uncompLength *= 2;
}
strm.next_out = (Bytef *)(uncompressedBytes.data() + strm.total_out);
strm.next_out = reinterpret_cast<Bytef *>((uncompressedBytes.data() + strm.total_out));
strm.avail_out = uncompLength - strm.total_out;
// Inflate another chunk.
@ -67,7 +102,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
return true;
}
unsigned compLength = std::min(uncompressedBytes.size(), 16);
unsigned compLength = qMin(uncompressedBytes.size(), 16);
compressedBytes.clear();
compressedBytes.resize(compLength);
@ -94,7 +129,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
{
compressedBytes.resize(compressedBytes.size() * 2);
}
zs.next_out = (Bytef *) (compressedBytes.data() + offset);
zs.next_out = reinterpret_cast<Bytef*>((compressedBytes.data() + offset));
temp = zs.avail_out = compressedBytes.size() - offset;
ret = deflate(&zs, Z_FINISH);
offset += temp - zs.avail_out;
@ -112,4 +147,4 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
return false;
}
return true;
}
}

View File

@ -42,7 +42,7 @@ public:
}
void put(QByteArray input)
{
hoedown_buffer_put(buf, (uint8_t *) input.data(), input.size());
hoedown_buffer_put(buf, reinterpret_cast<uint8_t *>(input.data()), input.size());
}
const uint8_t * data() const
{

View File

@ -44,7 +44,7 @@ void InstanceCopyTask::copyFinished()
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
inst->setName(m_instName);
inst->setName(name());
inst->setIconKey(m_instIcon);
if(!m_keepPlaytime) {
inst->resetTimePlayed();

View File

@ -1,40 +1,56 @@
#include "InstanceCreationTask.h"
#include "settings/INISettingsObject.h"
#include "FileSystem.h"
//FIXME: remove this
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include <QDebug>
#include <QFile>
InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version)
{
m_version = version;
m_usingLoader = false;
}
InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion)
{
m_version = version;
m_usingLoader = true;
m_loader = loader;
m_loaderVersion = loaderVersion;
}
InstanceCreationTask::InstanceCreationTask() = default;
void InstanceCreationTask::executeTask()
{
setStatus(tr("Creating instance from version %1").arg(m_version->name()));
{
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
instanceSettings->suspendSave();
MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath);
auto components = inst.getPackProfile();
components->buildingFromScratch();
components->setComponentVersion("net.minecraft", m_version->descriptor(), true);
if(m_usingLoader)
components->setComponentVersion(m_loader, m_loaderVersion->descriptor());
inst.setName(m_instName);
inst.setIconKey(m_instIcon);
instanceSettings->resumeSave();
setAbortable(true);
if (updateInstance()) {
emitSucceeded();
return;
}
// When the user aborted in the update stage.
if (m_abort) {
emitAborted();
return;
}
if (!createInstance()) {
if (m_abort)
return;
qWarning() << "Instance creation failed!";
if (!m_error_message.isEmpty())
qWarning() << "Reason: " << m_error_message;
emitFailed(tr("Error while creating new instance."));
return;
}
// If this is set, it means we're updating an instance. So, we now need to remove the
// files scheduled to, and we'd better not let the user abort in the middle of it, since it'd
// put the instance in an invalid state.
if (shouldOverride()) {
setAbortable(false);
setStatus(tr("Removing old conflicting files..."));
qDebug() << "Removing old files";
for (auto path : m_files_to_remove) {
if (!QFile::exists(path))
continue;
qDebug() << "Removing" << path;
if (!QFile::remove(path)) {
qCritical() << "Couldn't remove the old conflicting files.";
emitFailed(tr("Failed to remove old conflicting files."));
return;
}
}
}
emitSucceeded();
return;
}

View File

@ -1,26 +1,46 @@
#pragma once
#include "tasks/Task.h"
#include "net/NetJob.h"
#include <QUrl>
#include "settings/SettingsObject.h"
#include "BaseVersion.h"
#include "InstanceTask.h"
class InstanceCreationTask : public InstanceTask
{
class InstanceCreationTask : public InstanceTask {
Q_OBJECT
public:
explicit InstanceCreationTask(BaseVersionPtr version);
explicit InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion);
public:
InstanceCreationTask();
virtual ~InstanceCreationTask() = default;
protected:
//! Entry point for tasks.
virtual void executeTask() override;
protected:
void executeTask() final override;
private: /* data */
BaseVersionPtr m_version;
bool m_usingLoader;
QString m_loader;
BaseVersionPtr m_loaderVersion;
/**
* Tries to update an already existing instance.
*
* This can be implemented by subclasses to provide a way of updating an already existing
* instance, according to that implementation's concept of 'identity' (i.e. instances that
* are updates / downgrades of one another).
*
* If this returns true, createInstance() will not run, so you should do all update steps in here.
* Otherwise, createInstance() is run as normal.
*/
virtual bool updateInstance() { return false; };
/**
* Creates a new instance.
*
* Returns whether the instance creation was successful (true) or not (false).
*/
virtual bool createInstance() { return false; };
QString getError() const { return m_error_message; }
protected:
void setError(QString message) { m_error_message = message; };
protected:
bool m_abort = false;
QStringList m_files_to_remove;
private:
QString m_error_message;
};

View File

@ -1,75 +1,103 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* http://www.apache.org/licenses/LICENSE-2.0
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "InstanceImportTask.h"
#include "BaseInstance.h"
#include "FileSystem.h"
#include "Application.h"
#include "FileSystem.h"
#include "MMCZip.h"
#include "NullInstance.h"
#include "settings/INISettingsObject.h"
#include "icons/IconUtils.h"
#include <QtConcurrentRun>
// FIXME: this does not belong here, it's Minecraft/Flame specific
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "modplatform/flame/FileResolvingTask.h"
#include "modplatform/flame/PackManifest.h"
#include "Json.h"
#include <quazip/quazipdir.h>
#include "modplatform/technic/TechnicPackProcessor.h"
#include "icons/IconList.h"
#include "Application.h"
#include "icons/IconUtils.h"
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl)
#include "modplatform/technic/TechnicPackProcessor.h"
#include "modplatform/modrinth/ModrinthInstanceCreationTask.h"
#include "modplatform/flame/FlameInstanceCreationTask.h"
#include "settings/INISettingsObject.h"
#include <QtConcurrentRun>
#include <algorithm>
#include <quazip/quazipdir.h>
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent)
{
m_sourceUrl = sourceUrl;
m_parent = parent;
}
bool InstanceImportTask::abort()
{
m_filesNetJob->abort();
if (!canAbort())
return false;
if (m_filesNetJob)
m_filesNetJob->abort();
m_extractFuture.cancel();
return false;
return Task::abort();
}
void InstanceImportTask::executeTask()
{
if (m_sourceUrl.isLocalFile())
{
setAbortable(true);
if (m_sourceUrl.isLocalFile()) {
m_archivePath = m_sourceUrl.toLocalFile();
processZipPack();
}
else
{
} else {
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
m_downloadRequired = true;
const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path();
const QString path(m_sourceUrl.host() + '/' + m_sourceUrl.path());
auto entry = APPLICATION->metacache()->resolveEntry("general", path);
entry->setStale(true);
m_archivePath = entry->getFullPath();
m_filesNetJob = new NetJob(tr("Modpack download"), APPLICATION->network());
m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry));
m_archivePath = entry->getFullPath();
auto job = m_filesNetJob.get();
connect(job, &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
connect(job, &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
connect(job, &NetJob::failed, this, &InstanceImportTask::downloadFailed);
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
m_filesNetJob->start();
}
}
@ -88,7 +116,13 @@ void InstanceImportTask::downloadFailed(QString reason)
void InstanceImportTask::downloadProgressChanged(qint64 current, qint64 total)
{
setProgress(current / 2, total);
setProgress(current, total);
}
void InstanceImportTask::downloadAborted()
{
emitAborted();
m_filesNetJob.reset();
}
void InstanceImportTask::processZipPack()
@ -105,17 +139,20 @@ void InstanceImportTask::processZipPack()
return;
}
QStringList blacklist = {"instance.cfg", "manifest.json"};
QString mmcFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg");
bool technicFound = QuaZipDir(m_packZip.get()).exists("/bin/modpack.jar") || QuaZipDir(m_packZip.get()).exists("/bin/version.json");
QString flameFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json");
QuaZipDir packZipDir(m_packZip.get());
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
bool modrinthFound = packZipDir.exists("/modrinth.index.json");
bool technicFound = packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json");
QString root;
if(!mmcFound.isNull())
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
if(modrinthFound)
{
// process as MultiMC instance/pack
qDebug() << "MultiMC:" << mmcFound;
root = mmcFound;
m_modpackType = ModpackType::MultiMC;
// process as Modrinth pack
qDebug() << "Modrinth:" << modrinthFound;
m_modpackType = ModpackType::Modrinth;
}
else if (technicFound)
{
@ -125,12 +162,25 @@ void InstanceImportTask::processZipPack()
extractDir.cd(".minecraft");
m_modpackType = ModpackType::Technic;
}
else if(!flameFound.isNull())
else
{
// process as Flame pack
qDebug() << "Flame:" << flameFound;
root = flameFound;
m_modpackType = ModpackType::Flame;
QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg");
QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json");
if (!mmcRoot.isNull())
{
// process as MultiMC instance/pack
qDebug() << "MultiMC:" << mmcRoot;
root = mmcRoot;
m_modpackType = ModpackType::MultiMC;
}
else if(!flameRoot.isNull())
{
// process as Flame pack
qDebug() << "Flame:" << flameRoot;
root = flameRoot;
m_modpackType = ModpackType::Flame;
}
}
if(m_modpackType == ModpackType::Unknown)
{
@ -188,15 +238,18 @@ void InstanceImportTask::extractFinished()
switch(m_modpackType)
{
case ModpackType::Flame:
processFlame();
return;
case ModpackType::MultiMC:
processMultiMC();
return;
case ModpackType::Technic:
processTechnic();
return;
case ModpackType::Flame:
processFlame();
return;
case ModpackType::Modrinth:
processModrinth();
return;
case ModpackType::Unknown:
emitFailed(tr("Archive does not contain a recognized modpack type."));
return;
@ -205,216 +258,31 @@ void InstanceImportTask::extractFinished()
void InstanceImportTask::extractAborted()
{
emitFailed(tr("Instance import has been aborted."));
return;
emitAborted();
}
void InstanceImportTask::processFlame()
{
const static QMap<QString,QString> forgemap = {
{"1.2.5", "3.4.9.171"},
{"1.4.2", "6.0.1.355"},
{"1.4.7", "6.6.2.534"},
{"1.5.2", "7.8.1.737"}
};
Flame::Manifest pack;
try
{
QString configPath = FS::PathCombine(m_stagingPath, "manifest.json");
Flame::loadManifest(pack, configPath);
QFile::remove(configPath);
}
catch (const JSONValidationError &e)
{
emitFailed(tr("Could not understand pack manifest:\n") + e.cause());
return;
}
if(!pack.overrides.isEmpty())
{
QString overridePath = FS::PathCombine(m_stagingPath, pack.overrides);
if (QFile::exists(overridePath))
{
QString mcPath = FS::PathCombine(m_stagingPath, "minecraft");
if (!QFile::rename(overridePath, mcPath))
{
emitFailed(tr("Could not rename the overrides folder:\n") + pack.overrides);
return;
}
}
else
{
logWarning(tr("The specified overrides folder (%1) is missing. Maybe the modpack was already used before?").arg(pack.overrides));
}
}
auto* inst_creation_task = new FlameCreationTask(m_stagingPath, m_globalSettings, m_parent);
QString forgeVersion;
QString fabricVersion;
// TODO: is Quilt relevant here?
for(auto &loader: pack.minecraft.modLoaders)
{
auto id = loader.id;
if(id.startsWith("forge-"))
{
id.remove("forge-");
forgeVersion = id;
continue;
}
if(id.startsWith("fabric-"))
{
id.remove("fabric-");
fabricVersion = id;
continue;
}
logWarning(tr("Unknown mod loader in manifest: %1").arg(id));
}
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
auto mcVersion = pack.minecraft.version;
// Hack to correct some 'special sauce'...
if(mcVersion.endsWith('.'))
{
mcVersion.remove(QRegExp("[.]+$"));
logWarning(tr("Mysterious trailing dots removed from Minecraft version while importing pack."));
}
auto components = instance.getPackProfile();
components->buildingFromScratch();
components->setComponentVersion("net.minecraft", mcVersion, true);
if(!forgeVersion.isEmpty())
{
// FIXME: dirty, nasty, hack. Proper solution requires dependency resolution and knowledge of the metadata.
if(forgeVersion == "recommended")
{
if(forgemap.contains(mcVersion))
{
forgeVersion = forgemap[mcVersion];
}
else
{
logWarning(tr("Could not map recommended Forge version for Minecraft %1").arg(mcVersion));
}
}
components->setComponentVersion("net.minecraftforge", forgeVersion);
}
if(!fabricVersion.isEmpty())
{
components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion);
}
if (m_instIcon != "default")
{
instance.setIconKey(m_instIcon);
}
else
{
if(pack.name.contains("Direwolf20"))
{
instance.setIconKey("steve");
}
else if(pack.name.contains("FTB") || pack.name.contains("Feed The Beast"))
{
instance.setIconKey("ftb_logo");
}
else
{
// default to something other than the MultiMC default to distinguish these
instance.setIconKey("flame");
}
}
QString jarmodsPath = FS::PathCombine(m_stagingPath, "minecraft", "jarmods");
QFileInfo jarmodsInfo(jarmodsPath);
if(jarmodsInfo.isDir())
{
// install all the jar mods
qDebug() << "Found jarmods:";
QDir jarmodsDir(jarmodsPath);
QStringList jarMods;
for (auto info: jarmodsDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files))
{
qDebug() << info.fileName();
jarMods.push_back(info.absoluteFilePath());
}
auto profile = instance.getPackProfile();
profile->installJarMods(jarMods);
// nuke the original files
FS::deletePath(jarmodsPath);
}
instance.setName(m_instName);
m_modIdResolver = new Flame::FileResolvingTask(APPLICATION->network(), pack);
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::succeeded, [&]()
{
auto results = m_modIdResolver->getResults();
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
for(auto result: results.files)
{
QString filename = result.fileName;
if(!result.required)
{
filename += ".disabled";
}
auto relpath = FS::PathCombine("minecraft", result.targetFolder, filename);
auto path = FS::PathCombine(m_stagingPath , relpath);
switch(result.type)
{
case Flame::File::Type::Folder:
{
logWarning(tr("This 'Folder' may need extracting: %1").arg(relpath));
// fall-through intentional, we treat these as plain old mods and dump them wherever.
}
case Flame::File::Type::SingleFile:
case Flame::File::Type::Mod:
{
qDebug() << "Will download" << result.url << "to" << path;
auto dl = Net::Download::makeFile(result.url, path);
m_filesNetJob->addNetAction(dl);
break;
}
case Flame::File::Type::Modpack:
logWarning(tr("Nesting modpacks in modpacks is not implemented, nothing was downloaded: %1").arg(relpath));
break;
case Flame::File::Type::Cmod2:
case Flame::File::Type::Ctoc:
case Flame::File::Type::Unknown:
logWarning(tr("Unrecognized/unhandled PackageType for: %1").arg(relpath));
break;
}
}
m_modIdResolver.reset();
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]()
{
m_filesNetJob.reset();
emitSucceeded();
}
);
connect(m_filesNetJob.get(), &NetJob::failed, [&](QString reason)
{
m_filesNetJob.reset();
emitFailed(reason);
});
connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total)
{
setProgress(current, total);
});
setStatus(tr("Downloading mods..."));
m_filesNetJob->start();
}
);
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::failed, [&](QString reason)
{
m_modIdResolver.reset();
emitFailed(tr("Unable to resolve mod IDs:\n") + reason);
inst_creation_task->setName(*this);
inst_creation_task->setIcon(m_instIcon);
inst_creation_task->setGroup(m_instGroup);
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
setOverride(inst_creation_task->shouldOverride());
emitSucceeded();
});
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::progress, [&](qint64 current, qint64 total)
{
setProgress(current, total);
});
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::status, [&](QString status)
{
setStatus(status);
});
m_modIdResolver->start();
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);
connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort);
connect(inst_creation_task, &Task::aborted, this, &Task::abort);
connect(inst_creation_task, &Task::abortStatusChanged, this, &Task::setAbortable);
inst_creation_task->start();
}
void InstanceImportTask::processTechnic()
@ -422,7 +290,7 @@ void InstanceImportTask::processTechnic()
shared_qobject_ptr<Technic::TechnicPackProcessor> packProcessor = new Technic::TechnicPackProcessor();
connect(packProcessor.get(), &Technic::TechnicPackProcessor::succeeded, this, &InstanceImportTask::emitSucceeded);
connect(packProcessor.get(), &Technic::TechnicPackProcessor::failed, this, &InstanceImportTask::emitFailed);
packProcessor->run(m_globalSettings, m_instName, m_instIcon, m_stagingPath);
packProcessor->run(m_globalSettings, name(), m_instIcon, m_stagingPath);
}
void InstanceImportTask::processMultiMC()
@ -436,28 +304,47 @@ void InstanceImportTask::processMultiMC()
instance.resetTimePlayed();
// set a new nice name
instance.setName(m_instName);
instance.setName(name());
// if the icon was specified by user, use that. otherwise pull icon from the pack
if (m_instIcon != "default")
{
if (m_instIcon != "default") {
instance.setIconKey(m_instIcon);
}
else
{
} else {
m_instIcon = instance.iconKey();
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
if (!importIconPath.isNull() && QFile::exists(importIconPath))
{
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
// import icon
auto iconList = APPLICATION->icons();
if (iconList->iconFileExists(m_instIcon))
{
if (iconList->iconFileExists(m_instIcon)) {
iconList->deleteIcon(m_instIcon);
}
iconList->installIcons({importIconPath});
iconList->installIcons({ importIconPath });
}
}
emitSucceeded();
}
void InstanceImportTask::processModrinth()
{
auto* inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, m_sourceUrl.toString());
inst_creation_task->setName(*this);
inst_creation_task->setIcon(m_instIcon);
inst_creation_task->setGroup(m_instGroup);
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
setOverride(inst_creation_task->shouldOverride());
emitSucceeded();
});
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);
connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort);
connect(inst_creation_task, &Task::aborted, this, &Task::abort);
connect(inst_creation_task, &Task::abortStatusChanged, this, &Task::setAbortable);
inst_creation_task->start();
}

View File

@ -1,16 +1,36 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* http://www.apache.org/licenses/LICENSE-2.0
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
@ -22,8 +42,9 @@
#include <QFutureWatcher>
#include "settings/SettingsObject.h"
#include "QObjectPtr.h"
#include "modplatform/flame/PackManifest.h"
#include <nonstd/optional>
#include <optional>
class QuaZip;
namespace Flame
@ -35,10 +56,13 @@ class InstanceImportTask : public InstanceTask
{
Q_OBJECT
public:
explicit InstanceImportTask(const QUrl sourceUrl);
explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr);
bool canAbort() const override { return true; }
bool abort() override;
const QVector<Flame::File> &getBlockedFiles() const
{
return m_blockedMods;
}
protected:
//! Entry point for tasks.
@ -47,13 +71,15 @@ protected:
private:
void processZipPack();
void processMultiMC();
void processFlame();
void processTechnic();
void processFlame();
void processModrinth();
private slots:
void downloadSucceeded();
void downloadFailed(QString reason);
void downloadProgressChanged(qint64 current, qint64 total);
void downloadAborted();
void extractFinished();
void extractAborted();
@ -64,12 +90,17 @@ private: /* data */
QString m_archivePath;
bool m_downloadRequired = false;
std::unique_ptr<QuaZip> m_packZip;
QFuture<nonstd::optional<QStringList>> m_extractFuture;
QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
QFuture<std::optional<QStringList>> m_extractFuture;
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
QVector<Flame::File> m_blockedMods;
enum class ModpackType{
Unknown,
MultiMC,
Technic,
Flame,
Technic
Modrinth,
} m_modpackType = ModpackType::Unknown;
//FIXME: nuke
QWidget* m_parent;
};

File diff suppressed because it is too large Load Diff

View File

@ -19,13 +19,15 @@
#include <QAbstractListModel>
#include <QSet>
#include <QList>
#include <QStack>
#include <QPair>
#include "BaseInstance.h"
#include "QObjectPtr.h"
class QFileSystemWatcher;
class InstanceTask;
struct InstanceName;
using InstanceId = QString;
using GroupId = QString;
using InstanceLocator = std::pair<InstancePtr, int>;
@ -46,6 +48,12 @@ enum class GroupsState
Dirty
};
struct TrashHistoryItem {
QString id;
QString polyPath;
QString trashPath;
QString groupName;
};
class InstanceList : public QAbstractListModel
{
@ -93,7 +101,10 @@ public:
InstListError loadList();
void saveNow();
/* O(n) */
InstancePtr getInstanceById(QString id) const;
/* O(n) */
InstancePtr getInstanceByManagedName(const QString& managed_name) const;
QModelIndex getInstanceIndexById(const QString &id) const;
QStringList getGroups();
bool isGroupCollapsed(const QString &groupName);
@ -102,6 +113,9 @@ public:
void setInstanceGroup(const InstanceId & id, const GroupId& name);
void deleteGroup(const GroupId & name);
bool trashInstance(const InstanceId &id);
bool trashedSomething();
void undoTrashInstance();
void deleteInstance(const InstanceId & id);
// Wrap an instance creation task in some more task machinery and make it ready to be used
@ -116,8 +130,10 @@ public:
/**
* Commit the staging area given by @keyPath to the provider - used when creation succeeds.
* Used by instance manipulation tasks.
* should_override is used when another similar instance already exists, and we want to override it
* - for instance, when updating it.
*/
bool commitStagedInstance(const QString & keyPath, const QString& instanceName, const QString & groupName);
bool commitStagedInstance(const QString& keyPath, const InstanceName& instanceName, const QString& groupName, bool should_override);
/**
* Destroy a previously created staging area given by @keyPath - used when creation fails.
@ -180,4 +196,6 @@ private:
QSet<InstanceId> instanceSet;
bool m_groupsLoaded = false;
bool m_instancesProbed = false;
QStack<TrashHistoryItem> m_trashHistory;
};

View File

@ -33,13 +33,13 @@ public:
values.append(new LogPage(inst));
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
values.append(new VersionPage(onesix.get()));
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
values.append(modsPage);
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
values.append(new ResourcePackPage(onesix.get()));
values.append(new TexturePackPage(onesix.get()));
values.append(new ShaderPackPage(onesix.get()));
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList()));
values.append(new ResourcePackPage(onesix.get(), onesix->resourcePackList()));
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
values.append(new NotesPage(onesix.get()));
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
values.append(new ServersPage(onesix));

View File

@ -1,9 +1,52 @@
#include "InstanceTask.h"
InstanceTask::InstanceTask()
#include "ui/dialogs/CustomMessageBox.h"
InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name)
{
auto dialog =
CustomMessageBox::selectable(parent, QObject::tr("Change instance name"),
QObject::tr("The instance's name seems to include the old version. Would you like to update it?\n\n"
"Old name: %1\n"
"New name: %2")
.arg(old_name, new_name),
QMessageBox::Question, QMessageBox::No | QMessageBox::Yes);
auto result = dialog->exec();
if (result == QMessageBox::Yes)
return InstanceNameChange::ShouldChange;
return InstanceNameChange::ShouldKeep;
}
InstanceTask::~InstanceTask()
QString InstanceName::name() const
{
if (!m_modified_name.isEmpty())
return modifiedName();
return QString("%1 %2").arg(m_original_name, m_original_version);
}
QString InstanceName::originalName() const
{
return m_original_name;
}
QString InstanceName::modifiedName() const
{
if (!m_modified_name.isEmpty())
return m_modified_name;
return m_original_name;
}
QString InstanceName::version() const
{
return m_original_version;
}
void InstanceName::setName(InstanceName& other)
{
m_original_name = other.m_original_name;
m_original_version = other.m_original_version;
m_modified_name = other.m_modified_name;
}
InstanceTask::InstanceTask() : Task(), InstanceName() {}

View File

@ -1,52 +1,57 @@
#pragma once
#include "tasks/Task.h"
#include "settings/SettingsObject.h"
#include "tasks/Task.h"
class InstanceTask : public Task
{
/* Helpers */
enum class InstanceNameChange { ShouldChange, ShouldKeep };
[[nodiscard]] InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name);
struct InstanceName {
public:
InstanceName() = default;
InstanceName(QString name, QString version) : m_original_name(std::move(name)), m_original_version(std::move(version)) {}
[[nodiscard]] QString modifiedName() const;
[[nodiscard]] QString originalName() const;
[[nodiscard]] QString name() const;
[[nodiscard]] QString version() const;
void setName(QString name) { m_modified_name = name; }
void setName(InstanceName& other);
protected:
QString m_original_name;
QString m_original_version;
QString m_modified_name;
};
class InstanceTask : public Task, public InstanceName {
Q_OBJECT
public:
explicit InstanceTask();
virtual ~InstanceTask();
public:
InstanceTask();
~InstanceTask() override = default;
void setParentSettings(SettingsObjectPtr settings)
{
m_globalSettings = settings;
}
void setParentSettings(SettingsObjectPtr settings) { m_globalSettings = settings; }
void setStagingPath(const QString &stagingPath)
{
m_stagingPath = stagingPath;
}
void setStagingPath(const QString& stagingPath) { m_stagingPath = stagingPath; }
void setName(const QString &name)
{
m_instName = name;
}
QString name() const
{
return m_instName;
}
void setIcon(const QString& icon) { m_instIcon = icon; }
void setIcon(const QString &icon)
{
m_instIcon = icon;
}
void setGroup(const QString& group) { m_instGroup = group; }
QString group() const { return m_instGroup; }
void setGroup(const QString &group)
{
m_instGroup = group;
}
QString group() const
{
return m_instGroup;
}
bool shouldOverride() const { return m_override_existing; }
protected: /* data */
protected:
void setOverride(bool override) { m_override_existing = override; }
protected: /* data */
SettingsObjectPtr m_globalSettings;
QString m_instName;
QString m_instIcon;
QString m_instGroup;
QString m_stagingPath;
bool m_override_existing = false;
};

View File

@ -1,10 +1,47 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "JavaCommon.h"
#include "java/JavaUtils.h"
#include "ui/dialogs/CustomMessageBox.h"
#include <MMCStrings.h>
#include <QRegularExpression>
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
{
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]"))
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
{
auto warnStr = QObject::tr(
@ -18,7 +55,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
return false;
}
// block lunacy with passing required version to the JVM
if (jvmargs.contains(QRegExp("-version:.*"))) {
if (jvmargs.contains(QRegularExpression("-version:.*"))) {
auto warnStr = QObject::tr(
"You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be allowed.\n"
"This message will be displayed until you remove this from the JVM arguments.");
@ -65,6 +102,13 @@ void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result)
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}
void JavaCommon::javaCheckNotFound(QWidget *parent)
{
QString text;
text += QObject::tr("Java checker library could not be found. Please check your installation.");
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}
void JavaCommon::TestCheck::run()
{
if (!JavaCommon::checkJVMArgs(m_args, m_parent))
@ -72,6 +116,11 @@ void JavaCommon::TestCheck::run()
emit finished();
return;
}
if (JavaUtils::getJavaCheckPath().isEmpty()) {
javaCheckNotFound(m_parent);
emit finished();
return;
}
checker.reset(new JavaChecker());
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
SLOT(checkFinished(JavaCheckResult)));

View File

@ -10,12 +10,14 @@ namespace JavaCommon
{
bool checkJVMArgs(QString args, QWidget *parent);
// Show a dialog saying that the Java binary was not usable
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was not usable because of bad options
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was usable
void javaWasOk(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was not usable because of bad options
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was not usable
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
// Show a dialog if we couldn't find Java Checker
void javaCheckNotFound(QWidget *parent);
class TestCheck : public QObject
{

View File

@ -1,4 +1,37 @@
// Licensed under the Apache-2.0 license. See README.md for details.
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Json.h"
@ -22,14 +55,6 @@ void write(const QJsonArray &array, const QString &filename)
write(QJsonDocument(array), filename);
}
QByteArray toBinary(const QJsonObject &obj)
{
return QJsonDocument(obj).toBinaryData();
}
QByteArray toBinary(const QJsonArray &array)
{
return QJsonDocument(array).toBinaryData();
}
QByteArray toText(const QJsonObject &obj)
{
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
@ -48,12 +73,8 @@ QJsonDocument requireDocument(const QByteArray &data, const QString &what)
{
if (isBinaryJson(data))
{
QJsonDocument doc = QJsonDocument::fromBinaryData(data);
if (doc.isNull())
{
throw JsonException(what + ": Invalid JSON (binary JSON detected)");
}
return doc;
// FIXME: Is this needed?
throw JsonException(what + ": Invalid JSON. Binary JSON unsupported");
}
else
{

View File

@ -1,4 +1,37 @@
// Licensed under the Apache-2.0 license. See README.md for details.
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
@ -29,8 +62,6 @@ void write(const QJsonObject &object, const QString &filename);
/// @throw FileSystemException
void write(const QJsonArray &array, const QString &filename);
QByteArray toBinary(const QJsonObject &obj);
QByteArray toBinary(const QJsonArray &array);
QByteArray toText(const QJsonObject &obj);
QByteArray toText(const QJsonArray &array);

View File

@ -93,8 +93,8 @@ void LaunchController::decideAccount()
auto reply = CustomMessageBox::selectable(
m_parentWidget,
tr("No Accounts"),
tr("In order to play Minecraft, you must have at least one Mojang or Minecraft "
"account logged in. "
tr("In order to play Minecraft, you must have at least one Microsoft or Mojang "
"account logged in. Mojang accounts can only be used offline. "
"Would you like to open the account manager to add an account now?"),
QMessageBox::Information,
QMessageBox::Yes | QMessageBox::No
@ -105,6 +105,11 @@ void LaunchController::decideAccount()
// Open the account manager.
APPLICATION->ShowGlobalSettings(m_parentWidget, "accounts");
}
else if (reply == QMessageBox::No)
{
// Do not open "profile select" dialog.
return;
}
}
m_accountToUse = accounts->defaultAccount();
@ -140,18 +145,29 @@ void LaunchController::login() {
return;
}
// we try empty password first :)
QString password;
// we loop until the user succeeds in logging in or gives up
bool tryagain = true;
// the failure. the default failure.
const QString needLoginAgain = tr("Your account is currently not logged in. Please enter your password to log in again. <br /> <br /> This could be caused by a password change.");
QString failReason = needLoginAgain;
unsigned int tries = 0;
while (tryagain)
{
if (tries > 0 && tries % 3 == 0) {
auto result = QMessageBox::question(
m_parentWidget,
tr("Continue launch?"),
tr("It looks like we couldn't launch after %1 tries. Do you want to continue trying?")
.arg(tries)
);
if (result == QMessageBox::No) {
emitAborted();
return;
}
}
tries++;
m_session = std::make_shared<AuthSession>();
m_session->wants_online = m_online;
m_session->demo = m_demo;
m_accountToUse->fillSession(m_session);
// Launch immediately in true offline mode
@ -169,12 +185,18 @@ void LaunchController::login() {
if(!m_session->wants_online) {
// we ask the user for a player name
bool ok = false;
QString message = tr("Choose your offline mode player name.");
if(m_session->demo) {
message = tr("Choose your demo mode player name.");
}
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
QString name = QInputDialog::getText(
m_parentWidget,
tr("Player name"),
tr("Choose your offline mode player name."),
message,
QLineEdit::Normal,
usedname,
&ok
@ -354,13 +376,13 @@ void LaunchController::launchInstance()
}
m_launcher->prependStep(new TextPrint(m_launcher.get(), resolved_servers, MessageLevel::Launcher));
} else {
online_mode = "offline";
online_mode = m_demo ? "demo" : "offline";
}
m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
// Prepend Version
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_NAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_DISPLAYNAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
m_launcher->start();
}

View File

@ -63,6 +63,10 @@ public:
m_online = online;
}
void setDemo(bool demo) {
m_demo = demo;
}
void setProfiler(BaseProfilerFactory *profiler) {
m_profiler = profiler;
}
@ -101,6 +105,7 @@ private slots:
private:
BaseProfilerFactory *m_profiler = nullptr;
bool m_online = true;
bool m_demo = false;
InstancePtr m_instance;
QWidget * m_parentWidget = nullptr;
InstanceWindow *m_console = nullptr;

View File

@ -18,13 +18,17 @@ LAUNCHER_NAME=@Launcher_APP_BINARY_NAME@
LAUNCHER_DIR="$(dirname "$(readlink -f "$0")")"
echo "Launcher Dir: ${LAUNCHER_DIR}"
# Set up env - filter out input LD_ variables but pass them in under different names
export GAME_LIBRARY_PATH=${GAME_LIBRARY_PATH-${LD_LIBRARY_PATH}}
export GAME_PRELOAD=${GAME_PRELOAD-${LD_PRELOAD}}
export LD_LIBRARY_PATH="${LAUNCHER_DIR}/lib@LIB_SUFFIX@":$LAUNCHER_LIBRARY_PATH
export LD_PRELOAD=$LAUNCHER_PRELOAD
export QT_PLUGIN_PATH="${LAUNCHER_DIR}/plugins"
export QT_FONTPATH="${LAUNCHER_DIR}/fonts"
# Set up env.
# Pass our custom variables separately so that the launcher can remove them for child processes
export LAUNCHER_LD_LIBRARY_PATH="${LAUNCHER_DIR}/lib@LIB_SUFFIX@"
export LAUNCHER_LD_PRELOAD=""
export LAUNCHER_QT_PLUGIN_PATH="${LAUNCHER_DIR}/plugins"
export LAUNCHER_QT_FONTPATH="${LAUNCHER_DIR}/fonts"
export LD_LIBRARY_PATH="$LAUNCHER_LD_LIBRARY_PATH:$LD_LIBRARY_PATH"
export LD_PRELOAD="$LAUNCHER_LD_PRELOAD:$LD_PRELOAD"
export QT_PLUGIN_PATH="$LAUNCHER_QT_PLUGIN_PATH:$QT_PLUGIN_PATH"
export QT_FONTPATH="$LAUNCHER_QT_FONTPATH:$QT_FONTPATH"
# Detect missing dependencies...
DEPS_LIST=`ldd "${LAUNCHER_DIR}"/plugins/*/*.so 2>/dev/null | grep "not found" | sort -u | awk -vORS=", " '{ print $1 }'`

View File

@ -1,6 +1,42 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "LoggedProcess.h"
#include "MessageLevel.h"
#include <QDebug>
#include <QTextDecoder>
#include "MessageLevel.h"
LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
{
@ -8,7 +44,11 @@ LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr);
connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus)));
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
connect(this, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
#else
connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
#endif
connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange);
}
@ -20,25 +60,26 @@ LoggedProcess::~LoggedProcess()
}
}
QStringList reprocess(const QByteArray & data, QString & leftover)
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder)
{
QString str = leftover + QString::fromLocal8Bit(data);
str.remove('\r');
QStringList lines = str.split("\n");
leftover = lines.takeLast();
auto str = decoder.toUnicode(data);
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
auto lines = str.remove(QChar::CarriageReturn).split(QChar::LineFeed, QString::SkipEmptyParts);
#else
auto lines = str.remove(QChar::CarriageReturn).split(QChar::LineFeed, Qt::SkipEmptyParts);
#endif
return lines;
}
void LoggedProcess::on_stdErr()
{
auto lines = reprocess(readAllStandardError(), m_err_leftover);
auto lines = reprocess(readAllStandardError(), m_err_decoder);
emit log(lines, MessageLevel::StdErr);
}
void LoggedProcess::on_stdOut()
{
auto lines = reprocess(readAllStandardOutput(), m_out_leftover);
auto lines = reprocess(readAllStandardOutput(), m_out_decoder);
emit log(lines, MessageLevel::StdOut);
}
@ -47,18 +88,6 @@ void LoggedProcess::on_exit(int exit_code, QProcess::ExitStatus status)
// save the exit code
m_exit_code = exit_code;
// Flush console window
if (!m_err_leftover.isEmpty())
{
emit log({m_err_leftover}, MessageLevel::StdErr);
m_err_leftover.clear();
}
if (!m_out_leftover.isEmpty())
{
emit log({m_err_leftover}, MessageLevel::StdOut);
m_out_leftover.clear();
}
// based on state, send signals
if (!m_is_aborting)
{
@ -157,19 +186,6 @@ void LoggedProcess::on_stateChange(QProcess::ProcessState state)
}
}
#if defined Q_OS_WIN32
#include <windows.h>
#endif
qint64 LoggedProcess::processId() const
{
#ifdef Q_OS_WIN
return pid() ? pid()->dwProcessId : 0;
#else
return pid();
#endif
}
void LoggedProcess::setDetachable(bool detachable)
{
m_is_detachable = detachable;

View File

@ -1,21 +1,42 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* http://www.apache.org/licenses/LICENSE-2.0
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QProcess>
#include <QTextDecoder>
#include "MessageLevel.h"
/*
@ -43,7 +64,6 @@ public:
State state() const;
int exitCode() const;
qint64 processId() const;
void setDetachable(bool detachable);
@ -69,8 +89,8 @@ private:
void changeState(LoggedProcess::State state);
private:
QString m_err_leftover;
QString m_out_leftover;
QTextDecoder m_err_decoder = QTextDecoder(QTextCodec::codecForLocale());
QTextDecoder m_out_decoder = QTextDecoder(QTextCodec::codecForLocale());
bool m_killed = false;
State m_state = NotRunning;
int m_exit_code = 0;

View File

@ -127,7 +127,7 @@ bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList
}
// ours
bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods)
bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods)
{
QuaZip zipOut(targetJarPath);
if (!zipOut.open(QuaZip::mdCreate))
@ -141,42 +141,41 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
QSet<QString> addedFiles;
// Modify the jar
QListIterator<Mod> i(mods);
i.toBack();
while (i.hasPrevious())
// This needs to be done in reverse-order to ensure we respect the loading order of components
for (auto i = mods.crbegin(); i != mods.crend(); i++)
{
const Mod &mod = i.previous();
const auto* mod = *i;
// do not merge disabled mods.
if (!mod.enabled())
if (!mod->enabled())
continue;
if (mod.type() == Mod::MOD_ZIPFILE)
if (mod->type() == ResourceType::ZIPFILE)
{
if (!mergeZipFiles(&zipOut, mod.filename(), addedFiles))
if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles))
{
zipOut.close();
QFile::remove(targetJarPath);
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
return false;
}
}
else if (mod.type() == Mod::MOD_SINGLEFILE)
else if (mod->type() == ResourceType::SINGLEFILE)
{
// FIXME: buggy - does not work with addedFiles
auto filename = mod.filename();
auto filename = mod->fileinfo();
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName()))
{
zipOut.close();
QFile::remove(targetJarPath);
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
return false;
}
addedFiles.insert(filename.fileName());
}
else if (mod.type() == Mod::MOD_FOLDER)
else if (mod->type() == ResourceType::FOLDER)
{
// untested, but seems to be unused / not possible to reach
// FIXME: buggy - does not work with addedFiles
auto filename = mod.filename();
auto filename = mod->fileinfo();
QString what_to_zip = filename.absoluteFilePath();
QDir dir(what_to_zip);
dir.cdUp();
@ -193,7 +192,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
{
zipOut.close();
QFile::remove(targetJarPath);
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
return false;
}
qDebug() << "Adding folder " << filename.fileName() << " from "
@ -204,7 +203,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
// Make sure we do not continue launching when something is missing or undefined...
zipOut.close();
QFile::remove(targetJarPath);
qCritical() << "Failed to add unknown mod type" << mod.filename().fileName() << "to the jar.";
qCritical() << "Failed to add unknown mod type" << mod->fileinfo().fileName() << "to the jar.";
return false;
}
}
@ -269,7 +268,7 @@ bool MMCZip::findFilesInZip(QuaZip * zip, const QString & what, QStringList & re
// ours
nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target)
std::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target)
{
QDir directory(target);
QStringList extracted;
@ -278,7 +277,7 @@ nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString &
auto numEntries = zip->getEntriesCount();
if(numEntries < 0) {
qWarning() << "Failed to enumerate files in archive";
return nonstd::nullopt;
return std::nullopt;
}
else if(numEntries == 0) {
qDebug() << "Extracting empty archives seems odd...";
@ -287,7 +286,7 @@ nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString &
else if (!zip->goToFirstFile())
{
qWarning() << "Failed to seek to first file in zip";
return nonstd::nullopt;
return std::nullopt;
}
do
@ -297,20 +296,40 @@ nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString &
{
continue;
}
name.remove(0, subdir.size());
QString absFilePath = directory.absoluteFilePath(name);
auto original_name = name;
// Fix weird "folders with a single file get squashed" thing
QString path;
if(name.contains('/') && !name.endsWith('/')){
path = name.section('/', 0, -2) + "/";
FS::ensureFolderPathExists(FS::PathCombine(target, path));
name = name.split('/').last();
}
QString absFilePath;
if(name.isEmpty())
{
absFilePath += "/";
absFilePath = directory.absoluteFilePath(name) + "/";
}
else
{
absFilePath = directory.absoluteFilePath(path + name);
}
if (!JlCompress::extractFile(zip, "", absFilePath))
{
qWarning() << "Failed to extract file" << name << "to" << absFilePath;
qWarning() << "Failed to extract file" << original_name << "to" << absFilePath;
JlCompress::removeFile(extracted);
return nonstd::nullopt;
return std::nullopt;
}
extracted.append(absFilePath);
qDebug() << "Extracted file" << name;
QFile::setPermissions(absFilePath, QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser);
qDebug() << "Extracted file" << name << "to" << absFilePath;
} while (zip->goToNextFile());
return extracted;
}
@ -322,7 +341,7 @@ bool MMCZip::extractRelFile(QuaZip *zip, const QString &file, const QString &tar
}
// ours
nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString dir)
std::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString dir)
{
QuaZip zip(fileCompressed);
if (!zip.open(QuaZip::mdUnzip))
@ -333,13 +352,13 @@ nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString
return QStringList();
}
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
return nonstd::nullopt;
return std::nullopt;
}
return MMCZip::extractSubDir(&zip, "", dir);
}
// ours
nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir)
std::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir)
{
QuaZip zip(fileCompressed);
if (!zip.open(QuaZip::mdUnzip))
@ -350,7 +369,7 @@ nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString
return QStringList();
}
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
return nonstd::nullopt;
return std::nullopt;
}
return MMCZip::extractSubDir(&zip, subdir, dir);
}
@ -401,7 +420,7 @@ bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& s
continue;
}
files->append(e.filePath()); // we want the original paths for MMCZip::compressDirFiles
files->append(e); // we want the original paths for MMCZip::compressDirFiles
}
return true;
}

View File

@ -42,7 +42,7 @@
#include <functional>
#include <quazip/JlCompress.h>
#include <nonstd/optional>
#include <optional>
namespace MMCZip
{
@ -75,7 +75,7 @@ namespace MMCZip
/**
* take a source jar, add mods to it, resulting in target jar
*/
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods);
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods);
/**
* Find a single file in archive by file name (not path)
@ -95,7 +95,7 @@ namespace MMCZip
/**
* Extract a subdirectory from an archive
*/
nonstd::optional<QStringList> extractSubDir(QuaZip *zip, const QString & subdir, const QString &target);
std::optional<QStringList> extractSubDir(QuaZip *zip, const QString & subdir, const QString &target);
bool extractRelFile(QuaZip *zip, const QString & file, const QString &target);
@ -106,7 +106,7 @@ namespace MMCZip
* \param dir The directory to extract to, the current directory if left empty.
* \return The list of the full paths of the files extracted, empty on failure.
*/
nonstd::optional<QStringList> extractDir(QString fileCompressed, QString dir);
std::optional<QStringList> extractDir(QString fileCompressed, QString dir);
/**
* Extract a subdirectory from an archive
@ -116,7 +116,7 @@ namespace MMCZip
* \param dir The directory to extract to, the current directory if left empty.
* \return The list of the full paths of the files extracted, empty on failure.
*/
nonstd::optional<QStringList> extractDir(QString fileCompressed, QString subdir, QString dir);
std::optional<QStringList> extractDir(QString fileCompressed, QString subdir, QString dir);
/**
* Extract a single file from an archive into a directory

View File

@ -1,25 +1,56 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ModDownloadTask.h"
#include "Application.h"
#include "minecraft/mod/ModFolderModel.h"
ModDownloadTask::ModDownloadTask(const QUrl sourceUrl,const QString filename, const std::shared_ptr<ModFolderModel> mods)
: m_sourceUrl(sourceUrl), mods(mods), filename(filename) {
}
ModDownloadTask::ModDownloadTask(ModPlatform::IndexedPack mod, ModPlatform::IndexedVersion version, const std::shared_ptr<ModFolderModel> mods, bool is_indexed)
: m_mod(mod), m_mod_version(version), mods(mods)
{
if (is_indexed) {
m_update_task.reset(new LocalModUpdateTask(mods->indexDir(), m_mod, m_mod_version));
connect(m_update_task.get(), &LocalModUpdateTask::hasOldMod, this, &ModDownloadTask::hasOldMod);
void ModDownloadTask::executeTask() {
setStatus(tr("Downloading mod:\n%1").arg(m_sourceUrl.toString()));
addTask(m_update_task);
}
m_filesNetJob.reset(new NetJob(tr("Mod download"), APPLICATION->network()));
m_filesNetJob->addNetAction(Net::Download::makeFile(m_sourceUrl, mods->dir().absoluteFilePath(filename)));
m_filesNetJob->setStatus(tr("Downloading mod:\n%1").arg(m_mod_version.downloadUrl));
m_filesNetJob->addNetAction(Net::Download::makeFile(m_mod_version.downloadUrl, mods->dir().absoluteFilePath(getFilename())));
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ModDownloadTask::downloadSucceeded);
connect(m_filesNetJob.get(), &NetJob::progress, this, &ModDownloadTask::downloadProgressChanged);
connect(m_filesNetJob.get(), &NetJob::failed, this, &ModDownloadTask::downloadFailed);
m_filesNetJob->start();
addTask(m_filesNetJob);
}
void ModDownloadTask::downloadSucceeded()
{
emitSucceeded();
m_filesNetJob.reset();
auto name = std::get<0>(to_delete);
auto filename = std::get<1>(to_delete);
if (!name.isEmpty() && filename != m_mod_version.fileName) {
mods->uninstallMod(filename, true);
}
}
void ModDownloadTask::downloadFailed(QString reason)
@ -33,7 +64,9 @@ void ModDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
emit progress(current, total);
}
bool ModDownloadTask::abort() {
return m_filesNetJob->abort();
// This indirection is done so that we don't delete a mod before being sure it was
// downloaded successfully!
void ModDownloadTask::hasOldMod(QString name, QString filename)
{
to_delete = {name, filename};
}

View File

@ -1,34 +1,56 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "QObjectPtr.h"
#include "tasks/Task.h"
#include "minecraft/mod/ModFolderModel.h"
#include "net/NetJob.h"
#include <QUrl>
#include "tasks/SequentialTask.h"
#include "modplatform/ModIndex.h"
#include "minecraft/mod/tasks/LocalModUpdateTask.h"
class ModDownloadTask : public Task {
class ModFolderModel;
class ModDownloadTask : public SequentialTask {
Q_OBJECT
public:
explicit ModDownloadTask(const QUrl sourceUrl, const QString filename, const std::shared_ptr<ModFolderModel> mods);
const QString& getFilename() const { return filename; }
public slots:
bool abort() override;
protected:
//! Entry point for tasks.
void executeTask() override;
explicit ModDownloadTask(ModPlatform::IndexedPack mod, ModPlatform::IndexedVersion version, const std::shared_ptr<ModFolderModel> mods, bool is_indexed = true);
const QString& getFilename() const { return m_mod_version.fileName; }
private:
QUrl m_sourceUrl;
NetJob::Ptr m_filesNetJob;
ModPlatform::IndexedPack m_mod;
ModPlatform::IndexedVersion m_mod_version;
const std::shared_ptr<ModFolderModel> mods;
const QString filename;
NetJob::Ptr m_filesNetJob;
LocalModUpdateTask::Ptr m_update_task;
void downloadProgressChanged(qint64 current, qint64 total);
void downloadFailed(QString reason);
void downloadSucceeded();
std::tuple<QString, QString> to_delete {"", ""};
private slots:
void hasOldMod(QString name, QString filename);
};

View File

@ -1,3 +1,38 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "BaseInstance.h"
#include "launch/LaunchTask.h"
@ -15,6 +50,10 @@ public:
void saveNow() override
{
}
void loadSpecificSettings() override
{
setSpecificSettingsLoaded(true);
}
QString getStatusbarDescription() override
{
return tr("Unknown instance type");
@ -39,7 +78,11 @@ public:
{
return QProcessEnvironment();
}
QMap<QString, QString> getVariables() const override
QProcessEnvironment createLaunchEnvironment() override
{
return QProcessEnvironment();
}
QMap<QString, QString> getVariables() override
{
return QMap<QString, QString>();
}
@ -76,4 +119,8 @@ public:
QString modsRoot() const override {
return QString();
}
void updateRuntimeContext()
{
// NOOP
}
};

View File

@ -1,89 +1,37 @@
#pragma once
#include <QObject>
#include <QSharedPointer>
#include <functional>
#include <memory>
#include <QObject>
namespace details
{
struct DeleteQObjectLater
{
void operator()(QObject *obj) const
{
obj->deleteLater();
}
};
}
/**
* A unique pointer class with unique pointer semantics intended for derivates of QObject
* Calls deleteLater() instead of destroying the contained object immediately
*/
template<typename T> using unique_qobject_ptr = std::unique_ptr<T, details::DeleteQObjectLater>;
template <typename T>
using unique_qobject_ptr = QScopedPointer<T, QScopedPointerDeleteLater>;
/**
* A shared pointer class with shared pointer semantics intended for derivates of QObject
* Calls deleteLater() instead of destroying the contained object immediately
*/
template <typename T>
class shared_qobject_ptr
{
public:
shared_qobject_ptr(){}
shared_qobject_ptr(T * wrap)
{
reset(wrap);
}
shared_qobject_ptr(const shared_qobject_ptr<T>& other)
{
m_ptr = other.m_ptr;
}
template<typename Derived>
shared_qobject_ptr(const shared_qobject_ptr<Derived> &other)
{
m_ptr = other.unwrap();
}
class shared_qobject_ptr : public QSharedPointer<T> {
public:
constexpr shared_qobject_ptr() : QSharedPointer<T>() {}
constexpr shared_qobject_ptr(T* ptr) : QSharedPointer<T>(ptr, &QObject::deleteLater) {}
constexpr shared_qobject_ptr(std::nullptr_t null_ptr) : QSharedPointer<T>(null_ptr, &QObject::deleteLater) {}
public:
void reset(T * wrap)
{
using namespace std::placeholders;
m_ptr.reset(wrap, std::bind(&QObject::deleteLater, _1));
}
void reset(const shared_qobject_ptr<T> &other)
{
m_ptr = other.m_ptr;
}
void reset()
{
m_ptr.reset();
}
T * get() const
{
return m_ptr.get();
}
T * operator->() const
{
return m_ptr.get();
}
T & operator*() const
{
return *m_ptr.get();
}
operator bool() const
{
return m_ptr.get() != nullptr;
}
const std::shared_ptr <T> unwrap() const
{
return m_ptr;
}
bool operator==(const shared_qobject_ptr<T>& other) {
return m_ptr == other.m_ptr;
}
bool operator!=(const shared_qobject_ptr<T>& other) {
return m_ptr != other.m_ptr;
}
template <typename Derived>
constexpr shared_qobject_ptr(const shared_qobject_ptr<Derived>& other) : QSharedPointer<T>(other)
{}
private:
std::shared_ptr <T> m_ptr;
void reset() { QSharedPointer<T>::reset(); }
void reset(const shared_qobject_ptr<T>& other)
{
shared_qobject_ptr<T> t(other);
this->swap(t);
}
};

88
launcher/RuntimeContext.h Normal file
View File

@ -0,0 +1,88 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QSet>
#include <QString>
#include "settings/SettingsObject.h"
struct RuntimeContext {
QString javaArchitecture;
QString javaRealArchitecture;
QString javaPath;
QString system;
QString mappedJavaRealArchitecture() const
{
if (javaRealArchitecture == "amd64")
return "x86_64";
if (javaRealArchitecture == "i386" || javaRealArchitecture == "i686")
return "x86";
if (javaRealArchitecture == "aarch64")
return "arm64";
if (javaRealArchitecture == "arm" || javaRealArchitecture == "armhf")
return "arm32";
return javaRealArchitecture;
}
void updateFromInstanceSettings(SettingsObjectPtr instanceSettings)
{
javaArchitecture = instanceSettings->get("JavaArchitecture").toString();
javaRealArchitecture = instanceSettings->get("JavaRealArchitecture").toString();
javaPath = instanceSettings->get("JavaPath").toString();
system = currentSystem();
}
QString getClassifier() const { return system + "-" + mappedJavaRealArchitecture(); }
// "Legacy" refers to the fact that Mojang assumed that these are the only two architectures
bool isLegacyArch() const
{
const QString mapped = mappedJavaRealArchitecture();
return mapped == "x86_64" || mapped == "x86";
}
bool classifierMatches(QString target) const
{
// try to match precise classifier "[os]-[arch]"
bool x = target == getClassifier();
// try to match imprecise classifier on legacy architectures "[os]"
if (!x && isLegacyArch())
x = target == system;
return x;
}
static QString currentSystem()
{
#if defined(Q_OS_LINUX)
return "linux";
#elif defined(Q_OS_MACOS)
return "osx";
#elif defined(Q_OS_WINDOWS)
return "windows";
#elif defined(Q_OS_FREEBSD)
return "freebsd";
#elif defined(Q_OS_OPENBSD)
return "openbsd";
#else
return "unknown";
#endif
}
};

View File

@ -138,20 +138,6 @@ void UpdateController::installUpdates()
}
#endif
QFileInfo destination (FS::PathCombine(m_root, op.destination));
#ifdef Q_OS_WIN32
if(QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
{
if(destination.fileName() == windowsExeName)
{
QDir rootDir(m_root);
exeOrigin = rootDir.relativeFilePath(op.source);
exePath = rootDir.relativeFilePath(op.destination);
exeBackup = rootDir.relativeFilePath(FS::PathCombine(backupPath, destination.fileName()));
useXPHack = true;
continue;
}
}
#endif
if(destination.exists())
{
QString backupName = op.destination;
@ -372,7 +358,7 @@ void UpdateController::fail()
msg = QObject::tr(
"Couldn't replace file %1. Changes will be reverted.\n"
"See the %2 log file for details."
).arg(m_failedFile, BuildConfig.LAUNCHER_NAME);
).arg(m_failedFile, BuildConfig.LAUNCHER_DISPLAYNAME);
doRollback = true;
QMessageBox::critical(m_parent, failTitle, msg);
break;
@ -382,7 +368,7 @@ void UpdateController::fail()
msg = QObject::tr(
"Couldn't remove file %1. Changes will be reverted.\n"
"See the %2 log file for details."
).arg(m_failedFile, BuildConfig.LAUNCHER_NAME);
).arg(m_failedFile, BuildConfig.LAUNCHER_DISPLAYNAME);
doRollback = true;
QMessageBox::critical(m_parent, failTitle, msg);
break;
@ -413,7 +399,7 @@ void UpdateController::fail()
{
msg = QObject::tr("The rollback failed too.\n"
"You will have to repair %1 manually.\n"
"Please let us know why and how this happened.").arg(BuildConfig.LAUNCHER_NAME);
"Please let us know why and how this happened.").arg(BuildConfig.LAUNCHER_DISPLAYNAME);
QMessageBox::critical(m_parent, rollFailTitle, msg);
qApp->quit();
}

View File

@ -1,6 +1,42 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QString>
#include <QStringView>
#include <QList>
class QUrl;
@ -39,13 +75,21 @@ private:
break;
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto numPart = QStringView{m_fullString}.left(cutoff);
#else
auto numPart = m_fullString.leftRef(cutoff);
#endif
if(numPart.size())
{
numValid = true;
m_numPart = numPart.toInt();
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto stringPart = QStringView{m_fullString}.mid(cutoff);
#else
auto stringPart = m_fullString.midRef(cutoff);
#endif
if(stringPart.size())
{
m_stringPart = stringPart.toString();

View File

@ -1,3 +1,38 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "VersionProxyModel.h"
#include "Application.h"
#include <QSortFilterProxyModel>
@ -208,7 +243,8 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
{
return APPLICATION->getThemedIcon("bug");
}
auto pixmap = QPixmapCache::find("placeholder");
QPixmap pixmap;
QPixmapCache::find("placeholder", &pixmap);
if(!pixmap)
{
QPixmap px(16,16);
@ -216,7 +252,7 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
QPixmapCache::insert("placeholder", px);
return px;
}
return *pixmap;
return pixmap;
}
}
default:

View File

@ -1,16 +1,36 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* http://www.apache.org/licenses/LICENSE-2.0
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "IconList.h"
@ -36,7 +56,7 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren
auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name);
for (auto file_info : file_info_list)
{
builtinNames.insert(file_info.baseName());
builtinNames.insert(file_info.completeBaseName());
}
}
for(auto & builtinName : builtinNames)
@ -51,6 +71,18 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren
connect(m_watcher.get(), SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
directoryChanged(path);
// Forces the UI to update, so that lengthy icon names are shown properly from the start
emit iconUpdated({});
}
void IconList::sortIconList()
{
qDebug() << "Sorting icon list...";
std::sort(icons.begin(), icons.end(), [](const MMCIcon& a, const MMCIcon& b) {
return a.m_key.localeAwareCompare(b.m_key) < 0;
});
reindex();
}
void IconList::directoryChanged(const QString &path)
@ -74,7 +106,11 @@ void IconList::directoryChanged(const QString &path)
QString &foo = (*it);
foo = m_dir.filePath(foo);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QSet<QString> new_set(new_list.begin(), new_list.end());
#else
auto new_set = new_list.toSet();
#endif
QList<QString> current_list;
for (auto &it : icons)
{
@ -82,7 +118,11 @@ void IconList::directoryChanged(const QString &path)
continue;
current_list.push_back(it.m_images[IconType::FileBased].filename);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QSet<QString> current_set(current_list.begin(), current_list.end());
#else
QSet<QString> current_set = current_list.toSet();
#endif
QSet<QString> to_remove = current_set;
to_remove -= new_set;
@ -94,7 +134,13 @@ void IconList::directoryChanged(const QString &path)
{
qDebug() << "Removing " << remove;
QFileInfo rmfile(remove);
QString key = rmfile.baseName();
QString key = rmfile.completeBaseName();
QString suffix = rmfile.suffix();
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
key = rmfile.fileName();
int idx = getIconIndex(key);
if (idx == -1)
continue;
@ -117,14 +163,23 @@ void IconList::directoryChanged(const QString &path)
for (auto add : to_add)
{
qDebug() << "Adding " << add;
QFileInfo addfile(add);
QString key = addfile.baseName();
QString key = addfile.completeBaseName();
QString suffix = addfile.suffix();
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
key = addfile.fileName();
if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased))
{
m_watcher->addPath(add);
emit iconUpdated(key);
}
}
sortIconList();
}
void IconList::fileChanged(const QString &path)
@ -133,7 +188,7 @@ void IconList::fileChanged(const QString &path)
QFileInfo checkfile(path);
if (!checkfile.exists())
return;
QString key = checkfile.baseName();
QString key = checkfile.completeBaseName();
int idx = getIconIndex(key);
if (idx == -1)
return;
@ -257,7 +312,7 @@ void IconList::installIcons(const QStringList &iconFiles)
QFileInfo fileinfo(file);
if (!fileinfo.isReadable() || !fileinfo.isFile())
continue;
QString target = FS::PathCombine(m_dir.dirName(), fileinfo.fileName());
QString target = FS::PathCombine(getDirectory(), fileinfo.fileName());
QString suffix = fileinfo.suffix();
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
@ -274,7 +329,7 @@ void IconList::installIcon(const QString &file, const QString &name)
if(!fileinfo.isReadable() || !fileinfo.isFile())
return;
QString target = FS::PathCombine(m_dir.dirName(), name);
QString target = FS::PathCombine(getDirectory(), name);
QFile::copy(file, target);
}

View File

@ -71,6 +71,7 @@ private:
// hide assign op
IconList &operator=(const IconList &) = delete;
void reindex();
void sortIconList();
public slots:
void directoryChanged(const QString &path);

View File

@ -1,21 +1,41 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* http://www.apache.org/licenses/LICENSE-2.0
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MMCIcon.h"
#include <QFileInfo>
#include <xdgicon.h>
#include <QIcon>
IconType operator--(IconType &t, int)
{
@ -63,7 +83,7 @@ QIcon MMCIcon::icon() const
if(!icon.isNull())
return icon;
// FIXME: inject this.
return XdgIcon::fromTheme(m_images[m_current_type].key);
return QIcon::fromTheme(m_images[m_current_type].key);
}
void MMCIcon::remove(IconType rm_type)

View File

@ -1,3 +1,38 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "JavaChecker.h"
#include <QFile>
@ -16,7 +51,13 @@ JavaChecker::JavaChecker(QObject *parent) : QObject(parent)
void JavaChecker::performCheck()
{
QString checkerJar = FS::PathCombine(APPLICATION->getJarsPath(), "JavaCheck.jar");
QString checkerJar = JavaUtils::getJavaCheckPath();
if (checkerJar.isEmpty())
{
qDebug() << "Java checker library could not be found. Please check your installation.";
return;
}
QStringList args;
@ -47,7 +88,11 @@ void JavaChecker::performCheck()
qDebug() << "Running java checker: " + m_path + args.join(" ");;
connect(process.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)));
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
connect(process.get(), SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
#else
connect(process.get(), SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
#endif
connect(process.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(stdoutReady()));
connect(process.get(), SIGNAL(readyReadStandardError()), this, SLOT(stderrReady()));
connect(&killTimer, SIGNAL(timeout()), SLOT(timeout()));
@ -99,7 +144,12 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
bool success = true;
QMap<QString, QString> results;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList lines = m_stdout.split("\n", Qt::SkipEmptyParts);
#else
QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts);
#endif
for(QString line : lines)
{
line = line.trimmed();
@ -108,7 +158,11 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
continue;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
auto parts = line.split('=', Qt::SkipEmptyParts);
#else
auto parts = line.split('=', QString::SkipEmptyParts);
#endif
if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty())
{
continue;

View File

@ -1,21 +1,40 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* http://www.apache.org/licenses/LICENSE-2.0
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <QtNetwork>
#include <QtXml>
#include <QRegExp>
#include <QDebug>
@ -81,7 +100,7 @@ QVariant JavaInstallList::data(const QModelIndex &index, int role) const
switch (role)
{
case VersionPointerRole:
return qVariantFromValue(m_vlist[index.row()]);
return QVariant::fromValue(m_vlist[index.row()]);
case VersionIdRole:
return version->descriptor();
case VersionRole:

View File

@ -1,16 +1,36 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* http://www.apache.org/licenses/LICENSE-2.0
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <QStringList>
@ -24,6 +44,7 @@
#include "java/JavaUtils.h"
#include "java/JavaInstallList.h"
#include "FileSystem.h"
#include "Application.h"
#define IBUS "@im=ibus"
@ -31,26 +52,25 @@ JavaUtils::JavaUtils()
{
}
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
static QString processLD_LIBRARY_PATH(const QString & LD_LIBRARY_PATH)
QString stripVariableEntries(QString name, QString target, QString remove)
{
QDir mmcBin(QCoreApplication::applicationDirPath());
auto items = LD_LIBRARY_PATH.split(':');
QStringList final;
for(auto & item: items)
{
QDir test(item);
if(test == mmcBin)
{
qDebug() << "Env:LD_LIBRARY_PATH ignoring path" << item;
continue;
}
final.append(item);
}
return final.join(':');
}
char delimiter = ':';
#ifdef Q_OS_WIN32
delimiter = ';';
#endif
auto targetItems = target.split(delimiter);
auto toRemove = remove.split(delimiter);
for (QString item : toRemove) {
bool removed = targetItems.removeOne(item);
if (!removed)
qWarning() << "Entry" << item
<< "could not be stripped from variable" << name;
}
return targetItems.join(delimiter);
}
QProcessEnvironment CleanEnviroment()
{
// prepare the process environment
@ -68,6 +88,16 @@ QProcessEnvironment CleanEnviroment()
"JAVA_OPTIONS",
"JAVA_TOOL_OPTIONS"
};
QStringList stripped =
{
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
"LD_LIBRARY_PATH",
"LD_PRELOAD",
#endif
"QT_PLUGIN_PATH",
"QT_FONTPATH"
};
for(auto key: rawenv.keys())
{
auto value = rawenv.value(key);
@ -77,19 +107,22 @@ QProcessEnvironment CleanEnviroment()
qDebug() << "Env: ignoring" << key << value;
continue;
}
// filter PolyMC-related things
if(key.startsWith("QT_"))
// These are used to strip the original variables
// If there is "LD_LIBRARY_PATH" and "LAUNCHER_LD_LIBRARY_PATH", we want to
// remove all values in "LAUNCHER_LD_LIBRARY_PATH" from "LD_LIBRARY_PATH"
if(key.startsWith("LAUNCHER_"))
{
qDebug() << "Env: ignoring" << key << value;
continue;
}
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
// Do not pass LD_* variables to java. They were intended for PolyMC
if(key.startsWith("LD_"))
if(stripped.contains(key))
{
qDebug() << "Env: ignoring" << key << value;
continue;
QString newValue = stripVariableEntries(key, value, rawenv.value("LAUNCHER_" + key));
qDebug() << "Env: stripped" << key << value << "to" << newValue;
}
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
// Strip IBus
// IBus is a Linux IME framework. For some reason, it breaks MC?
if (key == "XMODIFIERS" && value.contains(IBUS))
@ -98,22 +131,12 @@ QProcessEnvironment CleanEnviroment()
value.replace(IBUS, "");
qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value;
}
if(key == "GAME_PRELOAD")
{
env.insert("LD_PRELOAD", value);
continue;
}
if(key == "GAME_LIBRARY_PATH")
{
env.insert("LD_LIBRARY_PATH", processLD_LIBRARY_PATH(value));
continue;
}
#endif
// qDebug() << "Env: " << key << value;
env.insert(key, value);
}
#ifdef Q_OS_LINUX
// HACK: Workaround for QTBUG42500
// HACK: Workaround for QTBUG-42500
if(!env.contains("LD_LIBRARY_PATH"))
{
env.insert("LD_LIBRARY_PATH", "");
@ -151,11 +174,17 @@ JavaInstallPtr JavaUtils::GetDefaultJava()
QStringList addJavasFromEnv(QList<QString> javas)
{
QByteArray env = qgetenv("POLYMC_JAVA_PATHS");
auto env = qEnvironmentVariable("PRISMLAUNCHER_JAVA_PATHS"); // FIXME: use launcher name from buildconfig
#if defined(Q_OS_WIN32)
QList<QString> javaPaths = QString::fromLocal8Bit(env).replace("\\", "/").split(QLatin1String(";"));
QList<QString> javaPaths = env.replace("\\", "/").split(QLatin1String(";"));
auto envPath = qEnvironmentVariable("PATH");
QList<QString> javaPathsfromPath = envPath.replace("\\", "/").split(QLatin1String(";"));
for (QString string : javaPathsfromPath) {
javaPaths.append(string + "/javaw.exe");
}
#else
QList<QString> javaPaths = QString::fromLocal8Bit(env).split(QLatin1String(":"));
QList<QString> javaPaths = env.split(QLatin1String(":"));
#endif
for(QString i : javaPaths)
{
@ -176,25 +205,17 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
archType = "32";
HKEY jreKey;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName.toStdString().c_str(), 0,
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0,
KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS)
{
// Read the current type version from the registry.
// This will be used to find any key that contains the JavaHome value.
char *value = new char[0];
DWORD valueSz = 0;
if (RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz) ==
ERROR_MORE_DATA)
{
value = new char[valueSz];
RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz);
}
TCHAR subKeyName[255];
WCHAR subKeyName[255];
DWORD subKeyNameSize, numSubKeys, retCode;
// Get the number of subkeys
RegQueryInfoKey(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
NULL, NULL);
// Iterate until RegEnumKeyEx fails
@ -203,34 +224,37 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
for (DWORD i = 0; i < numSubKeys; i++)
{
subKeyNameSize = 255;
retCode = RegEnumKeyEx(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
NULL);
retCode = RegEnumKeyExW(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
NULL);
QString newSubkeyName = QString::fromWCharArray(subKeyName);
if (retCode == ERROR_SUCCESS)
{
// Now open the registry key for the version that we just got.
QString newKeyName = keyName + "\\" + subKeyName + subkeySuffix;
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
HKEY newKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newKeyName.toStdString().c_str(), 0,
KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().c_str(), 0,
KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
{
// Read the JavaHome value to find where Java is installed.
value = new char[0];
valueSz = 0;
if (RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
&valueSz) == ERROR_MORE_DATA)
DWORD valueSz = 0;
if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, NULL,
&valueSz) == ERROR_SUCCESS)
{
value = new char[valueSz];
RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
&valueSz);
WCHAR *value = new WCHAR[valueSz];
RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE *)value,
&valueSz);
QString newValue = QString::fromWCharArray(value);
delete [] value;
// Now, we construct the version object and add it to the list.
JavaInstallPtr javaVersion(new JavaInstall());
javaVersion->id = subKeyName;
javaVersion->id = newSubkeyName;
javaVersion->arch = archType;
javaVersion->path =
QDir(FS::PathCombine(value, "bin")).absoluteFilePath("javaw.exe");
QDir(FS::PathCombine(newValue, "bin")).absoluteFilePath("javaw.exe");
javas.append(javaVersion);
}
@ -355,7 +379,9 @@ QList<QString> JavaUtils::FindJavaPaths()
}
}
return addJavasFromEnv(candidates);
candidates = addJavasFromEnv(candidates);
candidates.removeDuplicates();
return candidates;
}
#elif defined(Q_OS_MAC)
@ -378,7 +404,9 @@ QList<QString> JavaUtils::FindJavaPaths()
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java");
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
}
return addJavasFromEnv(javas);
javas = addJavasFromEnv(javas);
javas.removeDuplicates();
return javas;
}
#elif defined(Q_OS_LINUX)
@ -417,14 +445,16 @@ QList<QString> JavaUtils::FindJavaPaths()
scanJavaDir("/usr/lib/jvm");
scanJavaDir("/usr/lib64/jvm");
scanJavaDir("/usr/lib32/jvm");
// javas stored in PolyMC's folder
// javas stored in Prism Launcher's folder
scanJavaDir("java");
// manually installed JDKs in /opt
scanJavaDir("/opt/jdk");
scanJavaDir("/opt/jdks");
// flatpak
scanJavaDir("/app/jdk");
return addJavasFromEnv(javas);
javas = addJavasFromEnv(javas);
javas.removeDuplicates();
return javas;
}
#else
QList<QString> JavaUtils::FindJavaPaths()
@ -437,3 +467,8 @@ QList<QString> JavaUtils::FindJavaPaths()
return addJavasFromEnv(javas);
}
#endif
QString JavaUtils::getJavaCheckPath()
{
return APPLICATION->getJarPath("JavaCheck.jar");
}

View File

@ -24,6 +24,7 @@
#include <windows.h>
#endif
QString stripVariableEntries(QString name, QString target, QString remove);
QProcessEnvironment CleanEnviroment();
class JavaUtils : public QObject
@ -39,4 +40,6 @@ public:
#ifdef Q_OS_WIN
QList<JavaInstallPtr> FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix = "");
#endif
static QString getJavaCheckPath();
};

View File

@ -282,18 +282,22 @@ void LaunchTask::emitFailed(QString reason)
Task::emitFailed(reason);
}
QString LaunchTask::substituteVariables(const QString &cmd) const
void LaunchTask::substituteVariables(QStringList &args) const
{
QString out = cmd;
auto variables = m_instance->getVariables();
for (auto it = variables.begin(); it != variables.end(); ++it)
auto env = m_instance->createEnvironment();
for (auto key : env.keys())
{
out.replace("$" + it.key(), it.value());
args.replaceInStrings("$" + key, env.value(key));
}
}
void LaunchTask::substituteVariables(QString &cmd) const
{
auto env = m_instance->createEnvironment();
for (auto key : env.keys())
{
cmd.replace("$" + key, env.value(key));
}
auto env = QProcessEnvironment::systemEnvironment();
for (auto var : env.keys())
{
out.replace("$" + var, env.value(var));
}
return out;
}

View File

@ -1,18 +1,38 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* http://www.apache.org/licenses/LICENSE-2.0
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
@ -85,7 +105,8 @@ public: /* methods */
shared_qobject_ptr<LogModel> getLogModel();
public:
QString substituteVariables(const QString &cmd) const;
void substituteVariables(QStringList &args) const;
void substituteVariables(QString &cmd) const;
QString censorPrivateInfo(QString in);
protected: /* methods */

View File

@ -34,6 +34,7 @@
*/
#include "CheckJava.h"
#include "java/JavaUtils.h"
#include <launch/LaunchTask.h>
#include <FileSystem.h>
#include <QStandardPaths>
@ -71,15 +72,26 @@ void CheckJava::executeTask()
emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::Launcher);
}
if (JavaUtils::getJavaCheckPath().isEmpty())
{
const char *reason = QT_TR_NOOP("Java checker library could not be found. Please check your installation.");
emit logLine(tr(reason), MessageLevel::Fatal);
emitFailed(tr(reason));
return;
}
QFileInfo javaInfo(realJavaPath);
qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch();
auto storedUnixTime = settings->get("JavaTimestamp").toLongLong();
auto storedArchitecture = settings->get("JavaArchitecture").toString();
auto storedRealArchitecture = settings->get("JavaRealArchitecture").toString();
auto storedVersion = settings->get("JavaVersion").toString();
auto storedVendor = settings->get("JavaVendor").toString();
m_javaUnixTime = javaUnixTime;
// if timestamps are not the same, or something is missing, check!
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0 || storedArchitecture.size() == 0 || storedVendor.size() == 0)
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0
|| storedArchitecture.size() == 0 || storedRealArchitecture.size() == 0
|| storedVendor.size() == 0)
{
m_JavaChecker = new JavaChecker();
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
@ -92,8 +104,9 @@ void CheckJava::executeTask()
{
auto verString = instance->settings()->get("JavaVersion").toString();
auto archString = instance->settings()->get("JavaArchitecture").toString();
auto realArchString = settings->get("JavaRealArchitecture").toString();
auto vendorString = instance->settings()->get("JavaVendor").toString();
printJavaInfo(verString, archString, vendorString);
printJavaInfo(verString, archString, realArchString, vendorString);
}
emitSucceeded();
}
@ -108,7 +121,6 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
emit logLine(QString("Could not start java:"), MessageLevel::Error);
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
emit logLine(QString("\nCheck your Java settings."), MessageLevel::Launcher);
printSystemInfo(false, false);
emitFailed(QString("Could not start java!"));
return;
}
@ -117,17 +129,16 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
printSystemInfo(false, false);
emitSucceeded();
return;
}
case JavaCheckResult::Validity::Valid:
{
auto instance = m_parent->instance();
printJavaInfo(result.javaVersion.toString(), result.realPlatform, result.javaVendor);
printSystemInfo(true, result.is_64bit);
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
instance->settings()->set("JavaVersion", result.javaVersion.toString());
instance->settings()->set("JavaArchitecture", result.mojangPlatform);
instance->settings()->set("JavaRealArchitecture", result.realPlatform);
instance->settings()->set("JavaVendor", result.javaVendor);
instance->settings()->set("JavaTimestamp", m_javaUnixTime);
emitSucceeded();
@ -136,24 +147,8 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
}
}
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString & vendor)
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString & vendor)
{
emit logLine(QString("Java is version %1, using %2 architecture, from %3.\n\n").arg(version, architecture, vendor), MessageLevel::Launcher);
}
void CheckJava::printSystemInfo(bool javaIsKnown, bool javaIs64bit)
{
auto cpu64 = Sys::isCPU64bit();
auto system64 = Sys::isSystem64bit();
if(cpu64 != system64)
{
emit logLine(QString("Your CPU architecture is not matching your system architecture. You might want to install a 64bit Operating System.\n\n"), MessageLevel::Error);
}
if(javaIsKnown)
{
if(javaIs64bit != system64)
{
emit logLine(QString("Your Java architecture is not matching your system architecture. You might want to install a 64bit Java version.\n\n"), MessageLevel::Error);
}
}
emit logLine(QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n")
.arg(version, architecture, realArchitecture, vendor), MessageLevel::Launcher);
}

View File

@ -35,7 +35,7 @@ private slots:
void checkJavaFinished(JavaCheckResult result);
private:
void printJavaInfo(const QString & version, const QString & architecture, const QString & vendor);
void printJavaInfo(const QString & version, const QString & architecture, const QString & realArchitecture, const QString & vendor);
void printSystemInfo(bool javaIsKnown, bool javaIs64bit);
private:

View File

@ -1,16 +1,36 @@
/* Copyright 2013-2021 MultiMC Contributors
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* http://www.apache.org/licenses/LICENSE-2.0
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PostLaunchCommand.h"
@ -27,9 +47,20 @@ PostLaunchCommand::PostLaunchCommand(LaunchTask *parent) : LaunchStep(parent)
void PostLaunchCommand::executeTask()
{
QString postlaunch_cmd = m_parent->substituteVariables(m_command);
emit logLine(tr("Running Post-Launch command: %1").arg(postlaunch_cmd), MessageLevel::Launcher);
m_process.start(postlaunch_cmd);
//FIXME: where to put this?
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
auto args = QProcess::splitCommand(m_command);
m_parent->substituteVariables(args);
emit logLine(tr("Running Post-Launch command: %1").arg(args.join(' ')), MessageLevel::Launcher);
const QString program = args.takeFirst();
m_process.start(program, args);
#else
m_parent->substituteVariables(m_command);
emit logLine(tr("Running Post-Launch command: %1").arg(m_command), MessageLevel::Launcher);
m_process.start(m_command);
#endif
}
void PostLaunchCommand::on_state(LoggedProcess::State state)

Some files were not shown because too many files have changed in this diff Show More