Compare commits

...

440 Commits
1.0.2 ... 1.1.0

Author SHA1 Message Date
9f8983b570 Merge pull request #235 from Scrumplex/chore-bump-1.1.0
Bump to 1.1.0
2022-03-12 13:34:36 +00:00
e42c5b00a4 Merge pull request #251 from flowln/fix_tr 2022-03-12 10:58:36 +01:00
a3d7ad731d fix missing translation strings
my mistake, sorry! ToT
2022-03-11 18:43:17 -03:00
dc98609ef8 Merge pull request #241 from PolyMC/ZekeSmith-move-to-wiki-1 2022-03-11 10:42:13 +01:00
c799faaca6 fix: typos 2022-03-11 09:21:59 +01:00
07e4c4d189 Merge pull request #242 from deadmeu/develop
Fix missing space in "No Accounts" message
2022-03-11 14:53:05 +11:00
c4a8fd353c Merge pull request #243 from dada513/mx_button 2022-03-10 18:52:57 +01:00
91524d6d6e Merge pull request #247 from txtsd/actions_fix
Fix Ubuntu system Qt failure
2022-03-10 23:45:32 +11:00
c1201997a3 Fix Ubuntu system Qt failure 2022-03-10 13:38:16 +05:30
d814e21f0d add matrix button 2022-03-08 18:41:23 +01:00
49d122a2c4 Fix missing space in "No Accounts" message 2022-03-08 23:24:11 +10:00
0813eba367 Update BUILD.md 2022-03-08 19:09:54 +10:00
dc9e250868 Merge pull request #232 from Scrumplex/fix-help-links
Switch to polymc.org wiki
2022-03-08 01:22:34 +11:00
b6cf0359fa Merge pull request #230 from Scrumplex/fix-iconthemes
Reorganize icon themes
2022-03-08 01:20:35 +11:00
ae39d16c11 chore: bump to 1.1.0 2022-03-06 11:40:11 +01:00
b93daf1fb7 fix: update news links to point to polymc.org 2022-03-06 11:32:06 +01:00
6545d250e8 refactor: move help URL into buildconfig 2022-03-06 11:31:50 +01:00
b162351ff4 fix: switch to polymc.org wiki 2022-03-05 21:49:13 +01:00
53468ea474 Merge pull request #221 from flowln/install_button 2022-03-05 20:43:44 +01:00
3697d70b48 fix: reorganize icon themes
Rename MultiMC to Legacy
Simple (Colored) is now the first icon theme
Custom is now the last icon theme, which also fixes a loading issue when
Legacy was selected
Fix loading of Legacy theme
2022-03-05 20:29:54 +01:00
e0c025b162 fix extra spacing in resource packs and shader packs, and move button up
hopefully now its finally ok
2022-03-03 09:51:46 -03:00
9e443faba3 hack: hide 'Download Mods' button when not in the mods tab 2022-03-03 04:02:22 -03:00
f95cebaf06 change 'Install Mods' -> 'Download Mods' and change position 2022-03-03 01:10:10 -03:00
ca211558b5 Merge pull request #216 from txtsd/ignore_paths
Don't build when updating non-code
2022-03-02 11:48:45 +11:00
3a03f90831 Ignore certain paths for CI 2022-03-02 01:17:08 +05:30
9020f632b2 Merge pull request #214 from PolyMC/ZekeSmith-newReadme
Modify readme to use website
2022-03-01 16:56:41 +01:00
8bdd2befe9 Merge pull request #205 from timoreo22/fix-version-select
Fixed wrong version info
2022-03-01 16:56:10 +01:00
ebececf8c6 Update and link latest build to actions 2022-03-01 23:19:30 +10:00
e1f28be151 Merge pull request #163 from txtsd/windows_data_dir
Replace build layouts with Launcher_PORTABLE cmake flag
2022-03-02 00:03:31 +11:00
10231aa404 Modify readme to use website 2022-03-01 10:33:59 +10:00
139ff82432 Merge pull request #207 from flowln/curseforge_api 2022-02-28 13:35:58 +01:00
4e8f075ff3 fix: Do not loop when its not a fabric mod on Flame version validation
Since there's no validation for forge mods since the start, we were just
looping with no porpuse in this situation.
2022-02-27 22:02:43 -03:00
148775b3e9 Update FMLLIBS_BASE_URL
Updated FMLLIBS_BASE_URL to https://files.polymc.org/fmllibs/

Fixes #208
2022-02-27 19:40:52 +00:00
075d900d45 fix: Always tell Flame API which modloader we are using
Fixes #206 partially. Although we don't list mods that have no
compatibility with the mod loader we are using, mods that have support
for both loaders still show up, and the versions for both the loaders
are still shown.

Also simplifies a little the logic in
FlameModIndex::loadIndexedPackVersions
2022-02-27 16:07:45 -03:00
5d1ca33b84 Apply suggestions from code review
Co-authored-by: LennyMcLennington <lenny@sneed.church>
2022-02-27 08:35:47 -08:00
ccc493cb2b Cleanly free NetJob in flame modpack 2022-02-27 13:14:12 +01:00
2745325ae0 Fixed wrong version info 2022-02-27 11:55:24 +01:00
84e9ce71b0 Merge pull request #203 from glowiak/patch-4 2022-02-27 09:53:56 +01:00
88fc1e32ee Merge pull request #201 from Scrumplex/fix-instancetype-reregistration 2022-02-26 14:37:27 +01:00
4f975bfb04 Notify about needed AppBSD version 2022-02-26 13:04:35 +01:00
692b9cf0e0 Merge pull request #195 from babbaj/nix-refactor
nix: Use POLYMC_JAVA_PATHS
2022-02-26 07:34:19 +01:00
ae354688c9 Merge pull request #193 from flowln/develop
Allow for downloading multiple mods at once
2022-02-26 07:33:11 +01:00
c9bf7f9896 fix: load instances no matter their instance type 2022-02-26 00:31:37 +01:00
e8929599a5 nix: Use POLYMC_JAVA_PATHS 2022-02-25 16:47:47 -05:00
27f37315f8 Merge pull request #199 from Scrumplex/fix-translations 2022-02-25 17:47:08 +01:00
c4f4e9e620 merge upstream and resolve conflicts 2022-02-25 13:43:27 -03:00
f2b850ad20 Merge pull request #183 from timoreo22/fix-versions-segfault
Fixed segfault in mod download
2022-02-26 01:55:11 +11:00
ccc27d1b7c Merge pull request #192 from Scrumplex/refactor-remove-legacy-instances
Drop legacy instances
2022-02-26 01:54:15 +11:00
4835ec3f6d fix(i18n): update translations URL 2022-02-25 15:19:15 +01:00
40a9828fba fix: improve readability and set ok button as disabled by default 2022-02-23 19:17:33 -03:00
04840d0638 fix(ui): add translation func to text in the confirm dialog 2022-02-23 14:44:55 -03:00
38f12c50f7 Merge branch 'PolyMC:develop' into develop 2022-02-23 14:34:51 -03:00
ca8b62291f fix: use legacy data path if it exists 2022-02-23 16:22:53 +05:30
69d01204e0 Implement PR suggestions 2022-02-23 16:22:53 +05:30
1e3b896fda Replace layouts with LAUNCH_PORTABLE 2022-02-23 16:22:23 +05:30
9e35560554 Merge pull request #158 from txtsd/actions
CI: Release builds and workflow
2022-02-23 10:36:47 +01:00
f9d4751ec0 Use System Qt for generic Linux build 2022-02-22 20:40:16 +05:30
a66e6a413f Merge pull request #169 from Scrumplex/rfc-template
Add issue template for RFCs
2022-02-23 00:10:09 +10:00
2c911a5475 Merge pull request #174 from dada513/readme_better
Prepare readme for 1.1.0, mark unofficial packages as unofficial
2022-02-23 00:09:56 +10:00
e2c2a38005 Merge pull request #186 from theglitch76-forks/develop
Enable WSL support
2022-02-22 08:23:57 +01:00
aa4a6bb3be Merge pull request #172 from Scrumplex/fix-update-client-id
Switch to new MSA Client ID
2022-02-22 08:23:42 +01:00
4af020161d Merge pull request #180 from Scrumplex/feat-msa-clientid-detection
Detect MSA Client ID change
2022-02-22 08:23:28 +01:00
f8b0d6453a fix: sort mod list in confirmation dialog 2022-02-21 23:25:33 -03:00
0102e91940 feat: add confirm dialog for installing mods
When selecting multiple mods at once, it can become hard to keep track
of which ones you selected.

To address this, a dialog is now displayed
when you finish selecting the mods to download, showing you which ones
you selected and their filenames. From there, you can either accept it
and download the mods, or you can cancel it and go back to the mod
selection dialog.
2022-02-21 23:09:14 -03:00
1004211a66 fix(ui): change text in selection button when there's no valid version 2022-02-21 22:52:50 -03:00
f5cf4eb45f feat(ui): allow downloading multiple mods from CurseForge at once 2022-02-21 21:53:21 -03:00
512395e3f1 feat(ui): allow downloading multiple mods in Modrinth at once 2022-02-21 21:34:53 -03:00
9c6727e27f feat: change task container in ModDownloadDialog to a QHash
Previously, we used a unique_ptr to a ModDownloadTask to keep track of
the selected mod to download when we accepted the dialog.

In order to allow multiple mods to be selected at once for download,
this has been changed to a QHash where the key is the mods name (since
it doesn't seem right to allow for multiple versions of the same mod to
be downloaded at once), and the value is a pointer to the corresponding
ModDownloadTask.
2022-02-21 21:34:06 -03:00
624ab25cd4 refactor: set default InstanceType to OneSix 2022-02-21 22:59:07 +01:00
a70d1f1a91 refactor: drop LegacyInstance 2022-02-21 22:30:44 +01:00
3059f13011 refactor: drop migration for pre-component instances 2022-02-21 22:11:10 +01:00
d3e7d30ee0 Create releases in a separate workflow 2022-02-21 21:48:31 +05:30
5bbb4f31dc Add generic Linux system builds 2022-02-21 21:48:31 +05:30
8556ff5eac Revert ba6a97557a0d90d77e9eba560931414e39042447
Let evil win.
2022-02-20 15:00:23 -06:00
adacab3349 Fixed segfault when closing window while version info download is still going 2022-02-19 15:17:45 +01:00
613b351f13 Merge pull request #168 from Kloenk/nix_flake_meta
Nix flake meta
2022-02-19 08:25:30 +01:00
80a29af497 fix: typo for account disabled error messages 2022-02-18 19:18:29 +01:00
7e1fad55d9 Merge pull request #178 from Scrumplex/add-contributor-covenant
Add Contributor Covenant 2.1
2022-02-19 00:09:59 +10:00
9b7cd029a7 Grab short version 2022-02-18 19:27:15 +05:30
c5d9944993 feat(accounts): interrupt MSAStep when client ID doesn't match 2022-02-18 12:32:24 +01:00
14717396eb feat(accounts): save client id in MSAStep 2022-02-18 12:32:24 +01:00
9c71f364d2 feat(accounts): add disabled account state 2022-02-18 12:32:24 +01:00
be910374dc feat(accounts): support msa-client-id value 2022-02-18 12:32:24 +01:00
10de75623e readd all packages 2022-02-18 10:28:17 +01:00
7fc55b58fe chore: clarify trolling in code of conduct 2022-02-18 09:44:27 +01:00
12c8a04458 Merge pull request #173 from Scrumplex/fix-application-cpp
fix: improve code readability in Application.cpp
2022-02-17 23:43:59 +00:00
796e58b6f2 Merge pull request #176 from PolyMC/upstream-merge
upstream merge
2022-02-17 23:34:50 +00:00
a7d37fa69a chore: add Contributor Covenant 2022-02-17 23:55:34 +01:00
7b4b997a34 Merge remote-tracking branch 'upstream/develop' into develop 2022-02-17 15:47:43 -05:00
6b4469c6cc fix: combine errors if --launch is missing 2022-02-17 15:29:09 +01:00
107a0ea852 fix2 2022-02-17 13:19:35 +01:00
6d7676202f unofficial => community maintained 2022-02-17 12:53:44 +01:00
0305b7a1fd Prepare readme for 1.1.0, mark unofficial packages as unofficial 2022-02-17 11:55:09 +01:00
02384f81c7 Merge pull request #131 from glowiak/patch-1
Add Slackware package
2022-02-17 11:32:17 +01:00
4536b19512 Merge pull request #171 from DioEgizio/fix-org.polymc-macos
Change: set MACOSX_BUNDLE_GUI_IDENTIFIER to org.polymc (fixes org.multimc.PolyMC)
2022-02-16 21:07:50 +01:00
45f89c6255 Merge branch 'develop' into patch-1 2022-02-16 18:36:28 +01:00
b1cf77e847 update 2022-02-16 18:31:34 +01:00
037b0d7190 fix: improve code readability in Application.cpp 2022-02-16 17:33:28 +01:00
ff17202b43 refactor: switch to new MSA Client ID 2022-02-16 17:03:13 +01:00
a3d8313dcb Change: set MACOSX_BUNDLE_GUI_IDENTIFIER to org.polymc instead of org.multimc 2022-02-16 15:45:16 +01:00
36841eaf63 chore(github): add issue template for RFCs 2022-02-16 12:38:28 +01:00
e24a183dad Only trigger GH Release on stable branch 2022-02-15 14:38:26 +05:30
8596753a63 Allow building release builds and…
…trigger GH release using tags
2022-02-15 14:24:52 +05:30
51183bef33 nix: add meta attribute 2022-02-14 21:08:10 +01:00
2cd837896d Merge pull request #160 from Scrumplex/custom-be-gone 2022-02-14 16:56:53 +01:00
c75ae71190 flake.nix: drop aarch64-darwin
Currently qtbase is broken on aarch64-darwin, therefor dropping support, so the check can succeed
2022-02-14 15:45:51 +01:00
48c20f5aaa Merge pull request #164 from Scrumplex/rebase-stable
Merge stable into develop
2022-02-14 10:10:35 +01:00
929a035f96 Revert "make wsl work"
This reverts commit 5779f20fa1633577889b7bda839c5486eb2ba922.
2022-02-13 18:47:54 +00:00
5779f20fa1 make wsl work 2022-02-13 13:35:15 -05:00
384e0df9e1 Merge remote-tracking branch 'upstream/stable' into rebase-stable 2022-02-13 18:08:41 +01:00
a5b06514c6 Merge pull request #161 from Scrumplex/custom-clientid
Add MSA-Client-ID override in UI
2022-02-13 14:06:27 +00:00
a309f4e721 fix: MSA = Microsoft Authentication 2022-02-12 21:27:35 +01:00
159d868b77 fix(ui): explain why 'Add Microsoft' might be disabled 2022-02-12 21:27:35 +01:00
0854e83ce4 feat: implement MSA client id override
Closes #11
2022-02-12 21:27:32 +01:00
bb02226870 feat(ui): add custom MSA client id setting 2022-02-12 21:05:42 +01:00
9ddbaaf7e8 feat: use commit hash for channel if ref not available 2022-02-12 19:04:45 +01:00
3b7cc4391a fix: don't use custom for version channel
Closes #159
2022-02-12 18:17:56 +01:00
70a055bc27 Merge pull request #143 from Scrumplex/refactor-link-nbtpp-static 2022-02-12 17:47:38 +01:00
61db1c46be fix: use our own prefix for rainbow lib 2022-02-12 17:02:54 +01:00
a60b2feb5f Revert "refactor(build): link rainbow statically"
Windows build fails for some reason. Needs to be investigated later

This reverts commit 812f00eb81158bfb4c2d61b228c0c1c796641ac1.
2022-02-12 16:56:35 +01:00
6ba031f048 refactor(build): link iconfix statically 2022-02-12 16:10:53 +01:00
812f00eb81 refactor(build): link rainbow statically 2022-02-12 16:10:46 +01:00
2f6973e08b Merge pull request #157 from txtsd/actions_fix
Adjust OpenSSL step
2022-02-12 03:15:11 -08:00
fb14796ed7 Adjust OpenSSL step 2022-02-12 14:56:15 +05:30
7d912726d0 Merge pull request #134 from glowiak/patch-2
OpenBSD support and slackware build instructions
2022-02-12 03:30:24 +00:00
e3c8eb062c Merge pull request #149 from ZekeSmith/patch-1
License for assets
2022-02-12 03:29:59 +00:00
3cf81faabc change "loader mods" to "mods"
Closes: #128
2022-02-11 22:09:47 -05:00
0df605e559 Merge pull request #155 from txtsd/actions
fix(ci): Unsplit OpenSSL step
2022-02-12 02:22:23 +00:00
e97a6ef957 Unsplit OpenSSL step 2022-02-12 00:19:11 +05:30
c4dd8d9c72 Update LICENSE 2022-02-12 01:03:33 +10:00
bcfa3246cb Merge pull request #146 from dada513/macos_application_support
[MACOS] Move app data to Application Support
2022-02-11 13:52:56 +00:00
f67871e79e refactor(build): link nbt++ statically 2022-02-11 14:24:01 +01:00
11f892380e Merge pull request #145 from dada513/metainfix
Update metadata
2022-02-11 13:54:14 +01:00
fd72cb034c Merge pull request #140 from txtsd/actions
CI: Build AppImages
2022-02-11 12:38:03 +00:00
b9be8d08d2 Remove superfluous variable 2022-02-11 18:05:26 +05:30
33d369d78c Add missing deploy flags 2022-02-11 18:05:26 +05:30
0e6e6a7521 Remove generic Linux builds
They don't necessarily run on all distros
2022-02-11 18:05:26 +05:30
eb692c2ee9 Split OpenSSL step 2022-02-11 18:05:26 +05:30
3eee38fedd Make 32bit Windows build instead 2022-02-11 18:05:26 +05:30
0ba61bb590 Implement even more PR suggestions 2022-02-11 18:05:26 +05:30
9497485103 Implement more PR suggestions 2022-02-11 18:05:26 +05:30
551d9c86ba Implement PR suggestions 2022-02-11 18:05:26 +05:30
e61e827eb9 Use Adoptium JREs 2022-02-11 18:05:26 +05:30
92a5b12bd9 Remove PrefersNonDefaultGPU 2022-02-11 18:05:26 +05:30
35d1330fe2 Build AppImages for Linux
Now builds windows and macOS builds,
with windeployqt and macdeploqt.
Also adds SHA to the build filenames.
2022-02-11 18:05:26 +05:30
b4e0b7584a newlines 2022-02-11 13:17:11 +01:00
2341212337 Merge pull request #150 from dada513/fix_kwin_icon
Fix freedesktop icons. Again
2022-02-11 12:05:01 +00:00
53ea261350 Merge pull request #151 from dada513/rss_not_begone
Re-add RSS feed with the new PolyMC website
2022-02-11 12:03:29 +00:00
a17e5d0a4d Merge pull request #129 from timoreo22/fix-mod-name
Fixed the download menu putting the wrong name
2022-02-10 23:41:27 +00:00
5d4a66ed8a Merge pull request #152 from Scrumplex/update-translations-url
Update link to translations platform (Weblate)
2022-02-10 23:38:47 +00:00
8d2e7db178 fix: update link to translations platform 2022-02-10 14:55:52 +01:00
383c93ff01 Merge pull request #148 from helpimnotdrowning/develop
Fix Weblate link in README
2022-02-10 13:40:12 +00:00
13d41bde7f remove unused parsing of dates (bloat) 2022-02-10 13:57:18 +01:00
d42d6fe25a fix rss format 2022-02-10 13:57:06 +01:00
beaac54dc9 Merge remote-tracking branch 'polymc/develop' into rss_not_begone 2022-02-10 13:14:30 +01:00
70f8cb81b8 Initial RSS re-add and removed hardcoded strings 2022-02-10 13:14:25 +01:00
f8ca6b4867 Revert "refactor: remove news feed"
This reverts commit 361ce7818ec8891e9a35bdfac4cdea77a0b6a949.
2022-02-10 12:55:07 +01:00
49f5f67467 Update screenshots to use new site 2022-02-10 12:26:33 +01:00
35d2ae3ef7 Remove drama from readme and remove mmc discord link 2022-02-10 11:21:25 +00:00
22ca572ae0 ci: rebuild 2022-02-10 09:32:12 +01:00
619fcbfabf rename LAUNCHER_DESKTOPNAME to LAUNCHER_DESKTOPFILENAME 2022-02-10 08:56:34 +01:00
292869141f Merge remote-tracking branch 'polymc/develop' into fix_kwin_icon 2022-02-10 08:05:17 +01:00
ca9929214d Merge remote-tracking branch 'polymc/develop' into macos_application_support 2022-02-10 08:04:59 +01:00
121ad4e4bf Merge remote-tracking branch 'polymc/develop' into metainfix 2022-02-10 08:04:38 +01:00
2f87a4477e Fix desktop id for GH-150 2022-02-10 07:53:04 +01:00
d72c511131 Revert "Fix freedesktop icons" and fix icon on kwin 2022-02-10 07:46:41 +01:00
8b68c06547 License for assets
The PolyMC logo and assets are licensed under the CC BY-NC-SA 4.0 having it in this folder should help to clear this up.
2022-02-10 13:58:19 +10:00
b911151786 Fix Weblate link in README
original link was missing /projects/ dir and leading to a nonexistant page
2022-02-09 21:40:57 -06:00
7531a2894b Missed a closing parenthesis in README.md, oops. 2022-02-09 23:13:33 +00:00
5b507a8944 Add info about translating PolyMC to the README 2022-02-09 23:00:03 +00:00
d2f86cbf32 Move app data to Application Support 2022-02-09 12:23:18 +01:00
08dff6613b remove redundant data 2022-02-09 08:21:51 +01:00
901ec15dc8 Update metadata 2022-02-09 08:19:34 +01:00
5284d604ef translations 2022-02-09 00:02:51 +00:00
b2b4ab3f0c Update BUILD.md 2022-02-07 10:11:36 +01:00
b646fc5a13 Update build instructions for Slackware 14.2 2022-02-06 12:18:39 +01:00
d35cbfd9c4 Add Slackware instructions 2022-02-06 12:11:20 +01:00
f25152e068 Update BUILD.md 2022-02-06 12:06:08 +01:00
dd8946b15a Update BUILD.md 2022-02-06 12:03:17 +01:00
305350fdc8 Update BUILD.md 2022-02-06 09:41:13 +01:00
f31d5372e7 Update BUILD.md 2022-02-06 09:39:14 +01:00
ca1a2bbe2c Add OpenBSD instructions 2022-02-06 09:38:26 +01:00
dba9199e58 Support OpenBSD in UpdateController.cpp 2022-02-06 09:35:48 +01:00
e806903d7e Support OpenBSD without patches 2022-02-06 09:32:55 +01:00
41d8e3cbd7 add arches 2022-02-05 16:07:31 +01:00
5e32783c4e Update README.md 2022-02-05 16:05:34 +01:00
fdc3a4104b Add OpenBSD 2022-02-05 16:03:16 +01:00
8199941a81 Fix typo 2022-02-05 14:04:34 +01:00
651d237200 Update README.md 2022-02-04 21:07:34 +01:00
6f5b380199 Update README.md 2022-02-04 20:58:12 +01:00
c746d77a06 Update README.md
Co-authored-by: dada513 <dada513@protonmail.com>
2022-02-04 20:42:30 +01:00
9ab3841570 change fbsd icon
Co-authored-by: dada513 <dada513@protonmail.com>
2022-02-04 20:40:47 +01:00
3a28741cc3 Add FreeBSD 2022-02-04 18:12:32 +01:00
22f7a85cf2 Add Slackware package 2022-02-04 17:59:37 +01:00
86935068f5 Fix wrong mod file name 2022-02-04 16:24:19 +01:00
00e12b776b Merge pull request #126 from Scrumplex/fix-quazip-build
fix: link QuaZip statically
2022-02-04 07:40:09 -05:00
3b96a9a8fa Merge pull request #124 from babbaj/develop
nix: fix quazip input
2022-02-04 07:34:13 -05:00
5ac5c767e0 Merge pull request #125 from dada513/based_build_md
fix build.md
2022-02-04 07:33:22 -05:00
f1d3d4a366 fix: link QuaZip statically 2022-02-04 13:24:13 +01:00
1160066f0d fix build.md 2022-02-04 11:06:04 +00:00
8d603d6162 nix: fix quazip input 2022-02-04 02:13:48 -05:00
076efc4cb2 Merge branch 'update-quazip' of git://github.com/Scrumplex/PolyMC into develop 2022-02-03 14:14:12 -05:00
2c62a34c2f Merge branch 'feature/offline_mode' into develop 2022-02-03 13:59:25 -05:00
2177aa2a6b Merge branch 'offline-mode-accounts' of git://github.com/NyaomiDEV/PolyMC into feature/offline_mode 2022-02-03 13:54:27 -05:00
e8a4902a3d Merge branch 'feature/download_mods' into develop 2022-02-03 13:53:30 -05:00
e2952061af Merge branch 'feature/download_mods' of git://github.com/timoreo22/PolyMC into feature/download_mods 2022-02-03 13:45:20 -05:00
fcc4420cfe Merge branch 'feature/close_after_launch' into develop 2022-02-03 13:44:09 -05:00
f5358aa1ca Merge branch 'develop' into feature/close_after_launch 2022-02-03 13:43:44 -05:00
3d3f9a8609 make closeAfterLaunch good 2022-02-03 12:50:24 -05:00
1f176fcb7b fix aur formatting in README 2022-02-03 12:47:16 -05:00
3ca661127f NOISSUE Add missing tooltip for Export Instance action 2022-02-03 18:09:51 +01:00
407f9d9ef0 Merge remote-tracking branch 'upstream/develop' into develop 2022-02-02 11:17:04 -05:00
bff683e6d4 Merge pull request #108 from redstrate/improve_about_page
Improve the About page
2022-02-02 09:17:30 -05:00
770da6317e Merge pull request #122 from txtsd/actions
GitHub Actions for crossplatform builds
2022-02-02 09:14:12 -05:00
cf3c2482c9 fix some windows branding
Closes: #121
2022-02-02 08:46:26 -05:00
2001c5dec7 Merge pull request #123 from Skyblueborb/patch-1
Fix Gentoo Command Syntax
2022-02-02 08:41:31 -05:00
80cf716c98 Fix Gentoo Command Syntax
The proper syntax for adding repos is `eselect repository enable <repo>`
2022-02-02 10:34:26 +01:00
37e1962845 Add build.yml 2022-02-02 06:28:00 +00:00
f8c5d80c66 Merge pull request #4480 from Oreoezi/develop
Update BUILD.md
2022-02-01 22:33:45 +01:00
11841c47e6 Double braindead combo 2022-02-01 22:23:34 +01:00
71b1ac9f34 Fix braindead moments 2022-02-01 21:56:52 +01:00
eda06df878 Update BUILD.md 2022-02-01 20:33:38 +00:00
c4cb7ddc4f fix: bring back JAR Folder mods
what is this?
2022-01-31 21:40:59 +01:00
a8089b76c0 fix: bring back instance exports 2022-01-31 21:40:59 +01:00
71516e6c72 fix: set Launcher_FORCE_BUNDLED_LIBS=on by default
We need to wait for a new QuaZip release to become widely available, until we can turn this off again
2022-01-31 21:40:59 +01:00
88686ef065 refactor: restructure CMake to support future Qt versions 2022-01-31 21:40:59 +01:00
0442b80a2c refactor: simpler includes for quazip 2022-01-31 21:40:59 +01:00
81c72c2038 refactor: bring back methods that need to be reimplemented 2022-01-31 21:40:59 +01:00
3aa809b8c0 refactor: add in-tree QuaZip 2022-01-31 21:40:59 +01:00
efa414c442 refactor: initial migration to QuaZip 1.2
Let's move off our custom QuaZip. In the olden times we needed the
custom version of QuaZip, as it was basically unmaintained and on
SourceForge (eww). But nowadays it's maintained and on GitHub. See
new GitHub page: https://github.com/stachenov/quazip
2022-01-31 21:40:59 +01:00
c39da093bf change COPR to polymc/polymc 2022-01-31 12:35:30 -05:00
aa2c27bf69 Update to Modrinth API V2 2022-01-31 17:18:11 +01:00
1f92125a7f Move RPM package to a separate repo. 2022-01-31 10:41:05 -05:00
5c48b7dfab Merge pull request #104 from dada513/makedeb
Remove debian packages from repo
2022-01-31 10:40:12 -05:00
d664361b15 remove deb packaging 2022-01-31 10:36:57 -05:00
813de1c703 pkgs: remove debian packaging from repo 2022-01-31 16:03:50 +01:00
02f24117f0 better package list 2022-01-31 10:00:25 -05:00
7a7a937f1e remove changelog because it's annoying 2022-01-31 09:54:16 -05:00
0211ee3ef1 Add "PolyMC Contributors" to Credits section
This also adds a link to the PolyMC Contributors page on Github.
2022-01-31 09:09:58 -05:00
c569bfbe6d Merge pull request #111 from DioEgizio/patch-1
improve a bit MacOS build instructions
2022-01-30 11:33:42 -05:00
b925338688 Merge pull request #112 from muscaln/flake
Nix updates
2022-01-30 11:32:49 -05:00
2cf04d034a Merge pull request #4300 from Ghosty141/feature/screenshot_copy
GH-4044 Implemented copy screenshots to the clipboard
2022-01-30 16:11:47 +01:00
049aafd0a1 Merge pull request #4461 from Jan200101/rpm
Update rpm spec to support OpenSuse and conform to Fedora guidelines
2022-01-30 16:07:51 +01:00
e0a04c5031 Lock offline mode support behind insertion of at least one Minecraft account
Co-Authored-By: Naomi Calabretta <tony0000.ac@gmail.com>
2022-01-30 02:42:29 +01:00
9d23ac562f Add offline mode support 2022-01-30 02:35:56 +01:00
0065a29901 Close after Launch setting 2022-01-29 19:04:44 -05:00
8ea1ebaf1b I haven't tested qt 5.6, i use 5.12 2022-01-29 18:14:56 +01:00
5c2d3e430d Merge branch 'develop' into patch-1 2022-01-29 18:10:46 +01:00
b710b719a8 nix: use .desktop file provided by cmake 2022-01-29 17:38:12 +03:00
7df5091fdc flake.lock: Update
Flake lock file changes:

• Updated input 'flake-utils':
    'github:numtide/flake-utils/74f7e4319258e287b0f9cb95426c9853b282730b' (2021-11-28)
  → 'github:numtide/flake-utils/846b2ae0fc4cc943637d3d1def4454213e203cba' (2022-01-20)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/b2737d4980a17cc2b7d600d7d0b32fd7333aca88' (2022-01-11)
  → 'github:nixos/nixpkgs/945ec499041db73043f745fad3b2a3a01e826081' (2022-01-26)
2022-01-29 17:35:50 +03:00
5abb97362f Merge pull request #102 from dada513/rework_docs
docs: rework README and BUILD
2022-01-29 09:24:08 -05:00
b34239ebc6 adoptium 2022-01-29 11:00:13 +01:00
7ef6c586c5 update readme 2022-01-29 10:59:04 +01:00
9d36cf4b5a fix another typo (omg I'm doing too commits) 2022-01-29 10:26:13 +01:00
04be2404ce fix typo 2022-01-29 10:24:49 +01:00
7f4fd04cfe not needed actually 2022-01-29 10:24:06 +01:00
b2bcdb9d9b fix a typo+explain better 2022-01-29 10:18:12 +01:00
d81e2bb0b0 extra refinements 2022-01-29 10:14:00 +01:00
177c10bb0f fix MacOS build instructions 2022-01-29 10:12:04 +01:00
304775952f EVEN MORE BASED 2022-01-29 09:40:27 +01:00
ca00103ee2 make packaging based 2022-01-29 08:56:04 +01:00
3aa9f5c376 Update rpm spec to support OpenSuse and conform to Fedora guidelines 2022-01-28 19:42:30 +01:00
efc44c56a6 Fix button being present in other pages 2022-01-28 19:32:42 +01:00
8b790a6dd9 Merge branch 'PolyMC:develop' into feature/download_mods 2022-01-28 18:12:35 +01:00
f36930d812 Merge pull request #107 from redstrate/fix_icon_bug
Fix icons changing when exiting the settings window
2022-01-28 09:31:41 -05:00
232295bda7 add gentoo instructions 2022-01-28 09:12:55 +01:00
451768ccf9 Merge remote-tracking branch 'upstream/develop' into rework_docs 2022-01-28 09:10:47 +01:00
c1aaf89baa Improve the About page
Improves #106. This more clearly marks the original MultiMC contributors,
and now correctly hides the "Build Platform" if this is set as empty. The
version label is now moved under the "PolyMC" title so it looks just a
little bit better (and matches other applications). The copyright on the
"About" page now correctly attributes the MultiMC contributors just like on
the "License" page.
2022-01-27 19:06:07 -05:00
5ac528f141 Fix icons changing when exiting the settings window 2022-01-27 18:37:57 -05:00
204e3dca22 fix version 2022-01-27 17:23:50 -05:00
33aac2985a Merge pull request #105 from Scrumplex/rss-begone
Remove news
2022-01-27 17:00:15 -05:00
361ce7818e refactor: remove news feed
Closes #63
2022-01-27 22:59:20 +01:00
ad6e3a0868 Fix meta 2022-01-27 16:58:28 -05:00
fd2269ac15 Fix meta 2022-01-27 16:54:05 -05:00
14a8ead6b4 fix conflict 2022-01-27 19:01:20 +01:00
bbf0508846 docs: rework README and BUILD 2022-01-27 18:59:44 +01:00
79314ee67b Merge pull request #103 from redstrate/fix_rpm_build
Fix RPM build instructions
2022-01-27 12:43:54 -05:00
86b0637ef7 Merge pull request #101 from redstrate/fix_freedesktop_icon
Fix Freedesktop icons
2022-01-27 09:56:39 -05:00
1c982b0182 Fix RPM build instructions 2022-01-27 13:17:26 +00:00
cd5faee7d7 Fix RPM spec referencing old desktop file 2022-01-27 08:06:35 -05:00
ec1e27031a Fix Freedesktop icons
This fixes #51. The desktop file is now exactly the same as the window class,
which is also now corrected to org.polymc.polymc. The file capitalization
is also consistent with other Freedesktop files as well.
2022-01-27 00:08:53 -05:00
02889b7a11 Merge pull request #67 from PolyMC/feature/no_paste_ee
Full replacement of paste.ee
2022-01-26 17:40:49 -05:00
0eff21a4f1 Validate Pastebin URL with regex 2022-01-26 00:34:02 +00:00
0680945839 Merge pull request #96 from dada513/develop
rebase with upstream
2022-01-24 19:36:31 -05:00
631e670775 Merge pull request #99 from Jan200101/PR/rpm-opensuse
remove explicit dependencies, correct dependencies to work on OpenSuse
2022-01-24 18:40:44 -05:00
4edd2cff9f remove explicit dependencies, correct dependencies to work on OpenSuse 2022-01-24 23:15:54 +01:00
0235eb5c28 Fix error message
The code is trying to get a string from a json object, and if that fails it should log "is not a string", not "is not a timestamp".
2022-01-24 11:44:47 +01:00
8804b035b2 NOISSUE log server response when failing to fetch profile 2022-01-24 11:44:47 +01:00
54e3438e37 NOISSUE correctly set http status code in auth reply 2022-01-24 11:44:47 +01:00
ddfed7bb87 NOISSUE in java checker, ignore invalid lines altogether
Declaring them as errors is just causing problems because Java
randomly prints garbage to STDOUT now.
2022-01-24 11:44:47 +01:00
70c04745ee NOISSUE add some logging to profile fetching failures 2022-01-24 11:44:47 +01:00
63d4486855 Merge pull request #4447 from Stypox/patch-1
Fix error message
2022-01-24 10:32:14 +01:00
1d0e6bf453 Changed modrinth author data to not be a list 2022-01-24 07:23:01 +01:00
a2d88f6df4 Fixed spacing 2022-01-24 07:12:19 +01:00
019c77f9f7 Merge pull request #52 from oynqr/develop
Default to system locale language
2022-01-23 15:00:26 -05:00
5b5c5afc3a Merge pull request #88 from Scrumplex/launch-msa-login
Add open page & copy code button to MSA login dialog
2022-01-23 14:55:05 -05:00
af20b5ee0e support paste.polymc.org 2022-01-23 12:54:58 -05:00
a1b779da15 Merge pull request #95 from danielhuang/patch-1
Add StartupWMClass to desktop file
2022-01-23 12:05:39 -05:00
8b31c638f3 Fix error message
The code is trying to get a string from a json object, and if that fails it should log "is not a string", not "is not a timestamp".
2022-01-22 21:58:32 +01:00
3da69d8e53 Update org.polymc.PolyMC.desktop.in 2022-01-22 14:13:21 -05:00
dd76fb0ec7 feat(MSALogin): add open page & copy code button
Closes #55
2022-01-20 21:04:48 +01:00
caeab926bc PasteUpload: Trim whitespace from response body 2022-01-19 19:05:52 +00:00
35caa3c21a Merge pull request #87 from Scrumplex/themed-header-image
Header image's text color should follow GitHub theme
2022-01-19 13:06:45 -05:00
7022d3d401 fix(readme): header color should follow GH theme
As browser color scheme preference and GitHub theme can be different
from each other, let's follow GitHub theme instead of browser
preference.
2022-01-19 18:59:24 +01:00
6d22794cf9 Reduce spaghettiness 2022-01-19 09:47:09 +01:00
b50e584369 PasteUpload task changed to use 0x0.st's protocol
- Modified PasteUpload task to upload the log file to 0x0.st and other
  services with the same protocol.

- Modified Paste settings UI to allow the user to select a custom paste
  URL, simplified the settings page code.
2022-01-19 08:27:26 +00:00
affc2521aa Various fixes 2022-01-18 12:28:55 +01:00
63098b6f19 Merge pull request #4428 from MandipJoshi/patch-1
Update README.md copyright date changed
2022-01-17 10:00:40 +01:00
83e1dd285a Set default lang only if index received 2022-01-17 09:52:04 +01:00
b9beb3c7d2 Sort system locale to front of list 2022-01-17 09:52:04 +01:00
2dd2555a63 Update selected language automatically 2022-01-17 09:52:04 +01:00
126e6d13aa Use isEmpty instead of 0 length check 2022-01-17 09:52:04 +01:00
236c0166f6 Default to system locale language 2022-01-17 09:52:04 +01:00
9a33fb1f49 Update README.md 2022-01-17 12:09:36 +05:45
2c2c22ccf8 Merge pull request #82 from PolyMC/revert-offline-mode
Revert offline mode support (#81 and #50)
2022-01-17 03:56:27 +00:00
55597b458c Revert "Merge pull request #50 from bexnoss/offline-mode"
This reverts commit b4f750e7db40352111417ea89a9f375ae8c746ab, reversing
changes made to b19e3156154ba0dd232a3d165b1759c57e2858f2.
2022-01-17 03:45:47 +00:00
f55297eca9 Revert "Merge pull request #81 from bexnoss/fix-msa-account-refresh"
This reverts commit 0bc8baf1172d6967cdb2993826e3469ecd9aab66, reversing
changes made to 81fe41a038ee12ff2ee0200525b39e4ad650bec2.
2022-01-17 03:45:33 +00:00
0bc8baf117 Merge pull request #81 from bexnoss/fix-msa-account-refresh 2022-01-16 17:32:13 -05:00
5f9270ed4b Fix MSA account refresh 2022-01-16 23:30:17 +01:00
81fe41a038 Default to colored icons, update copyright
Closes: #74
2022-01-16 12:03:30 -05:00
0316cf88aa Merge pull request #78 from bexnoss/readme-svg-header 2022-01-16 10:33:35 -05:00
917f8a31e3 NOISSUE log server response when failing to fetch profile 2022-01-16 12:51:42 +01:00
aa770b63fb NOISSUE correctly set http status code in auth reply 2022-01-16 12:46:20 +01:00
c1bf31cb27 NOISSUE in java checker, ignore invalid lines altogether
Declaring them as errors is just causing problems because Java
randomly prints garbage to STDOUT now.
2022-01-16 12:05:40 +01:00
86d99f80c3 NOISSUE add some logging to profile fetching failures 2022-01-16 11:43:19 +01:00
975f77756d Added curseforge selection 2022-01-16 11:20:21 +01:00
8172dcd2d5 Replace PNG README header with SVG
Instead of GitHub specific MarkDown based theming this uses CSS in SVG.
2022-01-16 07:55:10 +01:00
b95c27ceef fix readme formatting 2022-01-15 21:26:00 -05:00
f78bb90ed9 GH-4125 fix it better 2022-01-15 16:25:52 -05:00
dc129fd886 GH-4125 workaround for java printing garbage to stdout on bedrock linux 2022-01-15 16:25:52 -05:00
621e0ba4a8 Added smart file selection
This might fail in a few special cases
2022-01-15 10:25:24 +01:00
f6de472da2 Added a no version message 2022-01-15 09:06:48 +01:00
4b37c46889 Filtering per mod loader & mc version 2022-01-15 08:51:47 +01:00
c371558883 Merge pull request #68 from GriffintheFolf/execname
Fix program executable name for shell script
2022-01-14 21:46:46 -05:00
0bbd0ac0b9 Change method of shell script fix per suggestion
The Launcher.in file is now modified rather than CMakeLists.txt
2022-01-14 19:28:10 -07:00
ac93c64cd4 Fix program executable name for shell script 2022-01-14 16:59:16 -07:00
6cd4375aff add arch linux package to readme
closes: #53
2022-01-14 18:39:25 -05:00
a606b47a22 pastebin URL app setting 2022-01-14 18:30:02 -05:00
a62155c1c9 preliminary stuff for paste.ee removal 2022-01-14 18:20:06 -05:00
b4f750e7db Merge pull request #50 from bexnoss/offline-mode
Offline Mode Support
2022-01-14 18:03:35 -05:00
b19e315615 Set maximum memory allocated to 4GB by default 2022-01-14 17:34:50 -05:00
41dba376a8 remove 5 from display name
Closes: #58
2022-01-14 17:33:34 -05:00
2896f70cd8 Removing copyrights 2022-01-14 22:07:54 +01:00
1a8c972aef Fixed icons
Also having a mod loader is now enforced
2022-01-14 20:22:15 +01:00
cdaa397dcf Reword offline mode disclaimer 2022-01-14 14:19:31 +01:00
9e6fa8f29a Added the downloading of the mods 2022-01-14 12:47:18 +01:00
4d599eb118 Added modrinth icon 2022-01-14 10:51:44 +01:00
4e9039be2d Start of mod downloading 2022-01-14 09:56:27 +01:00
395e265564 Add offline mode disclaimer 2022-01-14 00:01:05 +01:00
b07853c9ef Merge pull request #61 from meguminloli/develop 2022-01-13 13:55:29 -05:00
b635a7e693 update NIX.md 2022-01-13 15:43:29 +02:00
f84fc783b6 removed redundant recs
removed file
2022-01-13 15:29:10 +02:00
2301a934b0 Merge pull request #59 from A-UNDERSCORE-D/patch-1 2022-01-13 08:19:08 -05:00
60e9d2754a changed flake.nix
removed result
2022-01-13 13:14:50 +02:00
A_D
d06c2cacb1 Readd original MultiMC/Launcher copyright
The original MMC code remains Apache.
2022-01-13 09:59:16 +02:00
49c2bd477c Merge pull request #45 from cidkidnix/develop 2022-01-12 21:11:09 -05:00
46a3b4de6e Remove unnecessary semicolon 2022-01-12 18:41:33 +01:00
6ecc8c5496 Remove unnecessary license header 2022-01-12 14:57:32 +01:00
a1ff3b1ee3 Add offline mode support 2022-01-12 14:26:02 +01:00
d4b522b6cb Add offline mode UI 2022-01-12 10:36:26 +01:00
3b524e99cc Merge pull request #46 from muscaln/java 2022-01-11 14:44:21 -05:00
3329d94c9b Introduce POLYMC_JAVA_PATHS env 2022-01-11 18:24:37 +03:00
a12118f1a0 Sort java versions from current to oldest 2022-01-11 17:40:58 +03:00
5fe33a98a2 nix: remove patch due to breakage 2022-01-10 18:24:49 -06:00
1d8196e11a More rebranding
Closes: #39

Mostly done with rebranding now. We just need to translate some services
to PolyMC.
2022-01-10 12:47:35 -05:00
c7f6f94930 Merge pull request #42 from Eonfge/patch-1 2022-01-10 12:02:12 -05:00
131615811b Set PrefersNonDefaultGPU for hybrid devices
With the Property 'PrefersNonDefaultGPU', you can signal to dekstop environments like GNOME that you want to run the application using the more powerful secondary graphics card, if such a card is available. Specification: https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html

With this change, you won't have to include a special prime-run script.
2022-01-10 14:55:18 +01:00
3fa6e22430 Merge pull request #40 from Jan200101/PR/rpm-1.0.5 2022-01-09 17:57:18 -05:00
c86ac772c8 Update RPM and build instruction 2022-01-09 21:51:56 +01:00
1cc7a193c2 add logo to different styles
Also fixed genicons to automate this.
2022-01-09 14:18:51 -05:00
e50d07f791 remove patreon stuff
Closes: #22

Update to 1.0.5

Remove "Forking/Redistribution" tab in About (why is it even there?)

Metainfo now corresponds to version

add discord

Completely removed Patreon.
2022-01-09 13:51:46 -05:00
b515cb478e fix empty exec line when binary_name is unset 2022-01-09 13:34:01 -05:00
29e9d65cb2 rpm readme update 2022-01-09 13:32:12 -05:00
42574f185e Merge pull request #38 from cidkidnix/develop
Nix: Package fixup
2022-01-09 13:28:32 -05:00
92872e957b nix: package fixup 2022-01-09 12:00:37 -06:00
20747dd50a Merge pull request #37 from Jan200101/PR/rpm
rework rpm spec
2022-01-09 13:00:14 -05:00
a83cb2f2b8 rework rpm spec 2022-01-09 18:50:00 +01:00
541f26b33a Merge pull request #29 from cidkidnix/develop 2022-01-09 10:58:51 -05:00
459aafbca4 Merge pull request #34 from muscaln/develop 2022-01-09 10:56:47 -05:00
9bd86f84de nix: make sure tarball is pointed to proper repo
Co-authored-by: Louis Bettens <lourkeur@users.noreply.github.com>
2022-01-09 08:37:47 -06:00
0ce1b68261 Don't import channel as root, import channel as user
Co-authored-by: Louis Bettens <lourkeur@users.noreply.github.com>
2022-01-09 08:35:52 -06:00
fe9ce7a329 Make instuctions more clear 2022-01-09 08:17:52 -06:00
8ccef671d5 Update instructions 2022-01-09 08:16:15 -06:00
957cd29dbf nix: add support for non-flake builds 2022-01-09 17:08:19 +03:00
72656d41df Merge branch 'develop' into develop 2022-01-09 04:16:15 -06:00
15f62e54ab Make readme reflect new flake changes 2022-01-09 04:12:55 -06:00
5a09dcae68 forgot linebreak 2022-01-09 00:19:21 -05:00
87af5f631d Update branding: New Logo (#30)
New logo
Co-authored-by: swirl <swurl@swurl.xyz>
2022-01-09 00:13:15 -05:00
27eca06947 rpm in readme 2022-01-08 23:55:59 -05:00
c63b5bb132 Merge pull request #32 from getchoo/add-rpm-packaging
add rpm build script and spec file
2022-01-08 23:52:05 -05:00
3b09ee97be Merge pull request #33 from getchoo/remove-wsl-detection
stop cmake from blocking builds on wsl
2022-01-08 23:51:10 -05:00
59ef13f032 add documentation for building a .rpm 2022-01-08 23:13:10 -05:00
390a90b361 stop cmake from blocking builds on wsl 2022-01-08 22:49:30 -05:00
2ca094bd57 add rpm build script and spec file 2022-01-08 22:44:18 -05:00
42eb011e3f Merge pull request #31 from muscaln/flake 2022-01-08 19:59:10 -05:00
4a9d9b268a nix: fix 'nix run' 2022-01-09 02:40:13 +03:00
ae3c613f6c nix: use user package set on overlay and switch to ninja 2022-01-09 01:36:28 +03:00
ccde63bbab add nix result path to .gitignore 2022-01-09 01:36:28 +03:00
9499acedab nix: fix overlay 2022-01-09 00:40:55 +03:00
2a760a8e32 Revert "nix: revert overlay changes and add conditionals to derivation for flake build" 2022-01-08 23:09:53 +03:00
6065b4dcf9 nix: revert overlay changes and add conditionals to derivation for flake build 2022-01-08 23:06:56 +03:00
9611b92b07 nix: fix build 2022-01-08 22:33:06 +03:00
d29d020d6f {nix,flake}: add submodules 2022-01-08 22:33:06 +03:00
8d4f8795de nix: update package and remove meta section since we are not on nixpkgs 2022-01-08 22:33:06 +03:00
b1fa551fd2 flake: updates 2022-01-08 22:33:06 +03:00
8d184958d8 nix: init flake 2022-01-08 22:32:49 +03:00
1e51827ba3 add LICENSE file explicitly
Closes: #24
2022-01-08 10:32:30 -05:00
2776453dfe Make README.md look better for nix 2022-01-08 09:31:50 -06:00
e544637333 Add to README.md 2022-01-08 09:30:51 -06:00
e665d52044 add missing char 2022-01-08 09:28:37 -06:00
0ec2170b5e Add documentation for nix package 2022-01-08 09:27:47 -06:00
83fcebe2a9 Merge pull request #25 from cidkidnix/develop 2022-01-08 10:17:39 -05:00
0399fa7d2a Fix wrong path in overlay 2022-01-08 09:15:24 -06:00
8d000d29fa Fix desktop file and move directories around 2022-01-08 09:12:44 -06:00
52420963cf GH-4125 fix it better 2022-01-08 12:26:16 +01:00
addf5f4e52 NOISSUE update README for clarity 2022-01-08 11:45:10 +01:00
03d7300732 GH-4125 workaround for java printing garbage to stdout on bedrock linux 2022-01-08 11:14:07 +01:00
d68980810a make sure we use our desktop file 2022-01-08 01:50:23 -06:00
2a88099094 fix build 2022-01-08 01:45:52 -06:00
069d4dd2d1 Opps forgot something 2022-01-08 01:42:24 -06:00
e8f56d399b Fix desktop file 2022-01-08 01:41:31 -06:00
73c0a0d43b Make nix support not rely on flakes 2022-01-08 01:34:32 -06:00
fc81b81c26 Add nixos support 2022-01-08 01:33:26 -06:00
2c7d248703 New pixel Ouroboros logo by @karolinaabb 2022-01-06 22:42:33 -05:00
2e43d6cffa match license in metainfo
Closes: #18
2022-01-06 22:37:37 -05:00
915c658a52 Merge pull request #17 from dada513/develop
Fix metainfo parsing
2022-01-04 16:44:23 -05:00
3dcc7dee6c cleaner difference between flatpak and normal manifest 2022-01-04 15:43:41 +01:00
07649b6388 Fix metainfo parsing 2022-01-04 07:31:10 +01:00
0e4ccaca02 fix icon and version
Closes: #16

Fixed the icon so Qt renders it properly, and actually renders it
properly in the About page. Also, scaled it up a bit

Changed launcher.svg icon to temporary Ouroboros logo

fixed genicons again

Fix version to 1.0.3 (making tag rn)

Install the PolyMC icon properly.
2022-01-03 17:46:05 -05:00
b3d8ecb467 fix genicons.sh to new rDNS stuff 2022-01-03 15:54:08 -05:00
97d4b947d0 update README
grammar/punctuation
2022-01-03 15:42:44 -05:00
3613ffa80e rDNS for icons and desktop file, and metainfo
Closes: #12, #13
2022-01-03 15:42:09 -05:00
38a1772f86 Merge pull request #14 from dada513/flathub
Change flatpak to flathub
2022-01-03 15:35:13 -05:00
4382344a7c Merge pull request #15 from dada513/debian_update 2022-01-03 07:55:17 -05:00
c7283adb9f change up deb packaging 2022-01-03 12:13:16 +01:00
672646384f remove icon 2022-01-03 12:08:54 +01:00
52e156908e Change flatpak to flathub 2022-01-03 11:59:23 +01:00
a97d0a36f4 NOISSUE Copy Image is not shown if the selection is > 1 2021-12-03 16:29:28 +01:00
e9c52ec696 NOISSUE Added Copy File(s) feature for the screenshot page
- Ctrl+C now copies the file instead of the image data
- Renamed Copy to Copy Image
2021-12-03 16:08:11 +01:00
75f2dab3c8 NOISSUE Implemented copy screenshots to the clipboard
- Added context-menu entry
- Ctrl+C keybind works as well
- If multiple screenshots are selected, only the first one gets copied
2021-12-03 03:11:53 +01:00
205 changed files with 6200 additions and 4347 deletions

69
.github/ISSUE_TEMPLATE/rfc.yml vendored Normal file
View File

@ -0,0 +1,69 @@
# Template based on https://gitlab.archlinux.org/archlinux/rfcs/-/blob/0ba3b61e987e197f8d1901709409b8564958f78a/rfcs/0000-template.rst
name: Request for Comment (RFC)
description: Propose a larger change and start a discussion.
labels: [RFC]
body:
- type: markdown
attributes:
value: |
### Use this form to suggest a larger change for PolyMC.
- type: textarea
attributes:
label: Goal
description: Short description, 1-2 sentences.
placeholder: Remove the cat from the launcher.
validations:
required: true
- type: textarea
attributes:
label: Motivation
description: |
Introduce the topic. If this is a not-well-known section of PolyMC, a detailed explanation of the background is recommended.
Some example points of discussion:
- What specific problems are you facing right now that you're trying to address?
- Are there any previous discussions? Link to them and summarize them (don't
- force your readers to read them though!).
- Is there any precedent set by other software? If so, link to resources.
placeholder: I don't like cats. I think many users also don't like cats.
validations:
required: true
- type: textarea
attributes:
label: Specification
description: A concrete, thorough explanation of what is being planned.
placeholder: Remove the cat button and all references to the cat from the codebase. Including resource files.
validations:
required: true
- type: textarea
attributes:
label: Drawbacks
description: Carefully consider every possible objection and issue with your proposal. This section should be updated as feedback comes in from discussion.
placeholder: Some users might like cats.
validations:
required: true
- type: textarea
attributes:
label: Unresolved Questions
description: |
Are there any portions of your proposal which need to be discussed with the community before the RFC can proceed?
Be careful here -- an RFC with a lot of remaining questions is likely to be stalled.
If your RFC is mostly unresolved questions and not too much substance, it may not be ready.
placeholder: Do a lot of users care about the cat?
validations:
required: true
- type: textarea
attributes:
label: Alternatives Considered
description: A list of alternatives, that have been considered and offer equal or similar features to the proposed change.
placeholder: Maybe the cat could be replaced with an axolotl?
validations:
required: true
- type: checkboxes
attributes:
label: This suggestion is unique
options:
- label: I have searched the issue tracker and did not find an issue describing my suggestion, especially not one that has been rejected.
required: true
- type: textarea
attributes:
label: You may use the editor below to elaborate further.

41
.github/scripts/prepare_JREs.sh vendored Executable file
View File

@ -0,0 +1,41 @@
#!/usr/bin/env bash
URL_JDK8="https://api.adoptium.net/v3/binary/latest/8/ga/linux/x64/jre/hotspot/normal/eclipse"
URL_JDK17="https://api.adoptium.net/v3/binary/latest/17/ga/linux/x64/jre/hotspot/normal/eclipse"
mkdir -p JREs
pushd JREs
wget --content-disposition "$URL_JDK8"
wget --content-disposition "$URL_JDK17"
for file in *;
do
mkdir temp
re='(OpenJDK([[:digit:]]+)U-jre_x64_linux_hotspot_([[:digit:]]+)(.*).tar.gz)'
if [[ $file =~ $re ]];
then
version_major=${BASH_REMATCH[2]}
version_trailing=${BASH_REMATCH[4]}
if [ $version_major = 17 ];
then
hyphen='-'
else
hyphen=''
fi
version_edit=$(echo $version_trailing | sed -e 's/_/+/g' | sed -e 's/b/-b/g')
dir_name=jdk$hyphen$version_major$version_edit-jre
mkdir jre$version_major
tar -xzf $file -C temp
pushd temp/$dir_name
cp -r . ../../jre$version_major
popd
fi
rm -rf temp
done
popd

222
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,222 @@
name: Build
on:
workflow_call:
inputs:
build_type:
description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
type: string
default: Debug
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
qt_version: 5.12.8
qt_host: linux
- os: ubuntu-20.04
qt_version: 5.15.2
qt_host: linux
app_image: true
- os: windows-2022
qt_version: 5.15.2
qt_host: windows
qt_arch: win32_mingw81
- os: macos-11
qt_version: 5.12.12
qt_host: mac
macosx_deployment_target: 10.12
runs-on: ${{ matrix.os }}
env:
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}
INSTALL_DIR: "install"
BUILD_DIR: "build"
steps:
- name: Install 32bit mingw on Windows
if: runner.os == 'Windows'
uses: egor-tensin/setup-mingw@v2
with:
platform: x86
- name: Install 32bit zlib via Strawberry on Windows
if: runner.os == 'Windows'
run: |
choco install strawberryperl -y --force --x86
- name: Checkout
uses: actions/checkout@v2
with:
submodules: 'true'
# We need to do this here because it inexplicably fails if we split the step
- name: Download and install OpenSSL libs on Windows
if: runner.os == 'Windows'
run: |
python -m pip install --upgrade pip
python -m pip install aqtinstall==2.0.5
python -m aqt install-tool -O "${{ github.workspace }}\Qt\" windows desktop tools_openssl_x86
mkdir ${{ env.INSTALL_DIR }}
copy "${{ github.workspace }}\Qt\Tools\OpenSSL\Win_x86\bin\libssl-1_1.dll" "${{ github.workspace }}\${{ env.INSTALL_DIR }}\"
copy "${{ github.workspace }}\Qt\Tools\OpenSSL\Win_x86\bin\libcrypto-1_1.dll" "${{ github.workspace }}\${{ env.INSTALL_DIR }}\"
- name: Set short version
shell: bash
run: |
ver_short=`git rev-parse --short HEAD`
echo "VERSION=$ver_short" >> $GITHUB_ENV
- name: Install OpenJDK
uses: AdoptOpenJDK/install-jdk@v1
with:
version: '17'
- name: Cache Qt
id: cache-qt
uses: actions/cache@v2
with:
path: "${{ github.workspace }}/Qt/"
key: ${{ runner.os }}-${{ matrix.qt_version }}-${{ matrix.qt_arch }}-qt_cache
- name: Install Qt
if: runner.os != 'Linux' || matrix.app_image == true
uses: jurplel/install-qt-action@v2
with:
version: ${{ matrix.qt_version }}
host: ${{ matrix.qt_host }}
arch: ${{ matrix.qt_arch }}
cached: ${{ steps.cache-qt.outputs.cache-hit }}
dir: "${{ github.workspace }}/Qt/"
- name: Install System Qt on Linux
if: runner.os == 'Linux' && matrix.app_image != true
run: |
sudo apt-get -y update
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
- name: Install Ninja
uses: urkle/action-get-ninja@v1
- name: Download linuxdeploy family for AppImage on Linux
if: matrix.app_image == true
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"
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage"
- name: Download JREs for AppImage on Linux
if: matrix.app_image == true
shell: bash
run: |
${{ github.workspace }}/.github/scripts/prepare_JREs.sh
- name: Configure CMake
if: runner.os != 'Linux'
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -G Ninja
- name: Configure CMake on Linux
if: runner.os == 'Linux'
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DLauncher_PORTABLE=OFF -G Ninja
- name: Build
run: |
cmake --build ${{ env.BUILD_DIR }}
- name: Install
if: runner.os != 'Linux'
run: |
cmake --install ${{ env.BUILD_DIR }}
- name: Install on Linux
if: runner.os == 'Linux'
run: |
DESTDIR=${{ env.INSTALL_DIR }} cmake --install ${{ env.BUILD_DIR }}
- name: Bundle AppImage
if: matrix.app_image == true
shell: bash
run: |
export OUTPUT="PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
chmod +x linuxdeploy-*.AppImage
mkdir -p ${{ env.INSTALL_DIR }}/usr/lib/jvm/java-{8,17}-openjdk
cp -r ${{ github.workspace }}/JREs/jre8/* ${{ env.INSTALL_DIR }}/usr/lib/jvm/java-8-openjdk
cp -r ${{ github.workspace }}/JREs/jre17/* ${{ env.INSTALL_DIR }}/usr/lib/jvm/java-17-openjdk
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_DIR }}/usr/lib"
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64/server"
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64"
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_DIR }}/usr/lib/jvm/java-17-openjdk/lib/server"
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_DIR }}/usr/lib/jvm/java-17-openjdk/lib"
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_DIR }}/usr/share/icons/hicolor/scalable/apps/org.polymc.PolyMC.svg
- name: Run windeployqt
if: runner.os == 'Windows'
run: |
windeployqt --no-translations --no-system-d3d-compiler --no-opengl-sw "${{ env.INSTALL_DIR }}/polymc.exe"
- name: Run macdeployqt
if: runner.os == 'macOS'
run: |
cd ${{ env.INSTALL_DIR }}
macdeployqt "PolyMC.app" -executable="PolyMC.app/Contents/MacOS/polymc" -always-overwrite
- name: chmod binary on macOS
if: runner.os == 'macOS'
run: |
chmod +x "${{ github.workspace }}/${{ env.INSTALL_DIR }}/PolyMC.app/Contents/MacOS/polymc"
- name: tar bundle on macOS
if: runner.os == 'macOS'
run: |
cd ${{ env.INSTALL_DIR }}
tar -czf ../PolyMC.tar.gz *
- name: tar on Linux
if: runner.os == 'Linux' && matrix.app_image != true
run: |
cd ${{ env.INSTALL_DIR }}
tar -czf ../PolyMC.tar.gz *
- name: Upload Linux tar.gz
if: runner.os == 'Linux' && matrix.app_image != true
uses: actions/upload-artifact@v2
with:
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: PolyMC.tar.gz
- name: Upload AppImage for Linux
if: matrix.app_image == true
uses: actions/upload-artifact@v2
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: Upload package for Windows
if: runner.os == 'Windows'
uses: actions/upload-artifact@v2
with:
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: ${{ env.INSTALL_DIR }}/**
- name: Upload package for macOS
if: runner.os == 'macOS'
uses: actions/upload-artifact@v2
with:
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: PolyMC.tar.gz

32
.github/workflows/trigger_builds.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: Build Application
on:
push:
branches-ignore:
- 'stable'
paths-ignore:
- '**.md'
- '**/LICENSE'
- 'flake.lock'
- '**.nix'
pull_request:
paths-ignore:
- '**.md'
- '**/LICENSE'
- 'flake.lock'
- '**.nix'
workflow_dispatch:
jobs:
build_debug:
name: Build Debug
uses: ./.github/workflows/build.yml
with:
build_type: Debug
build_release:
name: Build Release
uses: ./.github/workflows/build.yml
with:
build_type: Release

99
.github/workflows/trigger_release.yml vendored Normal file
View File

@ -0,0 +1,99 @@
name: Build Application and Make Release
on:
push:
tags:
- '*'
jobs:
build_release:
name: Build Release
uses: ./.github/workflows/build.yml
with:
build_type: Release
create_release:
needs: build_release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Grab and store version
run: |
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
echo "VERSION=$tag_name" >> $GITHUB_ENV
- name: Create release
id: create_release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
name: PolyMC ${{ env.VERSION }}
draft: true
prerelease: false
upload_release:
needs: create_release
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v2
- name: Grab and store version
run: |
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
echo "VERSION=$tag_name" >> $GITHUB_ENV
- name: Package artifacts properly
run: |
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-Windows* PolyMC-Windows-${{ env.VERSION }}
mv PolyMC-macOS*/PolyMC.tar.gz PolyMC-macOS-${{ env.VERSION }}.tar.gz
cd PolyMC-Windows-${{ env.VERSION }}
zip -r -9 ../PolyMC-Windows-${{ env.VERSION }}.zip *
cd ..
- name: Upload Linux asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_name: PolyMC-Linux-${{ env.VERSION }}.tar.gz
asset_path: PolyMC-Linux-${{ env.VERSION }}.tar.gz
asset_content_type: application/gzip
- name: Upload Linux AppImage asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_name: PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
asset_path: PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
asset_content_type: application/x-executable
- name: Upload Windows asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_name: PolyMC-Windows-${{ env.VERSION }}.zip
asset_path: PolyMC-Windows-${{ env.VERSION }}.zip
asset_content_type: application/zip
- name: Upload macOS asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create_release.outputs.upload_url }}
asset_name: PolyMC-macOS-${{ env.VERSION }}.tar.gz
asset_path: PolyMC-macOS-${{ env.VERSION }}.tar.gz
asset_content_type: application/gzip

12
.gitignore vendored
View File

@ -40,13 +40,5 @@ run/
.cache/
# Flatpak builds
.flatpak-builder
flatbuild
builddir
# Deb
packages/debian/polymc/usr/bin
packages/debian/polymc/usr/lib
packages/debian/polymc/usr/share/polymc/jars
packages/debian/polymc.deb
packages/debian/polymc/DEBIAN/control
# Nix/NixOS
result/

6
.gitmodules vendored
View File

@ -2,7 +2,7 @@
path = libraries/libnbtplusplus
url = https://github.com/MultiMC/libnbtplusplus.git
pushurl = git@github.com:MultiMC/libnbtplusplus.git
[submodule "libraries/quazip"]
path = libraries/quazip
url = https://github.com/PolyMC/quazip.git
pushurl = git@github.com:PolyMC/quazip.git
path = libraries/quazip
url = https://github.com/stachenov/quazip.git

233
BUILD.md
View File

@ -1,232 +1,5 @@
Build Instructions
==================
# Build Instructions
# Contents
Build instructions are available on [the website](https://polymc.org/wiki/development/build-instructions/).
* [Note](#note)
* [Getting the source](#source)
* [Linux](#linux)
* [Windows](#windows)
* [macOS](#macos)
# Getting the source
Clone the source code using git and grab all the submodules:
```
git clone https://github.com/PolyMC/PolyMC.git
git submodule init
git submodule update
```
# Linux
Getting the project to build and run on Linux is easy if you use any modern and up-to-date linux distribution.
## Build dependencies
* A C++ compiler capable of building C++11 code.
* Qt Development tools 5.6 or newer (`qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5` on Debian-based system)
* cmake 3.1 or newer (`cmake` on Debian-based system)
* zlib (`zlib1g-dev` on Debian-based system)
* Java JDK (`openjdk-17-jdk`on Debian-based system)
* GL headers (`libgl1-mesa-dev` on Debian-based system)
### Building a .deb
You need to install the build dependencies first
```
git clone https://github.com/PolyMC/PolyMC.git
git submodule init && git submodule update
cd packages/debian
./makedeb.sh
```
If everything works correctly, the .deb will be next to the build script, in `PolyMC/packages/debian`
### Building from command line
You need a source folder, a build folder and an install folder.
```
# make all the folders
mkdir ~/PolyMC && cd ~/PolyMC
mkdir build
mkdir install
# clone the complete source
git clone --recursive https://github.com/PolyMC/PolyMC.git src
# configure the project
cd build
cmake -DCMAKE_INSTALL_PREFIX=../install ../src
make -j$(nproc) install
```
You can use IDEs like KDevelop or QtCreator to open the CMake project if you want to work on the code.
### Building & Installing to the System
This is the preferred method for installation, and is suitable for packages.
```
git clone --recursive https://github.com/PolyMC/PolyMC.git && cd PolyMC
# configure everything
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="/usr" \ # Use "/usr" for packages, otherwise, leave it at the default "/usr/local".
-DLauncher_LAYOUT=lin-system
make -j$(nproc) install # Optionally specify DESTDIR for packages (i.e. DESTDIR=${pkgdir})
```
### Installing Qt using the installer (optional)
1. Run the Qt installer.
2. Choose a place to install Qt.
3. Choose the components you want to install.
- You need Qt 5.6.x 64-bit ticked.
- You need Tools/Qt Creator ticked.
- Other components are selected by default, you can untick them if you don't need them.
4. Accept the license agreements.
5. Double check the install details and then click "Install".
- Installation can take a very long time, go grab a cup of tea or something and let it work.
### Loading the project in Qt Creator (optional)
1. Open Qt Creator.
2. Choose `File->Open File or Project`.
3. Navigate to the Launcher source folder you cloned and choose CMakeLists.txt.
4. Read the instructions that just popped up about a build location and choose one.
5. You should see "Run CMake" in the window.
- Make sure that Generator is set to "Unix Generator (Desktop Qt 5.6.x GCC 64bit)".
- Hit the "Run CMake" button.
- You'll see warnings and it might not be clear that it succeeded until you scroll to the bottom of the window.
- Hit "Finish" if CMake ran successfully.
6. Cross your fingers and press the Run button (bottom left of Qt Creator).
- If the project builds successfully it will run and the Launcher window will pop up.
**If this doesn't work for you, let us know on our Discord.**
# Windows
Getting the project to build and run on Windows is easy if you use Qt's IDE, Qt Creator. The project will simply not compile using Microsoft build tools, because that's not something we do. If it does compile, it is by chance only.
## Dependencies
* [Qt 5.6+ Development tools](http://qt-project.org/downloads) -- Qt Online Installer for Windows
- http://download.qt.io/new_archive/qt/5.6/5.6.0/qt-opensource-windows-x86-mingw492-5.6.0.exe
- Download the MinGW version (MSVC version does not work).
* [OpenSSL](https://github.com/IndySockets/OpenSSL-Binaries/tree/master/Archive/) -- Win32 OpenSSL, version 1.0.2g (from 2016)
- https://github.com/IndySockets/OpenSSL-Binaries/raw/master/Archive/openssl-1.0.2g-i386-win32.zip
- the usual OpenSSL for Windows (http://slproweb.com/products/Win32OpenSSL.html) only provides the newest version of OpenSSL, and we need the 1.0.2g version
- **Download the 32-bit version, not 64-bit.**
- Microsoft Visual C++ 2008 Redist is required for this, there's a link on the OpenSSL download page above next to the main download.
- We use a custom build of OpenSSL that doesn't have this dependency. For normal development, the custom build is not necessary though.
* [zlib 1.2+](http://gnuwin32.sourceforge.net/packages/zlib.htm) - the Setup is fine
* [Java JDK 8](https://adoptium.net/releases.html?variant=openjdk8) - Use the MSI installer.
* [CMake](http://www.cmake.org/cmake/resources/software.html) -- Windows (Win32 Installer)
Ensure that OpenSSL, zlib, Java and CMake are on `PATH`.
## Getting set up
### Installing Qt
1. Run the Qt installer
2. Choose a place to install Qt (C:\Qt is the default),
3. Choose the components you want to install
- You need Qt 5.6 (32 bit) ticked,
- You need Tools/Qt Creator ticked,
- Other components are selected by default, you can untick them if you don't need them.
4. Accept the license agreements,
5. Double check the install details and then click "Install"
- Installation can take a very long time, go grab a cup of tea or something and let it work.
### Installing OpenSSL
1. Download .zip file from the link above.
2. Unzip and add the directory to PATH, so CMake can find it.
### Installing CMake
1. Run the CMake installer,
2. It's easiest if you choose to add CMake to the PATH for all users,
- If you don't choose to do this, remember where you installed CMake.
### Loading the project
1. Open Qt Creator,
2. Choose File->Open File or Project,
3. Navigate to the Launcher source folder you cloned and choose CMakeLists.txt,
4. Read the instructions that just popped up about a build location and choose one,
5. If you chose not to add CMake to the system PATH, tell Qt Creator where you installed it,
- Otherwise you can skip this step.
6. You should see "Run CMake" in the window,
- Make sure that Generator is set to "MinGW Generator (Desktop Qt 5.6.x MinGW 32bit)",
- Hit the "Run CMake" button,
- You'll see warnings and it might not be clear that it succeeded until you scroll to the bottom of the window.
- Hit "Finish" if CMake ran successfully.
7. Cross your fingers and press the Run button (bottom left of Qt Creator)!
- If the project builds successfully it will run and the Launcher window will pop up,
- Test OpenSSL by making an instance and trying to log in. If Qt Creator couldn't find OpenSSL during the CMake stage, login will fail and you'll get an error.
The following .dlls are needed for the app to run (copy them to build directory if you want to be able to move the build to another pc):
```
platforms/qwindows.dll
libeay32.dll
libgcc_s_dw2-1.dll
libssp-0.dll
libstdc++-6.dll
libwinpthread-1.dll
Qt5Core.dll
Qt5Gui.dll
Qt5Network.dll
Qt5Svg.dll
Qt5Widgets.dll
Qt5Xml.dll
ssleay32.dll
zlib1.dll
```
**These build instructions worked for me (Drayshak) on a fresh Windows 8 x64 Professional install. If they don't work for you, let us know on our Discord.**
### Compile from command line on Windows
1. If you installed Qt with the web installer, there should be a shortcut called `Qt 5.4 for Desktop (MinGW 4.9 32-bit)` in the Start menu on Windows 7 and 10. Best way to find it is to search for it. Do note you cannot just use cmd.exe, you have to use the shortcut, otherwise the proper MinGW software will not be on the PATH.
2. Once that is open, change into your user directory, and clone PolyMC by doing `git clone --recursive https://github.com/PolyMC/PolyMC.git`, and change directory to the folder you cloned to.
3. Make a build directory, and change directory to the directory and do `cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=C:\Path\that\makes\sense\for\you`. By default, it will install to C:\Program Files (x86), which you might not want, if you want a local installation. If you want to install it to that directory, make sure to run the command window as administrator.
3. Do `mingw32-make -jX`, where X is the number of cores your CPU has plus one.
4. Now to wait for it to compile. This could take some time. Hopefully it compiles properly.
5. Run the command `mingw32-make install`, and it should install PolyMC, to whatever the `-DCMAKE_INSTALL_PREFIX` was.
6. In most cases, whenever compiling, the OpenSSL dll's aren't put into the directory to where PolyMC installs, meaning you cannot log in. The best way to fix this is just to do `copy C:\OpenSSL-Win32\*.dll C:\Where\you\installed\PolyMC\to`. This should copy the required OpenSSL dll's to log in.
# macOS
### Install prerequisites:
- Install XCode Command Line tools
- Install the official build of CMake (https://cmake.org/download/)
- Install JDK 8 (https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html)
- Get Qt 5.6 and install it (https://download.qt.io/new_archive/qt/5.6/5.6.3/)
### XCode Command Line tools
If you don't have XCode CommandLine tools installed, you can install them by using this command in the Terminal App
```bash
xcode-select --install
```
### Build
Pick an installation path - this is where the final `.app` will be constructed when you run `make install`. Supply it as the `CMAKE_INSTALL_PREFIX` argument during CMake configuration.
```
git clone --recursive https://github.com/PolyMC/PolyMC.git
cd Launcher
mkdir build
cd build
cmake \
-DCMAKE_C_COMPILER=/usr/bin/clang \
-DCMAKE_CXX_COMPILER=/usr/bin/clang++ \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX:PATH="$(dirname $PWD)/dist/" \
-DCMAKE_PREFIX_PATH="/path/to/Qt5.6/" \
-DQt5_DIR="/path/to/Qt5.6/" \
-DLauncher_LAYOUT=mac-bundle \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 \
..
make install
```
**Note:** The final app bundle may not run due to code signing issues, which
need to be fixed with `codesign -fs -`.
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

@ -13,14 +13,6 @@ 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()
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_HOST_SYSTEM_VERSION MATCHES ".*[Mm]icrosoft.*" OR
CMAKE_HOST_SYSTEM_VERSION MATCHES ".*WSL.*"
)
message(FATAL_ERROR "Building the Launcher is not supported in Linux-on-Windows distributions.")
endif()
endif()
##################################### Set CMake options #####################################
set(CMAKE_AUTOMOC ON)
@ -54,12 +46,14 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
##################################### Set Application options #####################################
######## Set URLs ########
set(Launcher_NEWS_RSS_URL "https://multimc.org/rss.xml" CACHE STRING "URL to fetch Launcher's news RSS feed from.")
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/%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 0)
set(Launcher_VERSION_MINOR 6)
set(Launcher_VERSION_HOTFIX 14)
set(Launcher_VERSION_MAJOR 1)
set(Launcher_VERSION_MINOR 1)
set(Launcher_VERSION_HOTFIX 0)
# Build number
set(Launcher_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
@ -74,26 +68,37 @@ set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.")
set(Launcher_NOTIFICATION_URL "" CACHE STRING "URL for checking for notifications.")
# The metadata server
set(Launcher_META_URL "https://meta.multimc.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
# paste.ee API key
set(Launcher_PASTE_EE_API_KEY "utLvciUouSURFzfjPxLBf5W4ISsUX4pwBDF7N1AfZ" CACHE STRING "API key you can get from paste.ee when you register an account")
set(Launcher_META_URL "https://meta.polymc.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 "17b47edd-c884-4997-926d-9e7f9a6b4647" CACHE STRING "Client ID you can get from Microsoft Identity Platform when you register an application")
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")
# Bug tracker URL
set(Launcher_BUG_TRACKER_URL "https://github.com/PolyMC/PolyMC/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.")
# Matrix Space
set(Launcher_MATRIX_URL "https://matrix.to/#/#polymc:polymc.org" CACHE STRING "URL to the Matrix Space")
# Discord URL
set(Launcher_DISCORD_URL "" CACHE STRING "URL for the Discord guild.")
set(Launcher_DISCORD_URL "https://discord.gg/Z52pwxWCHP" CACHE STRING "URL for the Discord guild.")
# Subreddit URL
set(Launcher_SUBREDDIT_URL "" CACHE STRING "URL for the subreddit.")
# Builds
# TODO: Launcher_FORCE_BUNDLED_LIBS should be off in the future, but as of QuaZip 1.2, we can't do that yet.
set(Launcher_FORCE_BUNDLED_LIBS ON 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")
#### Check the current Git commit and branch
include(GetGitRevisionDescription)
get_git_head_revision(Launcher_GIT_REFSPEC Launcher_GIT_COMMIT)
@ -102,6 +107,8 @@ message(STATUS "Git commit: ${Launcher_GIT_COMMIT}")
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}")
@ -110,12 +117,20 @@ add_custom_target(tcversion echo "\\#\\#teamcity[setParameter name=\\'env.LAUNCH
################################ 3rd Party Libs ################################
# Find the required Qt parts
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Concurrent REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5Test REQUIRED)
find_package(Qt5Xml REQUIRED)
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 REQUIRED)
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()
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)
@ -130,31 +145,18 @@ if (Qt5_POSITION_INDEPENDENT_CODE)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
####################################### Secrets #######################################
####################################### Program Info #######################################
set(Launcher_APP_BINARY_NAME "polymc" CACHE STRING "Name of the Launcher binary")
add_subdirectory(program_info)
####################################### Install layout #######################################
# How to install the build results
set(Launcher_LAYOUT "auto" CACHE STRING "The layout for the launcher installation (auto, win-bundle, lin-nodeps, lin-system, mac-bundle)")
set_property(CACHE Launcher_LAYOUT PROPERTY STRINGS auto win-bundle lin-nodeps lin-system mac-bundle)
# Install the build results according to platform
set(Launcher_PORTABLE 1 CACHE BOOL "The type of installation (Portable or System)")
if(Launcher_LAYOUT STREQUAL "auto")
if(UNIX AND APPLE)
set(Launcher_LAYOUT_REAL "mac-bundle")
elseif(UNIX)
set(Launcher_LAYOUT_REAL "lin-nodeps")
elseif(WIN32)
set(Launcher_LAYOUT_REAL "win-bundle")
else()
message(FATAL_ERROR "Cannot choose a sensible install layout for your platform.")
endif()
else()
set(Launcher_LAYOUT_REAL ${Launcher_LAYOUT})
endif()
if(Launcher_LAYOUT_REAL STREQUAL "mac-bundle")
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")
@ -169,7 +171,7 @@ if(Launcher_LAYOUT_REAL STREQUAL "mac-bundle")
# Mac bundle settings
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}")
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: Minecraft launcher and management utility.")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.multimc.${Launcher_Name}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.polymc.${Launcher_Name}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}.${Launcher_VERSION_BUILD}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}.${Launcher_VERSION_BUILD}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}.${Launcher_VERSION_BUILD}")
@ -185,13 +187,32 @@ if(Launcher_LAYOUT_REAL STREQUAL "mac-bundle")
# Add the icon
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
elseif(Launcher_LAYOUT_REAL STREQUAL "lin-nodeps")
elseif(UNIX)
set(BINARY_DEST_DIR "bin")
set(LIBRARY_DEST_DIR "bin")
set(PLUGIN_DEST_DIR "plugins")
set(BUNDLE_DEST_DIR ".")
set(RESOURCES_DEST_DIR ".")
set(JARS_DEST_DIR "bin/jars")
if(Launcher_PORTABLE)
set(LIBRARY_DEST_DIR "bin")
set(BUNDLE_DEST_DIR ".")
set(JARS_DEST_DIR "bin/jars")
# launcher/Application.cpp will use this value
set(Launcher_APP_BINARY_DEFS "-DLAUNCHER_PORTABLE")
# Install basic runner script
configure_file(launcher/Launcher.in "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" @ONLY)
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" DESTINATION ${BUNDLE_DEST_DIR} RENAME ${Launcher_Name})
else()
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
set(JARS_DEST_DIR "share/jars")
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")
set(Launcher_APP_BINARY_DEFS "-DMULTIMC_JARS_LOCATION=${CMAKE_INSTALL_PREFIX}/${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})
endif()
# install as bundle with no dependencies included
set(INSTALL_BUNDLE "nodeps")
@ -199,30 +220,7 @@ elseif(Launcher_LAYOUT_REAL STREQUAL "lin-nodeps")
# Set RPATH
SET(Launcher_BINARY_RPATH "$ORIGIN/")
# Install basic runner script
configure_file(launcher/Launcher.in "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" @ONLY)
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" DESTINATION ${BUNDLE_DEST_DIR} RENAME ${Launcher_Name})
elseif(Launcher_LAYOUT_REAL STREQUAL "lin-system")
set(Launcher_APP_BINARY_NAME "polymc" CACHE STRING "Name of the Launcher binary")
set(Launcher_BINARY_DEST_DIR "bin" CACHE STRING "Path to the binary directory")
set(Launcher_LIBRARY_DEST_DIR "lib${LIB_SUFFIX}" CACHE STRING "Path to the library directory")
set(Launcher_SHARE_DEST_DIR "share/polymc" CACHE STRING "Path to the shared data directory")
set(JARS_DEST_DIR "${Launcher_SHARE_DEST_DIR}/jars")
set(Launcher_DESKTOP_DEST_DIR "share/applications" CACHE STRING "Path to the desktop file directory")
set(BINARY_DEST_DIR ${Launcher_BINARY_DEST_DIR})
set(LIBRARY_DEST_DIR ${Launcher_LIBRARY_DEST_DIR})
MESSAGE(STATUS "Compiling for linux system with ${Launcher_SHARE_DEST_DIR} and LAUNCHER_LINUX_DATADIR")
SET(Launcher_APP_BINARY_DEFS "-DMULTIMC_JARS_LOCATION=${CMAKE_INSTALL_PREFIX}/${JARS_DEST_DIR}" "-DLAUNCHER_LINUX_DATADIR")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${Launcher_DESKTOP_DEST_DIR})
# install as bundle with no dependencies included
set(INSTALL_BUNDLE "nodeps")
elseif(Launcher_LAYOUT_REAL STREQUAL "win-bundle")
elseif(WIN32)
set(BINARY_DEST_DIR ".")
set(LIBRARY_DEST_DIR ".")
set(PLUGIN_DEST_DIR ".")
@ -239,7 +237,7 @@ elseif(Launcher_LAYOUT_REAL STREQUAL "win-bundle")
# install as bundle
set(INSTALL_BUNDLE "full")
else()
message(FATAL_ERROR "No sensible install layout set.")
message(FATAL_ERROR "Platform not supported")
endif()
################################ Included Libs ################################
@ -247,11 +245,9 @@ endif()
include(ExternalProject)
set_directory_properties(PROPERTIES EP_BASE External)
option(NBT_BUILD_SHARED "Build NBT shared library" ON)
option(NBT_BUILD_SHARED "Build NBT shared library" OFF)
option(NBT_USE_ZLIB "Build NBT library with zlib support" OFF)
option(NBT_BUILD_TESTS "Build NBT library tests" OFF) #FIXME: fix unit tests.
set(NBT_NAME Launcher_nbt++)
set(NBT_DEST_DIR ${LIBRARY_DEST_DIR})
add_subdirectory(libraries/libnbtplusplus)
add_subdirectory(libraries/systeminfo) # system information library
@ -259,7 +255,12 @@ 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
add_subdirectory(libraries/quazip) # zip manipulation library
if (FORCE_BUNDLED_QUAZIP)
message(STATUS "Using bundled QuaZip")
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
set(QUAZIP_INSTALL 0)
add_subdirectory(libraries/quazip) # zip manipulation library
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

136
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,136 @@
# Contributor Covenant Code of Conduct
This is a modified version of the Contributor Covenant.
See commit history to see our changes.
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling (antagonistic, inflammatory, insincere behaviour), insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
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
address subject to change).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@ -1,7 +1,7 @@
# PolyMC
Copyright (C) 2012-2021 MultiMC Contributors
Copyright (C) 2021 PolyMC Contributors
Copyright (C) 2021-2022 PolyMC 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
@ -16,6 +16,20 @@
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
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 runtime (Windows)
Copyright (c) 2012 MinGW.org project

674
LICENSE Normal file
View File

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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, either version 3 of the License, or
(at your option) any later version.
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/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@ -1,62 +1,74 @@
<p align="center">
<img src="https://avatars.githubusercontent.com/u/96310119" alt="PolyMC logo"/>
<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"/>
</p>
PolyMC 5
=========
<br>
PolyMC is a custom launcher for Minecraft that focuses on predictability, long term stability and simplicity.
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. Read "[Why was this fork made?](https://github.com/PolyMC/PolyMC/wiki/FAQ)" on the wiki for more details.
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>
## Packages
Several source build packages are available, along with experimental pre-built generic packages.
# Installation
- An [AUR package](https://aur.archlinux.org/packages/polymc-git/) is available.
- A Gentoo ebuild is available in the [swirl](https://git.swurl.xyz/swirl/ebuilds) overlay, named `games-action/polymc`. Check the README for instructions on how to add the overlay.
- A Flatpak is available. Instructions on building it can be found in [packages/flatpak/BUILDING.md](packages/flatpak/BUILDING.md).
- Generic, prebuilt packages (archived by version) can be found [here](https://packages.polymc.org/) ([latest](https://packages.polymc.org/latest))
- Last build status: https://jenkins.polymc.org/job/PolyMC/lastBuild/
- [Linux (AMD64) System](https://packages.polymc.org/latest/lin64-system/lin64-system.tar.zst) ([SHA256](https://packages.polymc.org/latest/lin64-system/lin64-system.tar.zst.sha256)) - this is a generic system package intended to be used as a base for making distro-specific packages.
- [Windows (32-bit)](https://packages.polymc.org/latest/win32/win32.zip) ([SHA256](https://packages.polymc.org/latest/win32/win32.zip.sha256)) - this is a portable package, you can extract it anywhere and run it. This package needs testing.
- [Debian (AMD64)](https://packages.polymc.org/latest/deb/polymc-amd64.deb) ([SHA256](https://packages.polymc.org/latest/deb/polymc-amd64.deb.sha256)) - this is intended to be installed with `dpkg -i`. Alternatively, you may build the `.deb` yourself, by going to `packages/debian` and running `./makedeb.sh`.
- [AppImage (AMD64)](https://packages.polymc.org/latest/appimage/PolyMC-latest-x86_64.AppImage) ([SHA256](https://packages.polymc.org/latest/appimage/PolyMC-latest-x86_64.AppImage.sha256)) - `chmod +x` must be run on this file before usage. This should work on any distribution
- MacOS currently does not have any packages. We are still working on setting up MacOS packaging.
- All downloads and instructions for PolyMC can be found [here](https://polymc.org/download/)
- Last build status: https://github.com/PolyMC/PolyMC/actions
## Development
If you want to contribute to PolyMC you might find it useful to join [#development:polymc.org on Matrix](https://matrix.to/#/#development:polymc.org) or join [our Discord server](https://discord.gg/xq7fxrgtMP), which is bridged with the PolyMC Matrix rooms. Thank you!
### Building
If you want to build PolyMC yourself, check [BUILD.md](BUILD.md) for build instructions.
## Development Builds
### Code formatting
Just follow the existing formatting.
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.
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.
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)
## Translations
TODO
# Help & Support
## 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.
## Help & Support
Feel free to create an issue if you need help. However, you might find it easier to ask in the Discord server.
[![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. Be sure to enable spaces first (Settings -> Labs -> Spaces), and then you may join the space:
For people who don't want to use Discord, we have a Matrix Space which is bridged to the Discord server:
[![PolyMC Space](https://img.shields.io/matrix/polymc:polymc.org?label=PolyMC%20Space&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#polymc:polymc.org)
Matrix's support for spaces is still in development, so if you have issues accessing rooms via the space, then you can join the rooms directly:
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:
[![Support](https://img.shields.io/matrix/support:polymc.org?label=%23support&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#support:polymc.org)
[![Discussion](https://img.shields.io/matrix/discussion:polymc.org?label=%23discussion&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#discussion:polymc.org)
[![Development](https://img.shields.io/matrix/development:polymc.org?label=%23development&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#development:polymc.org)
[![News](https://img.shields.io/matrix/news:polymc.org?label=%23news&server_fqdn=matrix.polymc.org)](https://matrix.to/#/#news:polymc.org)
# 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.md](BUILD.md) 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 infomation
To modify download infomation or change packaging infomation 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.

View File

@ -12,6 +12,7 @@ Config::Config()
LAUNCHER_DOMAIN = "@Launcher_Domain@";
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
LAUNCHER_GIT = "@Launcher_Git@";
LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
USER_AGENT = "@Launcher_UserAgent@";
USER_AGENT_UNCACHED = USER_AGENT + " (Uncached)";
@ -29,25 +30,34 @@ Config::Config()
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
if(GIT_REFSPEC.startsWith("refs/heads/") && !UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty() && VERSION_BUILD >= 0)
if(GIT_REFSPEC.startsWith("refs/heads/"))
{
VERSION_CHANNEL = GIT_REFSPEC;
VERSION_CHANNEL.remove("refs/heads/");
UPDATER_ENABLED = true;
if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty() && VERSION_BUILD >= 0) {
UPDATER_ENABLED = true;
}
}
else if (!GIT_COMMIT.isEmpty())
{
VERSION_CHANNEL = GIT_COMMIT.mid(0, 8);
}
else
{
VERSION_CHANNEL = QObject::tr("custom");
VERSION_CHANNEL = QObject::tr("unknown");
}
VERSION_STR = "@Launcher_VERSION_STRING@";
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
PASTE_EE_KEY = "@Launcher_PASTE_EE_API_KEY@";
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@";
META_URL = "@Launcher_META_URL@";
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@";
MATRIX_URL = "@Launcher_MATRIX_URL@";
DISCORD_URL = "@Launcher_DISCORD_URL@";
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
}

View File

@ -14,6 +14,7 @@ public:
QString LAUNCHER_DOMAIN;
QString LAUNCHER_CONFIGFILE;
QString LAUNCHER_GIT;
QString LAUNCHER_DESKTOPFILENAME;
/// The major version number.
int VERSION_MAJOR;
@ -68,9 +69,14 @@ public:
QString NEWS_RSS_URL;
/**
* API key you can get from paste.ee when you register an account
* URL that gets opened when the user clicks "More News"
*/
QString PASTE_EE_KEY;
QString NEWS_OPEN_URL;
/**
* URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help
*/
QString HELP_URL;
/**
* Client ID you can get from Imgur when you register an application
@ -88,6 +94,8 @@ public:
QString META_URL;
QString BUG_TRACKER_URL;
QString TRANSLATIONS_URL;
QString MATRIX_URL;
QString DISCORD_URL;
QString SUBREDDIT_URL;
@ -95,8 +103,8 @@ public:
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.multimc.org/fmllibs/";
QString TRANSLATIONS_BASE_URL = "https://files.multimc.org/translations/";
QString FMLLIBS_BASE_URL = "https://files.polymc.org/fmllibs/";
QString TRANSLATIONS_BASE_URL = "https://i18n.polymc.org/";
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ BEGIN
BEGIN
BLOCK "000004b0"
BEGIN
VALUE "CompanyName", "MultiMC Contributors"
VALUE "CompanyName", "MultiMC & PolyMC Contributors"
VALUE "FileDescription", "Testcase"
VALUE "FileVersion", "1.0.0.0"
VALUE "ProductName", "Launcher Testcase"

1
default.nix Normal file
View File

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

94
flake.lock generated Normal file
View File

@ -0,0 +1,94 @@
{
"nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1641205782,
"narHash": "sha256-4jY7RCWUoZ9cKD8co0/4tFARpWB+57+r1bLLvXNJliY=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "b7547d3eed6f32d06102ead8991ec52ab0a4f1a7",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1642700792,
"narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "846b2ae0fc4cc943637d3d1def4454213e203cba",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"libnbtplusplus": {
"flake": false,
"locked": {
"lastModified": 1591558203,
"narHash": "sha256-QgvNvaoFflCXEPCCFBCeZvYTpuiwScBG7EosUgFwFNQ=",
"owner": "multimc",
"repo": "libnbtplusplus",
"rev": "dc72a20b7efd304d12af2025223fad07b4b78464",
"type": "github"
},
"original": {
"owner": "multimc",
"repo": "libnbtplusplus",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1643169865,
"narHash": "sha256-+KIpNRazbc8Gac9jdWCKQkFv9bjceaLaLhlwqUEYu8c=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "945ec499041db73043f745fad3b2a3a01e826081",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"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",
"flake-utils": "flake-utils",
"libnbtplusplus": "libnbtplusplus",
"nixpkgs": "nixpkgs",
"quazip": "quazip"
}
}
},
"root": "root",
"version": 7
}

50
flake.nix Normal file
View File

@ -0,0 +1,50 @@
{
description = "PolyMC flake";
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
inputs.libnbtplusplus = {
url = "github:multimc/libnbtplusplus";
flake = false;
};
inputs.quazip = {
url = "github:stachenov/quazip";
flake = false;
};
outputs = args@{ self, nixpkgs, flake-utils, libnbtplusplus, quazip, ... }:
let
systems = [
"aarch64-linux"
# "aarch64-darwin" # qtbase is currently broken
"i686-linux"
"x86_64-darwin"
"x86_64-linux"
];
in {
overlay = final: prev: {
inherit (self.packages.${final.system}) polymc;
};
} // flake-utils.lib.eachSystem systems (system:
let pkgs = import nixpkgs { inherit system; };
in {
packages = {
polymc = pkgs.libsForQt5.callPackage ./packages/nix/polymc {
inherit self;
submoduleQuazip = quazip;
submoduleNbt = libnbtplusplus;
};
};
apps = {
polymc = flake-utils.lib.mkApp {
name = "polymc";
drv = self.packages.${system}.polymc;
};
};
defaultPackage = self.packages.${system}.polymc;
defaultApp = self.apps.${system}.polymc;
});
}

View File

@ -14,7 +14,7 @@
#include "ui/pages/global/ProxyPage.h"
#include "ui/pages/global/ExternalToolsPage.h"
#include "ui/pages/global/AccountListPage.h"
#include "ui/pages/global/PasteEEPage.h"
#include "ui/pages/global/APIPage.h"
#include "ui/pages/global/CustomCommandsPage.h"
#include "ui/themes/ITheme.h"
@ -187,30 +187,11 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
setApplicationName(BuildConfig.LAUNCHER_NAME);
setApplicationDisplayName(BuildConfig.LAUNCHER_DISPLAYNAME);
setApplicationVersion(BuildConfig.printableVersionString());
#if (QT_VERSION >= QT_VERSION_CHECK(5,7,0))
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
#endif
startTime = QDateTime::currentDateTime();
#ifdef Q_OS_LINUX
{
QFile osrelease("/proc/sys/kernel/osrelease");
if (osrelease.open(QFile::ReadOnly | QFile::Text)) {
QTextStream in(&osrelease);
auto contents = in.readAll();
if(
contents.contains("WSL", Qt::CaseInsensitive) ||
contents.contains("Microsoft", Qt::CaseInsensitive)
) {
showFatalErrorMessage(
"Unsupported system detected!",
"Linux-on-Windows distributions are not supported.\n\n"
"Please use the Windows binary when playing on Windows."
);
return;
}
}
}
#endif
// Don't quit on hiding the last window
this->setQuitOnLastWindowClosed(false);
@ -283,12 +264,21 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
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();
// error if --launch is missing with --server or --profile
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
{
std::cerr << "--server and --profile can only be used in combination with --launch!" << std::endl;
m_status = Application::Failed;
return;
}
QString origcwdPath = QDir::currentPath();
QString binPath = applicationDirPath();
QString adjustedBy;
@ -304,16 +294,20 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
}
else
{
#ifdef LAUNCHER_LINUX_DATADIR
QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
if (xdgDataHome.isEmpty())
xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
dataPath = xdgDataHome + "/polymc";
adjustedBy += "XDG standard " + dataPath;
#elif defined(Q_OS_MAC)
QDir foo(FS::PathCombine(applicationDirPath(), "../../Data"));
#if !defined(LAUNCHER_PORTABLE) || defined(Q_OS_MAC)
QDir foo(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), ".."));
dataPath = foo.absolutePath();
adjustedBy += "Fallback to special Mac location " + dataPath;
adjustedBy += dataPath;
#ifdef Q_OS_LINUX
// TODO: this should be removed in a future version
// TODO: provide a migration path similar to macOS migration
QDir bar(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "polymc"));
if (bar.exists()) {
dataPath = bar.absolutePath();
adjustedBy += "Legacy data path " + dataPath;
}
#endif
#else
dataPath = applicationDirPath();
adjustedBy += "Fallback to binary path " + dataPath;
@ -357,20 +351,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
return;
}
if(m_instanceIdToLaunch.isEmpty() && !m_serverToJoin.isEmpty())
{
std::cerr << "--server can only be used in combination with --launch!" << std::endl;
m_status = Application::Failed;
return;
}
if(m_instanceIdToLaunch.isEmpty() && !m_profileToUse.isEmpty())
{
std::cerr << "--account can only be used in combination with --launch!" << std::endl;
m_status = Application::Failed;
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());
@ -435,7 +415,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
#endif
/*
* Establish the mechanism for communication with an already running MultiMC that uses the same data path.
* 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.
* We want to initialize this before logging to avoid messing with the log of a potential already running copy.
*/
@ -566,26 +546,23 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
qDebug() << "<> Paths set.";
}
do // once
if(m_liveCheck)
{
if(m_liveCheck)
QFile check(liveCheckFile);
if(check.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
QFile check(liveCheckFile);
if(!check.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
qWarning() << "Could not open" << liveCheckFile << "for writing!";
break;
}
auto payload = appID.toString().toUtf8();
if(check.write(payload) != payload.size())
if(check.write(payload) == payload.size())
{
check.close();
} else {
qWarning() << "Could not write into" << liveCheckFile << "!";
check.remove();
break;
check.remove(); // also closes file!
}
check.close();
} else {
qWarning() << "Could not open" << liveCheckFile << "for writing!";
}
} while(false);
}
// Initialize application settings
{
@ -595,7 +572,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("AutoUpdate", true);
// Theming
m_settings->registerSetting("IconTheme", QString("multimc"));
m_settings->registerSetting("IconTheme", QString("pe_colored"));
m_settings->registerSetting("ApplicationTheme", QString("system"));
// Notifications
@ -662,7 +639,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
// Memory
m_settings->registerSetting({"MinMemAlloc", "MinMemoryAlloc"}, 512);
m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 1024);
m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 4096);
m_settings->registerSetting("PermGen", 128);
// Java Settings
@ -714,8 +691,13 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("UpdateDialogGeometry", "");
// paste.ee API key
m_settings->registerSetting("PasteEEAPIKey", "multimc");
// pastebin URL
m_settings->registerSetting("PastebinURL", "https://0x0.st");
m_settings->registerSetting("CloseAfterLaunch", false);
// Custom MSA credentials
m_settings->registerSetting("MSAClientIDOverride", "");
// Init page provider
{
@ -728,7 +710,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_globalSettingsProvider->addPage<ProxyPage>();
m_globalSettingsProvider->addPage<ExternalToolsPage>();
m_globalSettingsProvider->addPage<AccountListPage>();
m_globalSettingsProvider->addPage<PasteEEPage>();
m_globalSettingsProvider->addPage<APIPage>();
}
qDebug() << "<> Settings loaded.";
}
@ -1148,7 +1130,7 @@ void Application::setIconTheme(const QString& name)
QIcon Application::getThemedIcon(const QString& name)
{
if(name == "logo") {
return QIcon(":/polymc.svg");
return QIcon(":/org.polymc.PolyMC.svg");
}
return XdgIcon::fromTheme(name);
}
@ -1514,3 +1496,13 @@ QString Application::getJarsPath()
}
return m_jarsPath;
}
QString Application::getMSAClientID()
{
QString clientIDOverride = m_settings->get("MSAClientIDOverride").toString();
if (!clientIDOverride.isEmpty()) {
return clientIDOverride;
}
return BuildConfig.MSA_CLIENT_ID;
}

View File

@ -117,6 +117,8 @@ public:
QString getJarsPath();
QString getMSAClientID();
/// this is the root of the 'installation'. Used for automatic updates
const QString &root() {
return m_rootPath;

View File

@ -39,6 +39,7 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
m_settings->registerSetting("lastLaunchTime", 0);
m_settings->registerSetting("totalTimePlayed", 0);
m_settings->registerSetting("lastTimePlayed", 0);
m_settings->registerSetting("InstanceType", "OneSix");
// Custom Commands
auto commandSetting = m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false);

View File

@ -37,6 +37,10 @@ set(CORE_SOURCES
InstanceImportTask.h
InstanceImportTask.cpp
# Mod downloading task
ModDownloadTask.h
ModDownloadTask.cpp
# Use tracking separate from memory management
Usable.h
@ -221,7 +225,11 @@ set(MINECRAFT_SOURCES
minecraft/auth/flows/Mojang.h
minecraft/auth/flows/MSA.cpp
minecraft/auth/flows/MSA.h
minecraft/auth/flows/Offline.cpp
minecraft/auth/flows/Offline.h
minecraft/auth/steps/OfflineStep.cpp
minecraft/auth/steps/OfflineStep.h
minecraft/auth/steps/EntitlementsStep.cpp
minecraft/auth/steps/EntitlementsStep.h
minecraft/auth/steps/GetSkinStep.cpp
@ -278,13 +286,6 @@ set(MINECRAFT_SOURCES
minecraft/launch/VerifyJavaInstall.cpp
minecraft/launch/VerifyJavaInstall.h
minecraft/legacy/LegacyModList.h
minecraft/legacy/LegacyModList.cpp
minecraft/legacy/LegacyInstance.h
minecraft/legacy/LegacyInstance.cpp
minecraft/legacy/LegacyUpgradeTask.h
minecraft/legacy/LegacyUpgradeTask.cpp
minecraft/GradleSpecifier.h
minecraft/MinecraftInstance.cpp
minecraft/MinecraftInstance.h
@ -506,12 +507,19 @@ set(FLAME_SOURCES
# Flame
modplatform/flame/FlamePackIndex.cpp
modplatform/flame/FlamePackIndex.h
modplatform/flame/FlameModIndex.cpp
modplatform/flame/FlameModIndex.h
modplatform/flame/PackManifest.h
modplatform/flame/PackManifest.cpp
modplatform/flame/FileResolvingTask.h
modplatform/flame/FileResolvingTask.cpp
)
set(MODRINTH_SOURCES
modplatform/modrinth/ModrinthPackIndex.cpp
modplatform/modrinth/ModrinthPackIndex.h
)
set(MODPACKSCH_SOURCES
modplatform/modpacksch/FTBPackInstallTask.h
modplatform/modpacksch/FTBPackInstallTask.cpp
@ -566,6 +574,7 @@ set(LOGIC_SOURCES
${ICONS_SOURCES}
${FTB_SOURCES}
${FLAME_SOURCES}
${MODRINTH_SOURCES}
${MODPACKSCH_SOURCES}
${TECHNIC_SOURCES}
${ATLAUNCHER_SOURCES}
@ -685,8 +694,6 @@ SET(LAUNCHER_SOURCES
ui/pages/instance/OtherLogsPage.h
ui/pages/instance/ServersPage.cpp
ui/pages/instance/ServersPage.h
ui/pages/instance/LegacyUpgradePage.cpp
ui/pages/instance/LegacyUpgradePage.h
ui/pages/instance/WorldListPage.cpp
ui/pages/instance/WorldListPage.h
@ -707,8 +714,8 @@ SET(LAUNCHER_SOURCES
ui/pages/global/LauncherPage.h
ui/pages/global/ProxyPage.cpp
ui/pages/global/ProxyPage.h
ui/pages/global/PasteEEPage.cpp
ui/pages/global/PasteEEPage.h
ui/pages/global/APIPage.cpp
ui/pages/global/APIPage.h
# GUI - platform pages
ui/pages/modplatform/VanillaPage.cpp
@ -739,6 +746,10 @@ SET(LAUNCHER_SOURCES
ui/pages/modplatform/flame/FlameModel.h
ui/pages/modplatform/flame/FlamePage.cpp
ui/pages/modplatform/flame/FlamePage.h
ui/pages/modplatform/flame/FlameModModel.cpp
ui/pages/modplatform/flame/FlameModModel.h
ui/pages/modplatform/flame/FlameModPage.cpp
ui/pages/modplatform/flame/FlameModPage.h
ui/pages/modplatform/technic/TechnicModel.cpp
ui/pages/modplatform/technic/TechnicModel.h
@ -748,6 +759,11 @@ 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
# GUI - dialogs
ui/dialogs/AboutDialog.cpp
ui/dialogs/AboutDialog.h
@ -769,6 +785,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/LoginDialog.h
ui/dialogs/MSALoginDialog.cpp
ui/dialogs/MSALoginDialog.h
ui/dialogs/OfflineLoginDialog.cpp
ui/dialogs/OfflineLoginDialog.h
ui/dialogs/NewComponentDialog.cpp
ui/dialogs/NewComponentDialog.h
ui/dialogs/NewInstanceDialog.cpp
@ -785,6 +803,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/VersionSelectDialog.h
ui/dialogs/SkinUploadDialog.cpp
ui/dialogs/SkinUploadDialog.h
ui/dialogs/ModDownloadDialog.cpp
ui/dialogs/ModDownloadDialog.h
# GUI - widgets
@ -842,7 +862,7 @@ qt5_wrap_ui(LAUNCHER_UI
ui/pages/global/AccountListPage.ui
ui/pages/global/JavaPage.ui
ui/pages/global/LauncherPage.ui
ui/pages/global/PasteEEPage.ui
ui/pages/global/APIPage.ui
ui/pages/global/ProxyPage.ui
ui/pages/global/MinecraftPage.ui
ui/pages/global/ExternalToolsPage.ui
@ -855,16 +875,17 @@ qt5_wrap_ui(LAUNCHER_UI
ui/pages/instance/InstanceSettingsPage.ui
ui/pages/instance/VersionPage.ui
ui/pages/instance/WorldListPage.ui
ui/pages/instance/LegacyUpgradePage.ui
ui/pages/instance/ScreenshotsPage.ui
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
ui/pages/modplatform/atlauncher/AtlPage.ui
ui/pages/modplatform/VanillaPage.ui
ui/pages/modplatform/flame/FlamePage.ui
ui/pages/modplatform/flame/FlameModPage.ui
ui/pages/modplatform/legacy_ftb/Page.ui
ui/pages/modplatform/ImportPage.ui
ui/pages/modplatform/ftb/FtbPage.ui
ui/pages/modplatform/technic/TechnicPage.ui
ui/pages/modplatform/modrinth/ModrinthPage.ui
ui/widgets/InstanceCardWidget.ui
ui/widgets/CustomCommands.ui
ui/widgets/MCModInfoFrame.ui
@ -880,6 +901,7 @@ qt5_wrap_ui(LAUNCHER_UI
ui/dialogs/ExportInstanceDialog.ui
ui/dialogs/IconPickerDialog.ui
ui/dialogs/MSALoginDialog.ui
ui/dialogs/OfflineLoginDialog.ui
ui/dialogs/AboutDialog.ui
ui/dialogs/LoginDialog.ui
ui/dialogs/EditAccountDialog.ui
@ -908,9 +930,8 @@ endif()
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
target_link_libraries(Launcher_logic
systeminfo
Launcher_quazip
Launcher_classparser
${NBT_NAME}
nbt++
${ZLIB_LIBRARIES}
optional-bare
tomlc99
@ -926,9 +947,9 @@ target_link_libraries(Launcher_logic
)
target_link_libraries(Launcher_logic
Launcher_iconfix
${QUAZIP_LIBRARIES}
QuaZip::QuaZip
hoedown
Launcher_rainbow
PolyMC_rainbow
LocalPeer
)

View File

@ -42,7 +42,6 @@ void InstanceCopyTask::copyFinished()
}
// FIXME: shouldn't this be able to report errors?
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
instanceSettings->registerSetting("InstanceType", "Legacy");
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
inst->setName(m_instName);

View File

@ -17,8 +17,6 @@ void InstanceCreationTask::executeTask()
{
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
instanceSettings->suspendSave();
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath);
auto components = inst.getPackProfile();
components->buildingFromScratch();

View File

@ -29,7 +29,7 @@
#include "modplatform/flame/FileResolvingTask.h"
#include "modplatform/flame/PackManifest.h"
#include "Json.h"
#include <quazipdir.h>
#include <quazip/quazipdir.h>
#include "modplatform/technic/TechnicPackProcessor.h"
#include "icons/IconList.h"
@ -261,8 +261,6 @@ void InstanceImportTask::processFlame()
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
auto mcVersion = pack.minecraft.version;
// Hack to correct some 'special sauce'...
@ -422,7 +420,6 @@ void InstanceImportTask::processMultiMC()
{
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
instanceSettings->registerSetting("InstanceType", "Legacy");
NullInstance instance(m_globalSettings, instanceSettings, m_stagingPath);

View File

@ -32,7 +32,6 @@
#include "BaseInstance.h"
#include "InstanceTask.h"
#include "settings/INISettingsObject.h"
#include "minecraft/legacy/LegacyInstance.h"
#include "NullInstance.h"
#include "minecraft/MinecraftInstance.h"
#include "FileSystem.h"
@ -544,23 +543,8 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
auto instanceRoot = FS::PathCombine(m_instDir, id);
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(instanceRoot, "instance.cfg"));
InstancePtr inst;
instanceSettings->registerSetting("InstanceType", "Legacy");
QString inst_type = instanceSettings->get("InstanceType").toString();
if (inst_type == "OneSix" || inst_type == "Nostalgia")
{
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
}
else if (inst_type == "Legacy")
{
inst.reset(new LegacyInstance(m_globalSettings, instanceSettings, instanceRoot));
}
else
{
inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot));
}
// TODO: Handle incompatible instances
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
qDebug() << "Loaded instance " << inst->name() << " from " << inst->instanceRoot();
return inst;
}

View File

@ -1,6 +1,5 @@
#pragma once
#include "minecraft/MinecraftInstance.h"
#include "minecraft/legacy/LegacyInstance.h"
#include <FileSystem.h>
#include "ui/pages/BasePage.h"
#include "ui/pages/BasePageProvider.h"
@ -14,7 +13,6 @@
#include "ui/pages/instance/ScreenshotsPage.h"
#include "ui/pages/instance/InstanceSettingsPage.h"
#include "ui/pages/instance/OtherLogsPage.h"
#include "ui/pages/instance/LegacyUpgradePage.h"
#include "ui/pages/instance/WorldListPage.h"
#include "ui/pages/instance/ServersPage.h"
#include "ui/pages/instance/GameOptionsPage.h"
@ -34,31 +32,20 @@ public:
QList<BasePage *> values;
values.append(new LogPage(inst));
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
if(onesix)
{
values.append(new VersionPage(onesix.get()));
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Loader mods"), "Loader-mods");
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 NotesPage(onesix.get()));
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
values.append(new ServersPage(onesix));
// values.append(new GameOptionsPage(onesix.get()));
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
values.append(new InstanceSettingsPage(onesix.get()));
}
std::shared_ptr<LegacyInstance> legacy = std::dynamic_pointer_cast<LegacyInstance>(inst);
if(legacy)
{
values.append(new LegacyUpgradePage(legacy));
values.append(new NotesPage(legacy.get()));
values.append(new WorldListPage(legacy.get(), legacy->worldList()));
values.append(new ScreenshotsPage(FS::PathCombine(legacy->gameRoot(), "screenshots")));
}
values.append(new VersionPage(onesix.get()));
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
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 NotesPage(onesix.get()));
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
values.append(new ServersPage(onesix));
// values.append(new GameOptionsPage(onesix.get()));
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
values.append(new InstanceSettingsPage(onesix.get()));
auto logMatcher = inst->getLogFileMatcher();
if(logMatcher)
{
@ -74,3 +61,4 @@ public:
protected:
InstancePtr inst;
};

View File

@ -56,7 +56,7 @@ void LaunchController::decideAccount()
m_parentWidget,
tr("No Accounts"),
tr("In order to play Minecraft, you must have at least one Mojang or Minecraft "
"account logged in."
"account logged in. "
"Would you like to open the account manager to add an account now?"),
QMessageBox::Information,
QMessageBox::Yes | QMessageBox::No
@ -116,6 +116,12 @@ void LaunchController::login() {
m_session->wants_online = m_online;
m_accountToUse->fillSession(m_session);
// Launch immediately in true offline mode
if(m_accountToUse->isOffline()) {
launchInstance();
return;
}
switch(m_accountToUse->accountState()) {
case AccountState::Offline: {
m_session->wants_online = false;
@ -222,6 +228,18 @@ void LaunchController::login() {
emitFailed(errorString);
return;
}
case AccountState::Disabled: {
auto errorString = tr("The launcher's client identification has changed. Please remove this account and add it again.");
QMessageBox::warning(
m_parentWidget,
tr("Client identification changed"),
errorString,
QMessageBox::StandardButton::Ok,
QMessageBox::StandardButton::Ok
);
emitFailed(errorString);
return;
}
case AccountState::Gone: {
auto errorString = tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account you migrated this one to.");
QMessageBox::warning(

View File

@ -14,7 +14,7 @@ if [[ $EUID -eq 0 ]]; then
fi
LAUNCHER_NAME=@Launcher_Name@
LAUNCHER_NAME=@Launcher_APP_BINARY_NAME@
LAUNCHER_DIR="$(dirname "$(readlink -f "$0")")"
echo "Launcher Dir: ${LAUNCHER_DIR}"

View File

@ -13,17 +13,16 @@
* limitations under the License.
*/
#include <quazip.h>
#include <quazipdir.h>
#include <quazipfile.h>
#include <JlCompress.h>
#include <quazip/quazip.h>
#include <quazip/quazipdir.h>
#include <quazip/quazipfile.h>
#include "MMCZip.h"
#include "FileSystem.h"
#include <QDebug>
// ours
bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, const JlCompress::FilterFunction filter)
bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, const FilterFunction filter)
{
QuaZip modZip(from.filePath());
modZip.open(QuaZip::mdUnzip);
@ -74,6 +73,39 @@ bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &containe
return true;
}
bool MMCZip::compressDirFiles(QuaZip *zip, QString dir, QFileInfoList files)
{
QDir directory(dir);
if (!directory.exists()) return false;
for (auto e : files) {
auto filePath = directory.relativeFilePath(e.absoluteFilePath());
if( !JlCompress::compressFile(zip, e.absoluteFilePath(), filePath)) return false;
}
return true;
}
bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files)
{
QuaZip zip(fileCompressed);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
if(!zip.open(QuaZip::mdCreate)) {
QFile::remove(fileCompressed);
return false;
}
auto result = compressDirFiles(&zip, dir, files);
zip.close();
if(zip.getZipError()!=0) {
QFile::remove(fileCompressed);
return false;
}
return result;
}
// ours
bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods)
{
@ -122,13 +154,22 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
}
else if (mod.type() == Mod::MOD_FOLDER)
{
// untested, but seems to be unused / not possible to reach
// FIXME: buggy - does not work with addedFiles
auto filename = mod.filename();
QString what_to_zip = filename.absoluteFilePath();
QDir dir(what_to_zip);
dir.cdUp();
QString parent_dir = dir.absolutePath();
if (!JlCompress::compressSubDir(&zipOut, what_to_zip, parent_dir, addedFiles))
auto files = QFileInfoList();
MMCZip::collectFileListRecursively(what_to_zip, nullptr, &files, nullptr);
for (auto e : files) {
if (addedFiles.contains(e.filePath()))
files.removeAll(e);
}
if (!MMCZip::compressDirFiles(&zipOut, parent_dir, files))
{
zipOut.close();
QFile::remove(targetJarPath);
@ -136,7 +177,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
return false;
}
qDebug() << "Adding folder " << filename.fileName() << " from "
<< filename.absoluteFilePath();
<< filename.absoluteFilePath();
}
else
{
@ -310,3 +351,37 @@ bool MMCZip::extractFile(QString fileCompressed, QString file, QString target)
}
return MMCZip::extractRelFile(&zip, file, target);
}
bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList *files,
MMCZip::FilterFunction excludeFilter) {
QDir rootDirectory(rootDir);
if (!rootDirectory.exists()) return false;
QDir directory;
if (subDir == nullptr)
directory = rootDirectory;
else
directory = QDir(subDir);
if (!directory.exists()) return false; // shouldn't ever happen
// recurse directories
QFileInfoList entries = directory.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden);
for (const auto& e: entries) {
if (!collectFileListRecursively(rootDir, e.filePath(), files, excludeFilter))
return false;
}
// collect files
entries = directory.entryInfoList(QDir::Files);
for (const auto& e: entries) {
QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath());
if (excludeFilter && excludeFilter(relativeFilePath)) {
qDebug() << "Skipping file " << relativeFilePath;
continue;
}
files->append(e.filePath()); // we want the original paths for MMCZip::compressDirFiles
}
return true;
}

View File

@ -21,17 +21,36 @@
#include "minecraft/mod/Mod.h"
#include <functional>
#include <JlCompress.h>
#include <quazip/JlCompress.h>
#include <nonstd/optional>
namespace MMCZip
{
using FilterFunction = std::function<bool(const QString &)>;
/**
* Merge two zip files, using a filter function
*/
bool mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained,
const JlCompress::FilterFunction filter = nullptr);
const FilterFunction filter = nullptr);
/**
* Compress directory, by providing a list of files to compress
* \param zip target archive
* \param dir directory that will be compressed (to compress with relative paths)
* \param files list of files to compress
* \return true for success or false for failure
*/
bool compressDirFiles(QuaZip *zip, QString dir, QFileInfoList files);
/**
* Compress directory, by providing a list of files to compress
* \param fileCompressed target archive file
* \param dir directory that will be compressed (to compress with relative paths)
* \param files list of files to compress
* \return true for success or false for failure
*/
bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files);
/**
* take a source jar, add mods to it, resulting in target jar
@ -89,4 +108,13 @@ namespace MMCZip
*/
bool extractFile(QString fileCompressed, QString file, QString dir);
/**
* Populate a QFileInfoList with a directory tree recursively, while allowing to excludeFilter what shouldn't be included.
* \param rootDir directory to start off
* \param subDir subdirectory, should be nullptr for first invocation
* \param files resulting list of QFileInfo
* \param excludeFilter function to excludeFilter which files shouldn't be included (returning true means to excude)
* \return true for success or false for failure
*/
bool collectFileListRecursively(const QString &rootDir, const QString &subDir, QFileInfoList *files, FilterFunction excludeFilter);
}

View File

@ -0,0 +1,39 @@
#include "ModDownloadTask.h"
#include "Application.h"
ModDownloadTask::ModDownloadTask(const QUrl sourceUrl,const QString filename, const std::shared_ptr<ModFolderModel> mods)
: m_sourceUrl(sourceUrl), mods(mods), filename(filename) {
}
void ModDownloadTask::executeTask() {
setStatus(tr("Downloading mod:\n%1").arg(m_sourceUrl.toString()));
m_filesNetJob.reset(new NetJob(tr("Mod download"), APPLICATION->network()));
m_filesNetJob->addNetAction(Net::Download::makeFile(m_sourceUrl, mods->dir().absoluteFilePath(filename)));
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();
}
void ModDownloadTask::downloadSucceeded()
{
emitSucceeded();
m_filesNetJob.reset();
}
void ModDownloadTask::downloadFailed(QString reason)
{
emitFailed(reason);
m_filesNetJob.reset();
}
void ModDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
{
emit progress(current, total);
}
bool ModDownloadTask::abort() {
return m_filesNetJob->abort();
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "QObjectPtr.h"
#include "tasks/Task.h"
#include "minecraft/mod/ModFolderModel.h"
#include "net/NetJob.h"
#include <QUrl>
class ModDownloadTask : public Task {
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;
private:
QUrl m_sourceUrl;
NetJob::Ptr m_filesNetJob;
const std::shared_ptr<ModFolderModel> mods;
const QString filename;
void downloadProgressChanged(qint64 current, qint64 total);
void downloadFailed(QString reason);
void downloadSucceeded();
};

View File

@ -93,7 +93,7 @@ void UpdateController::installUpdates()
qDebug() << "Installing updates.";
#ifdef Q_OS_WIN
QString finishCmd = QApplication::applicationFilePath();
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined (Q_OS_OPENBSD)
QString finishCmd = FS::PathCombine(m_root, BuildConfig.LAUNCHER_NAME);
#elif defined Q_OS_MAC
QString finishCmd = QApplication::applicationFilePath();

View File

@ -103,11 +103,15 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
for(QString line : lines)
{
line = line.trimmed();
// NOTE: workaround for GH-4125, where garbage is getting printed into stdout on bedrock linux
if (line.contains("/bedrock/strata")) {
continue;
}
auto parts = line.split('=', QString::SkipEmptyParts);
if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty())
{
success = false;
continue;
}
else
{

View File

@ -120,8 +120,8 @@ void JavaInstallList::updateListData(QList<BaseVersionPtr> versions)
bool sortJavas(BaseVersionPtr left, BaseVersionPtr right)
{
auto rleft = std::dynamic_pointer_cast<JavaInstall>(left);
auto rright = std::dynamic_pointer_cast<JavaInstall>(right);
auto rleft = std::dynamic_pointer_cast<JavaInstall>(right);
auto rright = std::dynamic_pointer_cast<JavaInstall>(left);
return (*rleft) > (*rright);
}

View File

@ -77,14 +77,14 @@ QProcessEnvironment CleanEnviroment()
qDebug() << "Env: ignoring" << key << value;
continue;
}
// filter MultiMC-related things
// filter PolyMC-related things
if(key.startsWith("QT_"))
{
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 MultiMC
// Do not pass LD_* variables to java. They were intended for PolyMC
if(key.startsWith("LD_"))
{
qDebug() << "Env: ignoring" << key << value;
@ -149,6 +149,21 @@ JavaInstallPtr JavaUtils::GetDefaultJava()
return javaVersion;
}
QStringList addJavasFromEnv(QList<QString> javas)
{
QByteArray env = qgetenv("POLYMC_JAVA_PATHS");
#if defined(Q_OS_WIN32)
QList<QString> javaPaths = QString::fromLocal8Bit(env).split(QLatin1String(";"));
#else
QList<QString> javaPaths = QString::fromLocal8Bit(env).split(QLatin1String(":"));
#endif
for(QString i : javaPaths)
{
javas.append(i);
};
return javas;
}
#if defined(Q_OS_WIN32)
QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix)
{
@ -290,7 +305,7 @@ QList<QString> JavaUtils::FindJavaPaths()
KEY_WOW64_64KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath");
QList<JavaInstallPtr> ZULU32s = this->FindJavaFromRegistryKey(
KEY_WOW64_32KEY, "SOFTWARE\\Azul Systems\\Zulu", "InstallationPath");
// BellSoft Liberica
QList<JavaInstallPtr> LIBERICA64s = this->FindJavaFromRegistryKey(
KEY_WOW64_64KEY, "SOFTWARE\\BellSoft\\Liberica", "InstallationPath");
@ -328,7 +343,7 @@ QList<QString> JavaUtils::FindJavaPaths()
java_candidates.append(ADOPTIUMJDK32s);
java_candidates.append(ZULU32s);
java_candidates.append(LIBERICA32s);
java_candidates.append(MakeJavaPtr(this->GetDefaultJava()->path));
QList<QString> candidates;
@ -363,7 +378,7 @@ QList<QString> JavaUtils::FindJavaPaths()
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java");
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
}
return javas;
return addJavasFromEnv(javas);
}
#elif defined(Q_OS_LINUX)
@ -402,14 +417,14 @@ QList<QString> JavaUtils::FindJavaPaths()
scanJavaDir("/usr/lib/jvm");
scanJavaDir("/usr/lib64/jvm");
scanJavaDir("/usr/lib32/jvm");
// javas stored in MultiMC's folder
// javas stored in PolyMC's folder
scanJavaDir("java");
// manually installed JDKs in /opt
scanJavaDir("/opt/jdk");
scanJavaDir("/opt/jdks");
// flatpak
scanJavaDir("/app/jdk");
return javas;
return addJavasFromEnv(javas);
}
#else
QList<QString> JavaUtils::FindJavaPaths()
@ -419,6 +434,6 @@ QList<QString> JavaUtils::FindJavaPaths()
QList<QString> javas;
javas.append(this->GetDefaultJava()->path);
return javas;
return addJavasFromEnv(javas);
}
#endif

View File

@ -212,7 +212,7 @@ shared_qobject_ptr<LogModel> LaunchTask::getLogModel()
m_logModel->setMaxLines(m_instance->getConsoleMaxLines());
m_logModel->setStopOnOverflow(m_instance->shouldStopOnConsoleOverflow());
// FIXME: should this really be here?
m_logModel->setOverflowMessage(tr("MultiMC stopped watching the game log because the log length surpassed %1 lines.\n"
m_logModel->setOverflowMessage(tr("PolyMC stopped watching the game log because the log length surpassed %1 lines.\n"
"You may have to fix your mods because the game is still logging to files and"
" likely wasting harddrive space at an alarming rate!").arg(m_logModel->getMaxLines()));
}
@ -277,4 +277,3 @@ QString LaunchTask::substituteVariables(const QString &cmd) const
}
return out;
}

View File

@ -87,14 +87,14 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
// Error message displayed if java can't start
emit logLine(QString("Could not start java:"), MessageLevel::Error);
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
emit logLine("\nCheck your MultiMC Java settings.", MessageLevel::Launcher);
emit logLine("\nCheck your PolyMC Java settings.", MessageLevel::Launcher);
printSystemInfo(false, false);
emitFailed(QString("Could not start java!"));
return;
}
case JavaCheckResult::Validity::ReturnedInvalidData:
{
emit logLine(QString("Java checker returned some invalid data MultiMC doesn't understand:"), MessageLevel::Error);
emit logLine(QString("Java checker returned some invalid data PolyMC doesn't understand:"), MessageLevel::Error);
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
printSystemInfo(false, false);

View File

@ -156,7 +156,7 @@ public: /* methods */
QStringList & failedLocalFiles, const QString & overridePath) const;
private: /* methods */
/// the default storage prefix used by MultiMC
/// the default storage prefix used by PolyMC
static QString defaultStoragePrefix();
/// Get the prefix - root of the storage to be used
@ -177,23 +177,23 @@ protected: /* data */
/// DEPRECATED URL prefix of the maven repo where the file can be downloaded
QString m_repositoryURL;
/// DEPRECATED: MultiMC-specific absolute URL. takes precedence over the implicit maven repo URL, if defined
/// DEPRECATED: PolyMC-specific absolute URL. takes precedence over the implicit maven repo URL, if defined
QString m_absoluteURL;
/// MultiMC extension - filename override
/// PolyMC extension - filename override
QString m_filename;
/// DEPRECATED MultiMC extension - display name
/// DEPRECATED PolyMC extension - display name
QString m_displayname;
/**
* MultiMC-specific type hint - modifies how the library is treated
* PolyMC-specific type hint - modifies how the library is treated
*/
QString m_hint;
/**
* storage - by default the local libraries folder in multimc, but could be elsewhere
* MultiMC specific, because of FTB.
* storage - by default the local libraries folder in polymc, but could be elsewhere
* PolyMC specific, because of FTB.
*/
QString m_storagePrefix;
@ -215,3 +215,4 @@ protected: /* data */
/// MOJANG: container with Mojang style download info
MojangLibraryDownloadInfo::Ptr m_mojangDownloads;
};

View File

@ -124,18 +124,7 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO
m_settings->registerSetting("JoinServerOnLaunch", false);
m_settings->registerSetting("JoinServerOnLaunchAddress", "");
// DEPRECATED: Read what versions the user configuration thinks should be used
m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, "");
m_settings->registerSetting("LWJGLVersion", "");
m_settings->registerSetting("ForgeVersion", "");
m_settings->registerSetting("LiteloaderVersion", "");
m_components.reset(new PackProfile(this));
m_components->setOldConfigVersion("net.minecraft", m_settings->get("IntendedVersion").toString());
auto setting = m_settings->getSetting("LWJGLVersion");
m_components->setOldConfigVersion("org.lwjgl", m_settings->get("LWJGLVersion").toString());
m_components->setOldConfigVersion("net.minecraftforge", m_settings->get("ForgeVersion").toString());
m_components->setOldConfigVersion("com.mumfrey.liteloader", m_settings->get("LiteloaderVersion").toString());
}
void MinecraftInstance::saveNow()
@ -445,7 +434,7 @@ QStringList MinecraftInstance::processMinecraftArgs(
}
// blatant self-promotion.
token_mapping["profile_name"] = token_mapping["version_name"] = "MultiMC5";
token_mapping["profile_name"] = token_mapping["version_name"] = "PolyMC";
token_mapping["version_type"] = profile->getMinecraftVersionType();

View File

@ -20,7 +20,7 @@
#include <QUrl>
#include "tasks/Task.h"
#include <quazip.h>
#include <quazip/quazip.h>
#include "QObjectPtr.h"

View File

@ -22,7 +22,7 @@
#include "net/NetJob.h"
#include "tasks/Task.h"
#include "minecraft/VersionFilterData.h"
#include <quazip.h>
#include <quazip/quazip.h>
class MinecraftVersion;
class MinecraftInstance;

View File

@ -272,18 +272,6 @@ void PackProfile::save_internal()
bool PackProfile::load()
{
auto filename = componentsFilePath();
QFile componentsFile(filename);
// migrate old config to new one, if needed
if(!componentsFile.exists())
{
if(!migratePreComponentConfig())
{
// FIXME: the user should be notified...
qCritical() << "Failed to convert old pre-component config for instance" << d->m_instance->name();
return false;
}
}
// load the new component list and swap it with the current one...
ComponentContainer newComponents;
@ -369,239 +357,6 @@ void PackProfile::updateFailed(const QString& error)
invalidateLaunchProfile();
}
// NOTE this is really old stuff, and only needs to be used when loading the old hardcoded component-unaware format (loadPreComponentConfig).
static void upgradeDeprecatedFiles(QString root, QString instanceName)
{
auto versionJsonPath = FS::PathCombine(root, "version.json");
auto customJsonPath = FS::PathCombine(root, "custom.json");
auto mcJson = FS::PathCombine(root, "patches" , "net.minecraft.json");
QString sourceFile;
QString renameFile;
// convert old crap.
if(QFile::exists(customJsonPath))
{
sourceFile = customJsonPath;
renameFile = versionJsonPath;
}
else if(QFile::exists(versionJsonPath))
{
sourceFile = versionJsonPath;
}
if(!sourceFile.isEmpty() && !QFile::exists(mcJson))
{
if(!FS::ensureFilePathExists(mcJson))
{
qWarning() << "Couldn't create patches folder for" << instanceName;
return;
}
if(!renameFile.isEmpty() && QFile::exists(renameFile))
{
if(!QFile::rename(renameFile, renameFile + ".old"))
{
qWarning() << "Couldn't rename" << renameFile << "to" << renameFile + ".old" << "in" << instanceName;
return;
}
}
auto file = ProfileUtils::parseJsonFile(QFileInfo(sourceFile), false);
ProfileUtils::removeLwjglFromPatch(file);
file->uid = "net.minecraft";
file->version = file->minecraftVersion;
file->name = "Minecraft";
Meta::Require needsLwjgl;
needsLwjgl.uid = "org.lwjgl";
file->requires.insert(needsLwjgl);
if(!ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), mcJson))
{
return;
}
if(!QFile::rename(sourceFile, sourceFile + ".old"))
{
qWarning() << "Couldn't rename" << sourceFile << "to" << sourceFile + ".old" << "in" << instanceName;
return;
}
}
}
/*
* Migrate old layout to the component based one...
* - Part of the version information is taken from `instance.cfg` (fed to this class from outside).
* - Part is taken from the old order.json file.
* - Part is loaded from loose json files in the instance's `patches` directory.
*/
bool PackProfile::migratePreComponentConfig()
{
// upgrade the very old files from the beginnings of MultiMC 5
upgradeDeprecatedFiles(d->m_instance->instanceRoot(), d->m_instance->name());
QList<ComponentPtr> components;
QSet<QString> loaded;
auto addBuiltinPatch = [&](const QString &uid, bool asDependency, const QString & emptyVersion, const Meta::Require & req, const Meta::Require & conflict)
{
auto jsonFilePath = FS::PathCombine(d->m_instance->instanceRoot(), "patches" , uid + ".json");
auto intendedVersion = d->getOldConfigVersion(uid);
// load up the base minecraft patch
ComponentPtr component;
if(QFile::exists(jsonFilePath))
{
if(intendedVersion.isEmpty())
{
intendedVersion = emptyVersion;
}
auto file = ProfileUtils::parseJsonFile(QFileInfo(jsonFilePath), false);
// fix uid
file->uid = uid;
// if version is missing, add it from the outside.
if(file->version.isEmpty())
{
file->version = intendedVersion;
}
// if this is a dependency (LWJGL), mark it also as volatile
if(asDependency)
{
file->m_volatile = true;
}
// insert requirements if needed
if(!req.uid.isEmpty())
{
file->requires.insert(req);
}
// insert conflicts if needed
if(!conflict.uid.isEmpty())
{
file->conflicts.insert(conflict);
}
// FIXME: @QUALITY do not ignore return value
ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), jsonFilePath);
component = new Component(this, uid, file);
component->m_version = intendedVersion;
}
else if(!intendedVersion.isEmpty())
{
auto metaVersion = APPLICATION->metadataIndex()->get(uid, intendedVersion);
component = new Component(this, metaVersion);
}
else
{
return;
}
component->m_dependencyOnly = asDependency;
component->m_important = !asDependency;
components.append(component);
};
// TODO: insert depends and conflicts here if these are customized files...
Meta::Require reqLwjgl;
reqLwjgl.uid = "org.lwjgl";
reqLwjgl.suggests = "2.9.1";
Meta::Require conflictLwjgl3;
conflictLwjgl3.uid = "org.lwjgl3";
Meta::Require nullReq;
addBuiltinPatch("org.lwjgl", true, "2.9.1", nullReq, conflictLwjgl3);
addBuiltinPatch("net.minecraft", false, QString(), reqLwjgl, nullReq);
// first, collect all other file-based patches and load them
QMap<QString, ComponentPtr> loadedComponents;
QDir patchesDir(FS::PathCombine(d->m_instance->instanceRoot(),"patches"));
for (auto info : patchesDir.entryInfoList(QStringList() << "*.json", QDir::Files))
{
// parse the file
qDebug() << "Reading" << info.fileName();
auto file = ProfileUtils::parseJsonFile(info, true);
// correct missing or wrong uid based on the file name
QString uid = info.completeBaseName();
// ignore builtins, they've been handled already
if (uid == "net.minecraft")
continue;
if (uid == "org.lwjgl")
continue;
// handle horrible corner cases
if(uid.isEmpty())
{
// if you have a file named '.json', make it just go away.
// FIXME: @QUALITY do not ignore return value
QFile::remove(info.absoluteFilePath());
continue;
}
file->uid = uid;
// FIXME: @QUALITY do not ignore return value
ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), info.absoluteFilePath());
auto component = new Component(this, file->uid, file);
auto version = d->getOldConfigVersion(file->uid);
if(!version.isEmpty())
{
component->m_version = version;
}
loadedComponents[file->uid] = component;
}
// try to load the other 'hardcoded' patches (forge, liteloader), if they weren't loaded from files
auto loadSpecial = [&](const QString & uid, int order)
{
auto patchVersion = d->getOldConfigVersion(uid);
if(!patchVersion.isEmpty() && !loadedComponents.contains(uid))
{
auto patch = new Component(this, APPLICATION->metadataIndex()->get(uid, patchVersion));
patch->setOrder(order);
loadedComponents[uid] = patch;
}
};
loadSpecial("net.minecraftforge", 5);
loadSpecial("com.mumfrey.liteloader", 10);
// load the old order.json file, if present
ProfileUtils::PatchOrder userOrder;
ProfileUtils::readOverrideOrders(FS::PathCombine(d->m_instance->instanceRoot(), "order.json"), userOrder);
// now add all the patches by user sort order
for (auto uid : userOrder)
{
// ignore builtins
if (uid == "net.minecraft")
continue;
if (uid == "org.lwjgl")
continue;
// ordering has a patch that is gone?
if(!loadedComponents.contains(uid))
{
continue;
}
components.append(loadedComponents.take(uid));
}
// is there anything left to sort? - this is used when there are leftover components that aren't part of the order.json
if(!loadedComponents.isEmpty())
{
// inserting into multimap by order number as key sorts the patches and detects duplicates
QMultiMap<int, ComponentPtr> files;
auto iter = loadedComponents.begin();
while(iter != loadedComponents.end())
{
files.insert((*iter)->getOrder(), *iter);
iter++;
}
// then just extract the patches and put them in the list
for (auto order : files.keys())
{
const auto &values = files.values(order);
for(auto &value: values)
{
// TODO: put back the insertion of problem messages here, so the user knows about the id duplication
components.append(value);
}
}
}
// new we have a complete list of components...
return savePackProfile(componentsFilePath(), components);
}
// END: save/load
void PackProfile::appendComponent(ComponentPtr component)
@ -1169,15 +924,6 @@ std::shared_ptr<LaunchProfile> PackProfile::getProfile() const
return d->m_profile;
}
void PackProfile::setOldConfigVersion(const QString& uid, const QString& version)
{
if(version.isEmpty())
{
return;
}
d->m_oldConfigVersions[uid] = version;
}
bool PackProfile::setComponentVersion(const QString& uid, const QString& version, bool important)
{
auto iter = d->componentIndex.find(uid);

View File

@ -143,8 +143,6 @@ private:
bool installCustomJar_internal(QString filepath);
bool removeComponent_internal(ComponentPtr patch);
bool migratePreComponentConfig();
private: /* data */
std::unique_ptr<PackProfileData> d;

View File

@ -18,18 +18,6 @@ struct PackProfileData
// the launch profile (volatile, temporary thing created on demand)
std::shared_ptr<LaunchProfile> m_profile;
// version information migrated from instance.cfg file. Single use on migration!
std::map<QString, QString> m_oldConfigVersions;
QString getOldConfigVersion(const QString& uid) const
{
const auto iter = m_oldConfigVersions.find(uid);
if(iter != m_oldConfigVersions.cend())
{
return (*iter).second;
}
return QString();
}
// persistent list of components and related machinery
ComponentContainer components;
ComponentIndex componentIndex;

View File

@ -27,19 +27,19 @@ public: /* methods */
void applyTo(LaunchProfile* profile);
public: /* data */
/// MultiMC: order hint for this version file if no explicit order is set
/// PolyMC: order hint for this version file if no explicit order is set
int order = 0;
/// MultiMC: human readable name of this package
/// PolyMC: human readable name of this package
QString name;
/// MultiMC: package ID of this package
/// PolyMC: package ID of this package
QString uid;
/// MultiMC: version of this package
/// PolyMC: version of this package
QString version;
/// MultiMC: DEPRECATED dependency on a Minecraft version
/// PolyMC: DEPRECATED dependency on a Minecraft version
QString dependsOnMinecraftVersion;
/// Mojang: DEPRECATED used to version the Mojang version format
@ -51,7 +51,7 @@ public: /* data */
/// Mojang: class to launch Minecraft with
QString mainClass;
/// MultiMC: class to launch legacy Minecraft with (embed in a custom window)
/// PolyMC: class to launch legacy Minecraft with (embed in a custom window)
QString appletClass;
/// Mojang: Minecraft launch arguments (may contain placeholders for variable substitution)
@ -69,35 +69,35 @@ public: /* data */
/// Mojang: DEPRECATED asset group to be used with Minecraft
QString assets;
/// MultiMC: list of tweaker mod arguments for launchwrapper
/// PolyMC: list of tweaker mod arguments for launchwrapper
QStringList addTweakers;
/// Mojang: list of libraries to add to the version
QList<LibraryPtr> libraries;
/// MultiMC: list of maven files to put in the libraries folder, but not in classpath
/// PolyMC: list of maven files to put in the libraries folder, but not in classpath
QList<LibraryPtr> mavenFiles;
/// The main jar (Minecraft version library, normally)
LibraryPtr mainJar;
/// MultiMC: list of attached traits of this version file - used to enable features
/// PolyMC: list of attached traits of this version file - used to enable features
QSet<QString> traits;
/// MultiMC: list of jar mods added to this version
/// PolyMC: list of jar mods added to this version
QList<LibraryPtr> jarMods;
/// MultiMC: list of mods added to this version
/// PolyMC: list of mods added to this version
QList<LibraryPtr> mods;
/**
* MultiMC: set of packages this depends on
* PolyMC: set of packages this depends on
* NOTE: this is shared with the meta format!!!
*/
Meta::RequireSet requires;
/**
* MultiMC: set of packages this conflicts with
* PolyMC: set of packages this conflicts with
* NOTE: this is shared with the meta format!!!
*/
Meta::RequireSet conflicts;
@ -112,3 +112,4 @@ public:
// Mojang: extended asset index download information
std::shared_ptr<MojangAssetIndexInfo> mojangAssetIndex;
};

View File

@ -26,9 +26,9 @@
#include <io/stream_reader.h>
#include <tag_string.h>
#include <tag_primitive.h>
#include <quazip.h>
#include <quazipfile.h>
#include <quazipdir.h>
#include <quazip/quazip.h>
#include <quazip/quazipfile.h>
#include <quazip/quazipdir.h>
#include <QCoreApplication>

View File

@ -314,6 +314,8 @@ bool AccountData::resumeStateFromV3(QJsonObject data) {
type = AccountType::MSA;
} else if (typeS == "Mojang") {
type = AccountType::Mojang;
} else if (typeS == "Offline") {
type = AccountType::Offline;
} else {
qWarning() << "Failed to parse account data: type is not recognized.";
return false;
@ -325,6 +327,10 @@ bool AccountData::resumeStateFromV3(QJsonObject data) {
}
if(type == AccountType::MSA) {
auto clientIDV = data.value("msa-client-id");
if (clientIDV.isString()) {
msaClientID = clientIDV.toString();
} // leave msaClientID empty if it doesn't exist or isn't a string
msaToken = tokenFromJSONV3(data, "msa");
userToken = tokenFromJSONV3(data, "utoken");
xboxApiToken = tokenFromJSONV3(data, "xrp-main");
@ -358,11 +364,15 @@ QJsonObject AccountData::saveState() const {
}
else if (type == AccountType::MSA) {
output["type"] = "MSA";
output["msa-client-id"] = msaClientID;
tokenToJSONV3(output, msaToken, "msa");
tokenToJSONV3(output, userToken, "utoken");
tokenToJSONV3(output, xboxApiToken, "xrp-main");
tokenToJSONV3(output, mojangservicesToken, "xrp-mc");
}
else if (type == AccountType::Offline) {
output["type"] = "Offline";
}
tokenToJSONV3(output, yggdrasilToken, "ygg");
profileToJSONV3(output, minecraftProfile, "profile");
@ -371,7 +381,7 @@ QJsonObject AccountData::saveState() const {
}
QString AccountData::userName() const {
if(type != AccountType::Mojang) {
if(type == AccountType::MSA) {
return QString();
}
return yggdrasilToken.extra["userName"].toString();
@ -427,6 +437,9 @@ QString AccountData::accountDisplayString() const {
case AccountType::Mojang: {
return userName();
}
case AccountType::Offline: {
return userName();
}
case AccountType::MSA: {
if(xboxApiToken.extra.contains("gtg")) {
return xboxApiToken.extra["gtg"].toString();

View File

@ -38,7 +38,8 @@ struct MinecraftProfile {
enum class AccountType {
MSA,
Mojang
Mojang,
Offline
};
enum class AccountState {
@ -46,6 +47,7 @@ enum class AccountState {
Offline,
Working,
Online,
Disabled,
Errored,
Expired,
Gone
@ -80,6 +82,7 @@ struct AccountData {
bool legacy = false;
bool canMigrateToMSA = false;
QString msaClientID;
Katabasis::Token msaToken;
Katabasis::Token userToken;
Katabasis::Token xboxApiToken;

View File

@ -291,6 +291,9 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
case AccountState::Expired: {
return tr("Expired", "Account status");
}
case AccountState::Disabled: {
return tr("Disabled", "Account status");
}
case AccountState::Gone: {
return tr("Gone", "Account status");
}
@ -302,7 +305,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
}
case MigrationColumn: {
if(account->isMSA()) {
if(account->isMSA() || account->isOffline()) {
return tr("N/A", "Can Migrate?");
}
if (account->canMigrate()) {

View File

@ -24,7 +24,7 @@
/*!
* List of available Mojang accounts.
* This should be loaded in the background by MultiMC on startup.
* This should be loaded in the background by PolyMC on startup.
*/
class AccountList : public QAbstractListModel
{
@ -158,3 +158,4 @@ protected:
*/
bool m_autosave = false;
};

View File

@ -43,6 +43,8 @@ QString AccountTask::getStateMessage() const
return tr("Authentication task succeeded.");
case AccountTaskState::STATE_OFFLINE:
return tr("Failed to contact the authentication server.");
case AccountTaskState::STATE_DISABLED:
return tr("Client ID has changed. New session needs to be created.");
case AccountTaskState::STATE_FAILED_SOFT:
return tr("Encountered an error during authentication.");
case AccountTaskState::STATE_FAILED_HARD:
@ -78,6 +80,12 @@ bool AccountTask::changeState(AccountTaskState newState, QString reason)
emitFailed(reason);
return false;
}
case AccountTaskState::STATE_DISABLED: {
m_data->errorString = reason;
m_data->accountState = AccountState::Disabled;
emitFailed(reason);
return false;
}
case AccountTaskState::STATE_FAILED_SOFT: {
m_data->errorString = reason;
m_data->accountState = AccountState::Errored;

View File

@ -35,6 +35,7 @@ enum class AccountTaskState
STATE_CREATED,
STATE_WORKING,
STATE_SUCCEEDED,
STATE_DISABLED, //!< MSA Client ID has changed. Tell user to reloginn
STATE_FAILED_SOFT, //!< soft failure. authentication went through partially
STATE_FAILED_HARD, //!< hard failure. main tokens are invalid
STATE_FAILED_GONE, //!< hard failure. main tokens are invalid, and the account no longer exists

View File

@ -44,7 +44,7 @@ void AuthRequest::onRequestFinished() {
if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
return;
}
httpStatus_ = 200;
httpStatus_ = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
finish();
}

View File

@ -30,6 +30,7 @@
#include "flows/MSA.h"
#include "flows/Mojang.h"
#include "flows/Offline.h"
MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) {
data.internalId = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
@ -68,6 +69,23 @@ MinecraftAccountPtr MinecraftAccount::createBlankMSA()
return account;
}
MinecraftAccountPtr MinecraftAccount::createOffline(const QString &username)
{
MinecraftAccountPtr account = new MinecraftAccount();
account->data.type = AccountType::Offline;
account->data.yggdrasilToken.token = "offline";
account->data.yggdrasilToken.validity = Katabasis::Validity::Certain;
account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc();
account->data.yggdrasilToken.extra["userName"] = username;
account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
account->data.minecraftEntitlement.ownsMinecraft = true;
account->data.minecraftEntitlement.canPlayMinecraft = true;
account->data.minecraftProfile.id = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
account->data.minecraftProfile.name = username;
account->data.minecraftProfile.validity = Katabasis::Validity::Certain;
return account;
}
QJsonObject MinecraftAccount::saveToJson() const
{
@ -111,6 +129,16 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() {
return m_currentTask;
}
shared_qobject_ptr<AccountTask> MinecraftAccount::loginOffline() {
Q_ASSERT(m_currentTask.get() == nullptr);
m_currentTask.reset(new OfflineLogin(&data));
connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
emit activityChanged(true);
return m_currentTask;
}
shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() {
if(m_currentTask) {
return m_currentTask;
@ -119,6 +147,9 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() {
if(data.type == AccountType::MSA) {
m_currentTask.reset(new MSASilent(&data));
}
else if(data.type == AccountType::Offline) {
m_currentTask.reset(new OfflineRefresh(&data));
}
else {
m_currentTask.reset(new MojangRefresh(&data));
}
@ -145,6 +176,9 @@ void MinecraftAccount::authFailed(QString reason)
{
switch (m_currentTask->taskState()) {
case AccountTaskState::STATE_OFFLINE:
case AccountTaskState::STATE_DISABLED: {
// NOTE: user will need to fix this themselves.
}
case AccountTaskState::STATE_FAILED_SOFT: {
// NOTE: this doesn't do much. There was an error of some sort.
}

View File

@ -41,7 +41,7 @@ Q_DECLARE_METATYPE(MinecraftAccountPtr)
* A profile within someone's Mojang account.
*
* Currently, the profile system has not been implemented by Mojang yet,
* but we might as well add some things for it in MultiMC right now so
* but we might as well add some things for it in PolyMC right now so
* we don't have to rip the code to pieces to add it later.
*/
struct AccountProfile
@ -73,6 +73,8 @@ public: /* construction */
static MinecraftAccountPtr createBlankMSA();
static MinecraftAccountPtr createOffline(const QString &username);
static MinecraftAccountPtr loadFromJsonV2(const QJsonObject &json);
static MinecraftAccountPtr loadFromJsonV3(const QJsonObject &json);
@ -89,6 +91,8 @@ public: /* manipulation */
shared_qobject_ptr<AccountTask> loginMSA();
shared_qobject_ptr<AccountTask> loginOffline();
shared_qobject_ptr<AccountTask> refresh();
shared_qobject_ptr<AccountTask> currentTask();
@ -128,6 +132,10 @@ public: /* queries */
return data.type == AccountType::MSA;
}
bool isOffline() const {
return data.type == AccountType::Offline;
}
bool ownsMinecraft() const {
return data.minecraftEntitlement.ownsMinecraft;
}
@ -149,6 +157,10 @@ public: /* queries */
return "msa";
}
break;
case AccountType::Offline: {
return "offline";
}
break;
default: {
return "unknown";
}
@ -198,3 +210,4 @@ slots:
void authSucceeded();
void authFailed(QString reason);
};

View File

@ -94,7 +94,7 @@ bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString na
return false;
}
if(!getString(obj.value("Token"), output.token)) {
qWarning() << "User Token is not a timestamp";
qWarning() << "User Token is not a string";
return false;
}
auto arrayVal = obj.value("DisplayClaims").toObject().value("xui");

View File

@ -0,0 +1,17 @@
#include "Offline.h"
#include "minecraft/auth/steps/OfflineStep.h"
OfflineRefresh::OfflineRefresh(
AccountData *data,
QObject *parent
) : AuthFlow(data, parent) {
m_steps.append(new OfflineStep(m_data));
}
OfflineLogin::OfflineLogin(
AccountData *data,
QObject *parent
) : AuthFlow(data, parent) {
m_steps.append(new OfflineStep(m_data));
}

View File

@ -0,0 +1,22 @@
#pragma once
#include "AuthFlow.h"
class OfflineRefresh : public AuthFlow
{
Q_OBJECT
public:
explicit OfflineRefresh(
AccountData *data,
QObject *parent = 0
);
};
class OfflineLogin : public AuthFlow
{
Q_OBJECT
public:
explicit OfflineLogin(
AccountData *data,
QObject *parent = 0
);
};

View File

@ -12,9 +12,10 @@ using OAuth2 = Katabasis::DeviceFlow;
using Activity = Katabasis::Activity;
MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(action) {
m_clientId = APPLICATION->getMSAClientID();
OAuth2::Options opts;
opts.scope = "XboxLive.signin offline_access";
opts.clientIdentifier = BuildConfig.MSA_CLIENT_ID;
opts.clientIdentifier = m_clientId;
opts.authorizationUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode";
opts.accessTokenUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
@ -48,6 +49,10 @@ void MSAStep::rehydrate() {
void MSAStep::perform() {
switch(m_action) {
case Refresh: {
if (m_data->msaClientID != m_clientId) {
emit hideVerificationUriAndCode();
emit finished(AccountTaskState::STATE_DISABLED, tr("Microsoft user authentication failed - client identification has changed."));
}
m_oauth2->refresh();
return;
}
@ -57,6 +62,7 @@ void MSAStep::perform() {
m_oauth2->setExtraRequestParams(extraOpts);
*m_data = AccountData();
m_data->msaClientID = m_clientId;
m_oauth2->login();
return;
}

View File

@ -29,4 +29,5 @@ private slots:
private:
Katabasis::DeviceFlow *m_oauth2 = nullptr;
Action m_action;
QString m_clientId;
};

View File

@ -56,6 +56,14 @@ void MinecraftProfileStep::onRequestDone(
return;
}
if (error != QNetworkReply::NoError) {
qWarning() << "Error getting profile:";
qWarning() << " HTTP Status: " << requestor->httpStatus_;
qWarning() << " Internal error no.: " << error;
qWarning() << " Error string: " << requestor->errorString_;
qWarning() << " Response:";
qWarning() << QString::fromUtf8(data);
emit finished(
AccountTaskState::STATE_FAILED_SOFT,
tr("Minecraft Java profile acquisition failed.")

View File

@ -0,0 +1,18 @@
#include "OfflineStep.h"
#include "Application.h"
OfflineStep::OfflineStep(AccountData* data) : AuthStep(data) {}
OfflineStep::~OfflineStep() noexcept = default;
QString OfflineStep::describe() {
return tr("Creating offline account.");
}
void OfflineStep::rehydrate() {
// NOOP
}
void OfflineStep::perform() {
emit finished(AccountTaskState::STATE_WORKING, tr("Created offline account."));
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <QObject>
#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"
#include <katabasis/DeviceFlow.h>
class OfflineStep : public AuthStep {
Q_OBJECT
public:
explicit OfflineStep(AccountData *data);
virtual ~OfflineStep() noexcept;
void perform() override;
void rehydrate() override;
QString describe() override;
};

View File

@ -17,8 +17,8 @@
#include <minecraft/MinecraftInstance.h>
#include <launch/LaunchTask.h>
#include <quazip.h>
#include <quazipdir.h>
#include <quazip/quazip.h>
#include <quazip/quazipdir.h>
#include "MMCZip.h"
#include "FileSystem.h"
#include <QDir>

View File

@ -25,6 +25,19 @@
LauncherPartLaunch::LauncherPartLaunch(LaunchTask *parent) : LaunchStep(parent)
{
if (APPLICATION->settings()->get("CloseAfterLaunch").toBool())
{
std::shared_ptr<QMetaObject::Connection> connection{new QMetaObject::Connection};
*connection = connect(&m_process, &LoggedProcess::log, this, [=](QStringList lines, MessageLevel::Enum level) {
qDebug() << lines;
if (lines.filter(QRegularExpression(".*Setting user.+", QRegularExpression::CaseInsensitiveOption)).length() != 0)
{
APPLICATION->closeAllWindows();
disconnect(*connection);
}
});
}
connect(&m_process, &LoggedProcess::log, this, &LauncherPartLaunch::logLines);
connect(&m_process, &LoggedProcess::stateChanged, this, &LauncherPartLaunch::on_state);
}
@ -155,6 +168,8 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state)
}
case LoggedProcess::Finished:
{
if (APPLICATION->settings()->get("CloseAfterLaunch").toBool())
APPLICATION->showMainWindow();
m_parent->setPid(-1);
// if the exit code wasn't 0, report this as a crash
auto exitCode = m_process.exitCode();

View File

@ -23,7 +23,7 @@ MinecraftServerTarget MinecraftServerTarget::parse(const QString &fullAddress) {
// The logic below replicates the exact logic minecraft uses for parsing server addresses.
// While the conversion is not lossless and eats errors, it ensures the same behavior
// within Minecraft and MultiMC when entering server addresses.
// within Minecraft and PolyMC when entering server addresses.
if (fullAddress.startsWith("["))
{
int bracket = fullAddress.indexOf("]");

View File

@ -1,256 +0,0 @@
/* 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 <QFileInfo>
#include <minecraft/launch/LauncherPartLaunch.h>
#include <QDir>
#include <settings/Setting.h>
#include "LegacyInstance.h"
#include "minecraft/legacy/LegacyModList.h"
#include "minecraft/WorldList.h"
#include <MMCZip.h>
#include <FileSystem.h>
LegacyInstance::LegacyInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir)
: BaseInstance(globalSettings, settings, rootDir)
{
settings->registerSetting("NeedsRebuild", true);
settings->registerSetting("ShouldUpdate", false);
settings->registerSetting("JarVersion", QString());
settings->registerSetting("IntendedJarVersion", QString());
/*
* custom base jar has no default. it is determined in code... see the accessor methods for
*it
*
* for instances that DO NOT have the CustomBaseJar setting (legacy instances),
* [.]minecraft/bin/mcbackup.jar is the default base jar
*/
settings->registerSetting("UseCustomBaseJar", true);
settings->registerSetting("CustomBaseJar", "");
}
QString LegacyInstance::mainJarToPreserve() const
{
bool customJar = m_settings->get("UseCustomBaseJar").toBool();
if(customJar)
{
auto base = baseJar();
if(QFile::exists(base))
{
return base;
}
}
auto runnable = runnableJar();
if(QFile::exists(runnable))
{
return runnable;
}
return QString();
}
QString LegacyInstance::baseJar() const
{
bool customJar = m_settings->get("UseCustomBaseJar").toBool();
if (customJar)
{
return customBaseJar();
}
else
return defaultBaseJar();
}
QString LegacyInstance::customBaseJar() const
{
QString value = m_settings->get("CustomBaseJar").toString();
if (value.isNull() || value.isEmpty())
{
return defaultCustomBaseJar();
}
return value;
}
bool LegacyInstance::shouldUseCustomBaseJar() const
{
return m_settings->get("UseCustomBaseJar").toBool();
}
Task::Ptr LegacyInstance::createUpdateTask(Net::Mode)
{
return nullptr;
}
std::shared_ptr<LegacyModList> LegacyInstance::jarModList() const
{
if (!jar_mod_list)
{
auto list = new LegacyModList(jarModsDir(), modListFile());
jar_mod_list.reset(list);
}
jar_mod_list->update();
return jar_mod_list;
}
QString LegacyInstance::gameRoot() const
{
QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft"));
QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft"));
if (mcDir.exists() && !dotMCDir.exists())
return mcDir.filePath();
else
return dotMCDir.filePath();
}
QString LegacyInstance::binRoot() const
{
return FS::PathCombine(gameRoot(), "bin");
}
QString LegacyInstance::modsRoot() const {
return FS::PathCombine(gameRoot(), "mods");
}
QString LegacyInstance::jarModsDir() const
{
return FS::PathCombine(instanceRoot(), "instMods");
}
QString LegacyInstance::libDir() const
{
return FS::PathCombine(gameRoot(), "lib");
}
QString LegacyInstance::savesDir() const
{
return FS::PathCombine(gameRoot(), "saves");
}
QString LegacyInstance::coreModsDir() const
{
return FS::PathCombine(gameRoot(), "coremods");
}
QString LegacyInstance::resourceDir() const
{
return FS::PathCombine(gameRoot(), "resources");
}
QString LegacyInstance::texturePacksDir() const
{
return FS::PathCombine(gameRoot(), "texturepacks");
}
QString LegacyInstance::runnableJar() const
{
return FS::PathCombine(binRoot(), "minecraft.jar");
}
QString LegacyInstance::modListFile() const
{
return FS::PathCombine(instanceRoot(), "modlist");
}
QString LegacyInstance::instanceConfigFolder() const
{
return FS::PathCombine(gameRoot(), "config");
}
bool LegacyInstance::shouldRebuild() const
{
return m_settings->get("NeedsRebuild").toBool();
}
QString LegacyInstance::currentVersionId() const
{
return m_settings->get("JarVersion").toString();
}
QString LegacyInstance::intendedVersionId() const
{
return m_settings->get("IntendedJarVersion").toString();
}
bool LegacyInstance::shouldUpdate() const
{
QVariant var = settings()->get("ShouldUpdate");
if (!var.isValid() || var.toBool() == false)
{
return intendedVersionId() != currentVersionId();
}
return true;
}
QString LegacyInstance::defaultBaseJar() const
{
return "versions/" + intendedVersionId() + "/" + intendedVersionId() + ".jar";
}
QString LegacyInstance::defaultCustomBaseJar() const
{
return FS::PathCombine(binRoot(), "mcbackup.jar");
}
std::shared_ptr<WorldList> LegacyInstance::worldList() const
{
if (!m_world_list)
{
m_world_list.reset(new WorldList(savesDir()));
}
return m_world_list;
}
QString LegacyInstance::typeName() const
{
return tr("Legacy");
}
QString LegacyInstance::getStatusbarDescription()
{
return tr("Instance from previous versions.");
}
QStringList LegacyInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{
QStringList out;
auto alltraits = traits();
if(alltraits.size())
{
out << "Traits:";
for (auto trait : alltraits)
{
out << " " + trait;
}
out << "";
}
QString windowParams;
if (settings()->get("LaunchMaximized").toBool())
{
out << "Window size: max (if available)";
}
else
{
auto width = settings()->get("MinecraftWinWidth").toInt();
auto height = settings()->get("MinecraftWinHeight").toInt();
out << "Window size: " + QString::number(width) + " x " + QString::number(height);
}
out << "";
return out;
}

View File

@ -1,142 +0,0 @@
/* 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"
class ModFolderModel;
class LegacyModList;
class WorldList;
class Task;
/*
* WHY: Legacy instances - from MultiMC 3 and 4 - are here only to provide a way to upgrade them to the current format.
*/
class LegacyInstance : public BaseInstance
{
Q_OBJECT
public:
explicit LegacyInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir);
virtual void saveNow() override {}
/// Path to the instance's minecraft.jar
QString runnableJar() const;
//! Path to the instance's modlist file.
QString modListFile() const;
////// Directories //////
QString libDir() const;
QString savesDir() const;
QString texturePacksDir() const;
QString jarModsDir() const;
QString coreModsDir() const;
QString resourceDir() const;
QString instanceConfigFolder() const override;
QString gameRoot() const override; // Path to the instance's minecraft directory.
QString modsRoot() const override; // Path to the instance's minecraft directory.
QString binRoot() const; // Path to the instance's minecraft bin directory.
/// Get the curent base jar of this instance. By default, it's the
/// versions/$version/$version.jar
QString baseJar() const;
/// the default base jar of this instance
QString defaultBaseJar() const;
/// the default custom base jar of this instance
QString defaultCustomBaseJar() const;
// the main jar that we actually want to keep when migrating the instance
QString mainJarToPreserve() const;
/*!
* Whether or not custom base jar is used
*/
bool shouldUseCustomBaseJar() const;
/*!
* The value of the custom base jar
*/
QString customBaseJar() const;
std::shared_ptr<LegacyModList> jarModList() const;
std::shared_ptr<WorldList> worldList() const;
/*!
* Whether or not the instance's minecraft.jar needs to be rebuilt.
* If this is true, when the instance launches, its jar mods will be
* re-added to a fresh minecraft.jar file.
*/
bool shouldRebuild() const;
QString currentVersionId() const;
QString intendedVersionId() const;
QSet<QString> traits() const override
{
return {"legacy-instance", "texturepacks"};
};
virtual bool shouldUpdate() const;
virtual Task::Ptr createUpdateTask(Net::Mode mode) override;
virtual QString typeName() const override;
bool canLaunch() const override
{
return false;
}
bool canEdit() const override
{
return true;
}
bool canExport() const override
{
return false;
}
shared_qobject_ptr<LaunchTask> createLaunchTask(
AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override
{
return nullptr;
}
IPathMatcher::Ptr getLogFileMatcher() override
{
return nullptr;
}
QString getLogFileRoot() override
{
return gameRoot();
}
QString getStatusbarDescription() override;
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override;
QProcessEnvironment createEnvironment() override
{
return QProcessEnvironment();
}
QMap<QString, QString> getVariables() const override
{
return {};
}
protected:
mutable std::shared_ptr<LegacyModList> jar_mod_list;
mutable std::shared_ptr<WorldList> m_world_list;
};

View File

@ -1,136 +0,0 @@
/* 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 "LegacyModList.h"
#include <FileSystem.h>
#include <QString>
#include <QDebug>
LegacyModList::LegacyModList(const QString &dir, const QString &list_file)
: m_dir(dir), m_list_file(list_file)
{
FS::ensureFolderPathExists(m_dir.absolutePath());
m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
}
struct OrderItem
{
QString id;
bool enabled = false;
};
typedef QList<OrderItem> OrderList;
static void internalSort(QList<LegacyModList::Mod> &what)
{
auto predicate = [](const LegacyModList::Mod &left, const LegacyModList::Mod &right)
{
return left.fileName().localeAwareCompare(right.fileName()) < 0;
};
std::sort(what.begin(), what.end(), predicate);
}
static OrderList readListFile(const QString &m_list_file)
{
OrderList itemList;
if (m_list_file.isNull() || m_list_file.isEmpty())
return itemList;
QFile textFile(m_list_file);
if (!textFile.open(QIODevice::ReadOnly | QIODevice::Text))
return OrderList();
QTextStream textStream;
textStream.setAutoDetectUnicode(true);
textStream.setDevice(&textFile);
while (true)
{
QString line = textStream.readLine();
if (line.isNull() || line.isEmpty())
break;
else
{
OrderItem it;
it.enabled = !line.endsWith(".disabled");
if (!it.enabled)
{
line.chop(9);
}
it.id = line;
itemList.append(it);
}
}
textFile.close();
return itemList;
}
bool LegacyModList::update()
{
if (!m_dir.exists() || !m_dir.isReadable())
return false;
QList<Mod> orderedMods;
QList<Mod> newMods;
m_dir.refresh();
auto folderContents = m_dir.entryInfoList();
// first, process the ordered items (if any)
OrderList listOrder = readListFile(m_list_file);
for (auto item : listOrder)
{
QFileInfo infoEnabled(m_dir.filePath(item.id));
QFileInfo infoDisabled(m_dir.filePath(item.id + ".disabled"));
int idxEnabled = folderContents.indexOf(infoEnabled);
int idxDisabled = folderContents.indexOf(infoDisabled);
bool isEnabled;
// if both enabled and disabled versions are present, it's a special case...
if (idxEnabled >= 0 && idxDisabled >= 0)
{
// we only process the one we actually have in the order file.
// and exactly as we have it.
// THIS IS A CORNER CASE
isEnabled = item.enabled;
}
else
{
// only one is present.
// we pick the one that we found.
// we assume the mod was enabled/disabled by external means
isEnabled = idxEnabled >= 0;
}
int idx = isEnabled ? idxEnabled : idxDisabled;
QFileInfo &info = isEnabled ? infoEnabled : infoDisabled;
// if the file from the index file exists
if (idx != -1)
{
// remove from the actual folder contents list
folderContents.takeAt(idx);
// append the new mod
orderedMods.append(info);
}
}
// if there are any untracked files... append them sorted at the end
if (folderContents.size())
{
for (auto entry : folderContents)
{
newMods.append(entry);
}
internalSort(newMods);
orderedMods.append(newMods);
}
mods.swap(orderedMods);
return true;
}

View File

@ -1,47 +0,0 @@
/* 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 <QList>
#include <QString>
#include <QDir>
class LegacyModList
{
public:
using Mod = QFileInfo;
LegacyModList(const QString &dir, const QString &list_file = QString());
/// Reloads the mod list and returns true if the list changed.
bool update();
QDir dir()
{
return m_dir;
}
const QList<Mod> & allMods()
{
return mods;
}
protected:
QDir m_dir;
QString m_list_file;
QList<Mod> mods;
};

View File

@ -1,138 +0,0 @@
#include "LegacyUpgradeTask.h"
#include "settings/INISettingsObject.h"
#include "FileSystem.h"
#include "NullInstance.h"
#include "pathmatcher/RegexpMatcher.h"
#include <QtConcurrentRun>
#include "LegacyInstance.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "LegacyModList.h"
#include "classparser.h"
LegacyUpgradeTask::LegacyUpgradeTask(InstancePtr origInstance)
{
m_origInstance = origInstance;
}
void LegacyUpgradeTask::executeTask()
{
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
folderCopy.followSymlinks(true);
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), folderCopy);
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &LegacyUpgradeTask::copyFinished);
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &LegacyUpgradeTask::copyAborted);
m_copyFutureWatcher.setFuture(m_copyFuture);
}
static QString decideVersion(const QString& currentVersion, const QString& intendedVersion)
{
if(intendedVersion != currentVersion)
{
if(!intendedVersion.isEmpty())
{
return intendedVersion;
}
else if(!currentVersion.isEmpty())
{
return currentVersion;
}
}
else
{
if(!intendedVersion.isEmpty())
{
return intendedVersion;
}
}
return QString();
}
void LegacyUpgradeTask::copyFinished()
{
auto successful = m_copyFuture.result();
if(!successful)
{
emitFailed(tr("Instance folder copy failed."));
return;
}
auto legacyInst = std::dynamic_pointer_cast<LegacyInstance>(m_origInstance);
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
// NOTE: this scope ensures the instance is fully saved before we emitSucceeded
{
MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath);
inst.setName(m_instName);
QString preferredVersionNumber = decideVersion(legacyInst->currentVersionId(), legacyInst->intendedVersionId());
if(preferredVersionNumber.isNull())
{
// try to decide version based on the jar(s?)
preferredVersionNumber = classparser::GetMinecraftJarVersion(legacyInst->baseJar());
if(preferredVersionNumber.isNull())
{
preferredVersionNumber = classparser::GetMinecraftJarVersion(legacyInst->runnableJar());
if(preferredVersionNumber.isNull())
{
emitFailed(tr("Could not decide Minecraft version."));
return;
}
}
}
auto components = inst.getPackProfile();
components->buildingFromScratch();
components->setComponentVersion("net.minecraft", preferredVersionNumber, true);
QString jarPath = legacyInst->mainJarToPreserve();
if(!jarPath.isNull())
{
qDebug() << "Preserving base jar! : " << jarPath;
// FIXME: handle case when the jar is unreadable?
// TODO: check the hash, if it's the same as the upstream jar, do not do this
components->installCustomJar(jarPath);
}
auto jarMods = legacyInst->jarModList()->allMods();
for(auto & jarMod: jarMods)
{
QString modPath = jarMod.absoluteFilePath();
qDebug() << "jarMod: " << modPath;
components->installJarMods({modPath});
}
// remove all the extra garbage we no longer need
auto removeAll = [&](const QString &root, const QStringList &things)
{
for(auto &thing : things)
{
auto removePath = FS::PathCombine(root, thing);
QFileInfo stat(removePath);
if(stat.isDir())
{
FS::deletePath(removePath);
}
else
{
QFile::remove(removePath);
}
}
};
QStringList rootRemovables = {"modlist", "version", "instMods"};
QStringList mcRemovables = {"bin", "MultiMCLauncher.jar", "icon.png"};
removeAll(inst.instanceRoot(), rootRemovables);
removeAll(inst.gameRoot(), mcRemovables);
}
emitSucceeded();
}
void LegacyUpgradeTask::copyAborted()
{
emitFailed(tr("Instance folder copy has been aborted."));
return;
}

View File

@ -1,29 +0,0 @@
#pragma once
#include "InstanceTask.h"
#include "net/NetJob.h"
#include <QUrl>
#include <QFuture>
#include <QFutureWatcher>
#include "settings/SettingsObject.h"
#include "BaseVersion.h"
#include "BaseInstance.h"
class LegacyUpgradeTask : public InstanceTask
{
Q_OBJECT
public:
explicit LegacyUpgradeTask(InstancePtr origInstance);
protected:
//! Entry point for tasks.
virtual void executeTask() override;
void copyFinished();
void copyAborted();
private: /* data */
InstancePtr m_origInstance;
QFuture<bool> m_copyFuture;
QFutureWatcher<bool> m_copyFutureWatcher;
};

View File

@ -4,8 +4,8 @@
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <quazip.h>
#include <quazipfile.h>
#include <quazip/quazip.h>
#include <quazip/quazipfile.h>
#include <toml.h>
#include "settings/INIFile.h"

View File

@ -19,7 +19,7 @@
#include <QtConcurrent/QtConcurrent>
#include <quazip.h>
#include <quazip/quazip.h>
#include "MMCZip.h"
#include "minecraft/OneSixVersionFormat.h"
@ -720,8 +720,6 @@ void PackInstallTask::install()
auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(instanceConfigPath);
instanceSettings->suspendSave();
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
auto components = instance.getPackProfile();

View File

@ -0,0 +1,101 @@
#include <QObject>
#include "FlameModIndex.h"
#include "Json.h"
#include "net/NetJob.h"
#include "BaseInstance.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
void FlameMod::loadIndexedPack(FlameMod::IndexedPack & pack, QJsonObject & obj)
{
pack.addonId = Json::requireInteger(obj, "id");
pack.name = Json::requireString(obj, "name");
pack.websiteUrl = Json::ensureString(obj, "websiteUrl", "");
pack.description = Json::ensureString(obj, "summary", "");
bool thumbnailFound = false;
auto attachments = Json::requireArray(obj, "attachments");
for(auto attachmentRaw: attachments) {
auto attachmentObj = Json::requireObject(attachmentRaw);
bool isDefault = attachmentObj.value("isDefault").toBool(false);
if(isDefault) {
thumbnailFound = true;
pack.logoName = Json::requireString(attachmentObj, "title");
pack.logoUrl = Json::requireString(attachmentObj, "thumbnailUrl");
break;
}
}
if(!thumbnailFound) {
throw JSONValidationError(QString("Pack without an icon, skipping: %1").arg(pack.name));
}
auto authors = Json::requireArray(obj, "authors");
for(auto authorIter: authors) {
auto author = Json::requireObject(authorIter);
FlameMod::ModpackAuthor packAuthor;
packAuthor.name = Json::requireString(author, "name");
packAuthor.url = Json::requireString(author, "url");
pack.authors.append(packAuthor);
}
}
void FlameMod::loadIndexedPackVersions(FlameMod::IndexedPack & pack, QJsonArray & arr, const shared_qobject_ptr<QNetworkAccessManager>& network, BaseInstance * inst)
{
QVector<FlameMod::IndexedVersion> unsortedVersions;
bool hasFabric = !((MinecraftInstance *)inst)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty();
QString mcVersion = ((MinecraftInstance *)inst)->getPackProfile()->getComponentVersion("net.minecraft");
for(auto versionIter: arr) {
auto obj = versionIter.toObject();
auto versionArray = Json::requireArray(obj, "gameVersion");
if (versionArray.isEmpty()) {
continue;
}
FlameMod::IndexedVersion file;
for(auto mcVer : versionArray){
file.mcVersion.append(mcVer.toString());
}
file.addonId = pack.addonId;
file.fileId = Json::requireInteger(obj, "id");
file.date = Json::requireString(obj, "fileDate");
file.version = Json::requireString(obj, "displayName");
file.downloadUrl = Json::requireString(obj, "downloadUrl");
file.fileName = Json::requireString(obj, "fileName");
auto modules = Json::requireArray(obj, "modules");
bool is_valid_fabric_version = false;
for(auto m : modules){
auto fname = Json::requireString(m.toObject(),"foldername");
// FIXME: This does not work properly when a mod supports more than one mod loader, since
// they bundle the meta files for all of them in the same arquive, even when that version
// doesn't support the given mod loader.
if(hasFabric){
if(fname == "fabric.mod.json"){
is_valid_fabric_version = true;
break;
}
}
else break;
// NOTE: Since we're not validating forge versions, we can just skip this loop.
}
if(hasFabric && !is_valid_fabric_version)
continue;
unsortedVersions.append(file);
}
auto orderSortPredicate = [](const IndexedVersion & a, const IndexedVersion & b) -> bool
{
//dates are in RFC 3339 format
return a.date > b.date;
};
std::sort(unsortedVersions.begin(), unsortedVersions.end(), orderSortPredicate);
pack.versions = unsortedVersions;
pack.versionsLoaded = true;
}

View File

@ -0,0 +1,50 @@
//
// Created by timoreo on 16/01/2022.
//
#pragma once
#include <QList>
#include <QMetaType>
#include <QString>
#include <QVector>
#include <QNetworkAccessManager>
#include <QObjectPtr.h>
#include "net/NetJob.h"
#include "BaseInstance.h"
namespace FlameMod {
struct ModpackAuthor {
QString name;
QString url;
};
struct IndexedVersion {
int addonId;
int fileId;
QString version;
QVector<QString> mcVersion;
QString downloadUrl;
QString date;
QString fileName;
};
struct IndexedPack
{
int addonId;
QString name;
QString description;
QList<ModpackAuthor> authors;
QString logoName;
QString logoUrl;
QString websiteUrl;
bool versionsLoaded = false;
QVector<IndexedVersion> versions;
};
void loadIndexedPack(IndexedPack & m, QJsonObject & obj);
void loadIndexedPackVersions(IndexedPack &pack, QJsonArray &arr, const shared_qobject_ptr<QNetworkAccessManager> &network, BaseInstance *inst);
}
Q_DECLARE_METATYPE(FlameMod::IndexedPack)

View File

@ -122,8 +122,6 @@ void PackInstallTask::install()
QString instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(instanceConfigPath);
instanceSettings->suspendSave();
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
auto components = instance.getPackProfile();

View File

@ -1,8 +1,8 @@
#pragma once
#include "InstanceTask.h"
#include "net/NetJob.h"
#include "quazip.h"
#include "quazipdir.h"
#include <quazip/quazip.h>
#include <quazip/quazipdir.h>
#include "meta/Index.h"
#include "meta/Version.h"
#include "meta/VersionList.h"

View File

@ -181,8 +181,6 @@ void PackInstallTask::install()
auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(instanceConfigPath);
instanceSettings->suspendSave();
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
auto components = instance.getPackProfile();

View File

@ -0,0 +1,95 @@
#include <QObject>
#include "ModrinthPackIndex.h"
#include "Json.h"
#include "net/NetJob.h"
#include "BaseInstance.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
void Modrinth::loadIndexedPack(Modrinth::IndexedPack & pack, QJsonObject & obj)
{
pack.addonId = Json::requireString(obj, "project_id");
pack.name = Json::requireString(obj, "title");
pack.websiteUrl = Json::ensureString(obj, "page_url", "");
pack.description = Json::ensureString(obj, "description", "");
pack.logoUrl = Json::requireString(obj, "icon_url");
pack.logoName = pack.addonId;
Modrinth::ModpackAuthor modAuthor;
modAuthor.name = Json::requireString(obj, "author");
modAuthor.url = "https://modrinth.com/user/"+modAuthor.name;
pack.author = modAuthor;
}
void Modrinth::loadIndexedPackVersions(Modrinth::IndexedPack & pack, QJsonArray & arr, const shared_qobject_ptr<QNetworkAccessManager>& network, BaseInstance * inst)
{
QVector<Modrinth::IndexedVersion> unsortedVersions;
bool hasFabric = !((MinecraftInstance *)inst)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty();
QString mcVersion = ((MinecraftInstance *)inst)->getPackProfile()->getComponentVersion("net.minecraft");
for(auto versionIter: arr) {
auto obj = versionIter.toObject();
Modrinth::IndexedVersion file;
file.addonId = Json::requireString(obj,"project_id") ;
file.fileId = Json::requireString(obj, "id");
file.date = Json::requireString(obj, "date_published");
auto versionArray = Json::requireArray(obj, "game_versions");
if (versionArray.empty()) {
continue;
}
for(auto mcVer : versionArray){
file.mcVersion.append(mcVer.toString());
}
auto loaders = Json::requireArray(obj,"loaders");
for(auto loader : loaders){
file.loaders.append(loader.toString());
}
file.version = Json::requireString(obj, "name");
auto files = Json::requireArray(obj, "files");
int i = 0;
while (files.count() > 1 && i < files.count()){
//try to resolve the correct file
auto parent = files[i].toObject();
auto fileName = Json::requireString(parent, "filename");
//avoid grabbing "dev" files
if(fileName.contains("javadocs",Qt::CaseInsensitive) || fileName.contains("sources",Qt::CaseInsensitive)){
i++;
continue;
}
//grab the correct mod loader
if(fileName.contains("forge",Qt::CaseInsensitive) || fileName.contains("fabric",Qt::CaseInsensitive) ){
if(hasFabric){
if(fileName.contains("forge",Qt::CaseInsensitive)){
i++;
continue;
}
}else{
if(fileName.contains("fabric",Qt::CaseInsensitive)){
i++;
continue;
}
}
}
break;
}
auto parent = files[i].toObject();
if(parent.contains("url")) {
file.downloadUrl = Json::requireString(parent, "url");
file.fileName = Json::requireString(parent, "filename");
unsortedVersions.append(file);
}
}
auto orderSortPredicate = [](const IndexedVersion & a, const IndexedVersion & b) -> bool
{
//dates are in RFC 3339 format
return a.date > b.date;
};
std::sort(unsortedVersions.begin(), unsortedVersions.end(), orderSortPredicate);
pack.versions = unsortedVersions;
pack.versionsLoaded = true;
}

View File

@ -0,0 +1,48 @@
#pragma once
#include <QList>
#include <QMetaType>
#include <QString>
#include <QVector>
#include <QNetworkAccessManager>
#include <QObjectPtr.h>
#include "net/NetJob.h"
#include "BaseInstance.h"
namespace Modrinth {
struct ModpackAuthor {
QString name;
QString url;
};
struct IndexedVersion {
QString addonId;
QString fileId;
QString version;
QVector<QString> mcVersion;
QString downloadUrl;
QString date;
QString fileName;
QVector<QString> loaders;
};
struct IndexedPack
{
QString addonId;
QString name;
QString description;
ModpackAuthor author;
QString logoName;
QString logoUrl;
QString websiteUrl;
bool versionsLoaded = false;
QVector<IndexedVersion> versions;
};
void loadIndexedPack(IndexedPack & m, QJsonObject & obj);
void loadIndexedPackVersions(IndexedPack &pack, QJsonArray &arr, const shared_qobject_ptr<QNetworkAccessManager> &network, BaseInstance *inst);
}
Q_DECLARE_METATYPE(Modrinth::IndexedPack)

View File

@ -18,7 +18,7 @@
#include "InstanceTask.h"
#include "net/NetJob.h"
#include "quazip.h"
#include <quazip/quazip.h>
#include <QFutureWatcher>
#include <QStringList>

View File

@ -19,9 +19,9 @@
#include <Json.h>
#include <minecraft/MinecraftInstance.h>
#include <minecraft/PackProfile.h>
#include <quazip.h>
#include <quazipdir.h>
#include <quazipfile.h>
#include <quazip/quazip.h>
#include <quazip/quazipdir.h>
#include <quazip/quazipfile.h>
#include <settings/INISettingsObject.h>
#include <memory>
@ -31,8 +31,6 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings, const
QString minecraftPath = FS::PathCombine(stagingPath, ".minecraft");
QString configPath = FS::PathCombine(stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(globalSettings, instanceSettings, stagingPath);
instance.setName(instName);

View File

@ -8,44 +8,34 @@
#include <QJsonDocument>
#include <QFile>
PasteUpload::PasteUpload(QWidget *window, QString text, QString key) : m_window(window)
PasteUpload::PasteUpload(QWidget *window, QString text, QString url) : m_window(window), m_uploadUrl(url), m_text(text.toUtf8())
{
m_key = key;
QByteArray temp;
QJsonObject topLevelObj;
QJsonObject sectionObject;
sectionObject.insert("contents", text);
QJsonArray sectionArray;
sectionArray.append(sectionObject);
topLevelObj.insert("description", "Log Upload");
topLevelObj.insert("sections", sectionArray);
QJsonDocument docOut;
docOut.setObject(topLevelObj);
m_jsonContent = docOut.toJson();
}
PasteUpload::~PasteUpload()
{
}
bool PasteUpload::validateText()
{
return m_jsonContent.size() <= maxSize();
}
void PasteUpload::executeTask()
{
QNetworkRequest request(QUrl("https://api.paste.ee/v1/pastes"));
QNetworkRequest request{QUrl(m_uploadUrl)};
request.setHeader(QNetworkRequest::UserAgentHeader, BuildConfig.USER_AGENT_UNCACHED);
request.setRawHeader("Content-Type", "application/json");
request.setRawHeader("Content-Length", QByteArray::number(m_jsonContent.size()));
request.setRawHeader("X-Auth-Token", m_key.toStdString().c_str());
QHttpMultiPart *multiPart = new QHttpMultiPart{QHttpMultiPart::FormDataType};
QNetworkReply *rep = APPLICATION->network()->post(request, m_jsonContent);
QHttpPart filePart;
filePart.setBody(m_text);
filePart.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");
filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"file\"; filename=\"log.txt\"");
multiPart->append(filePart);
QNetworkReply *rep = APPLICATION->network()->post(request, multiPart);
multiPart->setParent(rep);
m_reply = std::shared_ptr<QNetworkReply>(rep);
setStatus(tr("Uploading to paste.ee"));
setStatus(tr("Uploading to %1").arg(m_uploadUrl));
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
@ -61,45 +51,23 @@ void PasteUpload::downloadError(QNetworkReply::NetworkError error)
void PasteUpload::downloadFinished()
{
QByteArray data = m_reply->readAll();
// if the download succeeded
if (m_reply->error() == QNetworkReply::NetworkError::NoError)
int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (m_reply->error() != QNetworkReply::NetworkError::NoError)
{
m_reply.reset();
QJsonParseError jsonError;
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
if (jsonError.error != QJsonParseError::NoError)
{
emitFailed(jsonError.errorString());
return;
}
if (!parseResult(doc))
{
emitFailed(tr("paste.ee returned an error. Please consult the logs for more information"));
return;
}
}
// else the download failed
else
{
emitFailed(QString("Network error: %1").arg(m_reply->errorString()));
emitFailed(tr("Network error: %1").arg(m_reply->errorString()));
m_reply.reset();
return;
}
else if (statusCode != 200 && statusCode != 201)
{
QString reasonPhrase = m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
emitFailed(tr("Error: %1 returned unexpected status code %2 %3").arg(m_uploadUrl).arg(statusCode).arg(reasonPhrase));
qCritical() << m_uploadUrl << " returned unexpected status code " << statusCode << " with body: " << data;
m_reply.reset();
return;
}
m_pasteLink = QString::fromUtf8(data).trimmed();
emitSucceeded();
}
bool PasteUpload::parseResult(QJsonDocument doc)
{
auto object = doc.object();
auto status = object.value("success").toBool();
if (!status)
{
qCritical() << "paste.ee reported error:" << QString(object.value("error").toString());
return false;
}
m_pasteLink = object.value("link").toString();
m_pasteID = object.value("id").toString();
qDebug() << m_pasteLink;
return true;
}

View File

@ -8,37 +8,21 @@ class PasteUpload : public Task
{
Q_OBJECT
public:
PasteUpload(QWidget *window, QString text, QString key = "public");
PasteUpload(QWidget *window, QString text, QString url);
virtual ~PasteUpload();
QString pasteLink()
{
return m_pasteLink;
}
QString pasteID()
{
return m_pasteID;
}
int maxSize()
{
// 2MB for paste.ee - public
if(m_key == "public")
return 1024*1024*2;
// 12MB for paste.ee - with actual key
return 1024*1024*12;
}
bool validateText();
protected:
virtual void executeTask();
private:
bool parseResult(QJsonDocument doc);
QString m_error;
QWidget *m_window;
QString m_pasteID;
QString m_pasteLink;
QString m_key;
QByteArray m_jsonContent;
QString m_uploadUrl;
QByteArray m_text;
std::shared_ptr<QNetworkReply> m_reply;
public
slots:

View File

@ -70,7 +70,7 @@ void NewsChecker::rssDownloadFinished()
}
// If the parsing succeeded, read it.
QDomNodeList items = doc.elementsByTagName("item");
QDomNodeList items = doc.elementsByTagName("entry");
m_newsEntries.clear();
for (int i = 0; i < items.length(); i++)
{

View File

@ -24,18 +24,14 @@ NewsEntry::NewsEntry(QObject* parent) :
this->title = tr("Untitled");
this->content = tr("No content.");
this->link = "";
this->author = tr("Unknown Author");
this->pubDate = QDateTime::currentDateTime();
}
NewsEntry::NewsEntry(const QString& title, const QString& content, const QString& link, const QString& author, const QDateTime& pubDate, QObject* parent) :
NewsEntry::NewsEntry(const QString& title, const QString& content, const QString& link, QObject* parent) :
QObject(parent)
{
this->title = title;
this->content = content;
this->link = link;
this->author = author;
this->pubDate = pubDate;
}
/*!
@ -59,19 +55,11 @@ bool NewsEntry::fromXmlElement(const QDomElement& element, NewsEntry* entry, QSt
{
QString title = childValue(element, "title", tr("Untitled"));
QString content = childValue(element, "description", tr("No content."));
QString link = childValue(element, "link");
QString author = childValue(element, "dc:creator", tr("Unknown Author"));
QString pubDateStr = childValue(element, "pubDate");
// FIXME: For now, we're just ignoring timezones. We assume that all time zones in the RSS feed are the same.
QString dateFormat("ddd, dd MMM yyyy hh:mm:ss");
QDateTime pubDate = QDateTime::fromString(pubDateStr, dateFormat);
QString link = childValue(element, "id");
entry->title = title;
entry->content = content;
entry->link = link;
entry->author = author;
entry->pubDate = pubDate;
return true;
}

View File

@ -18,8 +18,6 @@
#include <QObject>
#include <QString>
#include <QDomElement>
#include <QDateTime>
#include <memory>
class NewsEntry : public QObject
@ -36,7 +34,7 @@ public:
* Constructs a new news entry.
* Note that content may contain HTML.
*/
NewsEntry(const QString& title, const QString& content, const QString& link, const QString& author, const QDateTime& pubDate, QObject* parent=0);
NewsEntry(const QString& title, const QString& content, const QString& link, QObject* parent=0);
/*!
* Attempts to load information from the given XML element into the given news entry pointer.
@ -53,12 +51,6 @@ public:
//! URL to the post.
QString link;
//! The post's author.
QString author;
//! The date and time that this post was published.
QDateTime pubDate;
};
typedef std::shared_ptr<NewsEntry> NewsEntryPtr;

View File

@ -44,7 +44,7 @@ void NotificationChecker::checkForNotifications()
if (!m_notificationsUrl.isValid())
{
qCritical() << "Failed to check for notifications. No notifications URL set."
<< "If you'd like to use MultiMC's notification system, please pass the "
<< "If you'd like to use PolyMC's notification system, please pass the "
"URL to CMake at compile time.";
return;
}

View File

@ -23,7 +23,6 @@
<file>scalable/new.svg</file>
<file>scalable/news.svg</file>
<file>scalable/notes.svg</file>
<file>scalable/patreon.svg</file>
<file>scalable/proxy.svg</file>
<file>scalable/refresh.svg</file>
<file>scalable/resourcepacks.svg</file>

View File

@ -1,18 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<rect fill="none" width="24" height="24"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#E6E6E6" d="M22,6c0-0.6-0.4-1-1-1H9C8.4,5,8,5.4,8,6v12c0,0.6,0.4,1,1,1h12
c0.6,0,1-0.4,1-1V6z"/>
<polygon fill="#FFFFFF" points="12.5,8.1 12.5,15.9 18.6,12 "/>
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#585858" d="M21,20H9c-1.1,0-2-0.9-2-2V6c0-1.1,0.9-2,2-2h12c1.1,0,2,0.9,2,2
v12C23,19.1,22.1,20,21,20z M22,6c0-0.6-0.4-1-1-1H9C8.4,5,8,5.4,8,6v12c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1V6z"/>
<g>
<path fill="#585858" d="M12.3,17c-0.4,0-0.8-0.3-0.8-0.9V7.9c0-0.6,0.4-0.9,0.8-0.9c0.2,0,0.4,0.1,0.5,0.2l6.5,4.1
c0.3,0.2,0.4,0.4,0.4,0.7s-0.2,0.6-0.4,0.7l-6.5,4.1C12.7,16.9,12.5,17,12.3,17z M12.5,8.1l0,7.7l6.1-3.9L12.5,8.1z"/>
</g>
</g>
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="linearGradient84726" x1="4.4979" x2="12.435" y1="3.8011" y2="9.5681" gradientUnits="userSpaceOnUse">
<stop stop-color="#88b858" offset="0"/>
<stop stop-color="#72b147" offset=".5"/>
<stop stop-color="#5a9a30" offset="1"/>
</linearGradient>
</defs>
<g>
<path d="m3.561 16.016s0-3.5642 4.9056-3.5642c4.9069 0 4.9056 3.5642 4.9056 3.5642z" fill="#765338"/>
<path d="m8.4667 12.452-4.9056 3.5642-3.0319-9.3311z" fill="#b7835a"/>
<path d="m8.4667 12.452 7.9375-5.7669-3.0319 9.3311z" fill="#5b422d"/>
<path d="m8.8308 12.716-0.36417 0.26458-0.36417-0.26458c0-0.26458 0.36417-0.26458 0.36417-0.26458s0.36417 0 0.36417 0.26458z" fill="#72b147"/>
<path d="m8.4667 12.452s-2e-7 -5.7669 7.9375-5.7669l-0.22507 0.69269-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819z" fill="#5a9a30"/>
<path d="m8.1025 12.716-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.22507-0.69269c7.9375 1e-7 7.9375 5.7669 7.9375 5.7669z" fill="#88b858"/>
<path d="m0.52917 6.6846 7.9375 5.7669 7.9375-5.7669-7.9375-5.7669z" fill="url(#linearGradient84726)"/>
</g>
<path d="m0.75424 7.3773-0.22507-0.69269 7.9375 5.7669 7.9375-5.7669-0.22507 0.69269-7.7124 5.6034z" fill-opacity="0"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -26,7 +26,6 @@
<file>scalable/news.svg</file>
<file>scalable/notes.svg</file>
<file>scalable/packages.svg</file>
<file>scalable/patreon.svg</file>
<file>scalable/proxy.svg</file>
<file>scalable/quickmods.svg</file>
<file>scalable/reddit-alien.svg</file>

View File

@ -1,2 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24" height="24" fill="#757575" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m20 4h-16v16h16zm0 18h-16c-1.1046 0-2-0.89543-2-2v-16c0-1.1046 0.89543-2 2-2h16c1.1046 0 2 0.89543 2 2v16c0 1.1046-0.89543 2-2 2z"/><path d="m7.2 18c-0.225 0-0.45-0.075-0.6-0.15-0.375-0.225-0.6-0.6-0.6-1.05v-9.6c0-0.45 0.225-0.825 0.6-1.05 0.225-0.15 0.375-0.15 0.6-0.15 0.15 0 0.375 0.075 0.525 0.15l9.6 4.8c0.375 0.225 0.675 0.6 0.675 1.05 0 0.45-0.225 0.9-0.675 1.05l-9.6 4.8c-0.15 0.075-0.375 0.15-0.525 0.15z" clip-rule="evenodd" fill="#757575" fill-rule="evenodd" stroke-width=".99999"/></svg>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="linearGradient84726" x1="4.4979" x2="12.435" y1="3.8011" y2="9.5681" gradientUnits="userSpaceOnUse">
<stop stop-color="#88b858" offset="0"/>
<stop stop-color="#72b147" offset=".5"/>
<stop stop-color="#5a9a30" offset="1"/>
</linearGradient>
</defs>
<g>
<path d="m3.561 16.016s0-3.5642 4.9056-3.5642c4.9069 0 4.9056 3.5642 4.9056 3.5642z" fill="#765338"/>
<path d="m8.4667 12.452-4.9056 3.5642-3.0319-9.3311z" fill="#b7835a"/>
<path d="m8.4667 12.452 7.9375-5.7669-3.0319 9.3311z" fill="#5b422d"/>
<path d="m8.8308 12.716-0.36417 0.26458-0.36417-0.26458c0-0.26458 0.36417-0.26458 0.36417-0.26458s0.36417 0 0.36417 0.26458z" fill="#72b147"/>
<path d="m8.4667 12.452s-2e-7 -5.7669 7.9375-5.7669l-0.22507 0.69269-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819z" fill="#5a9a30"/>
<path d="m8.1025 12.716-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.22507-0.69269c7.9375 1e-7 7.9375 5.7669 7.9375 5.7669z" fill="#88b858"/>
<path d="m0.52917 6.6846 7.9375 5.7669 7.9375-5.7669-7.9375-5.7669z" fill="url(#linearGradient84726)"/>
</g>
<path d="m0.75424 7.3773-0.22507-0.69269 7.9375 5.7669 7.9375-5.7669-0.22507 0.69269-7.7124 5.6034z" fill-opacity="0"/>
</svg>

Before

Width:  |  Height:  |  Size: 660 B

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -23,7 +23,6 @@
<file>scalable/new.svg</file>
<file>scalable/news.svg</file>
<file>scalable/notes.svg</file>
<file>scalable/patreon.svg</file>
<file>scalable/proxy.svg</file>
<file>scalable/refresh.svg</file>
<file>scalable/resourcepacks.svg</file>

View File

@ -1,14 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#3366CC" d="M28,32H4c-2.2,0-4-1.8-4-4V4c0-2.2,1.8-4,4-4h24c2.2,0,4,1.8,4,4
v24C32,30.2,30.2,32,28,32z M30,4c0-1.1-0.9-2-2-2H4C2.9,2,2,2.9,2,4v24c0,1.1,0.9,2,2,2h24c1.1,0,2-0.9,2-2V4z"/>
<g>
<path fill="#3366CC" d="M10.6,26C9.8,26,9,25.4,9,24.2V7.8C9,6.6,9.8,6,10.6,6c0.4,0,0.7,0.1,1.1,0.3l13,8.2
c0.6,0.3,0.9,0.9,0.9,1.5s-0.3,1.1-0.9,1.5l-13,8.2C11.3,25.9,10.9,26,10.6,26z M11,8.3l0,15.4L23.2,16L11,8.3z"/>
</g>
</g>
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="linearGradient84726" x1="4.4979" x2="12.435" y1="3.8011" y2="9.5681" gradientUnits="userSpaceOnUse">
<stop stop-color="#88b858" offset="0"/>
<stop stop-color="#72b147" offset=".5"/>
<stop stop-color="#5a9a30" offset="1"/>
</linearGradient>
</defs>
<g>
<path d="m3.561 16.016s0-3.5642 4.9056-3.5642c4.9069 0 4.9056 3.5642 4.9056 3.5642z" fill="#765338"/>
<path d="m8.4667 12.452-4.9056 3.5642-3.0319-9.3311z" fill="#b7835a"/>
<path d="m8.4667 12.452 7.9375-5.7669-3.0319 9.3311z" fill="#5b422d"/>
<path d="m8.8308 12.716-0.36417 0.26458-0.36417-0.26458c0-0.26458 0.36417-0.26458 0.36417-0.26458s0.36417 0 0.36417 0.26458z" fill="#72b147"/>
<path d="m8.4667 12.452s-2e-7 -5.7669 7.9375-5.7669l-0.22507 0.69269-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819z" fill="#5a9a30"/>
<path d="m8.1025 12.716-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.22507-0.69269c7.9375 1e-7 7.9375 5.7669 7.9375 5.7669z" fill="#88b858"/>
<path d="m0.52917 6.6846 7.9375 5.7669 7.9375-5.7669-7.9375-5.7669z" fill="url(#linearGradient84726)"/>
</g>
<path d="m0.75424 7.3773-0.22507-0.69269 7.9375 5.7669 7.9375-5.7669-0.22507 0.69269-7.7124 5.6034z" fill-opacity="0"/>
</svg>

Before

Width:  |  Height:  |  Size: 928 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

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