Compare commits

...

166 Commits

Author SHA1 Message Date
Petr Mrázek
e2378c79ff NOISSUE meow meow prototype 2020-02-08 15:01:53 +01:00
Petr Mrázek
08f85f1a93 Update changelog and set version to 0.6.8 2020-02-08 15:00:20 +01:00
Petr Mrázek
bc98181ec2 GH-2769 add an option to not copy play time when copying instances 2020-01-09 15:31:32 +01:00
Petr Mrázek
6a095deea6 GH-2832 add .minecraft and libraries buttons to version page 2020-01-09 13:45:46 +01:00
Petr Mrázek
355e5e24da GH-2819 mod list filter now also looks at descriptions and authors 2020-01-08 21:12:45 +01:00
Petr Mrázek
8bdff97ac0 GH-2839 remove username wording from login and account dialogs 2020-01-08 13:37:05 +01:00
Petr Mrázek
6288805f37 GH-2853 fix collapsing state being sticky in group view
Now it resets properly and collapsing a group doesn't make
all subsequent clicks collapse groups.
2020-01-08 09:00:54 +01:00
Petr Mrázek
0d157d86b5 NOISSUE add wget as a dependency for deb package 2020-01-08 06:28:42 +01:00
Petr Mrázek
f413e61cd8 NOISSUE Do not crash when dependencies are customized and conflict 2020-01-08 04:41:47 +01:00
Petr Mrázek
3581f5384f GH-2880 make services status widget open a valid page
https://help.mojang.com/ no longer has API status
2020-01-07 08:56:00 +01:00
Petr Mrázek
480b298635 NOISSUE Attempt to add build status and test teamcity build reporting 2019-11-27 00:35:42 +01:00
Petr Mrázek
b54b25231e Remove travis-ci and github actions leftovers 2019-11-26 21:09:37 +01:00
Petr Mrázek
43628556ed NOISSUE fix comment in Commandline.h 2019-11-26 19:06:45 +01:00
Petr Mrázek
b5adff14ab NOISSUE remove dead reference to TwitchPage.ui 2019-11-18 02:38:08 +01:00
Petr Mrázek
af5120c828 GH-2859 remove twitch page and modpack import from URL
The functionality was broken, beyond repair and an ongoing maintenance
nightmare.
2019-11-18 00:38:36 +01:00
Petr Mrázek
47ed2f48d4 NOISSUE put legacy FTB support in a namespace, fix its base URL 2019-11-03 23:48:12 +01:00
Petr Mrázek
0c9340a3d2 NOISSUE fix translation string for Twitch drop area 2019-10-14 23:51:36 +02:00
Petr Mrázek
9cc5ebcdd1 GH-2859 improve UI for twitch pack import with drag&drop 2019-10-14 02:31:53 +02:00
Petr Mrázek
c60647523e NOISSUE remove remains of what could have been technic integration 2019-10-14 01:05:38 +02:00
Petr Mrázek
9165232ba4 NOISSUE remove unused 'PackagesPage' 2019-10-13 22:31:14 +02:00
Petr Mrázek
31d0507e07 NOISSUE make the main window title only 'MultiMC' for screen readers 2019-10-05 22:51:55 +02:00
Petr Mrázek
cca766cfd9 Merge pull request #2871 from kb-1000/fix-accessibility-fix
Remove include of qtguiglobal.h
2019-10-01 16:15:45 +02:00
kb1000
0d41bc5e13 Remove include of qtguiglobal.h 2019-10-01 15:55:40 +02:00
Petr Mrázek
e27309d08a Merge pull request #2870 from kb-1000/fix-accessibility
Add checks for QT_NO_ACCESSIBILITY to prevent build issues with Qt without accessibility
2019-10-01 15:40:39 +02:00
kb1000
dec6759e61 Add checks for QT_NO_ACCESSIBILITY to prevent build issues with Qt without accessibility 2019-10-01 14:28:06 +02:00
Petr Mrázek
ce7917048a NOISSUE remove more html rom About dialog 2019-09-30 23:50:32 +02:00
Petr Mrázek
e6936212d6 NOISSUE remove some ugly html strings to make translating slightly nicer 2019-09-27 00:23:30 +02:00
Petr Mrázek
1210d3abf1 NOISSUE fix display of european portuguese in language lists 2019-09-27 00:23:03 +02:00
Petr Mrázek
ffe84d6ec7 NOISSUE remove some dead things 2019-09-26 20:08:47 +02:00
Petr Mrázek
19015de258 NOISSUE correct some parts of the README, one more translation string change 2019-09-26 09:03:25 +02:00
Petr Mrázek
5c0c26cd25 TRANSLATIONS-82 fix typos: resove -> resolve 2019-09-25 22:31:09 +02:00
Petr Mrázek
4cc7427eb4 TRANSLATIONS-73 remove some strings that don't show up in the UI 2019-09-25 22:29:50 +02:00
Petr Mrázek
6531aaa7bc Try using github actions
Let's see how badly this goes
2019-09-19 10:56:11 +02:00
Petr Mrázek
a35a2e877e NOISSUE remove nonsensical logic related to 'MultiMC.app/' prefixes in update manifests 2019-09-19 01:13:02 +02:00
Petr Mrázek
4e93c4d012 NOISSUE escape tcversion more 2019-09-17 01:26:37 +02:00
Petr Mrázek
7bb23b4142 NOISSUE add some escaping to make the tc version print actually do something 2019-09-17 01:22:00 +02:00
Petr Mrázek
b420f4bafb Merge pull request #2849 from AshleighTheCutie/develop
Message cleanup
2019-09-17 01:12:45 +02:00
Petr Mrázek
0e0a017175 NOISSUE add a way to extract the version into a TC variable 2019-09-17 00:53:30 +02:00
Ashleigh
137fe7e3c0 Cleaned up messages, made some more descriptive, made some nicer. 2019-09-14 22:31:13 -05:00
Ashleigh
9689e5cea7 Added text notifying that password change may cause logout 2019-09-14 22:12:23 -05:00
Petr Mrázek
1ede75aa79 Merge pull request #2848 from AshleighTheCutie/develop
Window Size to 800x600
2019-09-15 04:34:03 +02:00
Ashleigh
9ee3a84817 Window Size to 800x600 2019-09-14 21:15:51 -05:00
Petr Mrázek
8750ca8b36 NOISSUE add bee icon 2019-08-26 02:25:42 +02:00
Petr Mrázek
1747f413b9 GH-851 save, load and use group expansion status 2019-08-20 02:58:27 +02:00
Petr Mrázek
6d975748c0 Merge pull request #2796 from QuImUfu/bug_fix
GH-2787 fix "Download All" button
2019-08-14 22:12:58 +02:00
Petr Mrázek
b050c7c075 Merge pull request #2803 from kb-1000/escape-semicolon
Escape ; too in instance folder names
2019-08-14 22:12:39 +02:00
Kaeptm Blaubaer
84e0cb1daa Escape ; too in instance folder names 2019-08-13 07:39:00 +02:00
Petr Mrázek
5074a97cb3 NOISSUE tweak toolbar and custom widget titles for better translations 2019-08-10 20:12:42 +02:00
Petr Mrázek
441e8980b8 NOISSUE fix small memory leaks 2019-08-10 19:58:58 +02:00
Johannes Michael Andreas Merl
84c53273ce GH-2787 fix "Download All" button 2019-08-09 00:11:42 +02:00
Petr Mrázek
c291946d2a NOISSUE do not lose selection on mod enable/disable toggle 2019-08-05 00:46:59 +02:00
Petr Mrázek
dfb30d9139 NOISSUE warn users about MS Edge being bad 2019-08-04 21:14:59 +02:00
Petr Mrázek
4ed67413ac GH-988 add ability to toggle mods with keyboard 2019-08-04 21:13:50 +02:00
Petr Mrázek
d31184f9a4 GH-2738 check for being in the temp folder better 2019-08-04 18:11:55 +02:00
Petr Mrázek
b75ba53d4b GH-2785 fix crash caused by starting multiple mod folder update tasks 2019-08-04 11:12:19 +02:00
Petr Mrázek
9037873928 NOISSUE update changelog 2019-08-04 06:26:09 +02:00
Petr Mrázek
ce4a55bc3b NOISSUE fix listing of mods in log, improve display with unicode 2019-08-04 05:08:40 +02:00
Petr Mrázek
6b82e942d0 NOISSUE fix build on linux 2019-08-04 03:39:25 +02:00
Petr Mrázek
a3ffa3d665 NOISSUE asynchronous, parallel mod folder listing and mod resolving 2019-08-04 03:27:53 +02:00
Petr Mrázek
7d13e31198 NOISSUE refactor Mod a bunch, get rid of dead code 2019-08-03 05:30:46 +02:00
Petr Mrázek
40c9af1a8b NOISSUE remove dependency of legacy mod list on the Mod class 2019-08-03 03:12:48 +02:00
Petr Mrázek
f5f3149dcf NOISSUE update changelog and version 2019-08-03 00:48:34 +02:00
Petr Mrázek
7b00d47fe0 NOISSUE tweak UI geometry and remove old language selection 2019-08-02 23:52:19 +02:00
Petr Mrázek
930d39b5f2 GH-2550 soring of mods by enabled status, cascade sorting to name and version 2019-07-31 01:28:55 +02:00
Petr Mrázek
bafcf93eb1 NOISSUE fix bug with drag & drop not working with empty mod list 2019-07-31 01:27:35 +02:00
Petr Mrázek
bd93c3b4e0 NOISSUE fix build 2019-07-30 01:25:37 +02:00
Petr Mrázek
09f7a426ab GH-2722 GH-2762 Improve mod list sorting
Sorting by version understands version numbers
Sorting by name removes 'The' prefixes before sorting
2019-07-30 01:16:56 +02:00
Petr Mrázek
e4fd50e210 NOISSUE make the language translation prompt translateable 2019-07-30 01:16:02 +02:00
Petr Mrázek
3ee5a63c5c NOISSUE make notes page focusable with tab key 2019-07-25 01:13:47 +02:00
Petr Mrázek
7dfe73df0c NOISSUE add context menus to pages with toolbars 2019-07-25 01:02:30 +02:00
Petr Mrázek
c3e61536a3 NOISSUE automatically open the log page when starting the instance 2019-07-24 00:24:02 +02:00
Petr Mrázek
a0e45c5d1d NOISSUE fix build 2019-07-23 01:05:23 +02:00
Petr Mrázek
bf38021937 NOISSUE improve toolbars 2019-07-23 00:48:14 +02:00
Petr Mrázek
1e5b595923 NOISSUE fix build failures 2019-07-22 01:44:19 +02:00
Petr Mrázek
d6c6653872 NOISSUE Add basic accessibility support to GroupView 2019-07-22 01:40:52 +02:00
Petr Mrázek
3b32730526 Merge pull request #2758 from telans/patch-1
Fix translation repository link
2019-07-21 01:33:31 +02:00
telans
1703dbeb57 Fix translation repository link 2019-07-21 10:50:30 +12:00
Petr Mrázek
81fdde6fdd NOISSUE convert accounts page to use a toolbar for the side menu 2019-07-19 08:29:31 +02:00
Petr Mrázek
3d5869e1cf NOISSUE fix overly large margins in the instance settings page 2019-07-17 02:17:09 +02:00
Petr Mrázek
edc5378333 NOISSUE add spacer to the screenshot page toolbar 2019-07-17 02:09:54 +02:00
Petr Mrázek
95febe5436 NOISSUE convert rest of the instance pages to use toolbars for side menus 2019-07-17 02:01:29 +02:00
Petr Mrázek
5b153a5165 GH-2748 disable the version page toolbar labels 2019-07-16 08:58:00 +02:00
Petr Mrázek
decd4ae7ab NOISSUE Make mod folder pages use toolbars instead of button layouts 2019-07-16 01:30:53 +02:00
Petr Mrázek
2eec1df1a0 NOISSUE hide main toolbar toggle action instead of working around it 2019-07-16 01:30:09 +02:00
Petr Mrázek
6fde775b90 NOISSUE Show Version page while the instancer is running.
All controls are disabled.
2019-07-15 23:16:34 +02:00
Petr Mrázek
80b3efff11 NOISSUE Do not hide mods list pages when the instance is running.
Instead, disable (most of) the controls.
2019-07-15 01:07:21 +02:00
Petr Mrázek
e4273d6a17 GH-358 Make version page use a toolbar for all the actions
This should make it possible to make it fit on small screens again.
2019-07-14 05:37:10 +02:00
Petr Mrázek
62e1bf327d Merge pull request #2740 from jturnism/patch-1
Update changelog.md
2019-07-12 08:19:20 +02:00
Joseph Turner
280e0e6e36 Update changelog.md
Just installing "qt5-qtbase" on Fedora 30 does not allow MultiMC to run. It still needs "libQt5Widgets.so.5" and by running "dnf whatprovides" it tells me "qt5-qtbase-gui" provides that file and also pulls in "qt5-qtbase" as a dependency if not already installed. I am assuming this is the same situation for CentOS/RHEL
2019-07-11 21:00:55 -05:00
Petr Mrázek
3a67990acd NOISSUE bump deb package version 2019-07-11 01:28:48 +02:00
Petr Mrázek
23eab74e6d NOISSUE make the deb package depend on Qt5 2019-07-11 01:26:33 +02:00
Petr Mrázek
b9d4293552 NOISSUE update component buttons some more when the versions change 2019-07-11 01:01:47 +02:00
Petr Mrázek
5110b58def NOISSUE update version and changelog 2019-07-11 00:35:44 +02:00
Petr Mrázek
791a8227b6 NOISSUE disable component install buttons in impossible cases 2019-07-10 22:30:42 +02:00
Petr Mrázek
725ec35635 NOISSUE recognize curseforge URLs dropped on top of MultiMC 2019-07-09 22:04:52 +02:00
Petr Mrázek
739a86f171 Revert "NOISSUE Import page is now a MultiMC pack page"
This reverts commit f74e3db804.
2019-07-09 21:51:19 +02:00
Petr Mrázek
48b2f95129 Revert "NOISSUE simple/stupid default game options, UI only"
This reverts commit 497d9bec02.
2019-07-09 21:43:12 +02:00
Petr Mrázek
497d9bec02 NOISSUE simple/stupid default game options, UI only 2019-07-09 02:37:04 +02:00
Petr Mrázek
c01d020afc GH-2723 disable deprecation warnings
We are targeting version 5.4 of the Qt ABI.
Deprecations from 2019 are irrelevant.
2019-07-03 01:11:18 +02:00
Petr Mrázek
ee83d432f6 GH-2724 update group view geometries in more cases
Fixes crashes when adding instances to groups that didn't exist before.
2019-07-02 02:09:41 +02:00
Petr Mrázek
8ee11b1a8e GH-2716 do not censor values shorter than 4 in logs 2019-07-01 00:00:34 +02:00
Petr Mrázek
0b86a7ebf3 Merge pull request #2718 from therealfarfetchd/hidpi-icon-fix
Enable HiDPI pixmaps to fix icon scaling for HiDPI displays
2019-06-30 15:39:29 +02:00
Petr Mrázek
63330bf111 NOISSUE connect twitch URL resolving to modpack resolving. works now. 2019-06-30 11:03:59 +02:00
Petr Mrázek
f74e3db804 NOISSUE Import page is now a MultiMC pack page 2019-06-29 01:13:39 +02:00
therealfarfetchd
a55fa04353 Enable HiDPI pixmaps to fix icon scaling for HiDPI displays 2019-06-27 23:04:53 +02:00
Petr Mrázek
fde43c993e NOISSUE add silly twitch URL and CCIP resolving page to 'add instance'
It needs a few more steps and it will handle all kinds of twitch packs.
2019-06-27 03:20:11 +02:00
Petr Mrázek
917f148fc4 NOISSUE add support for 'experiment' Minecraft versions 2019-06-26 20:51:04 +02:00
Petr Mrázek
34611c00e3 Merge branch 'feature/update_translation_fix' into develop 2019-06-25 23:41:16 +02:00
Petr Mrázek
44a7c5867b Merge pull request #2703 from Janrupf/feature/apply_proxy_settings
GH-2499 Apply proxy settings immediately
2019-06-23 21:38:30 +02:00
Petr Mrázek
75ddbc8851 Merge pull request #2705 from Janrupf/feature/fix_external_deletion_interaction
GH-2515 Save instance ID before display dialog
2019-06-23 21:31:56 +02:00
Petr Mrázek
2f1d31cf43 Merge pull request #2706 from Janrupf/feature/fix_hashtag_in_notes
Feature/fix hashtag in notes
2019-06-23 21:19:10 +02:00
Petr Mrázek
e7c5b266c8 Merge pull request #2708 from Janrupf/feature/single_imgur_uploads
GH-689 Don't create album for single screenshot
2019-06-23 21:15:06 +02:00
Petr Mrázek
384979bf94 Merge pull request #2704 from Janrupf/feature/autoselect_new_instances
GH-2592 Autoselect newly created instances
2019-06-23 19:58:21 +02:00
janrupf
b5a16935b7 NOISSUE Renaming for better understanding 2019-06-23 14:54:17 +02:00
janrupf
320637e8dc GH-1701 Check job size for translation 2019-06-22 01:54:08 +02:00
janrupf
77f3f028fa GH-2499 Apply proxy settings immediately 2019-06-22 01:48:37 +02:00
janrupf
2a96e16902 GH-689 Don't create album for single screenshot 2019-06-22 01:47:07 +02:00
janrupf
1ed84eddd5 GH-2515 Save instance ID before display dialog 2019-06-21 23:55:16 +02:00
janrupf
7b52b8689b NOISSUE Test comment escaping with unit tests 2019-06-21 23:46:54 +02:00
janrupf
d21700ee91 NOISSUE Revert INI parser back to single pass 2019-06-21 23:46:54 +02:00
janrupf
f87c890912 GH-1813 Escape # in INI (and better reader) 2019-06-21 23:46:54 +02:00
janrupf
306b98edac GH-2592 Autoselect newly created instances 2019-06-21 22:38:26 +02:00
Petr Mrázek
ce12f1a734 Merge pull request #2694 from Janrupf/fix-disabled-mods
Operate on copy of QString instead of appending
2019-06-17 23:21:26 +02:00
janrupf
c1953739d9 NOISSUE Don't append .disabled to string 2019-06-17 15:49:26 +02:00
Petr Mrázek
e8bf9cef24 Merge branch 'develop' of https://github.com/lelandliu/MultiMC5 into develop 2019-06-15 22:47:36 +02:00
Petr Mrázek
8aa4b9dac5 NOISSUE limit fabric intermediary selection options in UI by minecraft version 2019-06-15 22:45:56 +02:00
Petr Mrázek
4836ba22cd NOISSUE fix fabric tooltip string 2019-06-15 22:29:34 +02:00
Petr Mrázek
6c30076b6c GH-2639 Add simple fabric loader installation support 2019-06-15 21:25:23 +02:00
Petr Mrázek
83c48a0f1a Merge pull request #2690 from asiekierka/fabric-modparse
Add Fabric mod JSON parsing support
2019-06-15 20:41:42 +02:00
asie
d251097545 fix author name parsing 2019-06-15 16:36:13 +02:00
asie
c35dbd972e Add Fabric mod JSON parsing support 2019-06-15 13:54:20 +02:00
Leland Liu
0c5d121452 Fixed adding a disabled duplicate 2019-06-14 15:48:24 -04:00
Petr Mrázek
53ad5cb436 Merge pull request #2684 from isoraqathedh/patch-1
Pass command line arguments through to the executable
2019-06-08 15:53:01 +02:00
isoraqathedh
d87bd4b588 Update run.sh
Pass command line arguments through to the executable
2019-06-08 21:21:22 +08:00
Petr Mrázek
86850ef5d0 NOISSUE fix macOS build, remove bundled dependencies on linux
Your copy of MultiMC might stop working after this update
because we no longer bundle Qt and other system libraries.

Contact us at https://discord.gg/0k2zsXGNHs0fE4Wm if
you need help with installing Qt.

Qt 5.4.x or newer is required.
2019-06-08 15:08:24 +02:00
Petr Mrázek
30fba4d407 NOISSUE make the global settings button context sensitive 2019-06-01 18:05:42 +02:00
Petr Mrázek
932160818e NOISSUE add option to open global settings from instance settings
This should hopefully giude people towards using the right thing.
2019-06-01 12:28:53 +02:00
Petr Mrázek
59e1ed3d87 NOISSUE add the pocket fox icon 2019-06-01 00:59:02 +02:00
Petr Mrázek
3470a3df96 NOISSUE improve icon handling while importing and exporting instances
Now it handles formats other than png.
2019-05-31 21:53:58 +02:00
Petr Mrázek
61913daaf3 Merge pull request #2603 from AlexTMjugador/develop
Support launching profiler in offline mode
2019-04-14 23:34:10 +02:00
Alejandro González
cb71dfa605 Tweak strings as per peterix review 2019-04-14 23:02:01 +02:00
AlexTMjugador
2be98baaba Conform to existing code style 2019-04-15 00:44:59 +02:00
AlexTMjugador
0ce637bf0e Support launching profiler in offline mode
This commit adds the necessary GUI controls to let the user choose
whether they want to launch Minecraft in offline mode with a configured profiler.
2019-04-15 00:42:06 +02:00
Petr Mrázek
70ed30f9e6 GH-2591 less std::shared_ptr and more shared_qobject_ptr
This eliminates some weird crashes.
2019-04-07 23:59:04 +02:00
Petr Mrázek
414946cad9 Merge remote-tracking branch 'origin/feature/trim_server_details' into develop 2019-04-02 23:39:13 +02:00
Elise
1fc199697c GH-2551 Trim at serialization 2019-03-29 11:25:37 -04:00
Petr Mrázek
9292d846b6 Merge pull request #2565 from MultiMC/feature/deletion_harder
GH-2487 Make deleting instances harder
2019-03-23 14:23:45 +01:00
Elise
22db95ce3b Merge branch 'develop' into feature/deletion_harder 2019-03-19 16:29:40 -04:00
Elise
597fe50d37 GH-2551 Trim server name and IP strings 2019-03-19 13:28:11 -04:00
Petr Mrázek
bf93ba02e9 NOISSUE fix metadata URL 2019-03-08 02:04:08 +01:00
Petr Mrázek
07c1685ff1 NOISSUE create translations folder before starting to watch it for changes
Fixes issue where on first run, the translations don't show up.
2019-03-08 01:21:04 +01:00
Elise
a5e531d4f1 GH-2487 Make NO the default button 2019-02-26 16:56:08 -05:00
Petr Mrázek
ae956d8fd6 NOISSUE update changelog 2019-02-21 00:45:36 +01:00
Petr Mrázek
73e487a31e NOISSUE hide the game options screen again 2019-02-21 00:44:36 +01:00
Petr Mrázek
0b95d2b03f NOISSUE fix build 2019-02-19 01:11:54 +01:00
Petr Mrázek
9c82adaee5 GH-2209 Fix sounds in old (pre-1.6) versions 2019-02-19 01:00:03 +01:00
Petr Mrázek
0a99d037c4 Merge pull request #2532 from andersmmg/patch-1
Update title of Add Empty dialog
2019-02-05 08:44:07 +01:00
Joshua Anderson
6e8e4c5dfa Update title of Add Empty dialog 2019-02-05 00:06:29 -07:00
Petr Mrázek
e4599ee2d1 NOISSUE fix builds? 2019-01-30 01:12:21 +01:00
Petr Mrázek
62c9fcdc6c NOISSUE first step towards having game options management 2019-01-30 00:35:24 +01:00
Petr Mrázek
c1ea42d3d9 Merge branch 'stable' of https://github.com/Scotsguy/MultiMC5 into develop 2019-01-17 00:51:54 +01:00
AppleTheGolden
437dec91f9 Update Copyright Year 2019-01-16 21:14:24 +01:00
Petr Mrázek
7436c94976 NOISSUE Replace Quality with Completeness in language widget
Completeness does no imply quality.
2019-01-14 01:36:04 +01:00
Petr Mrázek
c08053d8b8 NOISSUE split out language selection widget, use it in settings 2019-01-09 04:38:35 +01:00
Petr Mrázek
e71786d7b9 NOISSUE language selection wizard improvements
Same needs to be applied to the application settings later.
2019-01-08 02:20:36 +01:00
Petr Mrázek
819503d530 NOISSUE bump version to 0.6.5 2019-01-06 22:56:05 +01:00
385 changed files with 7057 additions and 4086 deletions

View File

@@ -1,5 +0,0 @@
{
"project_id": "MultiMC5",
"conduit_uri": "http://ph.multimc.org"
}

View File

@@ -1,25 +0,0 @@
UseTab: false
IndentWidth: 4
TabWidth: 4
ConstructorInitializerIndentWidth: 4
AccessModifierOffset: -4
IndentCaseLabels: false
IndentFunctionDeclarationAfterType: false
NamespaceIndentation: None
BreakBeforeBraces: Allman
AllowShortIfStatementsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
ColumnLimit: 160
MaxEmptyLinesToKeep: 1
Standard: Cpp11
Cpp11BracedListStyle: true
SpacesInParentheses: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpaceAfterControlStatementKeyword: true
AlignTrailingComments: true
SpacesBeforeTrailingComments: 1

5
.gitignore vendored
View File

@@ -1,5 +1,5 @@
Thumbs.db
.kdev4
*.kdev4
.user
.directory
resources/CMakeFiles
@@ -9,8 +9,7 @@ resources/MultiMCLauncher.jar
html/
# Project Files
MultiMC5.kdev4
MultiMC.pro.user
*.pro.user
CMakeLists.txt.user
CMakeLists.txt.user.*
/.project

View File

@@ -1,38 +0,0 @@
# General set up
language: cpp
cache: apt
matrix:
include:
- os: linux
dist: precise
sudo: required
compiler: gcc
env: TRAVIS_DIST=precise QT_VERSION=5.4.2
- os: linux
dist: precise
sudo: required
compiler: gcc
env: TRAVIS_DIST=precise QT_VERSION=5.6.2
- os: linux
dist: trusty
sudo: required
compiler: gcc
env: TRAVIS_DIST=trusty QT_VERSION=5.4.2
- os: linux
dist: trusty
sudo: required
compiler: gcc
env: TRAVIS_DIST=trusty QT_VERSION=5.6.2
# Install dependencies
install:
- source travis/prepare.sh # installs qt and cmake. need to source because some env vars are set from there
# Actual work
before_script:
- mkdir build
- cd build
- cmake -DCMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH ..
script:
- make -j4 && make test ARGS="-V"

View File

@@ -32,7 +32,7 @@ set(CMAKE_C_STANDARD_REQUIRED true)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_C_STANDARD 11)
include(GenerateExportHeader)
set(CMAKE_CXX_FLAGS " -Wall -pedantic -Werror -D_GLIBCXX_USE_CXX11_ABI=0 -fstack-protector-strong --param=ssp-buffer-size=4 -O3 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS " -Wall -pedantic -Werror -Wno-deprecated-declarations -D_GLIBCXX_USE_CXX11_ABI=0 -fstack-protector-strong --param=ssp-buffer-size=4 -O3 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS}")
if(UNIX AND APPLE)
set(CMAKE_CXX_FLAGS " -stdlib=libc++ ${CMAKE_CXX_FLAGS}")
endif()
@@ -46,7 +46,7 @@ set(MultiMC_NEWS_RSS_URL "https://multimc.org/rss.xml" CACHE STRING "URL to fetc
######## Set version numbers ########
set(MultiMC_VERSION_MAJOR 0)
set(MultiMC_VERSION_MINOR 6)
set(MultiMC_VERSION_HOTFIX 4)
set(MultiMC_VERSION_HOTFIX 8)
# Build number
set(MultiMC_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
@@ -77,6 +77,7 @@ set(MultiMC_RELEASE_VERSION_NAME "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MIN
#### Custom target to just print the version.
add_custom_target(version echo "Version: ${MultiMC_RELEASE_VERSION_NAME}")
add_custom_target(tcversion echo "\\#\\#teamcity[setParameter name=\\'env.MULTIMC_VERSION\\' value=\\'${MultiMC_RELEASE_VERSION_NAME}\\']")
################################ 3rd Party Libs ################################
@@ -87,6 +88,7 @@ find_package(Qt5Concurrent REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5Test REQUIRED)
find_package(Qt5Xml REQUIRED)
find_package(Qt5Multimedia REQUIRED)
# The Qt5 cmake files don't provide its install paths, so ask qmake.
include(QMakeQuery)
@@ -141,7 +143,7 @@ if(MultiMC_LAYOUT_REAL STREQUAL "mac-bundle")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_HOTFIX}.${MultiMC_VERSION_BUILD}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_HOTFIX}.${MultiMC_VERSION_BUILD}")
set(MACOSX_BUNDLE_ICON_FILE MultiMC.icns)
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2015-2018 MultiMC Contributors")
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2015-2019 MultiMC Contributors")
# directories to look for dependencies
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

View File

@@ -1,6 +1,6 @@
# MultiMC
Copyright 2012-2018 MultiMC Contributors
Copyright 2012-2019 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

View File

@@ -13,21 +13,22 @@ The project uses C++ and Qt5 as the language and base framework. This might seem
We can do more, with less, on worse hardware and leave more resources for the game while keeping the launcher running and providing extra features.
If you want to contribute, either talk to us on [Discord](https://discord.gg/0k2zsXGNHs0fE4Wm), [IRC](http://webchat.esper.net/?nick=&channels=MultiMC)(esper.net/#MultiMC) or pick up some item from [workflowy](https://workflowy.com/s/2EyDMcp7CU) - there are many.
If you want to contribute, either talk to us on [Discord](https://discord.gg/0k2zsXGNHs0fE4Wm), [IRC](http://webchat.esper.net/?nick=&channels=MultiMC)(esper.net/#MultiMC) or pick up some item from the github issues [workflowy](https://github.com/MultiMC/MultiMC5/issues) - there is always plenty of ideas around.
### Building
If you want to build MultiMC yourself, check [BUILD.md](BUILD.md) for build instructions.
The ci server is running at [ci.multimc.org](http://ci.multimc.org), where you can watch the builds happen in (or very close to) real time. It can also serve as a nice reference on how to set up the build environment on your end.
According to travis.ci, the builds are currently [![Build Status](https://travis-ci.org/MultiMC/MultiMC5.svg?branch=develop)](https://travis-ci.org/MultiMC/MultiMC5)
### Code formatting
We use [Clang Format](http://clang.llvm.org/docs/ClangFormat.html) to format the project. We highly recommend setting it up so the project stays well formatted.
Just follow the existing formatting.
In general:
* Indent with 4 space unless it's in a submodule
* Keep lists (of arguments, parameters, initializators...) as lists, not paragraphs.
* Prefer readability over dogma.
## Translations
Translations can be done either directly in the [translations repository](https://github.com/MultiMC/MultiMC5). For more details, see: [Translating-MultiMC](https://github.com/MultiMC/MultiMC5/wiki/Translating-MultiMC).
Translations can be done [on crowdin](https://translate.multimc.org).
## Forking/Redistributing
We keep MultiMC open source because we think it's important to be able to see the source code for a project like this, and we do so using the Apache license.
@@ -38,8 +39,41 @@ Apache covers reasonable use for the name - a mention of the project's origins i
## License
Copyright © 2013-2018 MultiMC Contributors
Copyright © 2013-2019 MultiMC Contributors
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this program except in compliance with the License. You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](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.
## Build status
### Linux (Intel32)
<a href="https://teamcity.multimc.org/viewType.html?buildTypeId=MultiMC_Launcher_Linux32_Build&guest=1">
Build: <img src="https://teamcity.multimc.org/app/rest/builds/buildType:(id:MultiMC_Launcher_Linux32_Build)/statusIcon"/>
</a>
<a href="https://teamcity.multimc.org/viewType.html?buildTypeId=MultiMC_Launcher_Linux32_Deploy&guest=1">
Deploy: <img src="https://teamcity.multimc.org/app/rest/builds/buildType:(id:MultiMC_Launcher_Linux32_Deploy)/statusIcon"/>
</a>
### Linux (AMD64)
<a href="https://teamcity.multimc.org/viewType.html?buildTypeId=MultiMC_Launcher_Linux64_Build&guest=1">
Build: <img src="https://teamcity.multimc.org/app/rest/builds/buildType:(id:MultiMC_Launcher_Linux64_Build)/statusIcon"/>
</a>
<a href="https://teamcity.multimc.org/viewType.html?buildTypeId=MultiMC_Launcher_Linux64_Deploy&guest=1">
Deploy: <img src="https://teamcity.multimc.org/app/rest/builds/buildType:(id:MultiMC_Launcher_Linux64_Deploy)/statusIcon"/>
</a>
### macOS (AMD64)
<a href="https://teamcity.multimc.org/viewType.html?buildTypeId=MultiMC_Launcher_MacOS_Build&guest=1">
Build: <img src="https://teamcity.multimc.org/app/rest/builds/buildType:(id:MultiMC_Launcher_MacOS_Build)/statusIcon"/>
</a>
<a href="https://teamcity.multimc.org/viewType.html?buildTypeId=MultiMC_Launcher_MacOS_Deploy&guest=1">
Deploy: <img src="https://teamcity.multimc.org/app/rest/builds/buildType:(id:MultiMC_Launcher_MacOS_Deploy)/statusIcon"/>
</a>
### Windows (Intel32)
<a href="https://teamcity.multimc.org/viewType.html?buildTypeId=MultiMC_Launcher_Windows_Build&guest=1">
Build: <img src="https://teamcity.multimc.org/app/rest/builds/buildType:(id:MultiMC_Launcher_Windows_Build)/statusIcon"/>
</a>
<a href="https://teamcity.multimc.org/viewType.html?buildTypeId=MultiMC_Launcher_Windows_Deploy&guest=1">
Deploy: <img src="https://teamcity.multimc.org/app/rest/builds/buildType:(id:MultiMC_Launcher_Windows_Deploy)/statusIcon"/>
</a>

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -187,8 +187,7 @@ Qt::DropActions IconList::supportedDropActions() const
return Qt::CopyAction;
}
bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
const QModelIndex &parent)
bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
if (action == Qt::IgnoreAction)
return true;

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -80,7 +80,7 @@ protected slots:
void fileChanged(const QString &path);
void SettingChanged(const Setting & setting, QVariant value);
private:
std::shared_ptr<QFileSystemWatcher> m_watcher;
shared_qobject_ptr<QFileSystemWatcher> m_watcher;
bool is_watching;
QMap<QString, int> name_index;
QVector<MMCIcon> icons;

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -102,3 +102,17 @@ void MMCIcon::replace(IconType new_type, const QString& key)
m_images[new_type].filename = QString();
m_images[new_type].key = key;
}
QString MMCIcon::getFilePath() const
{
if(m_current_type == IconType::ToBeDeleted){
return QString();
}
return m_images[m_current_type].filename;
}
bool MMCIcon::isBuiltIn() const
{
return m_current_type == IconType::Builtin;
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,4 +46,6 @@ struct MULTIMC_GUI_EXPORT MMCIcon
void remove(IconType rm_type);
void replace(IconType new_type, QIcon icon, QString path = QString());
void replace(IconType new_type, const QString &key);
bool isBuiltIn() const;
QString getFilePath() const;
};

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -175,11 +175,6 @@ QString BaseInstance::instanceRoot() const
return m_rootDir;
}
InstancePtr BaseInstance::getSharedPtr()
{
return shared_from_this();
}
SettingsObjectPtr BaseInstance::settings() const
{
return m_settings;
@@ -253,7 +248,7 @@ QStringList BaseInstance::extraArguments() const
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
}
std::shared_ptr<LaunchTask> BaseInstance::getLaunchTask()
shared_qobject_ptr<LaunchTask> BaseInstance::getLaunchTask()
{
return m_launchProcess;
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -134,8 +134,6 @@ public:
/// Sets the last launched time to 'val' milliseconds since epoch
void setLastLaunch(qint64 val = QDateTime::currentMSecsSinceEpoch());
InstancePtr getSharedPtr();
/*!
* \brief Gets this instance's settings object.
* This settings object stores instance-specific settings.
@@ -147,10 +145,10 @@ public:
virtual shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) = 0;
/// returns a valid launcher (task container)
virtual std::shared_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) = 0;
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) = 0;
/// returns the current launch task (if any)
std::shared_ptr<LaunchTask> getLaunchTask();
shared_qobject_ptr<LaunchTask> getLaunchTask();
/*!
* Create envrironment variables for running the instance
@@ -241,7 +239,7 @@ signals:
*/
void propertiesChanged(BaseInstance *inst);
void launchTaskChanged(std::shared_ptr<LaunchTask>);
void launchTaskChanged(shared_qobject_ptr<LaunchTask>);
void runningStatusChanged(bool running);
@@ -255,7 +253,7 @@ protected: /* data */
SettingsObjectPtr m_settings;
// InstanceFlags m_flags;
bool m_isRunning = false;
std::shared_ptr<LaunchTask> m_launchProcess;
shared_qobject_ptr<LaunchTask> m_launchProcess;
QDateTime m_timeStarted;
private: /* data */
@@ -265,6 +263,6 @@ private: /* data */
bool m_hasBrokenVersion = false;
};
Q_DECLARE_METATYPE(std::shared_ptr<BaseInstance>)
Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>)
//Q_DECLARE_METATYPE(BaseInstance::InstanceFlag)
//Q_DECLARE_OPERATORS_FOR_FLAGS(BaseInstance::InstanceFlags)

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -182,9 +182,11 @@ set(NEWS_SOURCES
# Icon interface
set(ICONS_SOURCES
# News System
# Icons System and related code
icons/IIconList.h
icons/IIconList.cpp
icons/IconUtils.h
icons/IconUtils.cpp
)
# Minecraft services status checker
@@ -211,6 +213,10 @@ set(MINECRAFT_SOURCES
minecraft/auth/flows/RefreshTask.cpp
minecraft/auth/flows/ValidateTask.h
minecraft/auth/flows/ValidateTask.cpp
minecraft/gameoptions/GameOptions.h
minecraft/gameoptions/GameOptions.cpp
minecraft/update/AssetUpdateTask.h
minecraft/update/AssetUpdateTask.cpp
minecraft/update/FMLLibrariesTask.cpp
@@ -219,6 +225,7 @@ set(MINECRAFT_SOURCES
minecraft/update/FoldersTask.h
minecraft/update/LibrariesTask.cpp
minecraft/update/LibrariesTask.h
minecraft/launch/ClaimAccount.cpp
minecraft/launch/ClaimAccount.h
minecraft/launch/CreateServerResourcePacksFolder.cpp
@@ -233,12 +240,18 @@ set(MINECRAFT_SOURCES
minecraft/launch/LauncherPartLaunch.h
minecraft/launch/PrintInstanceInfo.cpp
minecraft/launch/PrintInstanceInfo.h
minecraft/launch/ReconstructAssets.cpp
minecraft/launch/ReconstructAssets.h
minecraft/launch/ScanModFolders.cpp
minecraft/launch/ScanModFolders.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
@@ -273,15 +286,21 @@ set(MINECRAFT_SOURCES
minecraft/VersionFile.h
minecraft/VersionFilterData.h
minecraft/VersionFilterData.cpp
minecraft/Mod.h
minecraft/Mod.cpp
minecraft/SimpleModList.h
minecraft/SimpleModList.cpp
minecraft/World.h
minecraft/World.cpp
minecraft/WorldList.h
minecraft/WorldList.cpp
minecraft/mod/Mod.h
minecraft/mod/Mod.cpp
minecraft/mod/ModDetails.h
minecraft/mod/ModFolderModel.h
minecraft/mod/ModFolderModel.cpp
minecraft/mod/ModFolderLoadTask.h
minecraft/mod/ModFolderLoadTask.cpp
minecraft/mod/LocalModParseTask.h
minecraft/mod/LocalModParseTask.cpp
# Assets
minecraft/AssetsUtils.h
minecraft/AssetsUtils.cpp
@@ -312,8 +331,8 @@ add_unit_test(Library
)
# FIXME: shares data with FileSystem test
add_unit_test(SimpleModList
SOURCES minecraft/SimpleModList_test.cpp
add_unit_test(ModFolderModel
SOURCES minecraft/mod/ModFolderModel_test.cpp
DATA testdata
LIBS MultiMC_logic
)
@@ -420,15 +439,14 @@ set(META_SOURCES
)
set(FTB_SOURCES
modplatform/ftb/FtbPackFetchTask.h
modplatform/ftb/FtbPackFetchTask.cpp
modplatform/ftb/FtbPackInstallTask.h
modplatform/ftb/FtbPackInstallTask.cpp
modplatform/legacy_ftb/PackFetchTask.h
modplatform/legacy_ftb/PackFetchTask.cpp
modplatform/legacy_ftb/PackInstallTask.h
modplatform/legacy_ftb/PackInstallTask.cpp
modplatform/legacy_ftb/PrivatePackManager.h
modplatform/legacy_ftb/PrivatePackManager.cpp
modplatform/ftb/FtbPrivatePackManager.h
modplatform/ftb/FtbPrivatePackManager.cpp
modplatform/ftb/PackHelpers.h
modplatform/legacy_ftb/PackHelpers.h
)
set(FLAME_SOURCES
@@ -471,8 +489,6 @@ set(LOGIC_SOURCES
${FLAME_SOURCES}
)
message(STATUS "FOO! ${LOGIC_SOURCES}")
add_library(MultiMC_logic SHARED ${LOGIC_SOURCES})
set_target_properties(MultiMC_logic PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN 1)

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
@@ -69,8 +69,8 @@ namespace ArgumentStyle
{
enum Enum
{
Space, /**< --option=value */
Equals, /**< --option value */
Space, /**< --option value */
Equals, /**< --option=value */
SpaceAndEquals, /**< --option[= ]value */
#ifdef Q_OS_WIN32
Default = Equals

View File

@@ -174,6 +174,11 @@ bool copy::operator()(const QString &offset)
bool deletePath(QString path)
{
bool OK = true;
QFileInfo finfo(path);
if(finfo.isFile()) {
return QFile::remove(path);
}
QDir dir(path);
if (!dir.exists())
@@ -294,7 +299,7 @@ QString NormalizePath(QString path)
}
}
QString badFilenameChars = "\"\\/?<>:*|!+\r\n";
QString badFilenameChars = "\"\\/?<>:;*|!+\r\n";
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
{

View File

@@ -5,9 +5,10 @@
#include "pathmatcher/RegexpMatcher.h"
#include <QtConcurrentRun>
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, bool copySaves)
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, bool copySaves, bool keepPlaytime)
{
m_origInstance = origInstance;
m_keepPlaytime = keepPlaytime;
if(!copySaves)
{
@@ -46,6 +47,9 @@ void InstanceCopyTask::copyFinished()
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
inst->setName(m_instName);
inst->setIconKey(m_instIcon);
if(!m_keepPlaytime) {
inst->resetTimePlayed();
}
emitSucceeded();
}

View File

@@ -15,7 +15,7 @@ class MULTIMC_LOGIC_EXPORT InstanceCopyTask : public InstanceTask
{
Q_OBJECT
public:
explicit InstanceCopyTask(InstancePtr origInstance, bool copySaves);
explicit InstanceCopyTask(InstancePtr origInstance, bool copySaves, bool keepPlaytime);
protected:
//! Entry point for tasks.
@@ -28,4 +28,5 @@ private: /* data */
QFuture<bool> m_copyFuture;
QFutureWatcher<bool> m_copyFutureWatcher;
std::unique_ptr<IPathMatcher> m_matcher;
bool m_keepPlaytime;
};

View File

@@ -6,6 +6,7 @@
#include "NullInstance.h"
#include "settings/INISettingsObject.h"
#include "icons/IIconList.h"
#include "icons/IconUtils.h"
#include <QtConcurrentRun>
// FIXME: this does not belong here, it's Minecraft/Flame specific
@@ -393,8 +394,9 @@ void InstanceImportTask::processMultiMC()
else
{
m_instIcon = instance.iconKey();
auto importIconPath = FS::PathCombine(instance.instanceRoot(), m_instIcon + ".png");
if (QFile::exists(importIconPath))
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
if (!importIconPath.isNull() && QFile::exists(importIconPath))
{
// import icon
auto iconList = ENV.icons();

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -100,6 +100,10 @@ QVariant InstanceList::data(const QModelIndex &index, int role) const
{
return pdata->name();
}
case Qt::AccessibleTextRole:
{
return tr("%1 Instance").arg(pdata->name());
}
case Qt::ToolTipRole:
{
return pdata->instanceRoot();
@@ -156,8 +160,8 @@ GroupId InstanceList::getInstanceGroup(const InstanceId& id) const
{
return GroupId();
}
auto iter = m_groupMap.find(inst->id());
if(iter != m_groupMap.end())
auto iter = m_instanceGroupIndex.find(inst->id());
if(iter != m_instanceGroupIndex.end())
{
return *iter;
}
@@ -174,8 +178,8 @@ void InstanceList::setInstanceGroup(const InstanceId& id, const GroupId& name)
}
bool changed = false;
auto iter = m_groupMap.find(inst->id());
if(iter != m_groupMap.end())
auto iter = m_instanceGroupIndex.find(inst->id());
if(iter != m_instanceGroupIndex.end())
{
if(*iter != name)
{
@@ -186,12 +190,12 @@ void InstanceList::setInstanceGroup(const InstanceId& id, const GroupId& name)
else
{
changed = true;
m_groupMap[id] = name;
m_instanceGroupIndex[id] = name;
}
if(changed)
{
m_groups.insert(name);
m_groupNameCache.insert(name);
auto idx = getInstIndex(inst.get());
emit dataChanged(index(idx), index(idx), {GroupRole});
saveGroupList();
@@ -200,7 +204,7 @@ void InstanceList::setInstanceGroup(const InstanceId& id, const GroupId& name)
QStringList InstanceList::getGroups()
{
return m_groups.toList();
return m_groupNameCache.toList();
}
void InstanceList::deleteGroup(const QString& name)
@@ -213,7 +217,7 @@ void InstanceList::deleteGroup(const QString& name)
auto instGroupName = getInstanceGroup(instID);
if(instGroupName == name)
{
m_groupMap.remove(instID);
m_instanceGroupIndex.remove(instID);
qDebug() << "Remove" << instID << "from group" << name;
removed = true;
auto idx = getInstIndex(instance.get());
@@ -229,16 +233,21 @@ void InstanceList::deleteGroup(const QString& name)
}
}
bool InstanceList::isGroupCollapsed(const QString& group)
{
return m_collapsedGroups.contains(group);
}
void InstanceList::deleteInstance(const InstanceId& id)
{
auto inst = getInstanceById(id);
if(!inst)
{
qDebug() << "Cannot delete instance" << id << " No such instance is present.";
qDebug() << "Cannot delete instance" << id << ". No such instance is present (deleted externally?).";
return;
}
if(m_groupMap.remove(id))
if(m_instanceGroupIndex.remove(id))
{
saveGroupList();
}
@@ -511,7 +520,7 @@ void InstanceList::saveGroupList()
WatchLock foo(m_watcher, m_instDir);
QString groupFileName = m_instDir + "/instgroups.json";
QMap<QString, QSet<QString>> reverseGroupMap;
for (auto iter = m_groupMap.begin(); iter != m_groupMap.end(); iter++)
for (auto iter = m_instanceGroupIndex.begin(); iter != m_instanceGroupIndex.end(); iter++)
{
QString id = iter.key();
QString group = iter.value();
@@ -544,7 +553,7 @@ void InstanceList::saveGroupList()
auto name = iter.key();
QJsonObject groupObj;
QJsonArray instanceArr;
groupObj.insert("hidden", QJsonValue(QString("false")));
groupObj.insert("hidden", QJsonValue(m_collapsedGroups.contains(name)));
for (auto item : list)
{
instanceArr.append(QJsonValue(item));
@@ -568,7 +577,6 @@ void InstanceList::saveGroupList()
void InstanceList::loadGroupList()
{
qDebug() << "Will load group list now.";
QSet<QString> groupSet;
QString groupFileName = m_instDir + "/instgroups.json";
@@ -619,7 +627,8 @@ void InstanceList::loadGroupList()
return;
}
m_groupMap.clear();
QSet<QString> groupSet;
m_instanceGroupIndex.clear();
// Iterate through all the groups.
QJsonObject groupMapping = rootObj.value("groups").toObject();
@@ -630,37 +639,35 @@ void InstanceList::loadGroupList()
// If not an object, complain and skip to the next one.
if (!iter.value().isObject())
{
qWarning() << QString("Group '%1' in the group list should "
"be an object.")
.arg(groupName)
.toUtf8();
qWarning() << QString("Group '%1' in the group list should be an object.").arg(groupName).toUtf8();
continue;
}
QJsonObject groupObj = iter.value().toObject();
if (!groupObj.value("instances").isArray())
{
qWarning() << QString("Group '%1' in the group list is invalid. "
"It should contain an array "
"called 'instances'.")
.arg(groupName)
.toUtf8();
qWarning() << QString("Group '%1' in the group list is invalid. It should contain an array called 'instances'.").arg(groupName).toUtf8();
continue;
}
// keep a list/set of groups for choosing
groupSet.insert(groupName);
auto hidden = groupObj.value("hidden").toBool(false);
if(hidden) {
m_collapsedGroups.insert(groupName);
}
// Iterate through the list of instances in the group.
QJsonArray instancesArray = groupObj.value("instances").toArray();
for (QJsonArray::iterator iter2 = instancesArray.begin(); iter2 != instancesArray.end(); iter2++)
{
m_groupMap[(*iter2).toString()] = groupName;
m_instanceGroupIndex[(*iter2).toString()] = groupName;
}
}
m_groupsLoaded = true;
m_groups.unite(groupSet);
m_groupNameCache.unite(groupSet);
qDebug() << "Group list loaded.";
}
@@ -685,6 +692,17 @@ void InstanceList::on_InstFolderChanged(const Setting &setting, QVariant value)
}
}
void InstanceList::on_GroupStateChanged(const QString& group, bool collapsed)
{
qDebug() << "Group" << group << (collapsed ? "collapsed" : "expanded");
if(collapsed) {
m_collapsedGroups.insert(group);
} else {
m_collapsedGroups.remove(group);
}
saveGroupList();
}
class InstanceStaging : public Task
{
Q_OBJECT
@@ -815,10 +833,11 @@ bool InstanceList::commitStagedInstance(const QString& path, const QString& inst
qWarning() << "Failed to move" << path << "to" << destination;
return false;
}
m_groupMap[instID] = groupName;
m_instanceGroupIndex[instID] = groupName;
instanceSet.insert(instID);
m_groups.insert(groupName);
m_groupNameCache.insert(groupName);
emit instancesChanged();
emit instanceSelectRequest(instID);
}
saveGroupList();
return true;

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -99,6 +99,8 @@ public:
InstancePtr getInstanceById(QString id) const;
QModelIndex getInstanceIndexById(const QString &id) const;
QStringList getGroups();
bool isGroupCollapsed(const QString &groupName);
GroupId getInstanceGroup(const InstanceId & id) const;
void setInstanceGroup(const InstanceId & id, const GroupId& name);
@@ -129,10 +131,12 @@ public:
signals:
void dataIsInvalid();
void instancesChanged();
void instanceSelectRequest(QString instanceId);
void groupsChanged(QSet<QString> groups);
public slots:
void on_InstFolderChanged(const Setting &setting, QVariant value);
void on_GroupStateChanged(const QString &group, bool collapsed);
private slots:
void propertiesChanged(BaseInstance *inst);
@@ -153,12 +157,14 @@ private:
int m_watchLevel = 0;
bool m_dirty = false;
QList<InstancePtr> m_instances;
QSet<QString> m_groups;
QSet<QString> m_groupNameCache;
SettingsObjectPtr m_globalSettings;
QString m_instDir;
QFileSystemWatcher * m_watcher;
QMap<InstanceId, GroupId> m_groupMap;
// FIXME: this is so inefficient that looking at it is almost painful.
QSet<QString> m_collapsedGroups;
QMap<InstanceId, GroupId> m_instanceGroupIndex;
QSet<InstanceId> instanceSet;
bool m_groupsLoaded = false;
bool m_instancesProbed = false;

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
#include <QString>
#include <QFileInfo>
#include <QSet>
#include "minecraft/Mod.h"
#include "minecraft/mod/Mod.h"
#include <functional>
#include "multimc_logic_export.h"

View File

@@ -1,5 +1,6 @@
#pragma once
#include "BaseInstance.h"
#include "launch/LaunchTask.h"
class NullInstance: public BaseInstance
{
@@ -11,46 +12,46 @@ public:
setVersionBroken(true);
}
virtual ~NullInstance() {};
virtual void saveNow() override
void saveNow() override
{
}
virtual QString getStatusbarDescription() override
QString getStatusbarDescription() override
{
return tr("Unknown instance type");
};
virtual QSet< QString > traits() const override
QSet< QString > traits() const override
{
return {};
};
virtual QString instanceConfigFolder() const override
QString instanceConfigFolder() const override
{
return instanceRoot();
};
virtual std::shared_ptr<LaunchTask> createLaunchTask(AuthSessionPtr) override
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr) override
{
return nullptr;
}
virtual shared_qobject_ptr< Task > createUpdateTask(Net::Mode mode) override
shared_qobject_ptr< Task > createUpdateTask(Net::Mode mode) override
{
return nullptr;
}
virtual QProcessEnvironment createEnvironment() override
QProcessEnvironment createEnvironment() override
{
return QProcessEnvironment();
}
virtual QMap<QString, QString> getVariables() const override
QMap<QString, QString> getVariables() const override
{
return QMap<QString, QString>();
}
virtual IPathMatcher::Ptr getLogFileMatcher() override
IPathMatcher::Ptr getLogFileMatcher() override
{
return nullptr;
}
virtual QString getLogFileRoot() override
QString getLogFileRoot() override
{
return instanceRoot();
}
virtual QString typeName() const override
QString typeName() const override
{
return "Null";
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,62 @@
#include "IconUtils.h"
#include "FileSystem.h"
#include <QDirIterator>
#include <array>
namespace {
std::array<const char *, 6> validIconExtensions = {{
"svg",
"png",
"ico",
"gif",
"jpg",
"jpeg"
}};
}
namespace IconUtils{
QString findBestIconIn(const QString &folder, const QString & iconKey) {
int best_found = validIconExtensions.size();
QString best_filename;
QDirIterator it(folder, QDir::NoDotAndDotDot | QDir::Files, QDirIterator::NoIteratorFlags);
while (it.hasNext()) {
it.next();
auto fileInfo = it.fileInfo();
if(fileInfo.completeBaseName() != iconKey)
continue;
auto extension = fileInfo.suffix();
for(int i = 0; i < best_found; i++) {
if(extension == validIconExtensions[i]) {
best_found = i;
qDebug() << i << " : " << fileInfo.fileName();
best_filename = fileInfo.fileName();
}
}
}
return FS::PathCombine(folder, best_filename);
}
QString getIconFilter() {
QString out;
QTextStream stream(&out);
stream << '(';
for(size_t i = 0; i < validIconExtensions.size() - 1; i++) {
if(i > 0) {
stream << " ";
}
stream << "*." << validIconExtensions[i];
}
stream << " *." << validIconExtensions[validIconExtensions.size() - 1];
stream << ')';
return out;
}
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <QString>
#include "multimc_logic_export.h"
namespace IconUtils {
// Given a folder and an icon key, find 'best' of the icons with the given key in there and return its path
MULTIMC_LOGIC_EXPORT QString findBestIconIn(const QString &folder, const QString & iconKey);
// Get icon file type filter for file browser dialogs
MULTIMC_LOGIC_EXPORT QString getIconFilter();
}

View File

@@ -75,8 +75,8 @@ void JavaChecker::stderrReady()
void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
{
killTimer.stop();
QProcessPtr _process;
_process.swap(process);
QProcessPtr _process = process;
process.reset();
JavaCheckResult result;
{

View File

@@ -3,6 +3,8 @@
#include <QTimer>
#include <memory>
#include "QObjectPtr.h"
#include "multimc_logic_export.h"
#include "JavaVersion.h"
@@ -27,8 +29,8 @@ struct MULTIMC_LOGIC_EXPORT JavaCheckResult
} validity = Validity::Errored;
};
typedef std::shared_ptr<QProcess> QProcessPtr;
typedef std::shared_ptr<JavaChecker> JavaCheckerPtr;
typedef shared_qobject_ptr<QProcess> QProcessPtr;
typedef shared_qobject_ptr<JavaChecker> JavaCheckerPtr;
class MULTIMC_LOGIC_EXPORT JavaChecker : public QObject
{
Q_OBJECT

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
#include "tasks/Task.h"
class JavaCheckerJob;
typedef std::shared_ptr<JavaCheckerJob> JavaCheckerJobPtr;
typedef shared_qobject_ptr<JavaCheckerJob> JavaCheckerJobPtr;
// FIXME: this just seems horribly redundant
class JavaCheckerJob : public Task

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -149,7 +149,7 @@ void JavaListLoadTask::executeTask()
JavaUtils ju;
QList<QString> candidate_paths = ju.FindJavaPaths();
m_job = std::shared_ptr<JavaCheckerJob>(new JavaCheckerJob("Java detection"));
m_job = new JavaCheckerJob("Java detection");
connect(m_job.get(), &Task::finished, this, &JavaListLoadTask::javaCheckerFinished);
connect(m_job.get(), &Task::progress, this, &Task::setProgress);

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
#include "JavaCheckerJob.h"
#include "JavaInstall.h"
#include "QObjectPtr.h"
#include "multimc_logic_export.h"
class JavaListLoadTask;
@@ -75,7 +77,7 @@ public slots:
void javaCheckerFinished();
protected:
std::shared_ptr<JavaCheckerJob> m_job;
shared_qobject_ptr<JavaCheckerJob> m_job;
JavaInstallList *m_list;
JavaInstall *m_currentRecommended;
};

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -60,7 +60,7 @@ void CheckJava::executeTask()
// if timestamps are not the same, or something is missing, check!
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0 || storedArchitecture.size() == 0)
{
m_JavaChecker = std::make_shared<JavaChecker>();
m_JavaChecker = new JavaChecker();
emit logLine(tr("Checking Java version..."), MessageLevel::MultiMC);
connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &CheckJava::checkJavaFinished);
m_JavaChecker->m_path = realJavaPath;

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
@@ -33,9 +33,9 @@ void LaunchTask::init()
m_instance->setRunning(true);
}
std::shared_ptr<LaunchTask> LaunchTask::create(InstancePtr inst)
shared_qobject_ptr<LaunchTask> LaunchTask::create(InstancePtr inst)
{
std::shared_ptr<LaunchTask> proc(new LaunchTask(inst));
shared_qobject_ptr<LaunchTask> proc(new LaunchTask(inst));
proc->init();
return proc;
}
@@ -44,12 +44,12 @@ LaunchTask::LaunchTask(InstancePtr instance): m_instance(instance)
{
}
void LaunchTask::appendStep(std::shared_ptr<LaunchStep> step)
void LaunchTask::appendStep(shared_qobject_ptr<LaunchStep> step)
{
m_steps.append(step);
}
void LaunchTask::prependStep(std::shared_ptr<LaunchStep> step)
void LaunchTask::prependStep(shared_qobject_ptr<LaunchStep> step)
{
m_steps.prepend(step);
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
@@ -45,11 +45,11 @@ public:
};
public: /* methods */
static std::shared_ptr<LaunchTask> create(InstancePtr inst);
static shared_qobject_ptr<LaunchTask> create(InstancePtr inst);
virtual ~LaunchTask() {};
void appendStep(std::shared_ptr<LaunchStep> step);
void prependStep(std::shared_ptr<LaunchStep> step);
void appendStep(shared_qobject_ptr<LaunchStep> step);
void prependStep(shared_qobject_ptr<LaunchStep> step);
void setCensorFilter(QMap<QString, QString> filter);
InstancePtr instance()
@@ -117,7 +117,7 @@ private: /*methods */
protected: /* data */
InstancePtr m_instance;
shared_qobject_ptr<LogModel> m_logModel;
QList <std::shared_ptr<LaunchStep>> m_steps;
QList <shared_qobject_ptr<LaunchStep>> m_steps;
QMap<QString, QString> m_censorFilter;
int currentStep = -1;
State state = NotStarted;

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -74,7 +74,7 @@ Meta::BaseEntity::~BaseEntity()
QUrl Meta::BaseEntity::url() const
{
return QUrl("https://v1.meta.multimc.org").resolved(localFilename());
return QUrl("https://meta.multimc.org/v1/").resolved(localFilename());
}
bool Meta::BaseEntity::loadLocalFile()

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,33 @@
#include "net/ChecksumValidator.h"
#include "net/URLConstants.h"
namespace {
QSet<QString> collectPathsFromDir(QString dirPath)
{
QFileInfo dirInfo(dirPath);
if (!dirInfo.exists())
{
return {};
}
QSet<QString> out;
QDirIterator iter(dirPath, QDirIterator::Subdirectories);
while (iter.hasNext())
{
QString value = iter.next();
QFileInfo info(value);
if(info.isFile())
{
out.insert(value);
qDebug() << value;
}
}
return out;
}
}
namespace AssetsUtils
{
@@ -37,7 +64,7 @@ namespace AssetsUtils
* Returns true on success, with index populated
* index is undefined otherwise
*/
bool loadAssetsIndexJson(QString assetsId, QString path, AssetsIndex *index)
bool loadAssetsIndexJson(const QString &assetsId, const QString &path, AssetsIndex& index)
{
/*
{
@@ -61,7 +88,7 @@ bool loadAssetsIndexJson(QString assetsId, QString path, AssetsIndex *index)
qCritical() << "Failed to read assets index file" << path;
return false;
}
index->id = assetsId;
index.id = assetsId;
// Read the file and close it.
QByteArray jsonData = file.readAll();
@@ -90,7 +117,13 @@ bool loadAssetsIndexJson(QString assetsId, QString path, AssetsIndex *index)
QJsonValue isVirtual = root.value("virtual");
if (!isVirtual.isUndefined())
{
index->isVirtual = isVirtual.toBool(false);
index.isVirtual = isVirtual.toBool(false);
}
QJsonValue mapToResources = root.value("map_to_resources");
if (!mapToResources.isUndefined())
{
index.mapToResources = mapToResources.toBool(false);
}
QJsonValue objects = root.value("objects");
@@ -122,13 +155,14 @@ bool loadAssetsIndexJson(QString assetsId, QString path, AssetsIndex *index)
}
}
index->objects.insert(iter.key(), object);
index.objects.insert(iter.key(), object);
}
return true;
}
QDir reconstructAssets(QString assetsId)
// FIXME: ugly code duplication
QDir getAssetsDir(const QString &assetsId, const QString &resourcesFolder)
{
QDir assetsDir = QDir("assets/");
QDir indexDir = QDir(FS::PathCombine(assetsDir.path(), "indexes"));
@@ -141,24 +175,77 @@ QDir reconstructAssets(QString assetsId)
if (!indexFile.exists())
{
qCritical() << "No assets index file" << indexPath << "; can't reconstruct assets";
qCritical() << "No assets index file" << indexPath << "; can't determine assets path!";
return virtualRoot;
}
qDebug() << "reconstructAssets" << assetsDir.path() << indexDir.path()
<< objectDir.path() << virtualDir.path() << virtualRoot.path();
AssetsIndex index;
if(!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index))
{
qCritical() << "Failed to load asset index file" << indexPath << "; can't determine assets path!";
return virtualRoot;
}
QString targetPath;
if(index.isVirtual)
{
return virtualRoot;
}
else if(index.mapToResources)
{
return QDir(resourcesFolder);
}
return virtualRoot;
}
// FIXME: ugly code duplication
bool reconstructAssets(QString assetsId, QString resourcesFolder)
{
QDir assetsDir = QDir("assets/");
QDir indexDir = QDir(FS::PathCombine(assetsDir.path(), "indexes"));
QDir objectDir = QDir(FS::PathCombine(assetsDir.path(), "objects"));
QDir virtualDir = QDir(FS::PathCombine(assetsDir.path(), "virtual"));
QString indexPath = FS::PathCombine(indexDir.path(), assetsId + ".json");
QFile indexFile(indexPath);
QDir virtualRoot(FS::PathCombine(virtualDir.path(), assetsId));
if (!indexFile.exists())
{
qCritical() << "No assets index file" << indexPath << "; can't reconstruct assets!";
return false;
}
qDebug() << "reconstructAssets" << assetsDir.path() << indexDir.path() << objectDir.path() << virtualDir.path() << virtualRoot.path();
AssetsIndex index;
bool loadAssetsIndex = AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, &index);
if (loadAssetsIndex && index.isVirtual)
if(!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index))
{
qDebug() << "Reconstructing virtual assets folder at" << virtualRoot.path();
qCritical() << "Failed to load asset index file" << indexPath << "; can't reconstruct assets!";
return false;
}
QString targetPath;
bool removeLeftovers = false;
if(index.isVirtual)
{
targetPath = virtualRoot.path();
removeLeftovers = true;
qDebug() << "Reconstructing virtual assets folder at" << targetPath;
}
else if(index.mapToResources)
{
targetPath = resourcesFolder;
qDebug() << "Reconstructing resources folder at" << targetPath;
}
if (!targetPath.isNull())
{
auto presentFiles = collectPathsFromDir(targetPath);
for (QString map : index.objects.keys())
{
AssetObject asset_object = index.objects.value(map);
QString target_path = FS::PathCombine(virtualRoot.path(), map);
QString target_path = FS::PathCombine(targetPath, map);
QFile target(target_path);
QString tlk = asset_object.hash.left(2);
@@ -167,24 +254,32 @@ QDir reconstructAssets(QString assetsId)
QFile original(original_path);
if (!original.exists())
continue;
presentFiles.remove(target_path);
if (!target.exists())
{
QFileInfo info(target_path);
QDir target_dir = info.dir();
// qDebug() << target_dir;
if (!target_dir.exists())
QDir("").mkpath(target_dir.path());
qDebug() << target_dir.path();
FS::ensureFolderPathExists(target_dir.path());
bool couldCopy = original.copy(target_path);
qDebug() << " Copying" << original_path << "to" << target_path
<< QString::number(couldCopy); // << original.errorString();
qDebug() << " Copying" << original_path << "to" << target_path << QString::number(couldCopy);
}
}
// TODO: Write last used time to virtualRoot/.lastused
if(removeLeftovers)
{
for(auto & file: presentFiles)
{
qDebug() << "Would remove" << file;
}
}
}
return virtualRoot;
return true;
}
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,11 +38,16 @@ struct AssetsIndex
QString id;
QMap<QString, AssetObject> objects;
bool isVirtual = false;
bool mapToResources = false;
};
/// FIXME: this is absolutely horrendous. REDO!!!!
namespace AssetsUtils
{
bool loadAssetsIndexJson(QString id, QString file, AssetsIndex* index);
bool loadAssetsIndexJson(const QString &id, const QString &file, AssetsIndex& index);
QDir getAssetsDir(const QString &assetsId, const QString &resourcesFolder);
/// Reconstruct a virtual assets folder for the given assets ID and return the folder
QDir reconstructAssets(QString assetsId);
bool reconstructAssets(QString assetsId, QString resourcesFolder);
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,6 +43,8 @@ ComponentList::ComponentList(MinecraftInstance * instance)
d->m_instance = instance;
d->m_saveTimer.setSingleShot(true);
d->m_saveTimer.setInterval(5000);
d->interactionDisabled = instance->isRunning();
connect(d->m_instance, &BaseInstance::runningStatusChanged, this, &ComponentList::disableInteraction);
connect(&d->m_saveTimer, &QTimer::timeout, this, &ComponentList::save_internal);
}
@@ -635,6 +637,9 @@ void ComponentList::componentDataChanged()
qWarning() << "ComponentList got dataChenged signal from a non-Component!";
return;
}
if(objPtr->getID() == "net.minecraft") {
emit minecraftChanged();
}
// figure out which one is it... in a seriously dumb way.
int index = 0;
for (auto component: d->components)
@@ -762,8 +767,9 @@ QVariant ComponentList::data(const QModelIndex &index, int role) const
{
switch (column)
{
case NameColumn:
return d->components.at(row)->isEnabled() ? Qt::Checked : Qt::Unchecked;
case NameColumn: {
return patch->isEnabled() ? Qt::Checked : Qt::Unchecked;
}
default:
return QVariant();
}
@@ -773,7 +779,7 @@ QVariant ComponentList::data(const QModelIndex &index, int role) const
switch (column)
{
case NameColumn:
return d->components.at(row)->getName();
return patch->getName();
case VersionColumn:
{
if(patch->isCustom())
@@ -853,21 +859,25 @@ QVariant ComponentList::headerData(int section, Qt::Orientation orientation, int
}
return QVariant();
}
// FIXME: zero precision mess
Qt::ItemFlags ComponentList::flags(const QModelIndex &index) const
{
if (!index.isValid())
if (!index.isValid()) {
return Qt::NoItemFlags;
}
Qt::ItemFlags outFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
int row = index.row();
if (row < 0 || row >= d->components.size())
if (row < 0 || row >= d->components.size()) {
return Qt::NoItemFlags;
}
auto patch = d->components.at(row);
// TODO: this will need fine-tuning later...
if(patch->canBeDisabled())
if(patch->canBeDisabled() && !d->interactionDisabled)
{
outFlags |= Qt::ItemIsUserCheckable;
}
@@ -1202,3 +1212,14 @@ QString ComponentList::getComponentVersion(const QString& uid) const
}
return QString();
}
void ComponentList::disableInteraction(bool disable)
{
if(d->interactionDisabled != disable) {
d->interactionDisabled = disable;
auto size = d->components.size();
if(size) {
emit dataChanged(index(0), index(size - 1));
}
}
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -104,6 +104,9 @@ public:
/// if there is a save scheduled, do it now.
void saveNow();
signals:
void minecraftChanged();
public:
/// get the profile component by id
Component * getComponent(const QString &id);
@@ -131,6 +134,7 @@ private slots:
void updateSucceeded();
void updateFailed(const QString & error);
void componentDataChanged();
void disableInteraction(bool disable);
private:
bool load();

View File

@@ -38,5 +38,6 @@ struct ComponentListData
QTimer m_saveTimer;
shared_qobject_ptr<Task> m_updateTask;
bool loaded = false;
bool interactionDisabled = true;
};

View File

@@ -451,13 +451,17 @@ static bool getTrivialComponentChanges(const ComponentIndex & index, const Requi
auto & comp = (*compIter);
if(comp->getVersion() != req.equalsVersion)
{
if(comp->m_dependencyOnly)
{
decision = Decision::VersionNotSame;
}
else
{
if(comp->isCustom()) {
decision = Decision::LockedVersionNotSame;
} else {
if(comp->m_dependencyOnly)
{
decision = Decision::VersionNotSame;
}
else
{
decision = Decision::LockedVersionNotSame;
}
}
break;
}
@@ -586,6 +590,15 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly)
{
component->m_version = "3.1.2";
}
else if (add.uid == "net.fabricmc.intermediary")
{
auto minecraft = std::find_if(components.begin(), components.end(), [](ComponentPtr & cmp){
return cmp->getID() == "net.minecraft";
});
if(minecraft != components.end()) {
component->m_version = (*minecraft)->getVersion();
}
}
}
// HACK HACK HACK HACK FIXME: this is a placeholder for deciding what version to use. For now, it is hardcoded.
// ############################################################################################################

View File

@@ -20,12 +20,14 @@
#include "minecraft/launch/DirectJavaLaunch.h"
#include "minecraft/launch/ModMinecraftJar.h"
#include "minecraft/launch/ClaimAccount.h"
#include "minecraft/launch/ReconstructAssets.h"
#include "minecraft/launch/ScanModFolders.h"
#include "java/launch/CheckJava.h"
#include "java/JavaUtils.h"
#include "meta/Index.h"
#include "meta/VersionList.h"
#include "SimpleModList.h"
#include "mod/ModFolderModel.h"
#include "WorldList.h"
#include "icons/IIconList.h"
@@ -35,6 +37,7 @@
#include "AssetsUtils.h"
#include "MinecraftUpdate.h"
#include "MinecraftLoadAndCheck.h"
#include <minecraft/gameoptions/GameOptions.h>
#define IBUS "@im=ibus"
@@ -215,6 +218,11 @@ QString MinecraftInstance::worldDir() const
return FS::PathCombine(gameRoot(), "saves");
}
QString MinecraftInstance::resourcesDir() const
{
return FS::PathCombine(gameRoot(), "resources");
}
QDir MinecraftInstance::librariesPath() const
{
return QDir::current().absoluteFilePath("libraries");
@@ -407,8 +415,7 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) cons
token_mapping["game_directory"] = absRootDir;
QString absAssetsDir = QDir("assets/").absolutePath();
auto assets = profile->getMinecraftAssets();
// FIXME: this is wrong and should be run as an async task
token_mapping["game_assets"] = AssetsUtils::reconstructAssets(assets->id).absolutePath();
token_mapping["game_assets"] = AssetsUtils::getAssetsDir(assets->id, resourcesDir()).absolutePath();
// 1.7.3+ assets tokens
token_mapping["assets_root"] = absAssetsDir;
@@ -544,37 +551,38 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session)
out << "";
}
if(loaderModList()->size())
{
out << "Mods:";
for(auto & mod: loaderModList()->allMods())
auto printModList = [&](const QString & label, ModFolderModel & model) {
if(model.size())
{
if(!mod.enabled())
continue;
if(mod.type() == Mod::MOD_FOLDER)
continue;
// TODO: proper implementation would need to descend into folders.
out << QString("%1:").arg(label);
auto modList = model.allMods();
std::sort(modList.begin(), modList.end(), [](Mod &a, Mod &b) {
auto aName = a.filename().completeBaseName();
auto bName = b.filename().completeBaseName();
return aName.localeAwareCompare(bName) < 0;
});
for(auto & mod: modList)
{
if(mod.type() == Mod::MOD_FOLDER)
{
out << u8" [📁] " + mod.filename().completeBaseName() + " (folder)";
continue;
}
out << " " + mod.filename().completeBaseName();
if(mod.enabled()) {
out << u8" [✔️] " + mod.filename().completeBaseName();
}
else {
out << u8" [❌] " + mod.filename().completeBaseName() + " (disabled)";
}
}
out << "";
}
out << "";
}
};
if(coreModList()->size())
{
out << "Core Mods:";
for(auto & coremod: coreModList()->allMods())
{
if(!coremod.enabled())
continue;
if(coremod.type() == Mod::MOD_FOLDER)
continue;
// TODO: proper implementation would need to descend into folders.
out << " " + coremod.filename().completeBaseName();
}
out << "";
}
printModList("Mods", *(loaderModList().get()));
printModList("Core Mods", *(coreModList().get()));
auto & jarMods = profile->getJarMods();
if(jarMods.size())
@@ -642,8 +650,7 @@ QMap<QString, QString> MinecraftInstance::createCensorFilterFromSession(AuthSess
auto i = sessionRef.u.properties.begin();
while (i != sessionRef.u.properties.end())
{
if(i.key() == "preferredLanguage")
{
if(i.value().length() <= 3) {
++i;
continue;
}
@@ -771,22 +778,22 @@ shared_qobject_ptr<Task> MinecraftInstance::createUpdateTask(Net::Mode mode)
return nullptr;
}
std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session)
shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session)
{
auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(getSharedPtr()));
// FIXME: get rid of shared_from_this ...
auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(shared_from_this()));
auto pptr = process.get();
ENV.icons()->saveIcon(iconKey(), FS::PathCombine(gameRoot(), "icon.png"), "PNG");
// print a header
{
process->appendStep(std::make_shared<TextPrint>(pptr, "Minecraft folder is:\n" + gameRoot() + "\n\n", MessageLevel::MultiMC));
process->appendStep(new TextPrint(pptr, "Minecraft folder is:\n" + gameRoot() + "\n\n", MessageLevel::MultiMC));
}
// check java
{
auto step = std::make_shared<CheckJava>(pptr);
process->appendStep(step);
process->appendStep(new CheckJava(pptr));
}
// check launch method
@@ -794,14 +801,14 @@ std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr s
QString method = launchMethod();
if(!validMethods.contains(method))
{
process->appendStep(std::make_shared<TextPrint>(pptr, "Selected launch method \"" + method + "\" is not valid.\n", MessageLevel::Fatal));
process->appendStep(new TextPrint(pptr, "Selected launch method \"" + method + "\" is not valid.\n", MessageLevel::Fatal));
return process;
}
// run pre-launch command if that's needed
if(getPreLaunchCommand().size())
{
auto step = std::make_shared<PreLaunchCommand>(pptr);
auto step = new PreLaunchCommand(pptr);
step->setWorkingDirectory(gameRoot());
process->appendStep(step);
}
@@ -809,36 +816,42 @@ std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr s
// if we aren't in offline mode,.
if(session->status != AuthSession::PlayableOffline)
{
process->appendStep(std::make_shared<ClaimAccount>(pptr, session));
process->appendStep(std::make_shared<Update>(pptr, Net::Mode::Online));
process->appendStep(new ClaimAccount(pptr, session));
process->appendStep(new Update(pptr, Net::Mode::Online));
}
else
{
process->appendStep(std::make_shared<Update>(pptr, Net::Mode::Offline));
process->appendStep(new Update(pptr, Net::Mode::Offline));
}
// if there are any jar mods
{
auto step = std::make_shared<ModMinecraftJar>(pptr);
process->appendStep(step);
process->appendStep(new ModMinecraftJar(pptr));
}
// if there are any jar mods
{
process->appendStep(new ScanModFolders(pptr));
}
// print some instance info here...
{
auto step = std::make_shared<PrintInstanceInfo>(pptr, session);
process->appendStep(step);
process->appendStep(new PrintInstanceInfo(pptr, session));
}
// create the server-resource-packs folder (workaround for Minecraft bug MCL-3732)
{
auto step = std::make_shared<CreateServerResourcePacksFolder>(pptr);
process->appendStep(step);
process->appendStep(new CreateServerResourcePacksFolder(pptr));
}
// extract native jars if needed
{
auto step = std::make_shared<ExtractNatives>(pptr);
process->appendStep(step);
process->appendStep(new ExtractNatives(pptr));
}
// reconstruct assets if needed
{
process->appendStep(new ReconstructAssets(pptr));
}
{
@@ -846,14 +859,14 @@ std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr s
auto method = launchMethod();
if(method == "LauncherPart")
{
auto step = std::make_shared<LauncherPartLaunch>(pptr);
auto step = new LauncherPartLaunch(pptr);
step->setWorkingDirectory(gameRoot());
step->setAuthSession(session);
process->appendStep(step);
}
else if (method == "DirectJava")
{
auto step = std::make_shared<DirectJavaLaunch>(pptr);
auto step = new DirectJavaLaunch(pptr);
step->setWorkingDirectory(gameRoot());
step->setAuthSession(session);
process->appendStep(step);
@@ -863,7 +876,7 @@ std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr s
// run post-exit command if that's needed
if(getPostExitCommand().size())
{
auto step = std::make_shared<PostLaunchCommand>(pptr);
auto step = new PostLaunchCommand(pptr);
step->setWorkingDirectory(gameRoot());
process->appendStep(step);
}
@@ -886,43 +899,47 @@ JavaVersion MinecraftInstance::getJavaVersion() const
return JavaVersion(settings()->get("JavaVersion").toString());
}
std::shared_ptr<SimpleModList> MinecraftInstance::loaderModList() const
std::shared_ptr<ModFolderModel> MinecraftInstance::loaderModList() const
{
if (!m_loader_mod_list)
{
m_loader_mod_list.reset(new SimpleModList(loaderModsDir()));
m_loader_mod_list.reset(new ModFolderModel(loaderModsDir()));
m_loader_mod_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_loader_mod_list.get(), &ModFolderModel::disableInteraction);
}
m_loader_mod_list->update();
return m_loader_mod_list;
}
std::shared_ptr<SimpleModList> MinecraftInstance::coreModList() const
std::shared_ptr<ModFolderModel> MinecraftInstance::coreModList() const
{
if (!m_core_mod_list)
{
m_core_mod_list.reset(new SimpleModList(coreModsDir()));
m_core_mod_list.reset(new ModFolderModel(coreModsDir()));
m_core_mod_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_core_mod_list.get(), &ModFolderModel::disableInteraction);
}
m_core_mod_list->update();
return m_core_mod_list;
}
std::shared_ptr<SimpleModList> MinecraftInstance::resourcePackList() const
std::shared_ptr<ModFolderModel> MinecraftInstance::resourcePackList() const
{
if (!m_resource_pack_list)
{
m_resource_pack_list.reset(new SimpleModList(resourcePacksDir()));
m_resource_pack_list.reset(new ModFolderModel(resourcePacksDir()));
m_resource_pack_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_resource_pack_list.get(), &ModFolderModel::disableInteraction);
}
m_resource_pack_list->update();
return m_resource_pack_list;
}
std::shared_ptr<SimpleModList> MinecraftInstance::texturePackList() const
std::shared_ptr<ModFolderModel> MinecraftInstance::texturePackList() const
{
if (!m_texture_pack_list)
{
m_texture_pack_list.reset(new SimpleModList(texturePacksDir()));
m_texture_pack_list.reset(new ModFolderModel(texturePacksDir()));
m_texture_pack_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_texture_pack_list.get(), &ModFolderModel::disableInteraction);
}
m_texture_pack_list->update();
return m_texture_pack_list;
}
@@ -935,6 +952,15 @@ std::shared_ptr<WorldList> MinecraftInstance::worldList() const
return m_world_list;
}
std::shared_ptr<GameOptions> MinecraftInstance::gameOptionsModel() const
{
if (!m_game_options)
{
m_game_options.reset(new GameOptions(FS::PathCombine(gameRoot(), "options.txt")));
}
return m_game_options;
}
QList< Mod > MinecraftInstance::getJarMods() const
{
auto profile = m_components->getProfile();

View File

@@ -1,14 +1,14 @@
#pragma once
#include "BaseInstance.h"
#include <java/JavaVersion.h>
#include "minecraft/Mod.h"
#include "minecraft/mod/Mod.h"
#include <QProcess>
#include <QDir>
#include "multimc_logic_export.h"
class ModsModel;
class SimpleModList;
class ModFolderModel;
class WorldList;
class GameOptions;
class LaunchStep;
class ComponentList;
@@ -44,6 +44,7 @@ public:
QString modsCacheLocation() const;
QString libDir() const;
QString worldDir() const;
QString resourcesDir() const;
QDir jarmodsPath() const;
QDir librariesPath() const;
QDir versionsPath() const;
@@ -66,17 +67,16 @@ public:
std::shared_ptr<ComponentList> getComponentList() const;
////// Mod Lists //////
std::shared_ptr<ModsModel> modsModel() const;
std::shared_ptr<SimpleModList> loaderModList() const;
std::shared_ptr<SimpleModList> coreModList() const;
std::shared_ptr<SimpleModList> resourcePackList() const;
std::shared_ptr<SimpleModList> texturePackList() const;
std::shared_ptr<ModFolderModel> loaderModList() const;
std::shared_ptr<ModFolderModel> coreModList() const;
std::shared_ptr<ModFolderModel> resourcePackList() const;
std::shared_ptr<ModFolderModel> texturePackList() const;
std::shared_ptr<WorldList> worldList() const;
std::shared_ptr<GameOptions> gameOptionsModel() const;
////// Launch stuff //////
shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override;
std::shared_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override;
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override;
QStringList extraArguments() const override;
QStringList verboseDescription(AuthSessionPtr session) override;
QList<Mod> getJarMods() const;
@@ -111,9 +111,6 @@ public:
virtual JavaVersion getJavaVersion() const;
signals:
void versionReloaded();
protected:
QMap<QString, QString> createCensorFilterFromSession(AuthSessionPtr session);
QStringList validLaunchMethods();
@@ -124,12 +121,12 @@ private:
protected: // data
std::shared_ptr<ComponentList> m_components;
mutable std::shared_ptr<ModsModel> m_mods_model;
mutable std::shared_ptr<SimpleModList> m_loader_mod_list;
mutable std::shared_ptr<SimpleModList> m_core_mod_list;
mutable std::shared_ptr<SimpleModList> m_resource_pack_list;
mutable std::shared_ptr<SimpleModList> m_texture_pack_list;
mutable std::shared_ptr<ModFolderModel> m_loader_mod_list;
mutable std::shared_ptr<ModFolderModel> m_core_mod_list;
mutable std::shared_ptr<ModFolderModel> m_resource_pack_list;
mutable std::shared_ptr<ModFolderModel> m_texture_pack_list;
mutable std::shared_ptr<WorldList> m_world_list;
mutable std::shared_ptr<GameOptions> m_game_options;
};
typedef std::shared_ptr<MinecraftInstance> MinecraftInstancePtr;

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,378 +0,0 @@
/* Copyright 2013-2018 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 <QDir>
#include <QString>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <quazip.h>
#include <quazipfile.h>
#include "Mod.h"
#include "settings/INIFile.h"
#include <FileSystem.h>
#include <QDebug>
Mod::Mod(const QFileInfo &file)
{
repath(file);
m_changedDateTime = file.lastModified();
}
void Mod::repath(const QFileInfo &file)
{
m_file = file;
QString name_base = file.fileName();
m_type = Mod::MOD_UNKNOWN;
if (m_file.isDir())
{
m_type = MOD_FOLDER;
m_name = name_base;
m_mmc_id = name_base;
}
else if (m_file.isFile())
{
if (name_base.endsWith(".disabled"))
{
m_enabled = false;
name_base.chop(9);
}
else
{
m_enabled = true;
}
m_mmc_id = name_base;
if (name_base.endsWith(".zip") || name_base.endsWith(".jar"))
{
m_type = MOD_ZIPFILE;
name_base.chop(4);
}
else if (name_base.endsWith(".litemod"))
{
m_type = MOD_LITEMOD;
name_base.chop(8);
}
else
{
m_type = MOD_SINGLEFILE;
}
m_name = name_base;
}
if (m_type == MOD_ZIPFILE)
{
QuaZip zip(m_file.filePath());
if (!zip.open(QuaZip::mdUnzip))
return;
QuaZipFile file(&zip);
if (zip.setCurrentFile("mcmod.info"))
{
if (!file.open(QIODevice::ReadOnly))
{
zip.close();
return;
}
ReadMCModInfo(file.readAll());
file.close();
zip.close();
return;
}
else if (zip.setCurrentFile("forgeversion.properties"))
{
if (!file.open(QIODevice::ReadOnly))
{
zip.close();
return;
}
ReadForgeInfo(file.readAll());
file.close();
zip.close();
return;
}
zip.close();
}
else if (m_type == MOD_FOLDER)
{
QFileInfo mcmod_info(FS::PathCombine(m_file.filePath(), "mcmod.info"));
if (mcmod_info.isFile())
{
QFile mcmod(mcmod_info.filePath());
if (!mcmod.open(QIODevice::ReadOnly))
return;
auto data = mcmod.readAll();
if (data.isEmpty() || data.isNull())
return;
ReadMCModInfo(data);
}
}
else if (m_type == MOD_LITEMOD)
{
QuaZip zip(m_file.filePath());
if (!zip.open(QuaZip::mdUnzip))
return;
QuaZipFile file(&zip);
if (zip.setCurrentFile("litemod.json"))
{
if (!file.open(QIODevice::ReadOnly))
{
zip.close();
return;
}
ReadLiteModInfo(file.readAll());
file.close();
}
zip.close();
}
}
// NEW format
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3
// OLD format:
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc
void Mod::ReadMCModInfo(QByteArray contents)
{
auto getInfoFromArray = [&](QJsonArray arr)->void
{
if (!arr.at(0).isObject())
return;
auto firstObj = arr.at(0).toObject();
m_mod_id = firstObj.value("modid").toString();
m_name = firstObj.value("name").toString();
m_version = firstObj.value("version").toString();
m_homeurl = firstObj.value("url").toString();
m_updateurl = firstObj.value("updateUrl").toString();
m_homeurl = m_homeurl.trimmed();
if(!m_homeurl.isEmpty())
{
// fix up url.
if (!m_homeurl.startsWith("http://") && !m_homeurl.startsWith("https://") &&
!m_homeurl.startsWith("ftp://"))
{
m_homeurl.prepend("http://");
}
}
m_description = firstObj.value("description").toString();
QJsonArray authors = firstObj.value("authorList").toArray();
if (authors.size() == 0)
authors = firstObj.value("authors").toArray();
if (authors.size() == 0)
m_authors = "";
else if (authors.size() >= 1)
{
m_authors = authors.at(0).toString();
for (int i = 1; i < authors.size(); i++)
{
m_authors += ", " + authors.at(i).toString();
}
}
m_credits = firstObj.value("credits").toString();
return;
}
;
QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
// this is the very old format that had just the array
if (jsonDoc.isArray())
{
getInfoFromArray(jsonDoc.array());
}
else if (jsonDoc.isObject())
{
auto val = jsonDoc.object().value("modinfoversion");
if(val.isUndefined())
val = jsonDoc.object().value("modListVersion");
int version = val.toDouble();
if (version != 2)
{
qCritical() << "BAD stuff happened to mod json:";
qCritical() << contents;
return;
}
auto arrVal = jsonDoc.object().value("modlist");
if(arrVal.isUndefined())
arrVal = jsonDoc.object().value("modList");
if (arrVal.isArray())
{
getInfoFromArray(arrVal.toArray());
}
}
}
void Mod::ReadForgeInfo(QByteArray contents)
{
// Read the data
m_name = "Minecraft Forge";
m_mod_id = "Forge";
m_homeurl = "http://www.minecraftforge.net/forum/";
INIFile ini;
if (!ini.loadFile(contents))
return;
QString major = ini.get("forge.major.number", "0").toString();
QString minor = ini.get("forge.minor.number", "0").toString();
QString revision = ini.get("forge.revision.number", "0").toString();
QString build = ini.get("forge.build.number", "0").toString();
m_version = major + "." + minor + "." + revision + "." + build;
}
void Mod::ReadLiteModInfo(QByteArray contents)
{
QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
auto object = jsonDoc.object();
if (object.contains("name"))
{
m_mod_id = m_name = object.value("name").toString();
}
if (object.contains("version"))
{
m_version = object.value("version").toString("");
}
else
{
m_version = object.value("revision").toString("");
}
m_mcversion = object.value("mcversion").toString();
m_authors = object.value("author").toString();
m_description = object.value("description").toString();
m_homeurl = object.value("url").toString();
}
bool Mod::replace(Mod &with)
{
if (!destroy())
return false;
bool success = false;
auto t = with.type();
if (t == MOD_ZIPFILE || t == MOD_SINGLEFILE || t == MOD_LITEMOD)
{
qDebug() << "Copy: " << with.m_file.filePath() << " to " << m_file.filePath();
success = QFile::copy(with.m_file.filePath(), m_file.filePath());
}
if (t == MOD_FOLDER)
{
success = FS::copy(with.m_file.filePath(), m_file.path())();
}
if (success)
{
m_name = with.m_name;
m_mmc_id = with.m_mmc_id;
m_mod_id = with.m_mod_id;
m_version = with.m_version;
m_mcversion = with.m_mcversion;
m_description = with.m_description;
m_authors = with.m_authors;
m_credits = with.m_credits;
m_homeurl = with.m_homeurl;
m_type = with.m_type;
m_file.refresh();
}
return success;
}
bool Mod::destroy()
{
if (m_type == MOD_FOLDER)
{
QDir d(m_file.filePath());
if (d.removeRecursively())
{
m_type = MOD_UNKNOWN;
return true;
}
return false;
}
else if (m_type == MOD_SINGLEFILE || m_type == MOD_ZIPFILE || m_type == MOD_LITEMOD)
{
QFile f(m_file.filePath());
if (f.remove())
{
m_type = MOD_UNKNOWN;
return true;
}
return false;
}
return true;
}
QString Mod::version() const
{
switch (type())
{
case MOD_ZIPFILE:
case MOD_LITEMOD:
return m_version;
case MOD_FOLDER:
return "Folder";
case MOD_SINGLEFILE:
return "File";
default:
return "VOID";
}
}
bool Mod::enable(bool value)
{
if (m_type == Mod::MOD_UNKNOWN || m_type == Mod::MOD_FOLDER)
return false;
if (m_enabled == value)
return false;
QString path = m_file.absoluteFilePath();
if (value)
{
QFile foo(path);
if (!path.endsWith(".disabled"))
return false;
path.chop(9);
if (!foo.rename(path))
return false;
}
else
{
QFile foo(path);
path += ".disabled";
if (!foo.rename(path))
return false;
}
m_file = QFileInfo(path);
m_enabled = value;
return true;
}
bool Mod::operator==(const Mod &other) const
{
return mmc_id() == other.mmc_id();
}
bool Mod::strongCompare(const Mod &other) const
{
return mmc_id() == other.mmc_id() && version() == other.version() && type() == other.type();
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -33,7 +33,7 @@ slots:
auto time_parsed = timeFromS3Time(timestamp);
auto time_serialized = timeToS3Time(time_parsed);
QCOMPARE(time_serialized, timestamp);
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -429,7 +429,3 @@ bool World::operator==(const World &other) const
{
return is_valid == other.is_valid && folderName() == other.folderName();
}
bool World::strongCompare(const World &other) const
{
return is_valid == other.is_valid && folderName() == other.folderName();
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -76,7 +76,6 @@ public:
// WEAK compare operator - used for replacing worlds
bool operator==(const World &other) const;
bool strongCompare(const World &other) const;
private:
void readFromZip(const QFileInfo &file);

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2015-2018 MultiMC Contributors
/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013-2018 MultiMC Contributors
/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

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