Compare commits

..
113 Commits
Author SHA1 Message Date
Chris Bessent 1e5c019767 Bump version to 2.4.3 2021-12-25 14:54:32 -07:00
Chris Bessent d41fbfd7e1 Bump version to 2.4.3rc3 2021-12-23 13:29:21 -07:00
Chris Bessent 2626649cc6 Bump version to 2.4.3 RC 2 2021-12-19 12:19:29 -07:00
Chris Bessent 8d08d7f6ba Update about dialog 2021-12-17 19:46:42 -07:00
Chris Bessent d30a095b3e Bump version to 2.4.3rc1 2021-12-17 05:57:40 -07:00
Chris Bessent b5efa60db9 Fix optional access on profiles dialog 2021-12-07 06:46:28 -07:00
Chris Bessent d82f196aa5 Bump version to 2.4.3alpha4 2021-11-26 13:39:28 -07:00
Chris Bessent 9f8827e3a5 Fix parsing plugins with dots in name 2021-11-26 13:37:28 -07:00
Chris Bessent d58f773c76 Don't blacklist empty usernames and passwords 2021-11-25 13:00:15 -07:00
Chris Bessent 01ad45c7aa Update translations 2021-11-23 20:58:03 -07:00
Chris Bessent 13bdf538a8 Bump version to 2.4.3alpha3 2021-11-23 20:12:03 -07:00
Chris Bessent fc40619fd9 Merge pull request #1621 from LostDragonist/misc_fixes
Misc fixes
2021-11-23 20:05:29 -07:00
Chris Bessent 565f2fddf4 Blacklist %USERNAME% from the log in case it contains PII 2021-11-23 17:48:40 -07:00
Chris Bessent 1d80c547d7 Blacklist Steam username and password from the log 2021-11-23 17:19:00 -07:00
Chris Bessent 1755f526c9 Fix extension parsing for the plugin list
The old code was just looking at the last three letters of the filename instead of looking for any kind of proper extension. This led to something like "alice.__esp" being considered a plugin which is just wrong.
2021-11-23 11:49:44 -07:00
Chris Bessent a1e953f409 Don't add invalid games to the "visit Nexus" list 2021-11-22 21:05:49 -07:00
Chris Bessent b1db3019f4 Fix selecting a new profile
This fixes clicking the "select" button in the profiles dialog when a newly created profile is selected. This was broken as the profile was being selected before the profile was added to the list of selections.

Fixes #1489
2021-11-22 17:12:51 -07:00
Chris Bessent cf137606fd Add Brave to the default blacklist
Fixes #1592
2021-11-22 17:12:51 -07:00
Chris Bessent 9644fef8bd Update Windows detection
Windows 11 reports itself as Windows 10 using the methods normally employed.  Microsoft seems to want people to use the BuildId to identify the version of Windows but I'm going to refuse to do that because it's stupid.

This change also prefers DisplayVersion over ReleaseId as somehow I have both and DisplayVersion is more correct (21H2 vs 2009).  /shrug.

Fixes #1607
2021-11-22 17:12:51 -07:00
Chris Bessent 1077a5bad0 Allow portable instances to set custom paths
Fixes #1610
2021-11-22 17:12:51 -07:00
Chris Bessent 57acd4949b Fix tab order of create instance dialog 2021-11-22 17:12:50 -07:00
Al 6ab88d5de1 Merge pull request #1616 from rux616/template-update
Update old Discord server link
2021-11-19 18:13:30 +01:00
Dan Cassidy 4a687cbfcc Update old Discord server link 2021-11-19 14:14:09 +13:00
Al 6df197579f Merge pull request #1599 from Qudix/disable_cache
Disable qml cache
2021-10-16 16:18:46 +02:00
Qudix 1d20b993d7 Remove from instance ignore list 2021-10-15 21:23:42 -05:00
Qudix 468a8b9383 Disable qml cache 2021-10-15 20:52:51 -05:00
Al 081fa3ec93 Merge pull request #1588 from Qudix/menubar_alt
Add a toggle for the Alt key showing the menubar
2021-10-13 13:12:21 +02:00
Qudix b261f3a1e5 Revert row changes 2021-09-16 15:49:28 -05:00
Qudix acf1730093 Add a toggle for the Alt key showing the menubar 2021-09-11 20:42:20 -05:00
Chris Bessent b5800435aa Bump to version 2.4.3alpha2 2021-08-27 16:53:32 -07:00
Chris Bessent 0e9da8d4f5 Fix checking for updates when no installedFile 2021-08-26 17:57:08 -07:00
Chris Bessent ee745353d9 Merge pull request #1578 from LostDragonist/forcedlib
Enable forced libraries by default
2021-08-23 10:13:23 -07:00
Chris Bessent ae311dd4dc Escape ampersands in game names in instance window
These are technically buttons so Qt tries to make shortcuts.
2021-08-22 13:10:47 -07:00
Chris Bessent 1b2f85a371 Enable forced libraries by default 2021-08-22 11:48:27 -07:00
Al a279745aa2 Merge pull request #1558 from ModOrganizer2/facegen
Added Facegen content icon
2021-07-16 14:40:28 +02:00
AL ac8b67dd63 Added Facegen content icon (found and edited by Atlntssplayer, original creator: Exuin) 2021-07-16 14:37:30 +02:00
Al 9256739e3a Merge pull request #1555 from ModOrganizer2/nexus-archived-support
Nexus archived support
2021-07-16 12:31:29 +02:00
AL d413f673e8 Added ARCHIVED support for nexus update check and download query.
Use FileStatus enum instead of scattered int literals.
Re-wrote the update check code
2021-07-12 02:33:05 +02:00
AL 4bdb4aff50 Added enum for nexus mod file status (main, update, etc). 2021-07-12 00:07:55 +02:00
Al 58e5058a2b Merge pull request #1553 from ModOrganizer2/download-sorting
Sort filetimes from newer to older while sorting by status in downloadlist
2021-07-10 20:59:47 +02:00
AL 197f619335 Sort filetimes from newer to older while sorting by status in downloadlist 2021-07-10 20:48:24 +02:00
Al 4e3d7d0180 Merge pull request #1552 from ModOrganizer2/fix-no-compile
Fix compiler error due to using same name for new dialog (VS v16.10.3)
2021-07-10 20:40:41 +02:00
AL b5cb1a2311 Fix compiler error due to using same name for new dialog (VS v16.10.3) 2021-07-10 20:36:36 +02:00
Al b5d04eff4f Update readme.md 2021-06-08 17:55:02 +02:00
Mikaël Capelle b2353278aa Merge pull request #1528 from Holt59/remove-boost-uibase
Update after removal of boost in uibase.
2021-05-27 15:43:26 +02:00
Mikaël Capelle 0bdfd4813f Update after removal of boost in uibase. 2021-05-26 20:03:08 +02:00
Mikaël Capelle e7f15ff4fd Merge pull request #1518 from LostDragonist/shortcut
Sanitize shortcut names as they result in files
2021-05-20 20:22:30 +02:00
Mikaël Capelle e8149a4b42 Merge pull request #1523 from Holt59/ignore-meta-filetree
Add option to ignore root meta.ini when creating IFileTree for QDir.
2021-05-20 20:21:17 +02:00
Mikaël Capelle d531245dea Merge pull request #1524 from Holt59/iorganizer-virtualfiletree
Add IOrganizer::virtualFileTree().
2021-05-20 20:20:45 +02:00
Mikaël Capelle ac38371648 Add IOrganizer::virtualFileTree(). 2021-05-14 14:40:15 +02:00
Mikaël Capelle c44b1cb3a3 Add option to ignore root meta.ini when creating IFileTree for QDir. 2021-05-12 20:41:41 +02:00
Chris Bessent 2a5dd6c7cf Bump to version 2.4.2 2021-05-11 06:25:20 -07:00
Chris Bessent ef5b9228da Sanitize shortcut names as they result in files 2021-05-06 03:44:40 -07:00
Chris Bessent ce2450885c Bump version to 2.4.2rc1.1 2021-05-01 19:38:14 -07:00
Chris Bessent d78cb58593 Update translation file 2021-05-01 17:53:37 -07:00
Chris Bessent 2c54d128b4 Add some more Microsoft Store errors 2021-05-01 17:10:27 -07:00
Chris Bessent f71288db16 Bump to 2.4.2 RC 1 2021-05-01 15:23:16 -07:00
Chris Bessent 8bac17c2c5 Merge pull request #1508 from LostDragonist/gamepass
Add log for Microsoft Store / Gamepass installs
2021-05-01 15:21:45 -07:00
Chris Bessent 4509911a8e Add log for Microsoft Store / Gamepass installs 2021-05-01 15:18:15 -07:00
Chris Bessent f098491306 Merge pull request #1503 from LostDragonist/filename
Sanitize download file names
2021-05-01 14:38:17 -07:00
Chris Bessent bcaceb9637 Merge pull request #1504 from LostDragonist/skipcwd
Ignore "." and ".." in archives
2021-05-01 14:38:10 -07:00
Chris Bessent b7e8e69f47 Merge pull request #1507 from LostDragonist/tutorials
Fix up tutorials
2021-05-01 14:37:59 -07:00
Chris Bessent a8bcbf6555 Fix up tutorials 2021-04-30 08:41:29 -07:00
Chris Bessent aafd523736 Merge pull request #1505 from LostDragonist/foresto
Add foresto as a contributor
2021-04-29 02:02:19 -07:00
Chris Bessent 4a9da205cd Merge pull request #1485 from foresto/patch-1
Reduce log level of harmless failures
2021-04-29 02:02:05 -07:00
Chris Bessent 68e7820154 Add foresto as a contributor 2021-04-29 02:01:38 -07:00
Chris Bessent 3c6190d713 Merge pull request #1470 from isanae/filtered-nav-crash
Crash for next/previous in mod info dialog
2021-04-29 01:59:05 -07:00
Chris Bessent 1197b562f6 Merge pull request #1496 from LostDragonist/nexus_links
Change the "Visit Nexus" button to support alternate sources
2021-04-29 01:57:13 -07:00
Chris Bessent 7df5329ea0 Merge pull request #1497 from LostDragonist/profile_fix
Fix selecting the profile in the dialog
2021-04-29 01:56:52 -07:00
Chris Bessent dc3dcd9500 Fix fixDirectoryName includes 2021-04-29 01:50:23 -07:00
Chris Bessent cc8fb9bd23 Ignore "." and ".." in archives 2021-04-29 01:29:38 -07:00
Chris Bessent 9638a797d1 Sanitize download file names
Also switch instance name sanitizer to MOBase version
2021-04-29 00:50:11 -07:00
Chris Bessent 8308dfcbff Fix selecting the profile in the dialog
Previously, when clicking the "select" button in the profiles
dialog (when the dialog was launched in the menu or toolbar),
everything would be refreshed without checking the selected
profile in the dialog.

Now, the selected profile is set with some signal blocking to
help prevent redundant refreshes from occurring.
2021-04-25 05:09:58 -07:00
Chris Bessent dfbaed0ade Add a separator after the primary game and sort the secondary games 2021-04-25 04:45:35 -07:00
Chris Bessent e475893ff4 Change the "Visit Nexus" button to support alternate sources
If a game plugin supports more than one Nexus site for downloads,
the "Visit Nexus" button will be turned into a drop-down that
lets you select each site.
2021-04-25 04:13:12 -07:00
Al 40a4bf1e3a Update issue templates 2021-04-08 16:51:11 +02:00
Forest 3ee2598533 Reduce log level of harmless failures
These two messages (along with their glaring red X icons) are cluttering up the log on linux/wine systems, misleading people who are trying to diagnose real problems. Let's reduce their log priority to make it clear that they're harmless.

As mentioned here:
https://github.com/ModOrganizer2/modorganizer/issues/372#issuecomment-575231673
2021-04-05 23:10:54 -07:00
isanae 234ee923fe model() can return null for invalid indexes
happens when looking at the mod info for a mod filtered out of the mod list
2021-03-20 14:51:44 -04:00
Mikaël Capelle 88ee41ae85 Bump to 2.4.1. 2021-03-20 17:03:36 +01:00
Mikaël Capelle 8a29bc5110 Bump to 2.4.1 RC2. 2021-03-14 20:08:58 +01:00
Mikaël Capelle 77dbd7ff31 Merge pull request #1465 from Holt59/fix-saves-tab-header
Stretch last section in the Saves tab.
2021-03-14 20:08:30 +01:00
Mikaël Capelle 7fab050adb Stretch last section in the Saves tab. 2021-03-14 20:07:09 +01:00
Mikaël Capelle b547045203 Bump to 2.4.1rc1.1. 2021-03-14 20:00:00 +01:00
Mikaël Capelle fcd2e1473f Merge pull request #1462 from Holt59/fix-stylesheets-qscrollarea
Remove border on QScrollArea from stylesheets.
2021-03-13 16:06:18 +01:00
Mikaël Capelle 287dd6d805 Remove border on QScrollArea from stylesheets. 2021-03-13 16:05:43 +01:00
Mikaël Capelle 717c2ca9cf Bump to 2.4.1rc1 and update translations. 2021-03-12 20:51:46 +01:00
Mikaël Capelle abd1a11768 Merge pull request #1449 from isanae/uilocker-disabled
Disabled uilocker for child dialogs
2021-03-03 18:52:55 +01:00
Mikaël Capelle 34636301ea Merge pull request #1447 from LostDragonist/settings_resize
Add scrollbars to some settings tabs to reduce minimum size
2021-03-03 18:52:46 +01:00
Mikaël Capelle f298ea0ae3 Merge pull request #1443 from Holt59/fix-savegame-name
Display savegame name and filepath in saves tab.
2021-03-03 18:52:28 +01:00
Chris Bessent eee1b4b3f1 Put stylesheet stuff into .ui file instead 2021-03-02 21:20:23 -07:00
isanae 00120605fb don't disable dialogs that are children of other dialogs 2021-03-02 14:41:23 -05:00
Mikaël Capelle 32088b47f1 Merge pull request #1446 from LostDragonist/disabled_plugins
Allow plugins to disable themselves by default
2021-03-02 19:27:24 +01:00
Chris Bessent 726b381ea7 Add scrollbars to some settings tabs to reduce minimum size
The previous minimum size was around 450 x 560px.  At a DPI scaling
of 200%, this means 900 x 1120px which extends off the typical 1080p
screen.  Why is someone using 200% scaling on a 1080p screen?  I have
no clue.

Now, the minimum size is around 450 x 410px for 900 x 820 px at 200%
scaling.  Which works for anything short of a 1376 x 768 screen at
200% scaling which I just don't really care about.
2021-03-02 04:07:46 -07:00
Chris Bessent 071550f7fb Allow plugins to disable themselves by default 2021-03-02 02:41:16 -07:00
Mikaël Capelle f8a50edd0f Merge pull request #1444 from LostDragonist/lockedorder
Fix load order when using locked plugins
2021-03-01 19:21:24 +01:00
Mikaël Capelle 08c7113ecb Merge pull request #1439 from Holt59/fix-downloadlist
Fix download list sorting.
2021-03-01 19:21:15 +01:00
Mikaël Capelle d436fe8cb3 Merge pull request #1442 from Holt59/fix-createempty-mod
Fix priority for 'Create Empty Mod'.
2021-03-01 19:21:06 +01:00
Chris Bessent d5183ebe6b Fix load order when using locked plugins 2021-02-27 18:50:45 -07:00
Mikaël Capelle c72326ee4b Display savegame name and filepath in saves tab. 2021-02-27 12:42:37 +01:00
Mikaël Capelle 75e90f2f3f Fix priority for 'Create Empty Mod'. 2021-02-27 10:36:17 +01:00
Mikaël Capelle be012715f3 Fix download list sorting. 2021-02-26 21:32:39 +01:00
Mikaël Capelle 2b86a14c86 Merge pull request #1437 from Holt59/fix-sendtoseparator
Fix 'Send to separator... ' in descending priority.
2021-02-26 21:12:04 +01:00
Mikaël Capelle c96c01f40e Fix 'Send to separator... ' in descending priority. 2021-02-24 20:07:55 +01:00
Mikaël Capelle d6edc5d6b7 Merge pull request #1433 from Holt59/fix-bycategory-sorting
Fix sorting by priority when grouping by priority.
2021-02-24 18:35:18 +01:00
isanae 4040dc12b7 Merge pull request #1436 from isanae/tutorial-fix
Fix tutorial stuck on mod info dialog
2021-02-24 05:46:48 -05:00
isanae d4fc7c3de1 emit modInfoDisplayed, it's required by the tutorial 2021-02-24 04:57:54 -05:00
Mikaël Capelle 27c4861907 Fix sorting by priority when grouping by priority. 2021-02-23 19:16:18 +01:00
Mikaël Capelle 8decb9df68 Merge pull request #1431 from Holt59/fix-update-filter
Switch back to invalidating filter when receiving mod updates.
2021-02-23 17:23:08 +01:00
Mikaël Capelle 8365f26d83 Merge pull request #1424 from isanae/dl-share
Network shares for envfs
2021-02-23 17:19:53 +01:00
Mikaël Capelle 0ca21d9a5e Merge pull request #1429 from Holt59/fix-stylesheets
Fix stylesheets for 2.4.
2021-02-23 17:19:43 +01:00
Mikaël Capelle f60d0e5ec6 Fix stylesheets for 2.4. 2021-02-23 09:38:52 +01:00
isanae d22d77d921 handle network shares for NtOpenFile()
changed error messages to use formatNtMessage(), which handles NTSTATUS errors
2021-02-22 18:28:07 -05:00
Mikaël Capelle 010a5d80d6 Switch back to invalidating filter when receiving mod updates. 2021-02-21 11:12:16 +01:00
79 changed files with 2972 additions and 2202 deletions
@@ -2,7 +2,7 @@
name: Game support Request
about: Request support for a new game
title: Add support for game [GAME NAME]
labels: 'additional games support, Feature Request, area: mo2 game plugins'
labels: 'Feature Request, additional games support, area: mo2 game plugins'
assignees: ''
---
@@ -18,7 +18,7 @@ assignees: ''
- **Nexus ID [optional]:** ID of the game on Nexus (you can usually find this in Nexus URL).
- **Executable:** Name of the main executable for the game (relative to the game folder).
- **Launcher [optional]:** Name of the game launcher (relative to the game folder).
- **Data path:** Path to the data folder of the game (relative to the game folder).
- **Data path:** Path to the data folder of the game (relative to the game folder). Please note that the Virtual Files System often does not work for top level dlls or exe files.
- **Documents path:** Path to folder containing INI files, etc., for the game (usually under "My Games", or the game folder itself).
- **Saves directory [optional]:** Path to the folder containing save games (this default to the path above).
- **Save extension [optional]:** Extension of the saves
+1 -1
View File
@@ -8,7 +8,7 @@ assignees: ''
---
## The problem:
Briefly describe the issue you are experiencing. Tell us what you were trying to do and what happened instead. Remember, this is _not_ a place to ask questions. For that, go to our [discord channel](https://discord.gg/5tCqt6V)
Briefly describe the issue you are experiencing. Tell us what you were trying to do and what happened instead. Remember, this is _not_ a place to ask questions. For that, go to our [Discord server](https://discord.gg/6GKR9jZ).
## To Reproduce:
+2 -2
View File
@@ -12,7 +12,7 @@ The project took up speed again after a few more coders showed up in late 2017,
## Help Wanted!
Mod Organizer 2 is an open project in the hands of the community, there are problems that need to be solved and things that could be added. MO2 really needs developers and if you have the programming skills and some free time you can really improve the experience of the modding community.
To have more information, please join the open MO2 Development discord server: [Mod Organizer 2](https://discord.gg/vD2ZbfX)
To have more information, please join the open MO2 Development discord server: [Mod Organizer 2](https://discord.gg/6GKR9jZ)
If you want to help translate MO2 to your language you should join the discord server too and head to the #translation channel.
To setup a development environment on your machine, there is the [mob project](https://github.com/modorganizer2/mob) that handles that.
If you want to submit your code changes, please use a good formatting style like the default one in Visual Studio.
@@ -20,7 +20,7 @@ If you want to submit your code changes, please use a good formatting style like
Through the work of a few people of the community MO2 has come quite far, now it needs some more of those people to go further.
## Reporting Issues:
Issues should be reported to the GitHub page or on the open discord server: [Mod Organizer 2](https://discord.gg/vD2ZbfX). Here is also where dev builds are tested, bugs are reported and investigated, suggestions are discussed and a lot more.
Issues should be reported to the GitHub page or on the open discord server: [Mod Organizer 2](https://discord.gg/6GKR9jZ). Here is also where dev builds are tested, bugs are reported and investigated, suggestions are discussed and a lot more.
Credits to Tannin, LePresidente, Silarn, erasmux, AL12, LostDragonist, AnyOldName3, isa, Holt59 and many others for the development.
+1
View File
@@ -37,6 +37,7 @@ add_filter(NAME src/core GROUPS
apiuseraccount
processrunner
qdirfiletree
virtualfiletree
uilocker
)
+84 -9
View File
@@ -127,7 +127,7 @@
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Copyright © 2011-2016 Sebastian Herbord&lt;br/&gt;Copyright © 2016-2019 Mod Organizer 2 Contributors&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Copyright © 2011-2016 Sebastian Herbord&lt;br/&gt;Copyright © 2016-2021 Mod Organizer 2 Contributors&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@@ -261,6 +261,11 @@
<string notr="true">przester</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Qudix</string>
</property>
</item>
</widget>
</item>
</layout>
@@ -292,11 +297,31 @@
<string notr="true">miraclefreak (Czech)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Meiton (Czech)</string>
</property>
</item>
<item>
<property name="text">
<string>Cyb3r (Dutch)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">madmedic (Dutch)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Ilja (Finnish)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Mikmet (Finnish)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Alyndiar (French)</string>
@@ -322,6 +347,11 @@
<string>Yoplala (French)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">CircleOfDao (German)</string>
</property>
</item>
<item>
<property name="text">
<string>Faron (German)</string>
@@ -337,6 +367,11 @@
<string notr="true">Xahtax (German)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Ypselon (German)</string>
</property>
</item>
<item>
<property name="text">
<string>yohru (Japanese)</string>
@@ -400,6 +435,11 @@
<string notr="true">Hakan &quot;Nyks45&quot; Albayrak (Turkish)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Kato (Turkish)</string>
</property>
</item>
<item>
<property name="text">
<string>...and all other contributors!</string>
@@ -426,7 +466,7 @@
</property>
<item>
<property name="text">
<string>Tannin (Original Creator)</string>
<string notr="true">Tannin (Original Creator)</string>
</property>
</item>
<item>
@@ -454,11 +494,21 @@
<string notr="true">Brixified</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">ddbb07</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">deathneko11</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">dekart811</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">DoubleYou</string>
@@ -469,6 +519,26 @@
<string notr="true">Drew Warwick</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">erri120</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">ianpatt</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Falsellyu</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">foresto</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">GamerPoet</string>
@@ -491,7 +561,17 @@
</item>
<item>
<property name="text">
<string>Luca|EzioTheDeadPoet</string>
<string notr="true">JayLCypher</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">jimfcarroll</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Luca|EzioTheDeadPoet</string>
</property>
</item>
<item>
@@ -506,7 +586,7 @@
</item>
<item>
<property name="text">
<string>Patchier</string>
<string notr="true">Patchier</string>
</property>
</item>
<item>
@@ -514,11 +594,6 @@
<string notr="true">PurpleFez</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Qudix</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">reedts</string>
+13 -6
View File
@@ -158,14 +158,14 @@ protected:
currentName = std::get<0>(p)[0];
}
// If the name is different, we need to create a directory from what we have
// If the name is different, we need to create a directory from what we have
// accumulated:
if (currentName != std::get<0>(p)[0]) {
// We may or may not have an index here, it depends on the type of archive (some archives list
// intermediate non-empty folders, some don't):
entries.push_back(std::make_shared<ArchiveFileTreeImpl>(parent, currentName, currentIndex, std::move(currentFiles)));
currentFiles.clear(); // Back to a valid state.
// Reset the index:
@@ -200,7 +200,7 @@ protected:
if (currentName != "") {
entries.push_back(std::make_shared<ArchiveFileTreeImpl>(parent, currentName, currentIndex, std::move(currentFiles)));
}
// Let the parent class sort the entries:
return false;
}
@@ -214,7 +214,7 @@ private:
mutable std::vector<File> m_Files;
};
std::shared_ptr<ArchiveFileTree> ArchiveFileTree::makeTree(Archive const& archive)
std::shared_ptr<ArchiveFileTree> ArchiveFileTree::makeTree(Archive const& archive)
{
auto const& data = archive.getFileList();
@@ -222,9 +222,16 @@ std::shared_ptr<ArchiveFileTree> ArchiveFileTree::makeTree(Archive const& archiv
files.reserve(data.size());
for (size_t i = 0; i < data.size(); ++i) {
// Ignore "." and ".." as they're useless and muck things up
if (data[i]->getArchiveFilePath().compare(L".") == 0 ||
data[i]->getArchiveFilePath().compare(L"..") == 0)
{
continue;
}
files.push_back(std::make_tuple(
QString::fromStdWString(data[i]->getArchiveFilePath()).replace("\\", "/").split("/", Qt::SkipEmptyParts),
data[i]->isDirectory(),
QString::fromStdWString(data[i]->getArchiveFilePath()).replace("\\", "/").split("/", Qt::SkipEmptyParts),
data[i]->isDirectory(),
(int) i));
}
+17 -20
View File
@@ -341,28 +341,25 @@ void CreateInstanceDialog::finish()
s.game().setEdition(ci.gameVariant);
}
if (ci.type == Global) {
if (ci.paths.base != ci.dataPath) {
s.paths().setBase(ci.paths.base);
}
if (ci.paths.downloads != cid::makeDefaultPath(AppConfig::downloadPath())) {
s.paths().setDownloads(ci.paths.downloads);
}
if (ci.paths.mods != cid::makeDefaultPath(AppConfig::modsPath())) {
s.paths().setMods(ci.paths.mods);
}
if (ci.paths.profiles != cid::makeDefaultPath(AppConfig::profilesPath())) {
s.paths().setProfiles(ci.paths.profiles);
}
if (ci.paths.overwrite != cid::makeDefaultPath(AppConfig::overwritePath())) {
s.paths().setOverwrite(ci.paths.overwrite);
}
if (ci.paths.base != ci.dataPath) {
s.paths().setBase(ci.paths.base);
}
if (ci.paths.downloads != cid::makeDefaultPath(AppConfig::downloadPath())) {
s.paths().setDownloads(ci.paths.downloads);
}
if (ci.paths.mods != cid::makeDefaultPath(AppConfig::modsPath())) {
s.paths().setMods(ci.paths.mods);
}
if (ci.paths.profiles != cid::makeDefaultPath(AppConfig::profilesPath())) {
s.paths().setProfiles(ci.paths.profiles);
}
if (ci.paths.overwrite != cid::makeDefaultPath(AppConfig::overwritePath())) {
s.paths().setOverwrite(ci.paths.overwrite);
}
logCreation(tr("Writing %1...").arg(ci.iniPath));
+40 -8
View File
@@ -67,7 +67,7 @@
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page_10">
<widget class="QWidget" name="page_1">
<layout class="QVBoxLayout" name="verticalLayout_21">
<item>
<widget class="QLabel" name="label_15">
@@ -115,7 +115,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page">
<widget class="QWidget" name="page_2">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QWidget" name="widget_7" native="true">
@@ -226,7 +226,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<widget class="QWidget" name="page_3">
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QWidget" name="widget_5" native="true">
@@ -367,7 +367,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page_9">
<widget class="QWidget" name="page_4">
<layout class="QVBoxLayout" name="verticalLayout_19">
<item>
<widget class="QWidget" name="widget_16" native="true">
@@ -594,7 +594,7 @@
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page_7">
<widget class="QWidget" name="page_6_simple">
<layout class="QVBoxLayout" name="verticalLayout_12">
<property name="leftMargin">
<number>0</number>
@@ -676,7 +676,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page_8">
<widget class="QWidget" name="page_6_advanced">
<layout class="QVBoxLayout" name="verticalLayout_13">
<property name="leftMargin">
<number>0</number>
@@ -906,7 +906,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page_3">
<widget class="QWidget" name="page_7">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QWidget" name="widget_4" native="true">
@@ -1048,7 +1048,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page_11">
<widget class="QWidget" name="page_8">
<layout class="QVBoxLayout" name="verticalLayout_22">
<item>
<widget class="QWidget" name="widget_18" native="true">
@@ -1232,6 +1232,38 @@
<header location="global">linklabel.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>next</tabstop>
<tabstop>cancel</tabstop>
<tabstop>hideIntro</tabstop>
<tabstop>createGlobal</tabstop>
<tabstop>createPortable</tabstop>
<tabstop>scrollArea_3</tabstop>
<tabstop>showAllGames</tabstop>
<tabstop>gamesFilter</tabstop>
<tabstop>scrollArea_2</tabstop>
<tabstop>instanceName</tabstop>
<tabstop>location</tabstop>
<tabstop>browseLocation</tabstop>
<tabstop>advancedPathOptions</tabstop>
<tabstop>base</tabstop>
<tabstop>browseBase</tabstop>
<tabstop>downloads</tabstop>
<tabstop>browseDownloads</tabstop>
<tabstop>mods</tabstop>
<tabstop>browseMods</tabstop>
<tabstop>profiles</tabstop>
<tabstop>browseProfiles</tabstop>
<tabstop>overwrite</tabstop>
<tabstop>browseOverwrite</tabstop>
<tabstop>nexusConnect</tabstop>
<tabstop>nexusManual</tabstop>
<tabstop>nexusLog</tabstop>
<tabstop>review</tabstop>
<tabstop>creationLog</tabstop>
<tabstop>launch</tabstop>
<tabstop>back</tabstop>
</tabstops>
<resources>
<include location="resources.qrc"/>
</resources>
+50 -5
View File
@@ -8,6 +8,7 @@
#include <iplugingame.h>
#include <report.h>
#include <utility.h>
#include "filesystemutilities.h"
namespace cid
{
@@ -292,7 +293,7 @@ void GamePage::select(IPluginGame* game, const QString& dir)
Game* checked = findGame(game);
if (checked) {
if (!checked->installed) {
if (!checked->installed || (detectMicrosoftStore(checked->dir) && !confirmMicrosoftStore(checked->dir, checked->game))) {
if (dir.isEmpty()) {
// the selected game has no installation directory and none was given,
// ask the user
@@ -304,6 +305,9 @@ void GamePage::select(IPluginGame* game, const QString& dir)
if (path.isEmpty()) {
// cancelled
checked = nullptr;
} else if (detectMicrosoftStore(path) && !confirmMicrosoftStore(path, game)) {
// cancelled
checked = nullptr;
} else {
// check whether a plugin supports the given directory; this can
// return the same plugin, a different one, or null
@@ -353,6 +357,13 @@ void GamePage::selectCustom()
return;
}
// Microsoft store games are not supported
if (detectMicrosoftStore(path) && !confirmMicrosoftStore(path, nullptr)) {
// reselect the previous button
selectButton(m_selection);
return;
}
// try to find a plugin that likes this directory
for (auto& g : m_games) {
if (g->game->looksValid(path)) {
@@ -463,7 +474,7 @@ void GamePage::updateButton(Game* g)
return;
}
g->button->setText(g->game->gameName());
g->button->setText(g->game->gameName().replace("&", "&&"));
g->button->setIcon(g->game->gameIcon());
if (g->installed) {
@@ -593,6 +604,11 @@ GamePage::Game* GamePage::checkInstallation(const QString& path, Game* g)
return g;
}
if (detectMicrosoftStore(path) && confirmMicrosoftStore(path, g->game)) {
// okay
return g;
}
// the selected game can't use that folder, find another one
IPluginGame* otherGame = nullptr;
@@ -639,6 +655,35 @@ GamePage::Game* GamePage::checkInstallation(const QString& path, Game* g)
return g;
}
bool GamePage::detectMicrosoftStore(const QString& path)
{
return path.contains("/ModifiableWindowsApps/") ||
path.contains("/WindowsApps/");
}
bool GamePage::confirmMicrosoftStore(const QString& path, IPluginGame* game)
{
const auto r = TaskDialog(&m_dlg)
.title(QObject::tr("Microsoft Store game"))
.main(QObject::tr("Microsoft Store game"))
.content(QObject::tr(
"The folder %1 seems to be a Microsoft Store game install. Games"
" installed through the Microsoft Store are not supported by Mod Organizer"
" and will not work properly.")
.arg(path))
.button({
game ? QObject::tr("Use this folder for %1").arg(game->gameName())
: QObject::tr("Use this folder"),
QObject::tr("I know what I'm doing"),
QMessageBox::Ignore})
.button({
QObject::tr("Cancel"),
QMessageBox::Cancel})
.exec();
return (r == QMessageBox::Ignore);
}
bool GamePage::confirmUnknown(const QString& path, IPluginGame* game)
{
const auto r = TaskDialog(&m_dlg)
@@ -856,7 +901,7 @@ QString NamePage::selectedInstanceName() const
}
const auto text = ui->instanceName->text().trimmed();
return InstanceManager::singleton().sanitizeInstanceName(text);
return MOBase::sanitizeFileName(text);
}
void NamePage::onChanged()
@@ -883,7 +928,7 @@ bool NamePage::checkName(QString parentDir, QString name)
if (name.isEmpty()) {
empty = true;
} else {
if (InstanceManager::singleton().validInstanceName(name)) {
if (MOBase::validFileName(name)) {
exists = QDir(parentDir).exists(name);
} else {
invalid = true;
@@ -1108,7 +1153,7 @@ bool PathsPage::checkPath(
} else {
const QDir d(path);
if (m.validInstanceName(d.dirName())) {
if (MOBase::validFileName(d.dirName())) {
if (m_dlg.rawCreationInfo().type == CreateInstanceDialog::Portable) {
// the default data path for a portable instance is the application
// directory, so it's not an error if it exists
+9
View File
@@ -354,6 +354,15 @@ private:
MOBase::IPluginGame* confirmOtherGame(
const QString& path,
MOBase::IPluginGame* selectedGame, MOBase::IPluginGame* guessedGame);
// detects if the given path likely contains a Microsoft Store game
//
bool detectMicrosoftStore(const QString& path);
// tells the user that the path probably contains a Microsoft Store game that
// is not supported, returns true if the user decides to accept anyway.
//
bool confirmMicrosoftStore(const QString& path, MOBase::IPluginGame* game);
};
+5
View File
@@ -265,6 +265,11 @@ void DirectoryRefresher::stealModFilesIntoStructure(
for (const QString &filename : stealFiles) {
if (filename.isEmpty()) {
log::warn("Trying to find file with no name");
log::warn(" . modName: {}", modName);
log::warn(" . directory: {}", directory);
log::warn(" . priority: {}", priority);
for (int i = 0; i < stealFiles.length(); ++i)
log::warn(" . stealFiles[{}]: {}", i, stealFiles[i]);
continue;
}
QFileInfo fileInfo(filename);
+3 -3
View File
@@ -226,7 +226,7 @@ bool DownloadList::lessThanPredicate(const QModelIndex &left, const QModelIndex
if ((leftIndex < m_manager.numTotalDownloads())
&& (rightIndex < m_manager.numTotalDownloads())) {
if (left.column() == DownloadList::COL_NAME) {
return m_manager.getFileName(left.row()).compare(m_manager.getFileName(right.row()), Qt::CaseInsensitive) < 0;
return left.data(Qt::DisplayRole).toString().compare(right.data(Qt::DisplayRole).toString(), Qt::CaseInsensitive) < 0;
} else if (left.column() == DownloadList::COL_MODNAME) {
QString leftName, rightName;
@@ -273,9 +273,9 @@ bool DownloadList::lessThanPredicate(const QModelIndex &left, const QModelIndex
DownloadManager::DownloadState leftState = m_manager.getState(left.row());
DownloadManager::DownloadState rightState = m_manager.getState(right.row());
if (leftState == rightState)
return m_manager.getFileTime(left.row()) < m_manager.getFileTime(right.row());
return m_manager.getFileTime(left.row()) > m_manager.getFileTime(right.row());
else
return leftState > rightState;
return leftState < rightState;
} else if (left.column() == DownloadList::COL_SIZE) {
return m_manager.getFileSize(left.row()) < m_manager.getFileSize(right.row());
} else if (left.column() == DownloadList::COL_FILETIME) {
+8 -4
View File
@@ -33,6 +33,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "shared/util.h"
#include <utility.h>
#include <report.h>
#include "filesystemutilities.h"
#include <QTimer>
#include <QFileInfo>
@@ -1222,6 +1223,7 @@ QString DownloadManager::getFileTypeString(int fileType)
case 4: return tr("Old");
case 5: return tr("Miscellaneous");
case 6: return tr("Deleted");
case 7: return tr("Archived");
default: return tr("Unknown");
}
}
@@ -1456,7 +1458,7 @@ void DownloadManager::markUninstalled(QString fileName)
QString DownloadManager::getDownloadFileName(const QString &baseName, bool rename) const
{
QString fullPath = m_OutputDirectory + "/" + baseName;
QString fullPath = m_OutputDirectory + "/" + MOBase::sanitizeFileName(baseName);
if (QFile::exists(fullPath) && rename) {
int i = 1;
while (QFile::exists(QString("%1/%2_%3").arg(m_OutputDirectory).arg(i).arg(baseName))) {
@@ -1476,7 +1478,7 @@ QString DownloadManager::getFileNameFromNetworkReply(QNetworkReply *reply)
std::cmatch result;
if (std::regex_search(reply->rawHeader("Content-Disposition").constData(), result, exp)) {
return QString::fromUtf8(result.str(1).c_str());
return MOBase::sanitizeFileName(QString::fromUtf8(result.str(1).c_str()));
}
}
@@ -1722,7 +1724,8 @@ void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, QVarian
{return lhs.toMap()["uploaded_timestamp"].toInt() > rhs.toMap()["uploaded_timestamp"].toInt();});
for (QVariant file : files) {
QVariantMap fileInfo = file.toMap();
if (fileInfo["category_id"].toInt() != 6)
if (fileInfo["category_id"].toInt() != NexusInterface::FileStatus::REMOVED &&
fileInfo["category_id"].toInt() != NexusInterface::FileStatus::ARCHIVED)
selection.addChoice(fileInfo["file_name"].toString(), "", file);
}
if (selection.exec() == QDialog::Accepted) {
@@ -1957,7 +1960,8 @@ void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant use
auto results = resultlist[i].toMap();
auto fileDetails = results["file_details"].toMap();
if (fileDetails["category_id"].toInt() != 6) { //6 = deleted
if (fileDetails["category_id"].toInt() != NexusInterface::FileStatus::REMOVED &&
fileDetails["category_id"].toInt() != NexusInterface::FileStatus::ARCHIVED) {
if (chosenIdx < 0) {
chosenIdx = i; //intentional to not break in order to check other results
} else {
+23 -5
View File
@@ -232,8 +232,8 @@ void forEachEntryImpl(
if (status < 0) {
log::error(
"NtOpenFile() failed for '{}', {}",
toString(poa), formatSystemMessage(status));
"failed to open directory '{}': {}",
toString(poa), formatNtMessage(status));
return;
}
@@ -264,8 +264,9 @@ void forEachEntryImpl(
break;
} else if (status < 0) {
log::error(
"NtQueryDirectoryFile() failed for '{}', {}",
toString(poa), formatSystemMessage(status));
"failed to read directory '{}': {}",
toString(poa), formatNtMessage(status));
break;
}
@@ -321,6 +322,23 @@ void forEachEntryImpl(
}
}
std::wstring makeNtPath(const std::wstring& path)
{
constexpr const wchar_t* nt_prefix = L"\\??\\";
constexpr const wchar_t* nt_unc_prefix = L"\\??\\UNC\\";
constexpr const wchar_t* share_prefix = L"\\\\";
if (path.starts_with(nt_prefix)) {
// already an nt path
return path;
} else if (path.starts_with(share_prefix)) {
// network shared need \??\UNC\ as a prefix
return nt_unc_prefix + path.substr(2);
} else {
// prepend the \??\ prefix
return nt_prefix + path;
}
}
void DirectoryWalker::forEachEntry(
const std::wstring& path, void* cx,
@@ -335,7 +353,7 @@ void DirectoryWalker::forEachEntry(
NtClose = (NtClose_type)::GetProcAddress(m.get(), "NtClose");
}
const std::wstring ntpath = std::wstring(L"\\??\\") + path;
const std::wstring ntpath = makeNtPath(path);
UNICODE_STRING ObjectName = {};
ObjectName.Buffer = const_cast<wchar_t*>(ntpath.c_str());
+2 -2
View File
@@ -130,7 +130,7 @@ Module::FileInfo Module::getFileInfo() const
return {};
}
log::error(
log::debug(
"GetFileVersionInfoSizeW() failed on '{}', {}",
m_path, formatSystemMessage(e));
@@ -268,7 +268,7 @@ QDateTime Module::getTimestamp(const VS_FIXEDFILEINFO& fi) const
if (h.get() == INVALID_HANDLE_VALUE) {
const auto e = GetLastError();
log::error(
log::debug(
"can't open file '{}' for timestamp, {}",
m_path, formatSystemMessage(e));
+3 -2
View File
@@ -2,6 +2,7 @@
#include "env.h"
#include "executableslist.h"
#include "instancemanager.h"
#include "filesystemutilities.h"
#include <utility.h>
#include <log.h>
@@ -147,7 +148,7 @@ Shortcut::Shortcut(const Executable& exe)
{
const auto i = *InstanceManager::singleton().currentInstance();
m_name = exe.title();
m_name = MOBase::sanitizeFileName(exe.title());
m_target = QFileInfo(qApp->applicationFilePath()).absoluteFilePath();
m_arguments = QString("\"moshortcut://%1:%2\"")
@@ -165,7 +166,7 @@ Shortcut::Shortcut(const Executable& exe)
Shortcut& Shortcut::name(const QString& s)
{
m_name = s;
m_name = MOBase::sanitizeFileName(s);
return *this;
}
+4 -9
View File
@@ -94,11 +94,6 @@ QString WindowsInfo::toString() const
sl.push_back(m_release.buildLab);
}
// product name
if (!m_release.productName.isEmpty()) {
sl.push_back(m_release.productName);
}
// elevated
QString elevated = "?";
if (m_elevated.has_value()) {
@@ -187,11 +182,11 @@ WindowsInfo::Release WindowsInfo::getRelease() const
}
}
// localized name of windows, such as "Windows 10 Pro"
r.productName = settings.value("ProductName", "").toString();
// release ID, such as 1803
r.ID = settings.value("ReleaseId", "").toString();
r.ID = settings.value("DisplayVersion", "").toString();
if (r.ID.isEmpty()) {
r.ID = settings.value("ReleaseId", "").toString();
}
// some other build number, shown in winver.exe
r.UBR = settings.value("UBR", 0).toUInt();
+1 -5
View File
@@ -40,11 +40,7 @@ public:
// the BuildLab entry from the registry, may be empty
QString buildLab;
// product name such as "Windows 10 Pro", may not be in English, may be
// empty
QString productName;
// release ID such as 1809, may be mepty
// release ID such as 1809, may be empty
QString ID;
// some sub-build number, undocumented, may be empty
+1 -1
View File
@@ -21,7 +21,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "installationmanager.h"
#include "utility.h"
#include "filesystemutilities.h"
#include "report.h"
#include "categories.h"
#include "questionboxmemory.h"
+3 -33
View File
@@ -32,6 +32,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <iplugingame.h>
#include <utility.h>
#include <log.h>
#include "filesystemutilities.h"
#include <QCoreApplication>
#include <QDir>
@@ -600,9 +601,7 @@ QString InstanceManager::iniPath(const QString& instanceDir) const
std::vector<QString> InstanceManager::globalInstancePaths() const
{
const std::set<QString> ignore = {
"cache", "qtwebengine",
};
const std::set<QString> ignore = { "qtwebengine" };
const QDir root(globalInstancesRootPath());
const auto dirs = root.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
@@ -721,7 +720,7 @@ const MOBase::IPluginGame* InstanceManager::gamePluginForDirectory(
QString InstanceManager::makeUniqueName(const QString& instanceName) const
{
const QString sanitized = sanitizeInstanceName(instanceName);
const QString sanitized = MOBase::sanitizeFileName(instanceName);
// trying "name (N)"
QString name = sanitized;
@@ -742,35 +741,6 @@ bool InstanceManager::instanceExists(const QString& instanceName) const
return root.exists(instanceName);
}
QString InstanceManager::sanitizeInstanceName(const QString &name) const
{
QString new_name = name;
// Restrict the allowed characters
new_name = new_name.remove(QRegExp("[^A-Za-z0-9 _=+;!@#$%^'\\-\\.\\[\\]\\{\\}\\(\\)]"));
// Don't end in spaces and periods
new_name = new_name.remove(QRegExp("\\.*$"));
new_name = new_name.remove(QRegExp(" *$"));
// Recurse until stuff stops changing
if (new_name != name) {
return sanitizeInstanceName(new_name);
}
return new_name;
}
bool InstanceManager::validInstanceName(const QString& instanceName) const
{
if (instanceName.isEmpty()) {
return false;
}
return (instanceName == sanitizeInstanceName(instanceName));
}
std::unique_ptr<Instance> selectInstance()
{
auto& m = InstanceManager::singleton();

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