From 47e37635f50c09b4f9a9ee7699e3120bab3e4088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 10 Apr 2016 04:29:29 +0200 Subject: NOISSUE split GUI stuff from logic library --- logic/AbstractCommonModel.cpp | 133 ----- logic/AbstractCommonModel.h | 462 ---------------- logic/BaseConfigObject.cpp | 103 ---- logic/BaseConfigObject.h | 50 -- logic/BaseInstaller.cpp | 61 -- logic/BaseInstaller.h | 46 -- logic/BaseInstance.cpp | 275 --------- logic/BaseInstance.h | 243 -------- logic/BaseVersion.h | 59 -- logic/BaseVersionList.cpp | 104 ---- logic/BaseVersionList.h | 126 ----- logic/CMakeLists.txt | 354 ------------ logic/Commandline.cpp | 483 ---------------- logic/Commandline.h | 252 --------- logic/DefaultVariable.h | 35 -- logic/DesktopServices.cpp | 149 ----- logic/DesktopServices.h | 37 -- logic/Env.cpp | 234 -------- logic/Env.h | 66 --- logic/Exception.h | 34 -- logic/FileSystem.cpp | 436 --------------- logic/FileSystem.h | 123 ---- logic/GZip.cpp | 115 ---- logic/GZip.h | 12 - logic/InstanceList.cpp | 582 ------------------- logic/InstanceList.h | 187 ------- logic/Json.cpp | 272 --------- logic/Json.h | 249 --------- logic/MMCStrings.cpp | 76 --- logic/MMCStrings.h | 10 - logic/MMCZip.cpp | 491 ---------------- logic/MMCZip.h | 88 --- logic/NullInstance.h | 90 --- logic/QObjectPtr.h | 78 --- logic/RWStorage.h | 60 -- logic/RecursiveFileSystemWatcher.cpp | 111 ---- logic/RecursiveFileSystemWatcher.h | 63 --- logic/SeparatorPrefixTree.h | 298 ---------- logic/TypeMagic.h | 37 -- logic/Version.cpp | 140 ----- logic/Version.h | 110 ---- logic/icons/IconList.cpp | 381 ------------- logic/icons/IconList.h | 85 --- logic/icons/MMCIcon.cpp | 89 --- logic/icons/MMCIcon.h | 55 -- logic/java/JavaChecker.cpp | 159 ------ logic/java/JavaChecker.h | 54 -- logic/java/JavaCheckerJob.cpp | 45 -- logic/java/JavaCheckerJob.h | 85 --- logic/java/JavaInstall.cpp | 28 - logic/java/JavaInstall.h | 38 -- logic/java/JavaInstallList.cpp | 186 ------- logic/java/JavaInstallList.h | 71 --- logic/java/JavaUtils.cpp | 219 -------- logic/java/JavaUtils.h | 44 -- logic/java/JavaVersion.cpp | 112 ---- logic/java/JavaVersion.h | 30 - logic/launch/LaunchStep.cpp | 27 - logic/launch/LaunchStep.h | 48 -- logic/launch/LaunchTask.cpp | 228 -------- logic/launch/LaunchTask.h | 122 ---- logic/launch/LoggedProcess.cpp | 163 ------ logic/launch/LoggedProcess.h | 76 --- logic/launch/MessageLevel.cpp | 36 -- logic/launch/MessageLevel.h | 28 - logic/launch/steps/CheckJava.cpp | 92 --- logic/launch/steps/CheckJava.h | 41 -- logic/launch/steps/LaunchMinecraft.cpp | 154 ------ logic/launch/steps/LaunchMinecraft.h | 48 -- logic/launch/steps/ModMinecraftJar.cpp | 44 -- logic/launch/steps/ModMinecraftJar.h | 39 -- logic/launch/steps/PostLaunchCommand.cpp | 84 --- logic/launch/steps/PostLaunchCommand.h | 39 -- logic/launch/steps/PreLaunchCommand.cpp | 85 --- logic/launch/steps/PreLaunchCommand.h | 39 -- logic/launch/steps/TextPrint.cpp | 29 - logic/launch/steps/TextPrint.h | 43 -- logic/launch/steps/Update.cpp | 50 -- logic/launch/steps/Update.h | 41 -- logic/minecraft/AssetsUtils.cpp | 230 -------- logic/minecraft/AssetsUtils.h | 48 -- logic/minecraft/GradleSpecifier.h | 129 ----- logic/minecraft/JarMod.h | 12 - logic/minecraft/Library.cpp | 239 -------- logic/minecraft/Library.h | 184 ------ logic/minecraft/MinecraftInstance.cpp | 369 ------------ logic/minecraft/MinecraftInstance.h | 69 --- logic/minecraft/MinecraftProfile.cpp | 610 -------------------- logic/minecraft/MinecraftProfile.h | 200 ------- logic/minecraft/MinecraftVersion.cpp | 215 ------- logic/minecraft/MinecraftVersion.h | 119 ---- logic/minecraft/MinecraftVersionList.cpp | 591 -------------------- logic/minecraft/MinecraftVersionList.h | 72 --- logic/minecraft/Mod.cpp | 377 ------------- logic/minecraft/Mod.h | 134 ----- logic/minecraft/ModList.cpp | 616 --------------------- logic/minecraft/ModList.h | 160 ------ logic/minecraft/MojangDownloadInfo.h | 71 --- logic/minecraft/MojangVersionFormat.cpp | 381 ------------- logic/minecraft/MojangVersionFormat.h | 25 - logic/minecraft/OpSys.cpp | 42 -- logic/minecraft/OpSys.h | 37 -- logic/minecraft/ParseUtils.cpp | 34 -- logic/minecraft/ParseUtils.h | 11 - logic/minecraft/ProfilePatch.h | 104 ---- logic/minecraft/ProfileStrategy.h | 35 -- logic/minecraft/ProfileUtils.cpp | 191 ------- logic/minecraft/ProfileUtils.h | 25 - logic/minecraft/Rule.cpp | 93 ---- logic/minecraft/Rule.h | 101 ---- logic/minecraft/SkinUtils.cpp | 47 -- logic/minecraft/SkinUtils.h | 25 - logic/minecraft/VersionBuildError.h | 58 -- logic/minecraft/VersionFile.cpp | 60 -- logic/minecraft/VersionFile.h | 195 ------- logic/minecraft/VersionFilterData.cpp | 75 --- logic/minecraft/VersionFilterData.h | 32 -- logic/minecraft/World.cpp | 385 ------------- logic/minecraft/World.h | 83 --- logic/minecraft/WorldList.cpp | 355 ------------ logic/minecraft/WorldList.h | 125 ----- logic/minecraft/auth/AuthSession.cpp | 30 - logic/minecraft/auth/AuthSession.h | 51 -- logic/minecraft/auth/MojangAccount.cpp | 278 ---------- logic/minecraft/auth/MojangAccount.h | 173 ------ logic/minecraft/auth/MojangAccountList.cpp | 427 -------------- logic/minecraft/auth/MojangAccountList.h | 201 ------- logic/minecraft/auth/YggdrasilTask.cpp | 255 --------- logic/minecraft/auth/YggdrasilTask.h | 150 ----- logic/minecraft/auth/flows/AuthenticateTask.cpp | 202 ------- logic/minecraft/auth/flows/AuthenticateTask.h | 46 -- logic/minecraft/auth/flows/RefreshTask.cpp | 144 ----- logic/minecraft/auth/flows/RefreshTask.h | 44 -- logic/minecraft/auth/flows/ValidateTask.cpp | 61 -- logic/minecraft/auth/flows/ValidateTask.h | 47 -- logic/minecraft/forge/ForgeInstaller.cpp | 458 --------------- logic/minecraft/forge/ForgeInstaller.h | 52 -- logic/minecraft/forge/ForgeVersion.cpp | 55 -- logic/minecraft/forge/ForgeVersion.h | 42 -- logic/minecraft/forge/ForgeVersionList.cpp | 450 --------------- logic/minecraft/forge/ForgeVersionList.h | 90 --- logic/minecraft/forge/ForgeXzDownload.cpp | 358 ------------ logic/minecraft/forge/ForgeXzDownload.h | 59 -- logic/minecraft/forge/LegacyForge.cpp | 56 -- logic/minecraft/forge/LegacyForge.h | 25 - logic/minecraft/ftb/FTBPlugin.cpp | 395 ------------- logic/minecraft/ftb/FTBPlugin.h | 13 - logic/minecraft/ftb/FTBProfileStrategy.cpp | 128 ----- logic/minecraft/ftb/FTBProfileStrategy.h | 21 - logic/minecraft/ftb/FTBVersion.h | 32 -- logic/minecraft/ftb/LegacyFTBInstance.cpp | 27 - logic/minecraft/ftb/LegacyFTBInstance.h | 17 - logic/minecraft/ftb/OneSixFTBInstance.cpp | 138 ----- logic/minecraft/ftb/OneSixFTBInstance.h | 30 - logic/minecraft/legacy/LegacyInstance.cpp | 459 --------------- logic/minecraft/legacy/LegacyInstance.h | 142 ----- logic/minecraft/legacy/LegacyUpdate.cpp | 393 ------------- logic/minecraft/legacy/LegacyUpdate.h | 70 --- logic/minecraft/legacy/LwjglVersionList.cpp | 189 ------- logic/minecraft/legacy/LwjglVersionList.h | 156 ------ logic/minecraft/liteloader/LiteLoaderInstaller.cpp | 142 ----- logic/minecraft/liteloader/LiteLoaderInstaller.h | 39 -- .../minecraft/liteloader/LiteLoaderVersionList.cpp | 276 --------- logic/minecraft/liteloader/LiteLoaderVersionList.h | 119 ---- logic/minecraft/onesix/OneSixInstance.cpp | 601 -------------------- logic/minecraft/onesix/OneSixInstance.h | 117 ---- logic/minecraft/onesix/OneSixProfileStrategy.cpp | 418 -------------- logic/minecraft/onesix/OneSixProfileStrategy.h | 26 - logic/minecraft/onesix/OneSixUpdate.cpp | 342 ------------ logic/minecraft/onesix/OneSixUpdate.h | 67 --- logic/minecraft/onesix/OneSixVersionFormat.cpp | 225 -------- logic/minecraft/onesix/OneSixVersionFormat.h | 22 - logic/net/ByteArrayDownload.cpp | 105 ---- logic/net/ByteArrayDownload.h | 48 -- logic/net/CacheDownload.cpp | 192 ------- logic/net/CacheDownload.h | 63 --- logic/net/HttpMetaCache.cpp | 273 --------- logic/net/HttpMetaCache.h | 125 ----- logic/net/MD5EtagDownload.cpp | 155 ------ logic/net/MD5EtagDownload.h | 52 -- logic/net/NetAction.h | 96 ---- logic/net/NetJob.cpp | 125 ----- logic/net/NetJob.h | 118 ---- logic/net/PasteUpload.cpp | 99 ---- logic/net/PasteUpload.h | 51 -- logic/net/URLConstants.cpp | 16 - logic/net/URLConstants.h | 40 -- logic/news/NewsChecker.cpp | 135 ----- logic/news/NewsChecker.h | 107 ---- logic/news/NewsEntry.cpp | 77 --- logic/news/NewsEntry.h | 65 --- logic/notifications/NotificationChecker.cpp | 130 ----- logic/notifications/NotificationChecker.h | 63 --- logic/pathmatcher/FSTreeMatcher.h | 21 - logic/pathmatcher/IPathMatcher.h | 12 - logic/pathmatcher/MultiMatcher.h | 31 -- logic/pathmatcher/RegexpMatcher.h | 42 -- logic/resources/Resource.cpp | 155 ------ logic/resources/Resource.h | 132 ----- logic/resources/ResourceHandler.cpp | 28 - logic/resources/ResourceHandler.h | 36 -- logic/resources/ResourceObserver.cpp | 55 -- logic/resources/ResourceObserver.h | 73 --- logic/resources/ResourceProxyModel.cpp | 89 --- logic/resources/ResourceProxyModel.h | 39 -- logic/screenshots/ImgurAlbumCreation.cpp | 90 --- logic/screenshots/ImgurAlbumCreation.h | 44 -- logic/screenshots/ImgurUpload.cpp | 114 ---- logic/screenshots/ImgurUpload.h | 33 -- logic/screenshots/Screenshot.h | 19 - logic/settings/INIFile.cpp | 151 ----- logic/settings/INIFile.h | 38 -- logic/settings/INISettingsObject.cpp | 107 ---- logic/settings/INISettingsObject.h | 66 --- logic/settings/OverrideSetting.cpp | 54 -- logic/settings/OverrideSetting.h | 46 -- logic/settings/PassthroughSetting.cpp | 66 --- logic/settings/PassthroughSetting.h | 45 -- logic/settings/Setting.cpp | 53 -- logic/settings/Setting.h | 119 ---- logic/settings/SettingsObject.cpp | 142 ----- logic/settings/SettingsObject.h | 214 ------- logic/status/StatusChecker.cpp | 153 ----- logic/status/StatusChecker.h | 60 -- logic/tasks/SequentialTask.cpp | 55 -- logic/tasks/SequentialTask.h | 31 -- logic/tasks/Task.cpp | 88 --- logic/tasks/Task.h | 96 ---- logic/tasks/ThreadTask.cpp | 41 -- logic/tasks/ThreadTask.h | 25 - logic/tools/BaseExternalTool.cpp | 42 -- logic/tools/BaseExternalTool.h | 60 -- logic/tools/BaseProfiler.cpp | 35 -- logic/tools/BaseProfiler.h | 38 -- logic/tools/JProfiler.cpp | 117 ---- logic/tools/JProfiler.h | 15 - logic/tools/JVisualVM.cpp | 103 ---- logic/tools/JVisualVM.h | 15 - logic/tools/MCEditTool.cpp | 124 ----- logic/tools/MCEditTool.h | 26 - logic/trans/TranslationDownloader.cpp | 53 -- logic/trans/TranslationDownloader.h | 32 -- logic/updater/DownloadTask.cpp | 169 ------ logic/updater/DownloadTask.h | 95 ---- logic/updater/GoUpdate.cpp | 216 -------- logic/updater/GoUpdate.h | 133 ----- logic/updater/UpdateChecker.cpp | 269 --------- logic/updater/UpdateChecker.h | 121 ---- logic/wonko/BaseWonkoEntity.cpp | 39 -- logic/wonko/BaseWonkoEntity.h | 51 -- logic/wonko/WonkoIndex.cpp | 147 ----- logic/wonko/WonkoIndex.h | 68 --- logic/wonko/WonkoReference.cpp | 44 -- logic/wonko/WonkoReference.h | 41 -- logic/wonko/WonkoUtil.cpp | 47 -- logic/wonko/WonkoUtil.h | 31 -- logic/wonko/WonkoVersion.cpp | 102 ---- logic/wonko/WonkoVersion.h | 83 --- logic/wonko/WonkoVersionList.cpp | 283 ---------- logic/wonko/WonkoVersionList.h | 92 --- logic/wonko/format/WonkoFormat.cpp | 80 --- logic/wonko/format/WonkoFormat.h | 54 -- logic/wonko/format/WonkoFormatV1.cpp | 156 ------ logic/wonko/format/WonkoFormatV1.h | 30 - logic/wonko/tasks/BaseWonkoEntityLocalLoadTask.cpp | 117 ---- logic/wonko/tasks/BaseWonkoEntityLocalLoadTask.h | 81 --- .../wonko/tasks/BaseWonkoEntityRemoteLoadTask.cpp | 126 ----- logic/wonko/tasks/BaseWonkoEntityRemoteLoadTask.h | 85 --- 268 files changed, 33711 deletions(-) delete mode 100644 logic/AbstractCommonModel.cpp delete mode 100644 logic/AbstractCommonModel.h delete mode 100644 logic/BaseConfigObject.cpp delete mode 100644 logic/BaseConfigObject.h delete mode 100644 logic/BaseInstaller.cpp delete mode 100644 logic/BaseInstaller.h delete mode 100644 logic/BaseInstance.cpp delete mode 100644 logic/BaseInstance.h delete mode 100644 logic/BaseVersion.h delete mode 100644 logic/BaseVersionList.cpp delete mode 100644 logic/BaseVersionList.h delete mode 100644 logic/CMakeLists.txt delete mode 100644 logic/Commandline.cpp delete mode 100644 logic/Commandline.h delete mode 100644 logic/DefaultVariable.h delete mode 100644 logic/DesktopServices.cpp delete mode 100644 logic/DesktopServices.h delete mode 100644 logic/Env.cpp delete mode 100644 logic/Env.h delete mode 100644 logic/Exception.h delete mode 100644 logic/FileSystem.cpp delete mode 100644 logic/FileSystem.h delete mode 100644 logic/GZip.cpp delete mode 100644 logic/GZip.h delete mode 100644 logic/InstanceList.cpp delete mode 100644 logic/InstanceList.h delete mode 100644 logic/Json.cpp delete mode 100644 logic/Json.h delete mode 100644 logic/MMCStrings.cpp delete mode 100644 logic/MMCStrings.h delete mode 100644 logic/MMCZip.cpp delete mode 100644 logic/MMCZip.h delete mode 100644 logic/NullInstance.h delete mode 100644 logic/QObjectPtr.h delete mode 100644 logic/RWStorage.h delete mode 100644 logic/RecursiveFileSystemWatcher.cpp delete mode 100644 logic/RecursiveFileSystemWatcher.h delete mode 100644 logic/SeparatorPrefixTree.h delete mode 100644 logic/TypeMagic.h delete mode 100644 logic/Version.cpp delete mode 100644 logic/Version.h delete mode 100644 logic/icons/IconList.cpp delete mode 100644 logic/icons/IconList.h delete mode 100644 logic/icons/MMCIcon.cpp delete mode 100644 logic/icons/MMCIcon.h delete mode 100644 logic/java/JavaChecker.cpp delete mode 100644 logic/java/JavaChecker.h delete mode 100644 logic/java/JavaCheckerJob.cpp delete mode 100644 logic/java/JavaCheckerJob.h delete mode 100644 logic/java/JavaInstall.cpp delete mode 100644 logic/java/JavaInstall.h delete mode 100644 logic/java/JavaInstallList.cpp delete mode 100644 logic/java/JavaInstallList.h delete mode 100644 logic/java/JavaUtils.cpp delete mode 100644 logic/java/JavaUtils.h delete mode 100644 logic/java/JavaVersion.cpp delete mode 100644 logic/java/JavaVersion.h delete mode 100644 logic/launch/LaunchStep.cpp delete mode 100644 logic/launch/LaunchStep.h delete mode 100644 logic/launch/LaunchTask.cpp delete mode 100644 logic/launch/LaunchTask.h delete mode 100644 logic/launch/LoggedProcess.cpp delete mode 100644 logic/launch/LoggedProcess.h delete mode 100644 logic/launch/MessageLevel.cpp delete mode 100644 logic/launch/MessageLevel.h delete mode 100644 logic/launch/steps/CheckJava.cpp delete mode 100644 logic/launch/steps/CheckJava.h delete mode 100644 logic/launch/steps/LaunchMinecraft.cpp delete mode 100644 logic/launch/steps/LaunchMinecraft.h delete mode 100644 logic/launch/steps/ModMinecraftJar.cpp delete mode 100644 logic/launch/steps/ModMinecraftJar.h delete mode 100644 logic/launch/steps/PostLaunchCommand.cpp delete mode 100644 logic/launch/steps/PostLaunchCommand.h delete mode 100644 logic/launch/steps/PreLaunchCommand.cpp delete mode 100644 logic/launch/steps/PreLaunchCommand.h delete mode 100644 logic/launch/steps/TextPrint.cpp delete mode 100644 logic/launch/steps/TextPrint.h delete mode 100644 logic/launch/steps/Update.cpp delete mode 100644 logic/launch/steps/Update.h delete mode 100644 logic/minecraft/AssetsUtils.cpp delete mode 100644 logic/minecraft/AssetsUtils.h delete mode 100644 logic/minecraft/GradleSpecifier.h delete mode 100644 logic/minecraft/JarMod.h delete mode 100644 logic/minecraft/Library.cpp delete mode 100644 logic/minecraft/Library.h delete mode 100644 logic/minecraft/MinecraftInstance.cpp delete mode 100644 logic/minecraft/MinecraftInstance.h delete mode 100644 logic/minecraft/MinecraftProfile.cpp delete mode 100644 logic/minecraft/MinecraftProfile.h delete mode 100644 logic/minecraft/MinecraftVersion.cpp delete mode 100644 logic/minecraft/MinecraftVersion.h delete mode 100644 logic/minecraft/MinecraftVersionList.cpp delete mode 100644 logic/minecraft/MinecraftVersionList.h delete mode 100644 logic/minecraft/Mod.cpp delete mode 100644 logic/minecraft/Mod.h delete mode 100644 logic/minecraft/ModList.cpp delete mode 100644 logic/minecraft/ModList.h delete mode 100644 logic/minecraft/MojangDownloadInfo.h delete mode 100644 logic/minecraft/MojangVersionFormat.cpp delete mode 100644 logic/minecraft/MojangVersionFormat.h delete mode 100644 logic/minecraft/OpSys.cpp delete mode 100644 logic/minecraft/OpSys.h delete mode 100644 logic/minecraft/ParseUtils.cpp delete mode 100644 logic/minecraft/ParseUtils.h delete mode 100644 logic/minecraft/ProfilePatch.h delete mode 100644 logic/minecraft/ProfileStrategy.h delete mode 100644 logic/minecraft/ProfileUtils.cpp delete mode 100644 logic/minecraft/ProfileUtils.h delete mode 100644 logic/minecraft/Rule.cpp delete mode 100644 logic/minecraft/Rule.h delete mode 100644 logic/minecraft/SkinUtils.cpp delete mode 100644 logic/minecraft/SkinUtils.h delete mode 100644 logic/minecraft/VersionBuildError.h delete mode 100644 logic/minecraft/VersionFile.cpp delete mode 100644 logic/minecraft/VersionFile.h delete mode 100644 logic/minecraft/VersionFilterData.cpp delete mode 100644 logic/minecraft/VersionFilterData.h delete mode 100644 logic/minecraft/World.cpp delete mode 100644 logic/minecraft/World.h delete mode 100644 logic/minecraft/WorldList.cpp delete mode 100644 logic/minecraft/WorldList.h delete mode 100644 logic/minecraft/auth/AuthSession.cpp delete mode 100644 logic/minecraft/auth/AuthSession.h delete mode 100644 logic/minecraft/auth/MojangAccount.cpp delete mode 100644 logic/minecraft/auth/MojangAccount.h delete mode 100644 logic/minecraft/auth/MojangAccountList.cpp delete mode 100644 logic/minecraft/auth/MojangAccountList.h delete mode 100644 logic/minecraft/auth/YggdrasilTask.cpp delete mode 100644 logic/minecraft/auth/YggdrasilTask.h delete mode 100644 logic/minecraft/auth/flows/AuthenticateTask.cpp delete mode 100644 logic/minecraft/auth/flows/AuthenticateTask.h delete mode 100644 logic/minecraft/auth/flows/RefreshTask.cpp delete mode 100644 logic/minecraft/auth/flows/RefreshTask.h delete mode 100644 logic/minecraft/auth/flows/ValidateTask.cpp delete mode 100644 logic/minecraft/auth/flows/ValidateTask.h delete mode 100644 logic/minecraft/forge/ForgeInstaller.cpp delete mode 100644 logic/minecraft/forge/ForgeInstaller.h delete mode 100644 logic/minecraft/forge/ForgeVersion.cpp delete mode 100644 logic/minecraft/forge/ForgeVersion.h delete mode 100644 logic/minecraft/forge/ForgeVersionList.cpp delete mode 100644 logic/minecraft/forge/ForgeVersionList.h delete mode 100644 logic/minecraft/forge/ForgeXzDownload.cpp delete mode 100644 logic/minecraft/forge/ForgeXzDownload.h delete mode 100644 logic/minecraft/forge/LegacyForge.cpp delete mode 100644 logic/minecraft/forge/LegacyForge.h delete mode 100644 logic/minecraft/ftb/FTBPlugin.cpp delete mode 100644 logic/minecraft/ftb/FTBPlugin.h delete mode 100644 logic/minecraft/ftb/FTBProfileStrategy.cpp delete mode 100644 logic/minecraft/ftb/FTBProfileStrategy.h delete mode 100644 logic/minecraft/ftb/FTBVersion.h delete mode 100644 logic/minecraft/ftb/LegacyFTBInstance.cpp delete mode 100644 logic/minecraft/ftb/LegacyFTBInstance.h delete mode 100644 logic/minecraft/ftb/OneSixFTBInstance.cpp delete mode 100644 logic/minecraft/ftb/OneSixFTBInstance.h delete mode 100644 logic/minecraft/legacy/LegacyInstance.cpp delete mode 100644 logic/minecraft/legacy/LegacyInstance.h delete mode 100644 logic/minecraft/legacy/LegacyUpdate.cpp delete mode 100644 logic/minecraft/legacy/LegacyUpdate.h delete mode 100644 logic/minecraft/legacy/LwjglVersionList.cpp delete mode 100644 logic/minecraft/legacy/LwjglVersionList.h delete mode 100644 logic/minecraft/liteloader/LiteLoaderInstaller.cpp delete mode 100644 logic/minecraft/liteloader/LiteLoaderInstaller.h delete mode 100644 logic/minecraft/liteloader/LiteLoaderVersionList.cpp delete mode 100644 logic/minecraft/liteloader/LiteLoaderVersionList.h delete mode 100644 logic/minecraft/onesix/OneSixInstance.cpp delete mode 100644 logic/minecraft/onesix/OneSixInstance.h delete mode 100644 logic/minecraft/onesix/OneSixProfileStrategy.cpp delete mode 100644 logic/minecraft/onesix/OneSixProfileStrategy.h delete mode 100644 logic/minecraft/onesix/OneSixUpdate.cpp delete mode 100644 logic/minecraft/onesix/OneSixUpdate.h delete mode 100644 logic/minecraft/onesix/OneSixVersionFormat.cpp delete mode 100644 logic/minecraft/onesix/OneSixVersionFormat.h delete mode 100644 logic/net/ByteArrayDownload.cpp delete mode 100644 logic/net/ByteArrayDownload.h delete mode 100644 logic/net/CacheDownload.cpp delete mode 100644 logic/net/CacheDownload.h delete mode 100644 logic/net/HttpMetaCache.cpp delete mode 100644 logic/net/HttpMetaCache.h delete mode 100644 logic/net/MD5EtagDownload.cpp delete mode 100644 logic/net/MD5EtagDownload.h delete mode 100644 logic/net/NetAction.h delete mode 100644 logic/net/NetJob.cpp delete mode 100644 logic/net/NetJob.h delete mode 100644 logic/net/PasteUpload.cpp delete mode 100644 logic/net/PasteUpload.h delete mode 100644 logic/net/URLConstants.cpp delete mode 100644 logic/net/URLConstants.h delete mode 100644 logic/news/NewsChecker.cpp delete mode 100644 logic/news/NewsChecker.h delete mode 100644 logic/news/NewsEntry.cpp delete mode 100644 logic/news/NewsEntry.h delete mode 100644 logic/notifications/NotificationChecker.cpp delete mode 100644 logic/notifications/NotificationChecker.h delete mode 100644 logic/pathmatcher/FSTreeMatcher.h delete mode 100644 logic/pathmatcher/IPathMatcher.h delete mode 100644 logic/pathmatcher/MultiMatcher.h delete mode 100644 logic/pathmatcher/RegexpMatcher.h delete mode 100644 logic/resources/Resource.cpp delete mode 100644 logic/resources/Resource.h delete mode 100644 logic/resources/ResourceHandler.cpp delete mode 100644 logic/resources/ResourceHandler.h delete mode 100644 logic/resources/ResourceObserver.cpp delete mode 100644 logic/resources/ResourceObserver.h delete mode 100644 logic/resources/ResourceProxyModel.cpp delete mode 100644 logic/resources/ResourceProxyModel.h delete mode 100644 logic/screenshots/ImgurAlbumCreation.cpp delete mode 100644 logic/screenshots/ImgurAlbumCreation.h delete mode 100644 logic/screenshots/ImgurUpload.cpp delete mode 100644 logic/screenshots/ImgurUpload.h delete mode 100644 logic/screenshots/Screenshot.h delete mode 100644 logic/settings/INIFile.cpp delete mode 100644 logic/settings/INIFile.h delete mode 100644 logic/settings/INISettingsObject.cpp delete mode 100644 logic/settings/INISettingsObject.h delete mode 100644 logic/settings/OverrideSetting.cpp delete mode 100644 logic/settings/OverrideSetting.h delete mode 100644 logic/settings/PassthroughSetting.cpp delete mode 100644 logic/settings/PassthroughSetting.h delete mode 100644 logic/settings/Setting.cpp delete mode 100644 logic/settings/Setting.h delete mode 100644 logic/settings/SettingsObject.cpp delete mode 100644 logic/settings/SettingsObject.h delete mode 100644 logic/status/StatusChecker.cpp delete mode 100644 logic/status/StatusChecker.h delete mode 100644 logic/tasks/SequentialTask.cpp delete mode 100644 logic/tasks/SequentialTask.h delete mode 100644 logic/tasks/Task.cpp delete mode 100644 logic/tasks/Task.h delete mode 100644 logic/tasks/ThreadTask.cpp delete mode 100644 logic/tasks/ThreadTask.h delete mode 100644 logic/tools/BaseExternalTool.cpp delete mode 100644 logic/tools/BaseExternalTool.h delete mode 100644 logic/tools/BaseProfiler.cpp delete mode 100644 logic/tools/BaseProfiler.h delete mode 100644 logic/tools/JProfiler.cpp delete mode 100644 logic/tools/JProfiler.h delete mode 100644 logic/tools/JVisualVM.cpp delete mode 100644 logic/tools/JVisualVM.h delete mode 100644 logic/tools/MCEditTool.cpp delete mode 100644 logic/tools/MCEditTool.h delete mode 100644 logic/trans/TranslationDownloader.cpp delete mode 100644 logic/trans/TranslationDownloader.h delete mode 100644 logic/updater/DownloadTask.cpp delete mode 100644 logic/updater/DownloadTask.h delete mode 100644 logic/updater/GoUpdate.cpp delete mode 100644 logic/updater/GoUpdate.h delete mode 100644 logic/updater/UpdateChecker.cpp delete mode 100644 logic/updater/UpdateChecker.h delete mode 100644 logic/wonko/BaseWonkoEntity.cpp delete mode 100644 logic/wonko/BaseWonkoEntity.h delete mode 100644 logic/wonko/WonkoIndex.cpp delete mode 100644 logic/wonko/WonkoIndex.h delete mode 100644 logic/wonko/WonkoReference.cpp delete mode 100644 logic/wonko/WonkoReference.h delete mode 100644 logic/wonko/WonkoUtil.cpp delete mode 100644 logic/wonko/WonkoUtil.h delete mode 100644 logic/wonko/WonkoVersion.cpp delete mode 100644 logic/wonko/WonkoVersion.h delete mode 100644 logic/wonko/WonkoVersionList.cpp delete mode 100644 logic/wonko/WonkoVersionList.h delete mode 100644 logic/wonko/format/WonkoFormat.cpp delete mode 100644 logic/wonko/format/WonkoFormat.h delete mode 100644 logic/wonko/format/WonkoFormatV1.cpp delete mode 100644 logic/wonko/format/WonkoFormatV1.h delete mode 100644 logic/wonko/tasks/BaseWonkoEntityLocalLoadTask.cpp delete mode 100644 logic/wonko/tasks/BaseWonkoEntityLocalLoadTask.h delete mode 100644 logic/wonko/tasks/BaseWonkoEntityRemoteLoadTask.cpp delete mode 100644 logic/wonko/tasks/BaseWonkoEntityRemoteLoadTask.h (limited to 'logic') diff --git a/logic/AbstractCommonModel.cpp b/logic/AbstractCommonModel.cpp deleted file mode 100644 index 71d75829..00000000 --- a/logic/AbstractCommonModel.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* Copyright 2015 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 "AbstractCommonModel.h" - -BaseAbstractCommonModel::BaseAbstractCommonModel(const Qt::Orientation orientation, QObject *parent) - : QAbstractListModel(parent), m_orientation(orientation) -{ -} - -int BaseAbstractCommonModel::rowCount(const QModelIndex &parent) const -{ - return m_orientation == Qt::Horizontal ? entryCount() : size(); -} -int BaseAbstractCommonModel::columnCount(const QModelIndex &parent) const -{ - return m_orientation == Qt::Horizontal ? size() : entryCount(); -} -QVariant BaseAbstractCommonModel::data(const QModelIndex &index, int role) const -{ - if (!hasIndex(index.row(), index.column(), index.parent())) - { - return QVariant(); - } - const int i = m_orientation == Qt::Horizontal ? index.column() : index.row(); - const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); - return formatData(i, role, get(i, entry, role)); -} -QVariant BaseAbstractCommonModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation != m_orientation && role == Qt::DisplayRole) - { - return entryTitle(section); - } - else - { - return QVariant(); - } -} -bool BaseAbstractCommonModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - const int i = m_orientation == Qt::Horizontal ? index.column() : index.row(); - const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); - const bool result = set(i, entry, role, sanetizeData(i, role, value)); - if (result) - { - emit dataChanged(index, index, QVector() << role); - } - return result; -} -Qt::ItemFlags BaseAbstractCommonModel::flags(const QModelIndex &index) const -{ - if (!hasIndex(index.row(), index.column(), index.parent())) - { - return Qt::NoItemFlags; - } - - const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); - if (canSet(entry)) - { - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled; - } - else - { - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; - } -} - -void BaseAbstractCommonModel::notifyAboutToAddObject(const int at) -{ - if (m_orientation == Qt::Horizontal) - { - beginInsertColumns(QModelIndex(), at, at); - } - else - { - beginInsertRows(QModelIndex(), at, at); - } -} -void BaseAbstractCommonModel::notifyObjectAdded() -{ - if (m_orientation == Qt::Horizontal) - { - endInsertColumns(); - } - else - { - endInsertRows(); - } -} -void BaseAbstractCommonModel::notifyAboutToRemoveObject(const int at) -{ - if (m_orientation == Qt::Horizontal) - { - beginRemoveColumns(QModelIndex(), at, at); - } - else - { - beginRemoveRows(QModelIndex(), at, at); - } -} -void BaseAbstractCommonModel::notifyObjectRemoved() -{ - if (m_orientation == Qt::Horizontal) - { - endRemoveColumns(); - } - else - { - endRemoveRows(); - } -} - -void BaseAbstractCommonModel::notifyBeginReset() -{ - beginResetModel(); -} -void BaseAbstractCommonModel::notifyEndReset() -{ - endResetModel(); -} diff --git a/logic/AbstractCommonModel.h b/logic/AbstractCommonModel.h deleted file mode 100644 index 31b86a23..00000000 --- a/logic/AbstractCommonModel.h +++ /dev/null @@ -1,462 +0,0 @@ -/* Copyright 2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -class BaseAbstractCommonModel : public QAbstractListModel -{ - Q_OBJECT -public: - explicit BaseAbstractCommonModel(const Qt::Orientation orientation, QObject *parent = nullptr); - - // begin QAbstractItemModel interface - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role) override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - // end QAbstractItemModel interface - - virtual int size() const = 0; - virtual int entryCount() const = 0; - - virtual QVariant formatData(const int index, int role, const QVariant &data) const { return data; } - virtual QVariant sanetizeData(const int index, int role, const QVariant &data) const { return data; } - -protected: - virtual QVariant get(const int index, const int entry, const int role) const = 0; - virtual bool set(const int index, const int entry, const int role, const QVariant &value) = 0; - virtual bool canSet(const int entry) const = 0; - virtual QString entryTitle(const int entry) const = 0; - - void notifyAboutToAddObject(const int at); - void notifyObjectAdded(); - void notifyAboutToRemoveObject(const int at); - void notifyObjectRemoved(); - void notifyBeginReset(); - void notifyEndReset(); - - const Qt::Orientation m_orientation; -}; - -template -class AbstractCommonModel : public BaseAbstractCommonModel -{ -public: - explicit AbstractCommonModel(const Qt::Orientation orientation) - : BaseAbstractCommonModel(orientation) {} - virtual ~AbstractCommonModel() {} - - int size() const override { return m_objects.size(); } - int entryCount() const override { return m_entries.size(); } - - void append(const Object &object) - { - notifyAboutToAddObject(size()); - m_objects.append(object); - notifyObjectAdded(); - } - void prepend(const Object &object) - { - notifyAboutToAddObject(0); - m_objects.prepend(object); - notifyObjectAdded(); - } - void insert(const Object &object, const int index) - { - if (index >= size()) - { - prepend(object); - } - else if (index <= 0) - { - append(object); - } - else - { - notifyAboutToAddObject(index); - m_objects.insert(index, object); - notifyObjectAdded(); - } - } - void remove(const int index) - { - notifyAboutToRemoveObject(index); - m_objects.removeAt(index); - notifyObjectRemoved(); - } - Object get(const int index) const - { - return m_objects.at(index); - } - -private: - friend class CommonModel; - QVariant get(const int index, const int entry, const int role) const override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) - { - return QVariant(); - } - return m_entries[entry].second.value(role)->get(m_objects.at(index)); - } - bool set(const int index, const int entry, const int role, const QVariant &value) override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) - { - return false; - } - IEntry *e = m_entries[entry].second.value(role); - if (!e->canSet()) - { - return false; - } - e->set(m_objects[index], value); - return true; - } - bool canSet(const int entry) const override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(Qt::EditRole)) - { - return false; - } - IEntry *e = m_entries[entry].second.value(Qt::EditRole); - return e->canSet(); - } - - QString entryTitle(const int entry) const override - { - return m_entries.at(entry).first; - } - -private: - struct IEntry - { - virtual ~IEntry() {} - virtual void set(Object &object, const QVariant &value) = 0; - virtual QVariant get(const Object &object) const = 0; - virtual bool canSet() const = 0; - }; - template - struct VariableEntry : public IEntry - { - typedef T (Object::*Member); - - explicit VariableEntry(Member member) - : m_member(member) {} - - void set(Object &object, const QVariant &value) override - { - object.*m_member = value.value(); - } - QVariant get(const Object &object) const override - { - return QVariant::fromValue(object.*m_member); - } - bool canSet() const override { return true; } - - private: - Member m_member; - }; - template - struct FunctionEntry : public IEntry - { - typedef T (Object::*Getter)() const; - typedef void (Object::*Setter)(T); - - explicit FunctionEntry(Getter getter, Setter setter) - : m_getter(m_getter), m_setter(m_setter) {} - - void set(Object &object, const QVariant &value) override - { - object.*m_setter(value.value()); - } - QVariant get(const Object &object) const override - { - return QVariant::fromValue(object.*m_getter()); - } - bool canSet() const override { return !!m_setter; } - - private: - Getter m_getter; - Setter m_setter; - }; - - QList m_objects; - QVector>> m_entries; - - void addEntryInternal(IEntry *e, const int entry, const int role) - { - if (m_entries.size() <= entry) - { - m_entries.resize(entry + 1); - } - m_entries[entry].second.insert(role, e); - } - -protected: - template - typename std::enable_if::value && std::is_member_function_pointer::value, void>::type - addEntry(Getter getter, Setter setter, const int entry, const int role) - { - addEntryInternal(new FunctionEntry::type>(getter, setter), entry, role); - } - template - typename std::enable_if::value, void>::type - addEntry(Getter getter, const int entry, const int role) - { - addEntryInternal(new FunctionEntry::type>(getter, nullptr), entry, role); - } - template - typename std::enable_if::value, void>::type - addEntry(T (Object::*member), const int entry, const int role) - { - addEntryInternal(new VariableEntry(member), entry, role); - } - - void setEntryTitle(const int entry, const QString &title) - { - m_entries[entry].first = title; - } -}; -template -class AbstractCommonModel : public BaseAbstractCommonModel -{ -public: - explicit AbstractCommonModel(const Qt::Orientation orientation) - : BaseAbstractCommonModel(orientation) {} - virtual ~AbstractCommonModel() - { - qDeleteAll(m_objects); - } - - int size() const override { return m_objects.size(); } - int entryCount() const override { return m_entries.size(); } - - void append(Object *object) - { - notifyAboutToAddObject(size()); - m_objects.append(object); - notifyObjectAdded(); - } - void prepend(Object *object) - { - notifyAboutToAddObject(0); - m_objects.prepend(object); - notifyObjectAdded(); - } - void insert(Object *object, const int index) - { - if (index >= size()) - { - prepend(object); - } - else if (index <= 0) - { - append(object); - } - else - { - notifyAboutToAddObject(index); - m_objects.insert(index, object); - notifyObjectAdded(); - } - } - void remove(const int index) - { - notifyAboutToRemoveObject(index); - m_objects.removeAt(index); - notifyObjectRemoved(); - } - Object *get(const int index) const - { - return m_objects.at(index); - } - int find(Object * const obj) const - { - return m_objects.indexOf(obj); - } - - QList getAll() const - { - return m_objects; - } - -private: - friend class CommonModel; - QVariant get(const int index, const int entry, const int role) const override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) - { - return QVariant(); - } - return m_entries[entry].second.value(role)->get(m_objects.at(index)); - } - bool set(const int index, const int entry, const int role, const QVariant &value) override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) - { - return false; - } - IEntry *e = m_entries[entry].second.value(role); - if (!e->canSet()) - { - return false; - } - e->set(m_objects[index], value); - return true; - } - bool canSet(const int entry) const override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(Qt::EditRole)) - { - return false; - } - IEntry *e = m_entries[entry].second.value(Qt::EditRole); - return e->canSet(); - } - - QString entryTitle(const int entry) const override - { - return m_entries.at(entry).first; - } - -private: - struct IEntry - { - virtual ~IEntry() {} - virtual void set(Object *object, const QVariant &value) = 0; - virtual QVariant get(Object *object) const = 0; - virtual bool canSet() const = 0; - }; - template - struct VariableEntry : public IEntry - { - typedef T (Object::*Member); - - explicit VariableEntry(Member member) - : m_member(member) {} - - void set(Object *object, const QVariant &value) override - { - object->*m_member = value.value(); - } - QVariant get(Object *object) const override - { - return QVariant::fromValue(object->*m_member); - } - bool canSet() const override { return true; } - - private: - Member m_member; - }; - template - struct FunctionEntry : public IEntry - { - typedef T (Object::*Getter)() const; - typedef void (Object::*Setter)(T); - - explicit FunctionEntry(Getter getter, Setter setter) - : m_getter(getter), m_setter(setter) {} - - void set(Object *object, const QVariant &value) override - { - (object->*m_setter)(value.value()); - } - QVariant get(Object *object) const override - { - return QVariant::fromValue((object->*m_getter)()); - } - bool canSet() const override { return !!m_setter; } - - private: - Getter m_getter; - Setter m_setter; - }; - template - struct LambdaEntry : public IEntry - { - using Getter = std::function; - - explicit LambdaEntry(Getter getter) - : m_getter(getter) {} - - void set(Object *object, const QVariant &value) override {} - QVariant get(Object *object) const override - { - return QVariant::fromValue(m_getter(object)); - } - bool canSet() const override { return false; } - - private: - Getter m_getter; - }; - - QList m_objects; - QVector>> m_entries; - - void addEntryInternal(IEntry *e, const int entry, const int role) - { - if (m_entries.size() <= entry) - { - m_entries.resize(entry + 1); - } - m_entries[entry].second.insert(role, e); - } - -protected: - template - typename std::enable_if::value && std::is_member_function_pointer::value, void>::type - addEntry(const int entry, const int role, Getter getter, Setter setter) - { - addEntryInternal(new FunctionEntry::type>(getter, setter), entry, role); - } - template - typename std::enable_if::Getter>::value, void>::type - addEntry(const int entry, const int role, typename FunctionEntry::Getter getter) - { - addEntryInternal(new FunctionEntry(getter, nullptr), entry, role); - } - template - typename std::enable_if::value, void>::type - addEntry(const int entry, const int role, T (Object::*member)) - { - addEntryInternal(new VariableEntry(member), entry, role); - } - template - void addEntry(const int entry, const int role, typename LambdaEntry::Getter lambda) - { - addEntryInternal(new LambdaEntry(lambda), entry, role); - } - - void setEntryTitle(const int entry, const QString &title) - { - m_entries[entry].first = title; - } - - void setAll(const QList objects) - { - notifyBeginReset(); - qDeleteAll(m_objects); - m_objects = objects; - notifyEndReset(); - } -}; diff --git a/logic/BaseConfigObject.cpp b/logic/BaseConfigObject.cpp deleted file mode 100644 index 3040ac2e..00000000 --- a/logic/BaseConfigObject.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright 2015 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 "BaseConfigObject.h" - -#include -#include -#include -#include - -#include "Exception.h" -#include "FileSystem.h" - -BaseConfigObject::BaseConfigObject(const QString &filename) - : m_filename(filename) -{ - m_saveTimer = new QTimer; - m_saveTimer->setSingleShot(true); - // cppcheck-suppress pureVirtualCall - QObject::connect(m_saveTimer, &QTimer::timeout, [this](){saveNow();}); - setSaveTimeout(250); - - m_initialReadTimer = new QTimer; - m_initialReadTimer->setSingleShot(true); - QObject::connect(m_initialReadTimer, &QTimer::timeout, [this]() - { - loadNow(); - m_initialReadTimer->deleteLater(); - m_initialReadTimer = 0; - }); - m_initialReadTimer->start(0); - - // cppcheck-suppress pureVirtualCall - m_appQuitConnection = QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this](){saveNow();}); -} -BaseConfigObject::~BaseConfigObject() -{ - delete m_saveTimer; - if (m_initialReadTimer) - { - delete m_initialReadTimer; - } - QObject::disconnect(m_appQuitConnection); -} - -void BaseConfigObject::setSaveTimeout(int msec) -{ - m_saveTimer->setInterval(msec); -} - -void BaseConfigObject::scheduleSave() -{ - m_saveTimer->stop(); - m_saveTimer->start(); -} -void BaseConfigObject::saveNow() -{ - if (m_saveTimer->isActive()) - { - m_saveTimer->stop(); - } - if (m_disableSaving) - { - return; - } - - try - { - FS::write(m_filename, doSave()); - } - catch (Exception & e) - { - qCritical() << e.cause(); - } -} -void BaseConfigObject::loadNow() -{ - if (m_saveTimer->isActive()) - { - saveNow(); - } - - try - { - doLoad(FS::read(m_filename)); - } - catch (Exception & e) - { - qWarning() << "Error loading" << m_filename << ":" << e.cause(); - } -} diff --git a/logic/BaseConfigObject.h b/logic/BaseConfigObject.h deleted file mode 100644 index 1c96b3d1..00000000 --- a/logic/BaseConfigObject.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright 2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -class QTimer; - -class BaseConfigObject -{ -public: - void setSaveTimeout(int msec); - -protected: - explicit BaseConfigObject(const QString &filename); - virtual ~BaseConfigObject(); - - // cppcheck-suppress pureVirtualCall - virtual QByteArray doSave() const = 0; - virtual void doLoad(const QByteArray &data) = 0; - - void setSavingDisabled(bool savingDisabled) { m_disableSaving = savingDisabled; } - - QString fileName() const { return m_filename; } - -public: - void scheduleSave(); - void saveNow(); - void loadNow(); - -private: - QTimer *m_saveTimer; - QTimer *m_initialReadTimer; - QString m_filename; - QMetaObject::Connection m_appQuitConnection; - bool m_disableSaving = false; -}; diff --git a/logic/BaseInstaller.cpp b/logic/BaseInstaller.cpp deleted file mode 100644 index cb762ebd..00000000 --- a/logic/BaseInstaller.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright 2013-2015 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 - -#include "BaseInstaller.h" -#include "minecraft/onesix/OneSixInstance.h" - -BaseInstaller::BaseInstaller() -{ - -} - -bool BaseInstaller::isApplied(OneSixInstance *on) -{ - return QFile::exists(filename(on->instanceRoot())); -} - -bool BaseInstaller::add(OneSixInstance *to) -{ - if (!patchesDir(to->instanceRoot()).exists()) - { - QDir(to->instanceRoot()).mkdir("patches"); - } - - if (isApplied(to)) - { - if (!remove(to)) - { - return false; - } - } - - return true; -} - -bool BaseInstaller::remove(OneSixInstance *from) -{ - return QFile::remove(filename(from->instanceRoot())); -} - -QString BaseInstaller::filename(const QString &root) const -{ - return patchesDir(root).absoluteFilePath(id() + ".json"); -} -QDir BaseInstaller::patchesDir(const QString &root) const -{ - return QDir(root + "/patches/"); -} diff --git a/logic/BaseInstaller.h b/logic/BaseInstaller.h deleted file mode 100644 index a50c8cb1..00000000 --- a/logic/BaseInstaller.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include "multimc_logic_export.h" - -class OneSixInstance; -class QDir; -class QString; -class QObject; -class Task; -class BaseVersion; -typedef std::shared_ptr BaseVersionPtr; - -class MULTIMC_LOGIC_EXPORT BaseInstaller -{ -public: - BaseInstaller(); - virtual ~BaseInstaller(){}; - bool isApplied(OneSixInstance *on); - - virtual bool add(OneSixInstance *to); - virtual bool remove(OneSixInstance *from); - - virtual Task *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) = 0; - -protected: - virtual QString id() const = 0; - QString filename(const QString &root) const; - QDir patchesDir(const QString &root) const; -}; diff --git a/logic/BaseInstance.cpp b/logic/BaseInstance.cpp deleted file mode 100644 index f8530c9d..00000000 --- a/logic/BaseInstance.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* Copyright 2013-2015 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 "BaseInstance.h" - -#include -#include - -#include "settings/INISettingsObject.h" -#include "settings/Setting.h" -#include "settings/OverrideSetting.h" - -#include "minecraft/MinecraftVersionList.h" -#include "icons/IconList.h" -#include "FileSystem.h" -#include "Commandline.h" - -BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir) - : QObject() -{ - m_settings = settings; - m_rootDir = rootDir; - - m_settings->registerSetting("name", "Unnamed Instance"); - m_settings->registerSetting("iconKey", "default"); - if (ENV.hasIcons()) - { - connect(ENV.icons().get(), SIGNAL(iconUpdated(QString)), SLOT(iconUpdated(QString))); - } - m_settings->registerSetting("notes", ""); - m_settings->registerSetting("lastLaunchTime", 0); - m_settings->registerSetting("totalTimePlayed", 0); - - // Custom Commands - auto commandSetting = m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false); - m_settings->registerOverride(globalSettings->getSetting("PreLaunchCommand"), commandSetting); - m_settings->registerOverride(globalSettings->getSetting("WrapperCommand"), commandSetting); - m_settings->registerOverride(globalSettings->getSetting("PostExitCommand"), commandSetting); - - // Console - auto consoleSetting = m_settings->registerSetting("OverrideConsole", false); - m_settings->registerOverride(globalSettings->getSetting("ShowConsole"), consoleSetting); - m_settings->registerOverride(globalSettings->getSetting("AutoCloseConsole"), consoleSetting); - m_settings->registerOverride(globalSettings->getSetting("LogPrePostOutput"), consoleSetting); -} - -QString BaseInstance::getPreLaunchCommand() -{ - return settings()->get("PreLaunchCommand").toString(); -} - -QString BaseInstance::getWrapperCommand() -{ - return settings()->get("WrapperCommand").toString(); -} - -QString BaseInstance::getPostExitCommand() -{ - return settings()->get("PostExitCommand").toString(); -} - -void BaseInstance::iconUpdated(QString key) -{ - if(iconKey() == key) - { - emit propertiesChanged(this); - } -} - -void BaseInstance::nuke() -{ - FS::deletePath(instanceRoot()); - emit nuked(this); -} - -QString BaseInstance::id() const -{ - return QFileInfo(instanceRoot()).fileName(); -} - -bool BaseInstance::isRunning() const -{ - return m_isRunning; -} - -void BaseInstance::setRunning(bool running) -{ - if(running && !m_isRunning) - { - m_timeStarted = QDateTime::currentDateTime(); - } - else if(!running && m_isRunning) - { - qint64 current = settings()->get("totalTimePlayed").toLongLong(); - QDateTime timeEnded = QDateTime::currentDateTime(); - settings()->set("totalTimePlayed", current + m_timeStarted.secsTo(timeEnded)); - emit propertiesChanged(this); - } - m_isRunning = running; -} - -int64_t BaseInstance::totalTimePlayed() const -{ - qint64 current = settings()->get("totalTimePlayed").toLongLong(); - if(m_isRunning) - { - QDateTime timeNow = QDateTime::currentDateTime(); - return current + m_timeStarted.secsTo(timeNow); - } - return current; -} - -void BaseInstance::resetTimePlayed() -{ - settings()->reset("totalTimePlayed"); -} - -QString BaseInstance::instanceType() const -{ - return m_settings->get("InstanceType").toString(); -} - -QString BaseInstance::instanceRoot() const -{ - return m_rootDir; -} - -InstancePtr BaseInstance::getSharedPtr() -{ - return shared_from_this(); -} - -SettingsObjectPtr BaseInstance::settings() const -{ - return m_settings; -} - -BaseInstance::InstanceFlags BaseInstance::flags() const -{ - return m_flags; -} - -void BaseInstance::setFlags(const InstanceFlags &flags) -{ - if (flags != m_flags) - { - m_flags = flags; - emit flagsChanged(); - emit propertiesChanged(this); - } -} - -void BaseInstance::setFlag(const BaseInstance::InstanceFlag flag) -{ - // nothing to set? - if(flag & m_flags) - return; - m_flags |= flag; - emit flagsChanged(); - emit propertiesChanged(this); -} - -void BaseInstance::unsetFlag(const BaseInstance::InstanceFlag flag) -{ - // nothing to unset? - if(!(flag & m_flags)) - return; - m_flags &= ~flag; - emit flagsChanged(); - emit propertiesChanged(this); -} - -bool BaseInstance::canLaunch() const -{ - return !(flags() & VersionBrokenFlag); -} - -bool BaseInstance::reload() -{ - return m_settings->reload(); -} - -qint64 BaseInstance::lastLaunch() const -{ - return m_settings->get("lastLaunchTime").value(); -} - -void BaseInstance::setLastLaunch(qint64 val) -{ - //FIXME: if no change, do not set. setting involves saving a file. - m_settings->set("lastLaunchTime", val); - emit propertiesChanged(this); -} - -void BaseInstance::setGroupInitial(QString val) -{ - if(m_group == val) - { - return; - } - m_group = val; - emit propertiesChanged(this); -} - -void BaseInstance::setGroupPost(QString val) -{ - if(m_group == val) - { - return; - } - setGroupInitial(val); - emit groupChanged(); -} - -QString BaseInstance::group() const -{ - return m_group; -} - -void BaseInstance::setNotes(QString val) -{ - //FIXME: if no change, do not set. setting involves saving a file. - m_settings->set("notes", val); -} - -QString BaseInstance::notes() const -{ - return m_settings->get("notes").toString(); -} - -void BaseInstance::setIconKey(QString val) -{ - //FIXME: if no change, do not set. setting involves saving a file. - m_settings->set("iconKey", val); - emit propertiesChanged(this); -} - -QString BaseInstance::iconKey() const -{ - return m_settings->get("iconKey").toString(); -} - -void BaseInstance::setName(QString val) -{ - //FIXME: if no change, do not set. setting involves saving a file. - m_settings->set("name", val); - emit propertiesChanged(this); -} - -QString BaseInstance::name() const -{ - return m_settings->get("name").toString(); -} - -QString BaseInstance::windowTitle() const -{ - return "MultiMC: " + name(); -} - -QStringList BaseInstance::extraArguments() const -{ - return Commandline::splitArgs(settings()->get("JvmArgs").toString()); -} diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h deleted file mode 100644 index 5e587c48..00000000 --- a/logic/BaseInstance.h +++ /dev/null @@ -1,243 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include "settings/SettingsObject.h" - -#include "settings/INIFile.h" -#include "BaseVersionList.h" -#include "minecraft/auth/MojangAccount.h" -#include "launch/MessageLevel.h" -#include "pathmatcher/IPathMatcher.h" - -#include "multimc_logic_export.h" - -class QDir; -class Task; -class LaunchTask; -class BaseInstance; - -// pointer for lazy people -typedef std::shared_ptr InstancePtr; - -/*! - * \brief Base class for instances. - * This class implements many functions that are common between instances and - * provides a standard interface for all instances. - * - * To create a new instance type, create a new class inheriting from this class - * and implement the pure virtual functions. - */ -class MULTIMC_LOGIC_EXPORT BaseInstance : public QObject, public std::enable_shared_from_this -{ - Q_OBJECT -protected: - /// no-touchy! - BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir); - -public: - /// virtual destructor to make sure the destruction is COMPLETE - virtual ~BaseInstance() {}; - - virtual void copy(const QDir &newDir) {} - - virtual void init() = 0; - - /// nuke thoroughly - deletes the instance contents, notifies the list/model which is - /// responsible of cleaning up the husk - void nuke(); - - /// The instance's ID. The ID SHALL be determined by MMC internally. The ID IS guaranteed to - /// be unique. - virtual QString id() const; - - void setRunning(bool running); - bool isRunning() const; - int64_t totalTimePlayed() const; - void resetTimePlayed(); - - /// get the type of this instance - QString instanceType() const; - - /// Path to the instance's root directory. - QString instanceRoot() const; - - QString name() const; - void setName(QString val); - - /// Value used for instance window titles - QString windowTitle() const; - - QString iconKey() const; - void setIconKey(QString val); - - QString notes() const; - void setNotes(QString val); - - QString group() const; - void setGroupInitial(QString val); - void setGroupPost(QString val); - - QString getPreLaunchCommand(); - QString getPostExitCommand(); - QString getWrapperCommand(); - - /// guess log level from a line of game log - virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level) - { - return level; - }; - - virtual QStringList extraArguments() const; - - virtual QString intendedVersionId() const = 0; - virtual bool setIntendedVersionId(QString version) = 0; - - /*! - * The instance's current version. - * This value represents the instance's current version. If this value is - * different from the intendedVersion, the instance should be updated. - * \warning Don't change this value unless you know what you're doing. - */ - virtual QString currentVersionId() const = 0; - - /*! - * Whether or not 'the game' should be downloaded when the instance is launched. - */ - virtual bool shouldUpdate() const = 0; - virtual void setShouldUpdate(bool val) = 0; - - /// Traits. Normally inside the version, depends on instance implementation. - virtual QSet traits() = 0; - - /** - * Gets the time that the instance was last launched. - * Stored in milliseconds since epoch. - */ - qint64 lastLaunch() const; - /// Sets the last launched time to 'val' milliseconds since epoch - void setLastLaunch(qint64 val = QDateTime::currentMSecsSinceEpoch()); - - InstancePtr getSharedPtr(); - - /*! - * \brief Gets a pointer to this instance's version list. - * \return A pointer to the available version list for this instance. - */ - virtual std::shared_ptr versionList() const = 0; - - /*! - * \brief Gets this instance's settings object. - * This settings object stores instance-specific settings. - * \return A pointer to this instance's settings object. - */ - virtual SettingsObjectPtr settings() const; - - /// returns a valid update task - virtual std::shared_ptr createUpdateTask() = 0; - - /// returns a valid launcher (task container) - virtual std::shared_ptr createLaunchTask(AuthSessionPtr account) = 0; - - /*! - * Returns a task that should be done right before launch - * This task should do any extra preparations needed - */ - virtual std::shared_ptr createJarModdingTask() = 0; - - /*! - * Create envrironment variables for running the instance - */ - virtual QProcessEnvironment createEnvironment() = 0; - - /*! - * Returns a matcher that can maps relative paths within the instance to whether they are 'log files' - */ - virtual IPathMatcher::Ptr getLogFileMatcher() = 0; - - /*! - * Returns the root folder to use for looking up log files - */ - virtual QString getLogFileRoot() = 0; - - /*! - * does any necessary cleanups after the instance finishes. also runs before\ - * TODO: turn into a task that can run asynchronously - */ - virtual void cleanupAfterRun() = 0; - - virtual QString getStatusbarDescription() = 0; - - /// FIXME: this really should be elsewhere... - virtual QString instanceConfigFolder() const = 0; - - /// get variables this instance exports - virtual QMap getVariables() const = 0; - - virtual QString typeName() const = 0; - - enum InstanceFlag - { - VersionBrokenFlag = 0x01, - UpdateAvailable = 0x02 - }; - Q_DECLARE_FLAGS(InstanceFlags, InstanceFlag) - InstanceFlags flags() const; - void setFlags(const InstanceFlags &flags); - void setFlag(const InstanceFlag flag); - void unsetFlag(const InstanceFlag flag); - - bool canLaunch() const; - virtual bool canExport() const = 0; - - virtual bool reload(); - -signals: - /*! - * \brief Signal emitted when properties relevant to the instance view change - */ - void propertiesChanged(BaseInstance *inst); - /*! - * \brief Signal emitted when groups are affected in any way - */ - void groupChanged(); - /*! - * \brief The instance just got nuked. Hurray! - */ - void nuked(BaseInstance *inst); - - void flagsChanged(); - -protected slots: - void iconUpdated(QString key); - -protected: - QString m_rootDir; - QString m_group; - SettingsObjectPtr m_settings; - InstanceFlags m_flags; - bool m_isRunning = false; - QDateTime m_timeStarted; -}; - -Q_DECLARE_METATYPE(std::shared_ptr) -Q_DECLARE_METATYPE(BaseInstance::InstanceFlag) -Q_DECLARE_OPERATORS_FOR_FLAGS(BaseInstance::InstanceFlags) diff --git a/logic/BaseVersion.h b/logic/BaseVersion.h deleted file mode 100644 index 80767518..00000000 --- a/logic/BaseVersion.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -/*! - * An abstract base class for versions. - */ -class BaseVersion -{ -public: - virtual ~BaseVersion() {} - /*! - * A string used to identify this version in config files. - * This should be unique within the version list or shenanigans will occur. - */ - virtual QString descriptor() = 0; - - /*! - * The name of this version as it is displayed to the user. - * For example: "1.5.1" - */ - virtual QString name() = 0; - - /*! - * This should return a string that describes - * the kind of version this is (Stable, Beta, Snapshot, whatever) - */ - virtual QString typeString() const = 0; - - virtual bool operator<(BaseVersion &a) - { - return name() < a.name(); - }; - virtual bool operator>(BaseVersion &a) - { - return name() > a.name(); - }; -}; - -typedef std::shared_ptr BaseVersionPtr; - -Q_DECLARE_METATYPE(BaseVersionPtr) diff --git a/logic/BaseVersionList.cpp b/logic/BaseVersionList.cpp deleted file mode 100644 index b34f318c..00000000 --- a/logic/BaseVersionList.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "BaseVersionList.h" -#include "BaseVersion.h" - -BaseVersionList::BaseVersionList(QObject *parent) : QAbstractListModel(parent) -{ -} - -BaseVersionPtr BaseVersionList::findVersion(const QString &descriptor) -{ - for (int i = 0; i < count(); i++) - { - if (at(i)->descriptor() == descriptor) - return at(i); - } - return BaseVersionPtr(); -} - -BaseVersionPtr BaseVersionList::getLatestStable() const -{ - if (count() <= 0) - return BaseVersionPtr(); - else - return at(0); -} - -BaseVersionPtr BaseVersionList::getRecommended() const -{ - return getLatestStable(); -} - -QVariant BaseVersionList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (index.row() > count()) - return QVariant(); - - BaseVersionPtr version = at(index.row()); - - switch (role) - { - case VersionPointerRole: - return qVariantFromValue(version); - - case VersionRole: - return version->name(); - - case VersionIdRole: - return version->descriptor(); - - case TypeRole: - return version->typeString(); - - default: - return QVariant(); - } -} - -BaseVersionList::RoleList BaseVersionList::providesRoles() const -{ - return {VersionPointerRole, VersionRole, VersionIdRole, TypeRole}; -} - -int BaseVersionList::rowCount(const QModelIndex &parent) const -{ - // Return count - return count(); -} - -int BaseVersionList::columnCount(const QModelIndex &parent) const -{ - return 1; -} - -QHash BaseVersionList::roleNames() const -{ - QHash roles = QAbstractListModel::roleNames(); - roles.insert(VersionRole, "version"); - roles.insert(VersionIdRole, "versionId"); - roles.insert(ParentGameVersionRole, "parentGameVersion"); - roles.insert(RecommendedRole, "recommended"); - roles.insert(LatestRole, "latest"); - roles.insert(TypeRole, "type"); - roles.insert(BranchRole, "branch"); - roles.insert(PathRole, "path"); - roles.insert(ArchitectureRole, "architecture"); - return roles; -} diff --git a/logic/BaseVersionList.h b/logic/BaseVersionList.h deleted file mode 100644 index 73d2ee1f..00000000 --- a/logic/BaseVersionList.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "BaseVersion.h" -#include "tasks/Task.h" -#include "multimc_logic_export.h" - -/*! - * \brief Class that each instance type's version list derives from. - * Version lists are the lists that keep track of the available game versions - * for that instance. This list will not be loaded on startup. It will be loaded - * when the list's load function is called. Before using the version list, you - * should check to see if it has been loaded yet and if not, load the list. - * - * Note that this class also inherits from QAbstractListModel. Methods from that - * class determine how this version list shows up in a list view. Said methods - * all have a default implementation, but they can be overridden by plugins to - * change the behavior of the list. - */ -class MULTIMC_LOGIC_EXPORT BaseVersionList : public QAbstractListModel -{ - Q_OBJECT -public: - enum ModelRoles - { - VersionPointerRole = Qt::UserRole, - VersionRole, - VersionIdRole, - ParentGameVersionRole, - RecommendedRole, - LatestRole, - TypeRole, - BranchRole, - PathRole, - ArchitectureRole, - SortRole - }; - typedef QList RoleList; - - explicit BaseVersionList(QObject *parent = 0); - - /*! - * \brief Gets a task that will reload the version list. - * Simply execute the task to load the list. - * The task returned by this function should reset the model when it's done. - * \return A pointer to a task that reloads the version list. - */ - virtual Task *getLoadTask() = 0; - - //! Checks whether or not the list is loaded. If this returns false, the list should be - //loaded. - virtual bool isLoaded() = 0; - - //! Gets the version at the given index. - virtual const BaseVersionPtr at(int i) const = 0; - - //! Returns the number of versions in the list. - virtual int count() const = 0; - - //////// List Model Functions //////// - virtual QVariant data(const QModelIndex &index, int role) const; - virtual int rowCount(const QModelIndex &parent) const; - virtual int columnCount(const QModelIndex &parent) const; - virtual QHash roleNames() const override; - - //! which roles are provided by this version list? - virtual RoleList providesRoles() const; - - /*! - * \brief Finds a version by its descriptor. - * \param The descriptor of the version to find. - * \return A const pointer to the version with the given descriptor. NULL if - * one doesn't exist. - */ - virtual BaseVersionPtr findVersion(const QString &descriptor); - - /*! - * \brief Gets the latest stable version from this list - */ - virtual BaseVersionPtr getLatestStable() const; - - /*! - * \brief Gets the recommended version from this list - * If the list doesn't support recommended versions, this works exactly as getLatestStable - */ - virtual BaseVersionPtr getRecommended() const; - - /*! - * Sorts the version list. - */ - virtual void sortVersions() = 0; - -protected -slots: - /*! - * Updates this list with the given list of versions. - * This is done by copying each version in the given list and inserting it - * into this one. - * We need to do this so that we can set the parents of the versions are set to this - * version list. This can't be done in the load task, because the versions the load - * task creates are on the load task's thread and Qt won't allow their parents - * to be set to something created on another thread. - * To get around that problem, we invoke this method on the GUI thread, which - * then copies the versions and sets their parents correctly. - * \param versions List of versions whose parents should be set. - */ - virtual void updateListData(QList versions) = 0; -}; diff --git a/logic/CMakeLists.txt b/logic/CMakeLists.txt deleted file mode 100644 index cd8aa246..00000000 --- a/logic/CMakeLists.txt +++ /dev/null @@ -1,354 +0,0 @@ -project(MultiMC_logic) - -set(LOGIC_SOURCES - # LOGIC - Base classes and infrastructure - BaseInstaller.h - BaseInstaller.cpp - BaseVersionList.h - BaseVersionList.cpp - InstanceList.h - InstanceList.cpp - BaseVersion.h - BaseInstance.h - BaseInstance.cpp - NullInstance.h - MMCZip.h - MMCZip.cpp - MMCStrings.h - MMCStrings.cpp - BaseConfigObject.h - BaseConfigObject.cpp - AbstractCommonModel.h - AbstractCommonModel.cpp - TypeMagic.h - - # Prefix tree where node names are strings between separators - SeparatorPrefixTree.h - - # WARNING: globals live here - Env.h - Env.cpp - - # JSON parsing helpers - Json.h - Json.cpp - - FileSystem.h - FileSystem.cpp - DesktopServices.h - DesktopServices.cpp - - Exception.h - - # RW lock protected map - RWStorage.h - - # A variable that has an implicit default value and keeps track of changes - DefaultVariable.h - - # a smart pointer wrapper intended for safer use with Qt signal/slot mechanisms - QObjectPtr.h - - # Resources - resources/Resource.cpp - resources/Resource.h - resources/ResourceHandler.cpp - resources/ResourceHandler.h - resources/ResourceObserver.cpp - resources/ResourceObserver.h - resources/ResourceProxyModel.h - resources/ResourceProxyModel.cpp - - # Path matchers - pathmatcher/FSTreeMatcher.h - pathmatcher/IPathMatcher.h - pathmatcher/MultiMatcher.h - pathmatcher/RegexpMatcher.h - - # Compression support - GZip.h - GZip.cpp - - # Command line parameter parsing - Commandline.h - Commandline.cpp - - # Version number string support - Version.h - Version.cpp - - # network stuffs - net/NetAction.h - net/MD5EtagDownload.h - net/MD5EtagDownload.cpp - net/ByteArrayDownload.h - net/ByteArrayDownload.cpp - net/CacheDownload.h - net/CacheDownload.cpp - net/NetJob.h - net/NetJob.cpp - net/HttpMetaCache.h - net/HttpMetaCache.cpp - net/PasteUpload.h - net/PasteUpload.cpp - net/URLConstants.h - net/URLConstants.cpp - - # Yggdrasil login stuff - minecraft/auth/AuthSession.h - minecraft/auth/AuthSession.cpp - minecraft/auth/MojangAccountList.h - minecraft/auth/MojangAccountList.cpp - minecraft/auth/MojangAccount.h - minecraft/auth/MojangAccount.cpp - minecraft/auth/YggdrasilTask.h - minecraft/auth/YggdrasilTask.cpp - minecraft/auth/flows/AuthenticateTask.h - minecraft/auth/flows/AuthenticateTask.cpp - minecraft/auth/flows/RefreshTask.cpp - minecraft/auth/flows/RefreshTask.cpp - minecraft/auth/flows/ValidateTask.h - minecraft/auth/flows/ValidateTask.cpp - - # Game launch logic - launch/steps/CheckJava.cpp - launch/steps/CheckJava.h - launch/steps/LaunchMinecraft.cpp - launch/steps/LaunchMinecraft.h - launch/steps/ModMinecraftJar.cpp - launch/steps/ModMinecraftJar.h - launch/steps/PostLaunchCommand.cpp - launch/steps/PostLaunchCommand.h - launch/steps/PreLaunchCommand.cpp - launch/steps/PreLaunchCommand.h - launch/steps/TextPrint.cpp - launch/steps/TextPrint.h - launch/steps/Update.cpp - launch/steps/Update.h - launch/LaunchStep.cpp - launch/LaunchStep.h - launch/LaunchTask.cpp - launch/LaunchTask.h - launch/LoggedProcess.cpp - launch/LoggedProcess.h - launch/MessageLevel.cpp - launch/MessageLevel.h - - # Update system - updater/GoUpdate.h - updater/GoUpdate.cpp - updater/UpdateChecker.h - updater/UpdateChecker.cpp - updater/DownloadTask.h - updater/DownloadTask.cpp - - # Notifications - short warning messages - notifications/NotificationChecker.h - notifications/NotificationChecker.cpp - - # News System - news/NewsChecker.h - news/NewsChecker.cpp - news/NewsEntry.h - news/NewsEntry.cpp - - # Status system - status/StatusChecker.h - status/StatusChecker.cpp - - # Minecraft support - minecraft/onesix/OneSixUpdate.h - minecraft/onesix/OneSixUpdate.cpp - minecraft/onesix/OneSixInstance.h - minecraft/onesix/OneSixInstance.cpp - minecraft/onesix/OneSixProfileStrategy.cpp - minecraft/onesix/OneSixProfileStrategy.h - minecraft/onesix/OneSixVersionFormat.cpp - minecraft/onesix/OneSixVersionFormat.h - minecraft/legacy/LegacyUpdate.h - minecraft/legacy/LegacyUpdate.cpp - minecraft/legacy/LegacyInstance.h - minecraft/legacy/LegacyInstance.cpp - minecraft/legacy/LwjglVersionList.h - minecraft/legacy/LwjglVersionList.cpp - minecraft/SkinUtils.h - minecraft/SkinUtils.cpp - minecraft/GradleSpecifier.h - minecraft/MinecraftProfile.cpp - minecraft/MinecraftProfile.h - minecraft/MojangVersionFormat.cpp - minecraft/MojangVersionFormat.h - minecraft/JarMod.h - minecraft/MinecraftInstance.cpp - minecraft/MinecraftInstance.h - minecraft/MinecraftVersion.cpp - minecraft/MinecraftVersion.h - minecraft/MinecraftVersionList.cpp - minecraft/MinecraftVersionList.h - minecraft/Rule.cpp - minecraft/Rule.h - minecraft/OpSys.cpp - minecraft/OpSys.h - minecraft/ParseUtils.cpp - minecraft/ParseUtils.h - minecraft/ProfileUtils.cpp - minecraft/ProfileUtils.h - minecraft/ProfileStrategy.h - minecraft/Library.cpp - minecraft/Library.h - minecraft/MojangDownloadInfo.h - minecraft/VersionBuildError.h - minecraft/VersionFile.cpp - minecraft/VersionFile.h - minecraft/ProfilePatch.h - minecraft/VersionFilterData.h - minecraft/VersionFilterData.cpp - minecraft/Mod.h - minecraft/Mod.cpp - minecraft/ModList.h - minecraft/ModList.cpp - minecraft/World.h - minecraft/World.cpp - minecraft/WorldList.h - minecraft/WorldList.cpp - - # FTB - minecraft/ftb/OneSixFTBInstance.h - minecraft/ftb/OneSixFTBInstance.cpp - minecraft/ftb/LegacyFTBInstance.h - minecraft/ftb/LegacyFTBInstance.cpp - minecraft/ftb/FTBProfileStrategy.h - minecraft/ftb/FTBProfileStrategy.cpp - minecraft/ftb/FTBPlugin.h - minecraft/ftb/FTBPlugin.cpp - - # A Recursive file system watcher - RecursiveFileSystemWatcher.h - RecursiveFileSystemWatcher.cpp - - # the screenshots feature - screenshots/Screenshot.h - screenshots/ImgurUpload.h - screenshots/ImgurUpload.cpp - screenshots/ImgurAlbumCreation.h - screenshots/ImgurAlbumCreation.cpp - - # Icons - icons/MMCIcon.h - icons/MMCIcon.cpp - icons/IconList.h - icons/IconList.cpp - - # Tasks - tasks/Task.h - tasks/Task.cpp - tasks/ThreadTask.h - tasks/ThreadTask.cpp - tasks/SequentialTask.h - tasks/SequentialTask.cpp - - # Settings - settings/INIFile.cpp - settings/INIFile.h - settings/INISettingsObject.cpp - settings/INISettingsObject.h - settings/OverrideSetting.cpp - settings/OverrideSetting.h - settings/PassthroughSetting.cpp - settings/PassthroughSetting.h - settings/Setting.cpp - settings/Setting.h - settings/SettingsObject.cpp - settings/SettingsObject.h - - # Java related code - java/JavaChecker.h - java/JavaChecker.cpp - java/JavaCheckerJob.h - java/JavaCheckerJob.cpp - java/JavaInstall.h - java/JavaInstall.cpp - java/JavaInstallList.h - java/JavaInstallList.cpp - java/JavaUtils.h - java/JavaUtils.cpp - java/JavaVersion.h - java/JavaVersion.cpp - - # Assets - minecraft/AssetsUtils.h - minecraft/AssetsUtils.cpp - - # Forge and all things forge related - minecraft/forge/ForgeVersion.h - minecraft/forge/ForgeVersion.cpp - minecraft/forge/ForgeVersionList.h - minecraft/forge/ForgeVersionList.cpp - minecraft/forge/ForgeXzDownload.h - minecraft/forge/ForgeXzDownload.cpp - minecraft/forge/LegacyForge.h - minecraft/forge/LegacyForge.cpp - minecraft/forge/ForgeInstaller.h - minecraft/forge/ForgeInstaller.cpp - - # Liteloader and related things - minecraft/liteloader/LiteLoaderInstaller.h - minecraft/liteloader/LiteLoaderInstaller.cpp - minecraft/liteloader/LiteLoaderVersionList.h - minecraft/liteloader/LiteLoaderVersionList.cpp - - # Translations - trans/TranslationDownloader.h - trans/TranslationDownloader.cpp - - # Tools - tools/BaseExternalTool.cpp - tools/BaseExternalTool.h - tools/BaseProfiler.cpp - tools/BaseProfiler.h - tools/JProfiler.cpp - tools/JProfiler.h - tools/JVisualVM.cpp - tools/JVisualVM.h - tools/MCEditTool.cpp - tools/MCEditTool.h - - # Wonko - wonko/tasks/BaseWonkoEntityRemoteLoadTask.cpp - wonko/tasks/BaseWonkoEntityRemoteLoadTask.h - wonko/tasks/BaseWonkoEntityLocalLoadTask.cpp - wonko/tasks/BaseWonkoEntityLocalLoadTask.h - wonko/format/WonkoFormatV1.cpp - wonko/format/WonkoFormatV1.h - wonko/format/WonkoFormat.cpp - wonko/format/WonkoFormat.h - wonko/BaseWonkoEntity.cpp - wonko/BaseWonkoEntity.h - wonko/WonkoVersionList.cpp - wonko/WonkoVersionList.h - wonko/WonkoVersion.cpp - wonko/WonkoVersion.h - wonko/WonkoIndex.cpp - wonko/WonkoIndex.h - wonko/WonkoUtil.cpp - wonko/WonkoUtil.h - wonko/WonkoReference.cpp - wonko/WonkoReference.h -) -################################ COMPILE ################################ - -# we need zlib -find_package(ZLIB REQUIRED) - -add_library(MultiMC_logic SHARED ${LOGIC_SOURCES}) -set_target_properties(MultiMC_logic PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN 1) - -generate_export_header(MultiMC_logic) - -# Link -target_link_libraries(MultiMC_logic xz-embedded unpack200 iconfix LogicalGui ${QUAZIP_LIBRARIES} nbt++ ${ZLIB_LIBRARIES}) -qt5_use_modules(MultiMC_logic Core Xml Widgets Network Concurrent) -add_dependencies(MultiMC_logic QuaZIP) - -# Mark and export headers -target_include_directories(MultiMC_logic PUBLIC "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" PRIVATE "${ZLIB_INCLUDE_DIRS}") diff --git a/logic/Commandline.cpp b/logic/Commandline.cpp deleted file mode 100644 index 9a8ddbf1..00000000 --- a/logic/Commandline.cpp +++ /dev/null @@ -1,483 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Commandline.h" - -/** - * @file libutil/src/cmdutils.cpp - */ - -namespace Commandline -{ - -// commandline splitter -QStringList splitArgs(QString args) -{ - QStringList argv; - QString current; - bool escape = false; - QChar inquotes; - for (int i = 0; i < args.length(); i++) - { - QChar cchar = args.at(i); - - // \ escaped - if (escape) - { - current += cchar; - escape = false; - // in "quotes" - } - else if (!inquotes.isNull()) - { - if (cchar == 0x5C) - escape = true; - else if (cchar == inquotes) - inquotes = 0; - else - current += cchar; - // otherwise - } - else - { - if (cchar == 0x20) - { - if (!current.isEmpty()) - { - argv << current; - current.clear(); - } - } - else if (cchar == 0x22 || cchar == 0x27) - inquotes = cchar; - else - current += cchar; - } - } - if (!current.isEmpty()) - argv << current; - return argv; -} - -Parser::Parser(FlagStyle::Enum flagStyle, ArgumentStyle::Enum argStyle) -{ - m_flagStyle = flagStyle; - m_argStyle = argStyle; -} - -// styles setter/getter -void Parser::setArgumentStyle(ArgumentStyle::Enum style) -{ - m_argStyle = style; -} -ArgumentStyle::Enum Parser::argumentStyle() -{ - return m_argStyle; -} - -void Parser::setFlagStyle(FlagStyle::Enum style) -{ - m_flagStyle = style; -} -FlagStyle::Enum Parser::flagStyle() -{ - return m_flagStyle; -} - -// setup methods -void Parser::addSwitch(QString name, bool def) -{ - if (m_params.contains(name)) - throw "Name not unique"; - - OptionDef *param = new OptionDef; - param->type = otSwitch; - param->name = name; - param->metavar = QString("<%1>").arg(name); - param->def = def; - - m_options[name] = param; - m_params[name] = (CommonDef *)param; - m_optionList.append(param); -} - -void Parser::addOption(QString name, QVariant def) -{ - if (m_params.contains(name)) - throw "Name not unique"; - - OptionDef *param = new OptionDef; - param->type = otOption; - param->name = name; - param->metavar = QString("<%1>").arg(name); - param->def = def; - - m_options[name] = param; - m_params[name] = (CommonDef *)param; - m_optionList.append(param); -} - -void Parser::addArgument(QString name, bool required, QVariant def) -{ - if (m_params.contains(name)) - throw "Name not unique"; - - PositionalDef *param = new PositionalDef; - param->name = name; - param->def = def; - param->required = required; - param->metavar = name; - - m_positionals.append(param); - m_params[name] = (CommonDef *)param; -} - -void Parser::addDocumentation(QString name, QString doc, QString metavar) -{ - if (!m_params.contains(name)) - throw "Name does not exist"; - - CommonDef *param = m_params[name]; - param->doc = doc; - if (!metavar.isNull()) - param->metavar = metavar; -} - -void Parser::addShortOpt(QString name, QChar flag) -{ - if (!m_params.contains(name)) - throw "Name does not exist"; - if (!m_options.contains(name)) - throw "Name is not an Option or Swtich"; - - OptionDef *param = m_options[name]; - m_flags[flag] = param; - param->flag = flag; -} - -// help methods -QString Parser::compileHelp(QString progName, int helpIndent, bool useFlags) -{ - QStringList help; - help << compileUsage(progName, useFlags) << "\r\n"; - - // positionals - if (!m_positionals.isEmpty()) - { - help << "\r\n"; - help << "Positional arguments:\r\n"; - QListIterator it2(m_positionals); - while (it2.hasNext()) - { - PositionalDef *param = it2.next(); - help << " " << param->metavar; - help << " " << QString(helpIndent - param->metavar.length() - 1, ' '); - help << param->doc << "\r\n"; - } - } - - // Options - if (!m_optionList.isEmpty()) - { - help << "\r\n"; - QString optPrefix, flagPrefix; - getPrefix(optPrefix, flagPrefix); - - help << "Options & Switches:\r\n"; - QListIterator it(m_optionList); - while (it.hasNext()) - { - OptionDef *option = it.next(); - help << " "; - int nameLength = optPrefix.length() + option->name.length(); - if (!option->flag.isNull()) - { - nameLength += 3 + flagPrefix.length(); - help << flagPrefix << option->flag << ", "; - } - help << optPrefix << option->name; - if (option->type == otOption) - { - QString arg = QString("%1%2").arg( - ((m_argStyle == ArgumentStyle::Equals) ? "=" : " "), option->metavar); - nameLength += arg.length(); - help << arg; - } - help << " " << QString(helpIndent - nameLength - 1, ' '); - help << option->doc << "\r\n"; - } - } - - return help.join(""); -} - -QString Parser::compileUsage(QString progName, bool useFlags) -{ - QStringList usage; - usage << "Usage: " << progName; - - QString optPrefix, flagPrefix; - getPrefix(optPrefix, flagPrefix); - - // options - QListIterator it(m_optionList); - while (it.hasNext()) - { - OptionDef *option = it.next(); - usage << " ["; - if (!option->flag.isNull() && useFlags) - usage << flagPrefix << option->flag; - else - usage << optPrefix << option->name; - if (option->type == otOption) - usage << ((m_argStyle == ArgumentStyle::Equals) ? "=" : " ") << option->metavar; - usage << "]"; - } - - // arguments - QListIterator it2(m_positionals); - while (it2.hasNext()) - { - PositionalDef *param = it2.next(); - usage << " " << (param->required ? "<" : "["); - usage << param->metavar; - usage << (param->required ? ">" : "]"); - } - - return usage.join(""); -} - -// parsing -QHash Parser::parse(QStringList argv) -{ - QHash map; - - QStringListIterator it(argv); - QString programName = it.next(); - - QString optionPrefix; - QString flagPrefix; - QListIterator positionals(m_positionals); - QStringList expecting; - - getPrefix(optionPrefix, flagPrefix); - - while (it.hasNext()) - { - QString arg = it.next(); - - if (!expecting.isEmpty()) - // we were expecting an argument - { - QString name = expecting.first(); -/* - if (map.contains(name)) - throw ParsingError( - QString("Option %2%1 was given multiple times").arg(name, optionPrefix)); -*/ - map[name] = QVariant(arg); - - expecting.removeFirst(); - continue; - } - - if (arg.startsWith(optionPrefix)) - // we have an option - { - // qDebug("Found option %s", qPrintable(arg)); - - QString name = arg.mid(optionPrefix.length()); - QString equals; - - if ((m_argStyle == ArgumentStyle::Equals || - m_argStyle == ArgumentStyle::SpaceAndEquals) && - name.contains("=")) - { - int i = name.indexOf("="); - equals = name.mid(i + 1); - name = name.left(i); - } - - if (m_options.contains(name)) - { - /* - if (map.contains(name)) - throw ParsingError(QString("Option %2%1 was given multiple times") - .arg(name, optionPrefix)); -*/ - OptionDef *option = m_options[name]; - if (option->type == otSwitch) - map[name] = true; - else // if (option->type == otOption) - { - if (m_argStyle == ArgumentStyle::Space) - expecting.append(name); - else if (!equals.isNull()) - map[name] = equals; - else if (m_argStyle == ArgumentStyle::SpaceAndEquals) - expecting.append(name); - else - throw ParsingError(QString("Option %2%1 reqires an argument.") - .arg(name, optionPrefix)); - } - - continue; - } - - throw ParsingError(QString("Unknown Option %2%1").arg(name, optionPrefix)); - } - - if (arg.startsWith(flagPrefix)) - // we have (a) flag(s) - { - // qDebug("Found flags %s", qPrintable(arg)); - - QString flags = arg.mid(flagPrefix.length()); - QString equals; - - if ((m_argStyle == ArgumentStyle::Equals || - m_argStyle == ArgumentStyle::SpaceAndEquals) && - flags.contains("=")) - { - int i = flags.indexOf("="); - equals = flags.mid(i + 1); - flags = flags.left(i); - } - - for (int i = 0; i < flags.length(); i++) - { - QChar flag = flags.at(i); - - if (!m_flags.contains(flag)) - throw ParsingError(QString("Unknown flag %2%1").arg(flag, flagPrefix)); - - OptionDef *option = m_flags[flag]; -/* - if (map.contains(option->name)) - throw ParsingError(QString("Option %2%1 was given multiple times") - .arg(option->name, optionPrefix)); -*/ - if (option->type == otSwitch) - map[option->name] = true; - else // if (option->type == otOption) - { - if (m_argStyle == ArgumentStyle::Space) - expecting.append(option->name); - else if (!equals.isNull()) - if (i == flags.length() - 1) - map[option->name] = equals; - else - throw ParsingError(QString("Flag %4%2 of Argument-requiring Option " - "%1 not last flag in %4%3") - .arg(option->name, flag, flags, flagPrefix)); - else if (m_argStyle == ArgumentStyle::SpaceAndEquals) - expecting.append(option->name); - else - throw ParsingError(QString("Option %1 reqires an argument. (flag %3%2)") - .arg(option->name, flag, flagPrefix)); - } - } - - continue; - } - - // must be a positional argument - if (!positionals.hasNext()) - throw ParsingError(QString("Don't know what to do with '%1'").arg(arg)); - - PositionalDef *param = positionals.next(); - - map[param->name] = arg; - } - - // check if we're missing something - if (!expecting.isEmpty()) - throw ParsingError(QString("Was still expecting arguments for %2%1").arg( - expecting.join(QString(", ") + optionPrefix), optionPrefix)); - - while (positionals.hasNext()) - { - PositionalDef *param = positionals.next(); - if (param->required) - throw ParsingError( - QString("Missing required positional argument '%1'").arg(param->name)); - else - map[param->name] = param->def; - } - - // fill out gaps - QListIterator iter(m_optionList); - while (iter.hasNext()) - { - OptionDef *option = iter.next(); - if (!map.contains(option->name)) - map[option->name] = option->def; - } - - return map; -} - -// clear defs -void Parser::clear() -{ - m_flags.clear(); - m_params.clear(); - m_options.clear(); - - QMutableListIterator it(m_optionList); - while (it.hasNext()) - { - OptionDef *option = it.next(); - it.remove(); - delete option; - } - - QMutableListIterator it2(m_positionals); - while (it2.hasNext()) - { - PositionalDef *arg = it2.next(); - it2.remove(); - delete arg; - } -} - -// Destructor -Parser::~Parser() -{ - clear(); -} - -// getPrefix -void Parser::getPrefix(QString &opt, QString &flag) -{ - if (m_flagStyle == FlagStyle::Windows) - opt = flag = "/"; - else if (m_flagStyle == FlagStyle::Unix) - opt = flag = "-"; - // else if (m_flagStyle == FlagStyle::GNU) - else - { - opt = "--"; - flag = "-"; - } -} - -// ParsingError -ParsingError::ParsingError(const QString &what) : std::runtime_error(what.toStdString()) -{ -} -} \ No newline at end of file diff --git a/logic/Commandline.h b/logic/Commandline.h deleted file mode 100644 index bee02bad..00000000 --- a/logic/Commandline.h +++ /dev/null @@ -1,252 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include - -#include "multimc_logic_export.h" - -/** - * @file libutil/include/cmdutils.h - * @brief commandline parsing and processing utilities - */ - -namespace Commandline -{ - -/** - * @brief split a string into argv items like a shell would do - * @param args the argument string - * @return a QStringList containing all arguments - */ -MULTIMC_LOGIC_EXPORT QStringList splitArgs(QString args); - -/** - * @brief The FlagStyle enum - * Specifies how flags are decorated - */ - -namespace FlagStyle -{ -enum Enum -{ - GNU, /**< --option and -o (GNU Style) */ - Unix, /**< -option and -o (Unix Style) */ - Windows, /**< /option and /o (Windows Style) */ -#ifdef Q_OS_WIN32 - Default = Windows -#else - Default = GNU -#endif -}; -} - -/** - * @brief The ArgumentStyle enum - */ -namespace ArgumentStyle -{ -enum Enum -{ - Space, /**< --option=value */ - Equals, /**< --option value */ - SpaceAndEquals, /**< --option[= ]value */ -#ifdef Q_OS_WIN32 - Default = Equals -#else - Default = SpaceAndEquals -#endif -}; -} - -/** - * @brief The ParsingError class - */ -class MULTIMC_LOGIC_EXPORT ParsingError : public std::runtime_error -{ -public: - ParsingError(const QString &what); -}; - -/** - * @brief The Parser class - */ -class MULTIMC_LOGIC_EXPORT Parser -{ -public: - /** - * @brief Parser constructor - * @param flagStyle the FlagStyle to use in this Parser - * @param argStyle the ArgumentStyle to use in this Parser - */ - Parser(FlagStyle::Enum flagStyle = FlagStyle::Default, - ArgumentStyle::Enum argStyle = ArgumentStyle::Default); - - /** - * @brief set the flag style - * @param style - */ - void setFlagStyle(FlagStyle::Enum style); - - /** - * @brief get the flag style - * @return - */ - FlagStyle::Enum flagStyle(); - - /** - * @brief set the argument style - * @param style - */ - void setArgumentStyle(ArgumentStyle::Enum style); - - /** - * @brief get the argument style - * @return - */ - ArgumentStyle::Enum argumentStyle(); - - /** - * @brief define a boolean switch - * @param name the parameter name - * @param def the default value - */ - void addSwitch(QString name, bool def = false); - - /** - * @brief define an option that takes an additional argument - * @param name the parameter name - * @param def the default value - */ - void addOption(QString name, QVariant def = QVariant()); - - /** - * @brief define a positional argument - * @param name the parameter name - * @param required wether this argument is required - * @param def the default value - */ - void addArgument(QString name, bool required = true, QVariant def = QVariant()); - - /** - * @brief adds a flag to an existing parameter - * @param name the (existing) parameter name - * @param flag the flag character - * @see addSwitch addArgument addOption - * Note: any one parameter can only have one flag - */ - void addShortOpt(QString name, QChar flag); - - /** - * @brief adds documentation to a Parameter - * @param name the parameter name - * @param metavar a string to be displayed as placeholder for the value - * @param doc a QString containing the documentation - * Note: on positional arguments, metavar replaces the name as displayed. - * on options , metavar replaces the value placeholder - */ - void addDocumentation(QString name, QString doc, QString metavar = QString()); - - /** - * @brief generate a help message - * @param progName the program name to use in the help message - * @param helpIndent how much the parameter documentation should be indented - * @param flagsInUsage whether we should use flags instead of options in the usage - * @return a help message - */ - QString compileHelp(QString progName, int helpIndent = 22, bool flagsInUsage = true); - - /** - * @brief generate a short usage message - * @param progName the program name to use in the usage message - * @param useFlags whether we should use flags instead of options - * @return a usage message - */ - QString compileUsage(QString progName, bool useFlags = true); - - /** - * @brief parse - * @param argv a QStringList containing the program ARGV - * @return a QHash mapping argument names to their values - */ - QHash parse(QStringList argv); - - /** - * @brief clear all definitions - */ - void clear(); - - ~Parser(); - -private: - FlagStyle::Enum m_flagStyle; - ArgumentStyle::Enum m_argStyle; - - enum OptionType - { - otSwitch, - otOption - }; - - // Important: the common part MUST BE COMMON ON ALL THREE structs - struct CommonDef - { - QString name; - QString doc; - QString metavar; - QVariant def; - }; - - struct OptionDef - { - // common - QString name; - QString doc; - QString metavar; - QVariant def; - // option - OptionType type; - QChar flag; - }; - - struct PositionalDef - { - // common - QString name; - QString doc; - QString metavar; - QVariant def; - // positional - bool required; - }; - - QHash m_options; - QHash m_flags; - QHash m_params; - QList m_positionals; - QList m_optionList; - - void getPrefix(QString &opt, QString &flag); -}; -} diff --git a/logic/DefaultVariable.h b/logic/DefaultVariable.h deleted file mode 100644 index 38d7ecc2..00000000 --- a/logic/DefaultVariable.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -template -class DefaultVariable -{ -public: - DefaultVariable(const T & value) - { - defaultValue = value; - } - DefaultVariable & operator =(const T & value) - { - currentValue = value; - is_default = currentValue == defaultValue; - is_explicit = true; - return *this; - } - operator const T &() const - { - return is_default ? defaultValue : currentValue; - } - bool isDefault() const - { - return is_default; - } - bool isExplicit() const - { - return is_explicit; - } -private: - T currentValue; - T defaultValue; - bool is_default = true; - bool is_explicit = false; -}; diff --git a/logic/DesktopServices.cpp b/logic/DesktopServices.cpp deleted file mode 100644 index 3154ea01..00000000 --- a/logic/DesktopServices.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include "DesktopServices.h" -#include -#include -#include -#include - -/** - * This shouldn't exist, but until QTBUG-9328 and other unreported bugs are fixed, it needs to be a thing. - */ -#if defined(Q_OS_LINUX) - -#include -#include -#include -#include - -template -bool IndirectOpen(T callable, qint64 *pid_forked = nullptr) -{ - auto pid = fork(); - if(pid_forked) - { - if(pid > 0) - *pid_forked = pid; - else - *pid_forked = 0; - } - if(pid == -1) - { - qWarning() << "IndirectOpen failed to fork: " << errno; - return false; - } - // child - do the stuff - if(pid == 0) - { - // unset all this garbage so it doesn't get passed to the child process - qunsetenv("LD_PRELOAD"); - qunsetenv("LD_LIBRARY_PATH"); - qunsetenv("LD_DEBUG"); - qunsetenv("QT_PLUGIN_PATH"); - qunsetenv("QT_FONTPATH"); - - // open the URL - auto status = callable(); - - // detach from the parent process group. - setsid(); - - // die. now. do not clean up anything, it would just hang forever. - _exit(status ? 0 : 1); - } - else - { - //parent - assume it worked. - int status; - while (waitpid(pid, &status, 0)) - { - if(WIFEXITED(status)) - { - return WEXITSTATUS(status) == 0; - } - if(WIFSIGNALED(status)) - { - return false; - } - } - return true; - } -} -#endif - -namespace DesktopServices { -bool openDirectory(const QString &path, bool ensureExists) -{ - qDebug() << "Opening directory" << path; - QDir parentPath; - QDir dir(path); - if (!dir.exists()) - { - parentPath.mkpath(dir.absolutePath()); - } - auto f = [&]() - { - return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); - }; -#if defined(Q_OS_LINUX) - return IndirectOpen(f); -#else - return f(); -#endif -} - -bool openFile(const QString &path) -{ - qDebug() << "Opening file" << path; - auto f = [&]() - { - return QDesktopServices::openUrl(QUrl::fromLocalFile(path)); - }; -#if defined(Q_OS_LINUX) - return IndirectOpen(f); -#else - return f(); -#endif -} - -bool openFile(const QString &application, const QString &path, const QString &workingDirectory, qint64 *pid) -{ - qDebug() << "Opening file" << path << "using" << application; -#if defined(Q_OS_LINUX) - // FIXME: the pid here is fake. So if something depends on it, it will likely misbehave - return IndirectOpen([&]() - { - return QProcess::startDetached(application, QStringList() << path, workingDirectory); - }, pid); -#else - return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid); -#endif -} - -bool run(const QString &application, const QStringList &args, const QString &workingDirectory, qint64 *pid) -{ - qDebug() << "Running" << application << "with args" << args.join(' '); -#if defined(Q_OS_LINUX) - // FIXME: the pid here is fake. So if something depends on it, it will likely misbehave - return IndirectOpen([&]() - { - return QProcess::startDetached(application, args, workingDirectory); - }, pid); -#else - return QProcess::startDetached(application, args, workingDirectory, pid); -#endif -} - -bool openUrl(const QUrl &url) -{ - qDebug() << "Opening URL" << url.toString(); - auto f = [&]() - { - return QDesktopServices::openUrl(url); - }; -#if defined(Q_OS_LINUX) - return IndirectOpen(f); -#else - return f(); -#endif -} - -} diff --git a/logic/DesktopServices.h b/logic/DesktopServices.h deleted file mode 100644 index 1e67e4cb..00000000 --- a/logic/DesktopServices.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include "multimc_logic_export.h" - -/** - * This wraps around QDesktopServices and adds workarounds where needed - * Use this instead of QDesktopServices! - */ -namespace DesktopServices -{ - /** - * Open a file in whatever application is applicable - */ - MULTIMC_LOGIC_EXPORT bool openFile(const QString &path); - - /** - * Open a file in the specified application - */ - MULTIMC_LOGIC_EXPORT bool openFile(const QString &application, const QString &path, const QString & workingDirectory = QString(), qint64 *pid = 0); - - /** - * Run an application - */ - MULTIMC_LOGIC_EXPORT bool run(const QString &application,const QStringList &args, const QString & workingDirectory = QString(), qint64 *pid = 0); - - /** - * Open a directory - */ - MULTIMC_LOGIC_EXPORT bool openDirectory(const QString &path, bool ensureExists = false); - - /** - * Open the URL, most likely in a browser. Maybe. - */ - MULTIMC_LOGIC_EXPORT bool openUrl(const QUrl &url); -}; diff --git a/logic/Env.cpp b/logic/Env.cpp deleted file mode 100644 index d66ec184..00000000 --- a/logic/Env.cpp +++ /dev/null @@ -1,234 +0,0 @@ -#include "Env.h" -#include "net/HttpMetaCache.h" -#include "icons/IconList.h" -#include "BaseVersion.h" -#include "BaseVersionList.h" -#include -#include -#include -#include -#include "tasks/Task.h" -#include "wonko/WonkoIndex.h" -#include - -/* - * The *NEW* global rat nest of an object. Handle with care. - */ - -Env::Env() -{ - m_qnam = std::make_shared(); -} - -void Env::destroy() -{ - m_metacache.reset(); - m_qnam.reset(); - m_icons.reset(); - m_versionLists.clear(); -} - -Env& Env::Env::getInstance() -{ - static Env instance; - return instance; -} - -std::shared_ptr< HttpMetaCache > Env::metacache() -{ - Q_ASSERT(m_metacache != nullptr); - return m_metacache; -} - -std::shared_ptr< QNetworkAccessManager > Env::qnam() -{ - return m_qnam; -} - -std::shared_ptr Env::icons() -{ - Q_ASSERT(m_icons != nullptr); - return m_icons; -} - -bool Env::hasIcons() -{ - return m_icons != nullptr; -} -/* -class NullVersion : public BaseVersion -{ - Q_OBJECT -public: - virtual QString name() - { - return "null"; - } - virtual QString descriptor() - { - return "null"; - } - virtual QString typeString() const - { - return "Null"; - } -}; - -class NullTask: public Task -{ - Q_OBJECT -public: - virtual void executeTask() - { - emitFailed(tr("Nothing to do.")); - } -}; - -class NullVersionList: public BaseVersionList -{ - Q_OBJECT -public: - virtual const BaseVersionPtr at(int i) const - { - return std::make_shared(); - } - virtual int count() const - { - return 0; - }; - virtual Task* getLoadTask() - { - return new NullTask; - } - virtual bool isLoaded() - { - return false; - } - virtual void sort() - { - } - virtual void updateListData(QList< BaseVersionPtr >) - { - } -}; -*/ - -BaseVersionPtr Env::getVersion(QString component, QString version) -{ - auto list = getVersionList(component); - if(!list) - { - return nullptr; - } - return list->findVersion(version); -} - -std::shared_ptr< BaseVersionList > Env::getVersionList(QString component) -{ - auto iter = m_versionLists.find(component); - if(iter != m_versionLists.end()) - { - return *iter; - } - //return std::make_shared(); - return nullptr; -} - -void Env::registerVersionList(QString name, std::shared_ptr< BaseVersionList > vlist) -{ - m_versionLists[name] = vlist; -} - -std::shared_ptr Env::wonkoIndex() -{ - if (!m_wonkoIndex) - { - m_wonkoIndex = std::make_shared(); - } - return m_wonkoIndex; -} - - -void Env::initHttpMetaCache() -{ - m_metacache.reset(new HttpMetaCache("metacache")); - m_metacache->addBase("asset_indexes", QDir("assets/indexes").absolutePath()); - m_metacache->addBase("asset_objects", QDir("assets/objects").absolutePath()); - m_metacache->addBase("versions", QDir("versions").absolutePath()); - m_metacache->addBase("libraries", QDir("libraries").absolutePath()); - m_metacache->addBase("minecraftforge", QDir("mods/minecraftforge").absolutePath()); - m_metacache->addBase("fmllibs", QDir("mods/minecraftforge/libs").absolutePath()); - m_metacache->addBase("liteloader", QDir("mods/liteloader").absolutePath()); - m_metacache->addBase("general", QDir("cache").absolutePath()); - m_metacache->addBase("skins", QDir("accounts/skins").absolutePath()); - m_metacache->addBase("root", QDir::currentPath()); - m_metacache->addBase("translations", QDir("translations").absolutePath()); - m_metacache->addBase("icons", QDir("cache/icons").absolutePath()); - m_metacache->addBase("wonko", QDir("cache/wonko").absolutePath()); - m_metacache->Load(); -} - -void Env::updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password) -{ - // Set the application proxy settings. - if (proxyTypeStr == "SOCKS5") - { - QNetworkProxy::setApplicationProxy( - QNetworkProxy(QNetworkProxy::Socks5Proxy, addr, port, user, password)); - } - else if (proxyTypeStr == "HTTP") - { - QNetworkProxy::setApplicationProxy( - QNetworkProxy(QNetworkProxy::HttpProxy, addr, port, user, password)); - } - else if (proxyTypeStr == "None") - { - // If we have no proxy set, set no proxy and return. - QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::NoProxy)); - } - else - { - // If we have "Default" selected, set Qt to use the system proxy settings. - QNetworkProxyFactory::setUseSystemConfiguration(true); - } - - qDebug() << "Detecting proxy settings..."; - QNetworkProxy proxy = QNetworkProxy::applicationProxy(); - if (m_qnam.get()) - m_qnam->setProxy(proxy); - QString proxyDesc; - if (proxy.type() == QNetworkProxy::NoProxy) - { - qDebug() << "Using no proxy is an option!"; - return; - } - switch (proxy.type()) - { - case QNetworkProxy::DefaultProxy: - proxyDesc = "Default proxy: "; - break; - case QNetworkProxy::Socks5Proxy: - proxyDesc = "Socks5 proxy: "; - break; - case QNetworkProxy::HttpProxy: - proxyDesc = "HTTP proxy: "; - break; - case QNetworkProxy::HttpCachingProxy: - proxyDesc = "HTTP caching: "; - break; - case QNetworkProxy::FtpCachingProxy: - proxyDesc = "FTP caching: "; - break; - default: - proxyDesc = "DERP proxy: "; - break; - } - proxyDesc += QString("%3@%1:%2 pass %4") - .arg(proxy.hostName()) - .arg(proxy.port()) - .arg(proxy.user()) - .arg(proxy.password()); - qDebug() << proxyDesc; -} - -#include "Env.moc" diff --git a/logic/Env.h b/logic/Env.h deleted file mode 100644 index 2b29acaa..00000000 --- a/logic/Env.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "multimc_logic_export.h" - -class IconList; -class QNetworkAccessManager; -class HttpMetaCache; -class BaseVersionList; -class BaseVersion; -class WonkoIndex; - -#if defined(ENV) - #undef ENV -#endif -#define ENV (Env::getInstance()) - -class MULTIMC_LOGIC_EXPORT Env -{ - friend class MultiMC; -private: - Env(); -public: - static Env& getInstance(); - - // call when Qt stuff is being torn down - void destroy(); - - std::shared_ptr qnam(); - - std::shared_ptr metacache(); - - std::shared_ptr icons(); - - bool hasIcons(); - - /// init the cache. FIXME: possible future hook point - void initHttpMetaCache(); - - /// Updates the application proxy settings from the settings object. - void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password); - - /// get a version list by name - std::shared_ptr getVersionList(QString component); - - /// get a version by list name and version name - std::shared_ptr getVersion(QString component, QString version); - - void registerVersionList(QString name, std::shared_ptr vlist); - - std::shared_ptr wonkoIndex(); - - QString wonkoRootUrl() const { return m_wonkoRootUrl; } - void setWonkoRootUrl(const QString &url) { m_wonkoRootUrl = url; } - -protected: - std::shared_ptr m_qnam; - std::shared_ptr m_metacache; - std::shared_ptr m_icons; - QMap> m_versionLists; - std::shared_ptr m_wonkoIndex; - QString m_wonkoRootUrl; -}; diff --git a/logic/Exception.h b/logic/Exception.h deleted file mode 100644 index 30c7aa45..00000000 --- a/logic/Exception.h +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed under the Apache-2.0 license. See README.md for details. - -#pragma once - -#include -#include -#include - -#include "multimc_logic_export.h" - -class MULTIMC_LOGIC_EXPORT Exception : public std::exception -{ -public: - Exception(const QString &message) : std::exception(), m_message(message) - { - qCritical() << "Exception:" << message; - } - Exception(const Exception &other) - : std::exception(), m_message(other.cause()) - { - } - virtual ~Exception() noexcept {} - const char *what() const noexcept - { - return m_message.toLatin1().constData(); - } - QString cause() const - { - return m_message; - } - -private: - QString m_message; -}; diff --git a/logic/FileSystem.cpp b/logic/FileSystem.cpp deleted file mode 100644 index 049f1e38..00000000 --- a/logic/FileSystem.cpp +++ /dev/null @@ -1,436 +0,0 @@ -// Licensed under the Apache-2.0 license. See README.md for details. - -#include "FileSystem.h" - -#include -#include -#include -#include -#include -#include - -namespace FS { - -void ensureExists(const QDir &dir) -{ - if (!QDir().mkpath(dir.absolutePath())) - { - throw FileSystemException("Unable to create directory " + dir.dirName() + " (" + - dir.absolutePath() + ")"); - } -} - -void write(const QString &filename, const QByteArray &data) -{ - ensureExists(QFileInfo(filename).dir()); - QSaveFile file(filename); - if (!file.open(QSaveFile::WriteOnly)) - { - throw FileSystemException("Couldn't open " + filename + " for writing: " + - file.errorString()); - } - if (data.size() != file.write(data)) - { - throw FileSystemException("Error writing data to " + filename + ": " + - file.errorString()); - } - if (!file.commit()) - { - throw FileSystemException("Error while committing data to " + filename + ": " + - file.errorString()); - } -} - -QByteArray read(const QString &filename) -{ - QFile file(filename); - if (!file.open(QFile::ReadOnly)) - { - throw FileSystemException("Unable to open " + filename + " for reading: " + - file.errorString()); - } - const qint64 size = file.size(); - QByteArray data(int(size), 0); - const qint64 ret = file.read(data.data(), size); - if (ret == -1 || ret != size) - { - throw FileSystemException("Error reading data from " + filename + ": " + - file.errorString()); - } - return data; -} - -bool ensureFilePathExists(QString filenamepath) -{ - QFileInfo a(filenamepath); - QDir dir; - QString ensuredPath = a.path(); - bool success = dir.mkpath(ensuredPath); - return success; -} - -bool ensureFolderPathExists(QString foldernamepath) -{ - QFileInfo a(foldernamepath); - QDir dir; - QString ensuredPath = a.filePath(); - bool success = dir.mkpath(ensuredPath); - return success; -} - -bool copy::operator()(const QString &offset) -{ - //NOTE always deep copy on windows. the alternatives are too messy. - #if defined Q_OS_WIN32 - m_followSymlinks = true; - #endif - - auto src = PathCombine(m_src.absolutePath(), offset); - auto dst = PathCombine(m_dst.absolutePath(), offset); - - QFileInfo currentSrc(src); - if (!currentSrc.exists()) - return false; - - if(!m_followSymlinks && currentSrc.isSymLink()) - { - qDebug() << "creating symlink" << src << " - " << dst; - if (!ensureFilePathExists(dst)) - { - qWarning() << "Cannot create path!"; - return false; - } - return QFile::link(currentSrc.symLinkTarget(), dst); - } - else if(currentSrc.isFile()) - { - qDebug() << "copying file" << src << " - " << dst; - if (!ensureFilePathExists(dst)) - { - qWarning() << "Cannot create path!"; - return false; - } - return QFile::copy(src, dst); - } - else if(currentSrc.isDir()) - { - qDebug() << "recursing" << offset; - if (!ensureFolderPathExists(dst)) - { - qWarning() << "Cannot create path!"; - return false; - } - QDir currentDir(src); - for(auto & f : currentDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System)) - { - auto inner_offset = PathCombine(offset, f); - // ignore and skip stuff that matches the blacklist. - if(m_blacklist && m_blacklist->matches(inner_offset)) - { - continue; - } - if(!operator()(inner_offset)) - { - return false; - } - } - } - else - { - qCritical() << "Copy ERROR: Unknown filesystem object:" << src; - return false; - } - return true; -} - - -#if defined Q_OS_WIN32 -#include -#include -#endif -bool deletePath(QString path) -{ - bool OK = true; - QDir dir(path); - - if (!dir.exists()) - { - return OK; - } - auto allEntries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | - QDir::AllDirs | QDir::Files, - QDir::DirsFirst); - - for(auto & info: allEntries) - { -#if defined Q_OS_WIN32 - QString nativePath = QDir::toNativeSeparators(info.absoluteFilePath()); - auto wString = nativePath.toStdWString(); - DWORD dwAttrs = GetFileAttributesW(wString.c_str()); - // Windows: check for junctions, reparse points and other nasty things of that sort - if(dwAttrs & FILE_ATTRIBUTE_REPARSE_POINT) - { - if (info.isFile()) - { - OK &= QFile::remove(info.absoluteFilePath()); - } - else if (info.isDir()) - { - OK &= dir.rmdir(info.absoluteFilePath()); - } - } -#else - // We do not trust Qt with reparse points, but do trust it with unix symlinks. - if(info.isSymLink()) - { - OK &= QFile::remove(info.absoluteFilePath()); - } -#endif - else if (info.isDir()) - { - OK &= deletePath(info.absoluteFilePath()); - } - else if (info.isFile()) - { - OK &= QFile::remove(info.absoluteFilePath()); - } - else - { - OK = false; - qCritical() << "Delete ERROR: Unknown filesystem object:" << info.absoluteFilePath(); - } - } - OK &= dir.rmdir(dir.absolutePath()); - return OK; -} - - -QString PathCombine(QString path1, QString path2) -{ - if(!path1.size()) - return path2; - if(!path2.size()) - return path1; - return QDir::cleanPath(path1 + QDir::separator() + path2); -} - -QString PathCombine(QString path1, QString path2, QString path3) -{ - return PathCombine(PathCombine(path1, path2), path3); -} - -QString AbsolutePath(QString path) -{ - return QFileInfo(path).absolutePath(); -} - -QString ResolveExecutable(QString path) -{ - if (path.isEmpty()) - { - return QString(); - } - if(!path.contains('/')) - { - path = QStandardPaths::findExecutable(path); - } - QFileInfo pathInfo(path); - if(!pathInfo.exists() || !pathInfo.isExecutable()) - { - return QString(); - } - return pathInfo.absoluteFilePath(); -} - -/** - * Normalize path - * - * Any paths inside the current directory will be normalized to relative paths (to current) - * Other paths will be made absolute - */ -QString NormalizePath(QString path) -{ - QDir a = QDir::currentPath(); - QString currentAbsolute = a.absolutePath(); - - QDir b(path); - QString newAbsolute = b.absolutePath(); - - if (newAbsolute.startsWith(currentAbsolute)) - { - return a.relativeFilePath(newAbsolute); - } - else - { - return newAbsolute; - } -} - -QString badFilenameChars = "\"\\/?<>:*|!"; - -QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) -{ - for (int i = 0; i < string.length(); i++) - { - if (badFilenameChars.contains(string[i])) - { - string[i] = replaceWith; - } - } - return string; -} - -QString DirNameFromString(QString string, QString inDir) -{ - int num = 0; - QString baseName = RemoveInvalidFilenameChars(string, '-'); - QString dirName; - do - { - if(num == 0) - { - dirName = baseName; - } - else - { - dirName = baseName + QString::number(num);; - } - - // If it's over 9000 - if (num > 9000) - return ""; - num++; - } while (QFileInfo(PathCombine(inDir, dirName)).exists()); - return dirName; -} - -// Does the directory path contain any '!'? If yes, return true, otherwise false. -// (This is a problem for Java) -bool checkProblemticPathJava(QDir folder) -{ - QString pathfoldername = folder.absolutePath(); - return pathfoldername.contains("!", Qt::CaseInsensitive); -} - -#include -#include -#include - -// Win32 crap -#if defined Q_OS_WIN - -#include -#include -#include -#include -#include -#include -#include - -bool called_coinit = false; - -HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args) -{ - HRESULT hres; - - if (!called_coinit) - { - hres = CoInitialize(NULL); - called_coinit = true; - - if (!SUCCEEDED(hres)) - { - qWarning("Failed to initialize COM. Error 0x%08X", hres); - return hres; - } - } - - IShellLink *link; - hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, - (LPVOID *)&link); - - if (SUCCEEDED(hres)) - { - IPersistFile *persistFile; - - link->SetPath(targetPath); - link->SetArguments(args); - - hres = link->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile); - if (SUCCEEDED(hres)) - { - WCHAR wstr[MAX_PATH]; - - MultiByteToWideChar(CP_ACP, 0, linkPath, -1, wstr, MAX_PATH); - - hres = persistFile->Save(wstr, TRUE); - persistFile->Release(); - } - link->Release(); - } - return hres; -} - -#endif - -QString getDesktopDir() -{ - return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); -} - -// Cross-platform Shortcut creation -bool createShortCut(QString location, QString dest, QStringList args, QString name, - QString icon) -{ -#if defined Q_OS_LINUX - location = PathCombine(location, name + ".desktop"); - - QFile f(location); - f.open(QIODevice::WriteOnly | QIODevice::Text); - QTextStream stream(&f); - - QString argstring; - if (!args.empty()) - argstring = " '" + args.join("' '") + "'"; - - stream << "[Desktop Entry]" - << "\n"; - stream << "Type=Application" - << "\n"; - stream << "TryExec=" << dest.toLocal8Bit() << "\n"; - stream << "Exec=" << dest.toLocal8Bit() << argstring.toLocal8Bit() << "\n"; - stream << "Name=" << name.toLocal8Bit() << "\n"; - stream << "Icon=" << icon.toLocal8Bit() << "\n"; - - stream.flush(); - f.close(); - - f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | - QFileDevice::ExeOther); - - return true; -#elif defined Q_OS_WIN - // TODO: Fix - // QFile file(PathCombine(location, name + ".lnk")); - // WCHAR *file_w; - // WCHAR *dest_w; - // WCHAR *args_w; - // file.fileName().toWCharArray(file_w); - // dest.toWCharArray(dest_w); - - // QString argStr; - // for (int i = 0; i < args.count(); i++) - // { - // argStr.append(args[i]); - // argStr.append(" "); - // } - // argStr.toWCharArray(args_w); - - // return SUCCEEDED(CreateLink(file_w, dest_w, args_w)); - return false; -#else - qWarning("Desktop Shortcuts not supported on your platform!"); - return false; -#endif -} -} diff --git a/logic/FileSystem.h b/logic/FileSystem.h deleted file mode 100644 index 80637f90..00000000 --- a/logic/FileSystem.h +++ /dev/null @@ -1,123 +0,0 @@ -// Licensed under the Apache-2.0 license. See README.md for details. - -#pragma once - -#include "Exception.h" -#include "pathmatcher/IPathMatcher.h" - -#include "multimc_logic_export.h" -#include -#include - -namespace FS -{ - -class MULTIMC_LOGIC_EXPORT FileSystemException : public ::Exception -{ -public: - FileSystemException(const QString &message) : Exception(message) {} -}; - -/** - * write data to a file safely - */ -MULTIMC_LOGIC_EXPORT void write(const QString &filename, const QByteArray &data); - -/** - * read data from a file safely\ - */ -MULTIMC_LOGIC_EXPORT QByteArray read(const QString &filename); - -/** - * Creates all the folders in a path for the specified path - * last segment of the path is treated as a file name and is ignored! - */ -MULTIMC_LOGIC_EXPORT bool ensureFilePathExists(QString filenamepath); - -/** - * Creates all the folders in a path for the specified path - * last segment of the path is treated as a folder name and is created! - */ -MULTIMC_LOGIC_EXPORT bool ensureFolderPathExists(QString filenamepath); - -class MULTIMC_LOGIC_EXPORT copy -{ -public: - copy(const copy&) = delete; - copy(const QString & src, const QString & dst) - { - m_src = src; - m_dst = dst; - } - copy & followSymlinks(const bool follow) - { - m_followSymlinks = follow; - return *this; - } - copy & blacklist(const IPathMatcher * filter) - { - m_blacklist = filter; - return *this; - } - bool operator()() - { - return operator()(QString()); - } - -private: - bool operator()(const QString &offset); - -private: - bool m_followSymlinks = true; - const IPathMatcher * m_blacklist = nullptr; - QDir m_src; - QDir m_dst; -}; - -/** - * Delete a folder recursively - */ -MULTIMC_LOGIC_EXPORT bool deletePath(QString path); - -MULTIMC_LOGIC_EXPORT QString PathCombine(QString path1, QString path2); -MULTIMC_LOGIC_EXPORT QString PathCombine(QString path1, QString path2, QString path3); - -MULTIMC_LOGIC_EXPORT QString AbsolutePath(QString path); - -/** - * Resolve an executable - * - * Will resolve: - * single executable (by name) - * relative path - * absolute path - * - * @return absolute path to executable or null string - */ -MULTIMC_LOGIC_EXPORT QString ResolveExecutable(QString path); - -/** - * Normalize path - * - * Any paths inside the current directory will be normalized to relative paths (to current) - * Other paths will be made absolute - * - * Returns false if the path logic somehow filed (and normalizedPath in invalid) - */ -MULTIMC_LOGIC_EXPORT QString NormalizePath(QString path); - -MULTIMC_LOGIC_EXPORT QString RemoveInvalidFilenameChars(QString string, QChar replaceWith = '-'); - -MULTIMC_LOGIC_EXPORT QString DirNameFromString(QString string, QString inDir = "."); - -/// Checks if the a given Path contains "!" -MULTIMC_LOGIC_EXPORT bool checkProblemticPathJava(QDir folder); - -// Get the Directory representing the User's Desktop -MULTIMC_LOGIC_EXPORT QString getDesktopDir(); - -// Create a shortcut at *location*, pointing to *dest* called with the arguments *args* -// call it *name* and assign it the icon *icon* -// return true if operation succeeded -MULTIMC_LOGIC_EXPORT bool createShortCut(QString location, QString dest, QStringList args, QString name, QString iconLocation); -} diff --git a/logic/GZip.cpp b/logic/GZip.cpp deleted file mode 100644 index 38605df6..00000000 --- a/logic/GZip.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "GZip.h" -#include -#include - -bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedBytes) -{ - if (compressedBytes.size() == 0) - { - uncompressedBytes = compressedBytes; - return true; - } - - unsigned uncompLength = compressedBytes.size(); - uncompressedBytes.clear(); - uncompressedBytes.resize(uncompLength); - - z_stream strm; - memset(&strm, 0, sizeof(strm)); - strm.next_in = (Bytef *)compressedBytes.data(); - strm.avail_in = compressedBytes.size(); - - bool done = false; - - if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) - { - return false; - } - - int err = Z_OK; - - while (!done) - { - // If our output buffer is too small - if (strm.total_out >= uncompLength) - { - uncompressedBytes.resize(uncompLength * 2); - uncompLength *= 2; - } - - strm.next_out = (Bytef *)(uncompressedBytes.data() + strm.total_out); - strm.avail_out = uncompLength - strm.total_out; - - // Inflate another chunk. - err = inflate(&strm, Z_SYNC_FLUSH); - if (err == Z_STREAM_END) - done = true; - else if (err != Z_OK) - { - break; - } - } - - if (inflateEnd(&strm) != Z_OK || !done) - { - return false; - } - - uncompressedBytes.resize(strm.total_out); - return true; -} - -bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes) -{ - if (uncompressedBytes.size() == 0) - { - compressedBytes = uncompressedBytes; - return true; - } - - unsigned compLength = std::min(uncompressedBytes.size(), 16); - compressedBytes.clear(); - compressedBytes.resize(compLength); - - z_stream zs; - memset(&zs, 0, sizeof(zs)); - - if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (16 + MAX_WBITS), 8, Z_DEFAULT_STRATEGY) != Z_OK) - { - return false; - } - - zs.next_in = (Bytef*)uncompressedBytes.data(); - zs.avail_in = uncompressedBytes.size(); - - int ret; - compressedBytes.resize(uncompressedBytes.size()); - - unsigned offset = 0; - unsigned temp = 0; - do - { - auto remaining = compressedBytes.size() - offset; - if(remaining < 1) - { - compressedBytes.resize(compressedBytes.size() * 2); - } - zs.next_out = (Bytef *) (compressedBytes.data() + offset); - temp = zs.avail_out = compressedBytes.size() - offset; - ret = deflate(&zs, Z_FINISH); - offset += temp - zs.avail_out; - } while (ret == Z_OK); - - compressedBytes.resize(offset); - - if (deflateEnd(&zs) != Z_OK) - { - return false; - } - - if (ret != Z_STREAM_END) - { - return false; - } - return true; -} \ No newline at end of file diff --git a/logic/GZip.h b/logic/GZip.h deleted file mode 100644 index 6993a222..00000000 --- a/logic/GZip.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -#include "multimc_logic_export.h" - -class MULTIMC_LOGIC_EXPORT GZip -{ -public: - static bool unzip(const QByteArray &compressedBytes, QByteArray &uncompressedBytes); - static bool zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes); -}; - diff --git a/logic/InstanceList.cpp b/logic/InstanceList.cpp deleted file mode 100644 index 741b8611..00000000 --- a/logic/InstanceList.cpp +++ /dev/null @@ -1,582 +0,0 @@ -/* Copyright 2013-2015 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "InstanceList.h" -#include "icons/IconList.h" -#include "BaseInstance.h" - -//FIXME: this really doesn't belong *here* -#include "minecraft/onesix/OneSixInstance.h" -#include "minecraft/legacy/LegacyInstance.h" -#include "minecraft/ftb/FTBPlugin.h" -#include "minecraft/MinecraftVersion.h" -#include "settings/INISettingsObject.h" -#include "NullInstance.h" -#include "FileSystem.h" -#include "pathmatcher/RegexpMatcher.h" - -const static int GROUP_FILE_FORMAT_VERSION = 1; - -InstanceList::InstanceList(SettingsObjectPtr globalSettings, const QString &instDir, QObject *parent) - : QAbstractListModel(parent), m_instDir(instDir) -{ - m_globalSettings = globalSettings; - if (!QDir::current().exists(m_instDir)) - { - QDir::current().mkpath(m_instDir); - } -} - -InstanceList::~InstanceList() -{ -} - -int InstanceList::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return m_instances.count(); -} - -QModelIndex InstanceList::index(int row, int column, const QModelIndex &parent) const -{ - Q_UNUSED(parent); - if (row < 0 || row >= m_instances.size()) - return QModelIndex(); - return createIndex(row, column, (void *)m_instances.at(row).get()); -} - -QVariant InstanceList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - { - return QVariant(); - } - BaseInstance *pdata = static_cast(index.internalPointer()); - switch (role) - { - case InstancePointerRole: - { - QVariant v = qVariantFromValue((void *)pdata); - return v; - } - case InstanceIDRole: - { - return pdata->id(); - } - case Qt::DisplayRole: - { - return pdata->name(); - } - case Qt::ToolTipRole: - { - return pdata->instanceRoot(); - } - case Qt::DecorationRole: - { - QString key = pdata->iconKey(); - return ENV.icons()->getIcon(key); - } - // HACK: see GroupView.h in gui! - case GroupRole: - { - return pdata->group(); - } - default: - break; - } - return QVariant(); -} - -Qt::ItemFlags InstanceList::flags(const QModelIndex &index) const -{ - Qt::ItemFlags f; - if (index.isValid()) - { - f |= (Qt::ItemIsEnabled | Qt::ItemIsSelectable); - } - return f; -} - -void InstanceList::groupChanged() -{ - // save the groups. save all of them. - saveGroupList(); -} - -QStringList InstanceList::getGroups() -{ - return m_groups.toList(); -} - -void InstanceList::suspendGroupSaving() -{ - suspendedGroupSave = true; -} - -void InstanceList::resumeGroupSaving() -{ - if(suspendedGroupSave) - { - suspendedGroupSave = false; - if(queuedGroupSave) - { - saveGroupList(); - } - } -} - -void InstanceList::deleteGroup(const QString& name) -{ - for(auto & instance: m_instances) - { - auto instGroupName = instance->group(); - if(instGroupName == name) - { - instance->setGroupPost(QString()); - } - } -} - -void InstanceList::saveGroupList() -{ - if(suspendedGroupSave) - { - queuedGroupSave = true; - return; - } - - QString groupFileName = m_instDir + "/instgroups.json"; - QMap> groupMap; - for (auto instance : m_instances) - { - QString id = instance->id(); - QString group = instance->group(); - if (group.isEmpty()) - continue; - - // keep a list/set of groups for choosing - m_groups.insert(group); - - if (!groupMap.count(group)) - { - QSet set; - set.insert(id); - groupMap[group] = set; - } - else - { - QSet &set = groupMap[group]; - set.insert(id); - } - } - QJsonObject toplevel; - toplevel.insert("formatVersion", QJsonValue(QString("1"))); - QJsonObject groupsArr; - for (auto iter = groupMap.begin(); iter != groupMap.end(); iter++) - { - auto list = iter.value(); - auto name = iter.key(); - QJsonObject groupObj; - QJsonArray instanceArr; - groupObj.insert("hidden", QJsonValue(QString("false"))); - for (auto item : list) - { - instanceArr.append(QJsonValue(item)); - } - groupObj.insert("instances", instanceArr); - groupsArr.insert(name, groupObj); - } - toplevel.insert("groups", groupsArr); - QJsonDocument doc(toplevel); - try - { - FS::write(groupFileName, doc.toJson()); - } - catch(FS::FileSystemException & e) - { - qCritical() << "Failed to write instance group file :" << e.cause(); - } -} - -void InstanceList::loadGroupList(QMap &groupMap) -{ - QString groupFileName = m_instDir + "/instgroups.json"; - - // if there's no group file, fail - if (!QFileInfo(groupFileName).exists()) - return; - - QByteArray jsonData; - try - { - jsonData = FS::read(groupFileName); - } - catch (FS::FileSystemException & e) - { - qCritical() << "Failed to read instance group file :" << e.cause(); - return; - } - - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &error); - - // if the json was bad, fail - if (error.error != QJsonParseError::NoError) - { - qCritical() << QString("Failed to parse instance group file: %1 at offset %2") - .arg(error.errorString(), QString::number(error.offset)) - .toUtf8(); - return; - } - - // if the root of the json wasn't an object, fail - if (!jsonDoc.isObject()) - { - qWarning() << "Invalid group file. Root entry should be an object."; - return; - } - - QJsonObject rootObj = jsonDoc.object(); - - // Make sure the format version matches, otherwise fail. - if (rootObj.value("formatVersion").toVariant().toInt() != GROUP_FILE_FORMAT_VERSION) - return; - - // Get the groups. if it's not an object, fail - if (!rootObj.value("groups").isObject()) - { - qWarning() << "Invalid group list JSON: 'groups' should be an object."; - return; - } - - // Iterate through all the groups. - QJsonObject groupMapping = rootObj.value("groups").toObject(); - for (QJsonObject::iterator iter = groupMapping.begin(); iter != groupMapping.end(); iter++) - { - QString groupName = iter.key(); - - // 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(); - 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(); - continue; - } - - // keep a list/set of groups for choosing - m_groups.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++) - { - groupMap[(*iter2).toString()] = groupName; - } - } -} - -InstanceList::InstListError InstanceList::loadList() -{ - // load the instance groups - QMap groupMap; - loadGroupList(groupMap); - - QList tempList; - { - QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable, - QDirIterator::FollowSymlinks); - while (iter.hasNext()) - { - QString subDir = iter.next(); - if (!QFileInfo(FS::PathCombine(subDir, "instance.cfg")).exists()) - continue; - qDebug() << "Loading MultiMC instance from " << subDir; - InstancePtr instPtr; - auto error = loadInstance(instPtr, subDir); - if(!continueProcessInstance(instPtr, error, subDir, groupMap)) - continue; - tempList.append(instPtr); - } - } - - // FIXME: generalize - FTBPlugin::loadInstances(m_globalSettings, groupMap, tempList); - - beginResetModel(); - m_instances.clear(); - for(auto inst: tempList) - { - inst->setParent(this); - connect(inst.get(), SIGNAL(propertiesChanged(BaseInstance *)), this, - SLOT(propertiesChanged(BaseInstance *))); - connect(inst.get(), SIGNAL(groupChanged()), this, SLOT(groupChanged())); - connect(inst.get(), SIGNAL(nuked(BaseInstance *)), this, - SLOT(instanceNuked(BaseInstance *))); - m_instances.append(inst); - } - endResetModel(); - emit dataIsInvalid(); - return NoError; -} - -/// Clear all instances. Triggers notifications. -void InstanceList::clear() -{ - beginResetModel(); - saveGroupList(); - m_instances.clear(); - endResetModel(); - emit dataIsInvalid(); -} - -void InstanceList::on_InstFolderChanged(const Setting &setting, QVariant value) -{ - m_instDir = value.toString(); - loadList(); -} - -/// Add an instance. Triggers notifications, returns the new index -int InstanceList::add(InstancePtr t) -{ - beginInsertRows(QModelIndex(), m_instances.size(), m_instances.size()); - m_instances.append(t); - t->setParent(this); - connect(t.get(), SIGNAL(propertiesChanged(BaseInstance *)), this, - SLOT(propertiesChanged(BaseInstance *))); - connect(t.get(), SIGNAL(groupChanged()), this, SLOT(groupChanged())); - connect(t.get(), SIGNAL(nuked(BaseInstance *)), this, SLOT(instanceNuked(BaseInstance *))); - endInsertRows(); - return count() - 1; -} - -InstancePtr InstanceList::getInstanceById(QString instId) const -{ - if(instId.isEmpty()) - return InstancePtr(); - for(auto & inst: m_instances) - { - if (inst->id() == instId) - { - return inst; - } - } - return InstancePtr(); -} - -QModelIndex InstanceList::getInstanceIndexById(const QString &id) const -{ - return index(getInstIndex(getInstanceById(id).get())); -} - -int InstanceList::getInstIndex(BaseInstance *inst) const -{ - int count = m_instances.count(); - for (int i = 0; i < count; i++) - { - if (inst == m_instances[i].get()) - { - return i; - } - } - return -1; -} - -bool InstanceList::continueProcessInstance(InstancePtr instPtr, const int error, - const QDir &dir, QMap &groupMap) -{ - if (error != InstanceList::NoLoadError && error != InstanceList::NotAnInstance) - { - QString errorMsg = QString("Failed to load instance %1: ") - .arg(QFileInfo(dir.absolutePath()).baseName()) - .toUtf8(); - - switch (error) - { - default: - errorMsg += QString("Unknown instance loader error %1").arg(error); - break; - } - qCritical() << errorMsg.toUtf8(); - return false; - } - else if (!instPtr) - { - qCritical() << QString("Error loading instance %1. Instance loader returned null.") - .arg(QFileInfo(dir.absolutePath()).baseName()) - .toUtf8(); - return false; - } - else - { - auto iter = groupMap.find(instPtr->id()); - if (iter != groupMap.end()) - { - instPtr->setGroupInitial((*iter)); - } - qDebug() << "Loaded instance " << instPtr->name() << " from " << dir.absolutePath(); - return true; - } -} - -InstanceList::InstLoadError -InstanceList::loadInstance(InstancePtr &inst, const QString &instDir) -{ - auto instanceSettings = std::make_shared(FS::PathCombine(instDir, "instance.cfg")); - - instanceSettings->registerSetting("InstanceType", "Legacy"); - - QString inst_type = instanceSettings->get("InstanceType").toString(); - - // FIXME: replace with a map lookup, where instance classes register their types - if (inst_type == "OneSix" || inst_type == "Nostalgia") - { - inst.reset(new OneSixInstance(m_globalSettings, instanceSettings, instDir)); - } - else if (inst_type == "Legacy") - { - inst.reset(new LegacyInstance(m_globalSettings, instanceSettings, instDir)); - } - else - { - inst.reset(new NullInstance(m_globalSettings, instanceSettings, instDir)); - } - inst->init(); - return NoLoadError; -} - -InstanceList::InstCreateError -InstanceList::createInstance(InstancePtr &inst, BaseVersionPtr version, const QString &instDir) -{ - QDir rootDir(instDir); - - qDebug() << instDir.toUtf8(); - if (!rootDir.exists() && !rootDir.mkpath(".")) - { - qCritical() << "Can't create instance folder" << instDir; - return InstanceList::CantCreateDir; - } - - if (!version) - { - qCritical() << "Can't create instance for non-existing MC version"; - return InstanceList::NoSuchVersion; - } - - auto instanceSettings = std::make_shared(FS::PathCombine(instDir, "instance.cfg")); - instanceSettings->registerSetting("InstanceType", "Legacy"); - - auto minecraftVersion = std::dynamic_pointer_cast(version); - if(minecraftVersion) - { - auto mcVer = std::dynamic_pointer_cast(version); - instanceSettings->set("InstanceType", "OneSix"); - inst.reset(new OneSixInstance(m_globalSettings, instanceSettings, instDir)); - inst->setIntendedVersionId(version->descriptor()); - inst->init(); - return InstanceList::NoCreateError; - } - return InstanceList::NoSuchVersion; -} - -InstanceList::InstCreateError -InstanceList::copyInstance(InstancePtr &newInstance, InstancePtr &oldInstance, const QString &instDir, bool copySaves) -{ - QDir rootDir(instDir); - std::unique_ptr matcher; - if(!copySaves) - { - auto matcherReal = new RegexpMatcher("[.]?minecraft/saves"); - matcherReal->caseSensitive(false); - matcher.reset(matcherReal); - } - - qDebug() << instDir.toUtf8(); - FS::copy folderCopy(oldInstance->instanceRoot(), instDir); - folderCopy.followSymlinks(false).blacklist(matcher.get()); - if (!folderCopy()) - { - FS::deletePath(instDir); - return InstanceList::CantCreateDir; - } - - INISettingsObject settings_obj(FS::PathCombine(instDir, "instance.cfg")); - settings_obj.registerSetting("InstanceType", "Legacy"); - QString inst_type = settings_obj.get("InstanceType").toString(); - - oldInstance->copy(instDir); - - auto error = loadInstance(newInstance, instDir); - - switch (error) - { - case NoLoadError: - return NoCreateError; - case NotAnInstance: - rootDir.removeRecursively(); - return CantCreateDir; - default: - case UnknownLoadError: - rootDir.removeRecursively(); - return UnknownCreateError; - } -} - -void InstanceList::instanceNuked(BaseInstance *inst) -{ - int i = getInstIndex(inst); - if (i != -1) - { - beginRemoveRows(QModelIndex(), i, i); - m_instances.removeAt(i); - endRemoveRows(); - } -} - -void InstanceList::propertiesChanged(BaseInstance *inst) -{ - int i = getInstIndex(inst); - if (i != -1) - { - emit dataChanged(index(i), index(i)); - } -} diff --git a/logic/InstanceList.h b/logic/InstanceList.h deleted file mode 100644 index 074cca7c..00000000 --- a/logic/InstanceList.h +++ /dev/null @@ -1,187 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "BaseInstance.h" - -#include "multimc_logic_export.h" - -class BaseInstance; -class QDir; - -class MULTIMC_LOGIC_EXPORT InstanceList : public QAbstractListModel -{ - Q_OBJECT -private: - void loadGroupList(QMap &groupList); - void suspendGroupSaving(); - void resumeGroupSaving(); - -public slots: - void saveGroupList(); - -public: - explicit InstanceList(SettingsObjectPtr globalSettings, const QString &instDir, QObject *parent = 0); - virtual ~InstanceList(); - -public: - QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role) const; - Qt::ItemFlags flags(const QModelIndex &index) const; - - enum AdditionalRoles - { - GroupRole = Qt::UserRole, - InstancePointerRole = 0x34B1CB48, ///< Return pointer to real instance - InstanceIDRole = 0x34B1CB49 ///< Return id if the instance - }; - /*! - * \brief Error codes returned by functions in the InstanceList class. - * NoError Indicates that no error occurred. - * UnknownError indicates that an unspecified error occurred. - */ - enum InstListError - { - NoError = 0, - UnknownError - }; - - enum InstLoadError - { - NoLoadError = 0, - UnknownLoadError, - NotAnInstance - }; - - enum InstCreateError - { - NoCreateError = 0, - NoSuchVersion, - UnknownCreateError, - InstExists, - CantCreateDir - }; - - QString instDir() const - { - return m_instDir; - } - - /*! - * \brief Get the instance at index - */ - InstancePtr at(int i) const - { - return m_instances.at(i); - } - ; - - /*! - * \brief Get the count of loaded instances - */ - int count() const - { - return m_instances.count(); - } - ; - - /// Clear all instances. Triggers notifications. - void clear(); - - /// Add an instance. Triggers notifications, returns the new index - int add(InstancePtr t); - - /// Get an instance by ID - InstancePtr getInstanceById(QString id) const; - - QModelIndex getInstanceIndexById(const QString &id) const; - - // FIXME: instead of iterating through all instances and forming a set, keep the set around - QStringList getGroups(); - - void deleteGroup(const QString & name); - - /*! - * \brief Creates a stub instance - * - * \param inst Pointer to store the created instance in. - * \param version Game version to use for the instance - * \param instDir The new instance's directory. - * \return An InstCreateError error code. - * - InstExists if the given instance directory is already an instance. - * - CantCreateDir if the given instance directory cannot be created. - */ - InstCreateError createInstance(InstancePtr &inst, BaseVersionPtr version, - const QString &instDir); - - /*! - * \brief Creates a copy of an existing instance with a new name - * - * \param newInstance Pointer to store the created instance in. - * \param oldInstance The instance to copy - * \param instDir The new instance's directory. - * \return An InstCreateError error code. - * - InstExists if the given instance directory is already an instance. - * - CantCreateDir if the given instance directory cannot be created. - */ - InstCreateError copyInstance(InstancePtr &newInstance, InstancePtr &oldInstance, - const QString &instDir, bool copySaves); - - /*! - * \brief Loads an instance from the given directory. - * Checks the instance's INI file to figure out what the instance's type is first. - * \param inst Pointer to store the loaded instance in. - * \param instDir The instance's directory. - * \return An InstLoadError error code. - * - NotAnInstance if the given instance directory isn't a valid instance. - */ - InstLoadError loadInstance(InstancePtr &inst, const QString &instDir); - -signals: - void dataIsInvalid(); - -public slots: - void on_InstFolderChanged(const Setting &setting, QVariant value); - - /*! - * \brief Loads the instance list. Triggers notifications. - */ - InstListError loadList(); - -private slots: - void propertiesChanged(BaseInstance *inst); - void instanceNuked(BaseInstance *inst); - void groupChanged(); - -private: - int getInstIndex(BaseInstance *inst) const; - -public: - static bool continueProcessInstance(InstancePtr instPtr, const int error, const QDir &dir, QMap &groupMap); - -protected: - QString m_instDir; - QList m_instances; - QSet m_groups; - SettingsObjectPtr m_globalSettings; - bool suspendedGroupSave = false; - bool queuedGroupSave = false; -}; diff --git a/logic/Json.cpp b/logic/Json.cpp deleted file mode 100644 index f2cbc8a3..00000000 --- a/logic/Json.cpp +++ /dev/null @@ -1,272 +0,0 @@ -// Licensed under the Apache-2.0 license. See README.md for details. - -#include "Json.h" - -#include - -#include "FileSystem.h" -#include - -namespace Json -{ -void write(const QJsonDocument &doc, const QString &filename) -{ - FS::write(filename, doc.toJson()); -} -void write(const QJsonObject &object, const QString &filename) -{ - write(QJsonDocument(object), filename); -} -void write(const QJsonArray &array, const QString &filename) -{ - write(QJsonDocument(array), filename); -} - -QByteArray toBinary(const QJsonObject &obj) -{ - return QJsonDocument(obj).toBinaryData(); -} -QByteArray toBinary(const QJsonArray &array) -{ - return QJsonDocument(array).toBinaryData(); -} -QByteArray toText(const QJsonObject &obj) -{ - return QJsonDocument(obj).toJson(QJsonDocument::Compact); -} -QByteArray toText(const QJsonArray &array) -{ - return QJsonDocument(array).toJson(QJsonDocument::Compact); -} - -static bool isBinaryJson(const QByteArray &data) -{ - decltype(QJsonDocument::BinaryFormatTag) tag = QJsonDocument::BinaryFormatTag; - return memcmp(data.constData(), &tag, sizeof(QJsonDocument::BinaryFormatTag)) == 0; -} -QJsonDocument requireDocument(const QByteArray &data, const QString &what) -{ - if (isBinaryJson(data)) - { - QJsonDocument doc = QJsonDocument::fromBinaryData(data); - if (doc.isNull()) - { - throw JsonException(what + ": Invalid JSON (binary JSON detected)"); - } - return doc; - } - else - { - QJsonParseError error; - QJsonDocument doc = QJsonDocument::fromJson(data, &error); - if (error.error != QJsonParseError::NoError) - { - throw JsonException(what + ": Error parsing JSON: " + error.errorString()); - } - return doc; - } -} -QJsonDocument requireDocument(const QString &filename, const QString &what) -{ - return requireDocument(FS::read(filename), what); -} -QJsonObject requireObject(const QJsonDocument &doc, const QString &what) -{ - if (!doc.isObject()) - { - throw JsonException(what + " is not an object"); - } - return doc.object(); -} -QJsonArray requireArray(const QJsonDocument &doc, const QString &what) -{ - if (!doc.isArray()) - { - throw JsonException(what + " is not an array"); - } - return doc.array(); -} - -void writeString(QJsonObject &to, const QString &key, const QString &value) -{ - if (!value.isEmpty()) - { - to.insert(key, value); - } -} - -void writeStringList(QJsonObject &to, const QString &key, const QStringList &values) -{ - if (!values.isEmpty()) - { - QJsonArray array; - for(auto value: values) - { - array.append(value); - } - to.insert(key, array); - } -} - -template<> -QJsonValue toJson(const QUrl &url) -{ - return QJsonValue(url.toString(QUrl::FullyEncoded)); -} -template<> -QJsonValue toJson(const QByteArray &data) -{ - return QJsonValue(QString::fromLatin1(data.toHex())); -} -template<> -QJsonValue toJson(const QDateTime &datetime) -{ - return QJsonValue(datetime.toString(Qt::ISODate)); -} -template<> -QJsonValue toJson(const QDir &dir) -{ - return QDir::current().relativeFilePath(dir.absolutePath()); -} -template<> -QJsonValue toJson(const QUuid &uuid) -{ - return uuid.toString(); -} -template<> -QJsonValue toJson(const QVariant &variant) -{ - return QJsonValue::fromVariant(variant); -} - - -template<> QByteArray requireIsType(const QJsonValue &value, const QString &what) -{ - const QString string = ensureIsType(value, what); - // ensure that the string can be safely cast to Latin1 - if (string != QString::fromLatin1(string.toLatin1())) - { - throw JsonException(what + " is not encodable as Latin1"); - } - return QByteArray::fromHex(string.toLatin1()); -} - -template<> QJsonArray requireIsType(const QJsonValue &value, const QString &what) -{ - if (!value.isArray()) - { - throw JsonException(what + " is not an array"); - } - return value.toArray(); -} - - -template<> QString requireIsType(const QJsonValue &value, const QString &what) -{ - if (!value.isString()) - { - throw JsonException(what + " is not a string"); - } - return value.toString(); -} - -template<> bool requireIsType(const QJsonValue &value, const QString &what) -{ - if (!value.isBool()) - { - throw JsonException(what + " is not a bool"); - } - return value.toBool(); -} - -template<> double requireIsType(const QJsonValue &value, const QString &what) -{ - if (!value.isDouble()) - { - throw JsonException(what + " is not a double"); - } - return value.toDouble(); -} - -template<> int requireIsType(const QJsonValue &value, const QString &what) -{ - const double doubl = requireIsType(value, what); - if (fmod(doubl, 1) != 0) - { - throw JsonException(what + " is not an integer"); - } - return int(doubl); -} - -template<> QDateTime requireIsType(const QJsonValue &value, const QString &what) -{ - const QString string = requireIsType(value, what); - const QDateTime datetime = QDateTime::fromString(string, Qt::ISODate); - if (!datetime.isValid()) - { - throw JsonException(what + " is not a ISO formatted date/time value"); - } - return datetime; -} - -template<> QUrl requireIsType(const QJsonValue &value, const QString &what) -{ - const QString string = ensureIsType(value, what); - if (string.isEmpty()) - { - return QUrl(); - } - const QUrl url = QUrl(string, QUrl::StrictMode); - if (!url.isValid()) - { - throw JsonException(what + " is not a correctly formatted URL"); - } - return url; -} - -template<> QDir requireIsType(const QJsonValue &value, const QString &what) -{ - const QString string = requireIsType(value, what); - // FIXME: does not handle invalid characters! - return QDir::current().absoluteFilePath(string); -} - -template<> QUuid requireIsType(const QJsonValue &value, const QString &what) -{ - const QString string = requireIsType(value, what); - const QUuid uuid = QUuid(string); - if (uuid.toString() != string) // converts back => valid - { - throw JsonException(what + " is not a valid UUID"); - } - return uuid; -} - -template<> QJsonObject requireIsType(const QJsonValue &value, const QString &what) -{ - if (!value.isObject()) - { - throw JsonException(what + " is not an object"); - } - return value.toObject(); -} - -template<> QVariant requireIsType(const QJsonValue &value, const QString &what) -{ - if (value.isNull() || value.isUndefined()) - { - throw JsonException(what + " is null or undefined"); - } - return value.toVariant(); -} - -template<> QJsonValue requireIsType(const QJsonValue &value, const QString &what) -{ - if (value.isNull() || value.isUndefined()) - { - throw JsonException(what + " is null or undefined"); - } - return value; -} - -} diff --git a/logic/Json.h b/logic/Json.h deleted file mode 100644 index 2cb60f0e..00000000 --- a/logic/Json.h +++ /dev/null @@ -1,249 +0,0 @@ -// Licensed under the Apache-2.0 license. See README.md for details. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Exception.h" - -namespace Json -{ -class MULTIMC_LOGIC_EXPORT JsonException : public ::Exception -{ -public: - JsonException(const QString &message) : Exception(message) {} -}; - -/// @throw FileSystemException -void write(const QJsonDocument &doc, const QString &filename); -/// @throw FileSystemException -void write(const QJsonObject &object, const QString &filename); -/// @throw FileSystemException -void write(const QJsonArray &array, const QString &filename); - -QByteArray toBinary(const QJsonObject &obj); -QByteArray toBinary(const QJsonArray &array); -QByteArray toText(const QJsonObject &obj); -QByteArray toText(const QJsonArray &array); - -/// @throw JsonException -MULTIMC_LOGIC_EXPORT QJsonDocument requireDocument(const QByteArray &data, const QString &what = "Document"); -/// @throw JsonException -MULTIMC_LOGIC_EXPORT QJsonDocument requireDocument(const QString &filename, const QString &what = "Document"); -/// @throw JsonException -MULTIMC_LOGIC_EXPORT QJsonObject requireObject(const QJsonDocument &doc, const QString &what = "Document"); -/// @throw JsonException -MULTIMC_LOGIC_EXPORT QJsonArray requireArray(const QJsonDocument &doc, const QString &what = "Document"); - -/////////////////// WRITING //////////////////// - -void writeString(QJsonObject & to, const QString &key, const QString &value); -void writeStringList(QJsonObject & to, const QString &key, const QStringList &values); - -template -QJsonValue toJson(const T &t) -{ - return QJsonValue(t); -} -template<> -QJsonValue toJson(const QUrl &url); -template<> -QJsonValue toJson(const QByteArray &data); -template<> -QJsonValue toJson(const QDateTime &datetime); -template<> -QJsonValue toJson(const QDir &dir); -template<> -QJsonValue toJson(const QUuid &uuid); -template<> -QJsonValue toJson(const QVariant &variant); - -template -QJsonArray toJsonArray(const QList &container) -{ - QJsonArray array; - for (const T item : container) - { - array.append(toJson(item)); - } - return array; -} - -////////////////// READING //////////////////// - -/// @throw JsonException -template -T requireIsType(const QJsonValue &value, const QString &what = "Value"); - -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT double requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT bool requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT int requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QJsonObject requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QJsonArray requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QJsonValue requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QByteArray requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QDateTime requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QVariant requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QString requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QUuid requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QDir requireIsType(const QJsonValue &value, const QString &what); -/// @throw JsonException -template<> MULTIMC_LOGIC_EXPORT QUrl requireIsType(const QJsonValue &value, const QString &what); - -// the following functions are higher level functions, that make use of the above functions for -// type conversion -template -T ensureIsType(const QJsonValue &value, const T default_ = T(), const QString &what = "Value") -{ - if (value.isUndefined() || value.isNull()) - { - return default_; - } - try - { - return requireIsType(value, what); - } - catch (JsonException &) - { - return default_; - } -} - -/// @throw JsonException -template -T requireIsType(const QJsonObject &parent, const QString &key, const QString &what = "__placeholder__") -{ - const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); - if (!parent.contains(key)) - { - throw JsonException(localWhat + "s parent does not contain " + localWhat); - } - return requireIsType(parent.value(key), localWhat); -} - -template -T ensureIsType(const QJsonObject &parent, const QString &key, const T default_ = T(), const QString &what = "__placeholder__") -{ - const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); - if (!parent.contains(key)) - { - return default_; - } - return ensureIsType(parent.value(key), default_, localWhat); -} - -template -QVector requireIsArrayOf(const QJsonDocument &doc) -{ - const QJsonArray array = requireArray(doc); - QVector out; - for (const QJsonValue val : array) - { - out.append(requireIsType(val, "Document")); - } - return out; -} - -template -QVector ensureIsArrayOf(const QJsonValue &value, const QString &what = "Value") -{ - const QJsonArray array = ensureIsType(value, QJsonArray(), what); - QVector out; - for (const QJsonValue val : array) - { - out.append(requireIsType(val, what)); - } - return out; -} - -template -QVector ensureIsArrayOf(const QJsonValue &value, const QVector default_, const QString &what = "Value") -{ - if (value.isUndefined()) - { - return default_; - } - return ensureIsArrayOf(value, what); -} - -/// @throw JsonException -template -QVector requireIsArrayOf(const QJsonObject &parent, const QString &key, const QString &what = "__placeholder__") -{ - const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); - if (!parent.contains(key)) - { - throw JsonException(localWhat + "s parent does not contain " + localWhat); - } - return ensureIsArrayOf(parent.value(key), localWhat); -} - -template -QVector ensureIsArrayOf(const QJsonObject &parent, const QString &key, - const QVector &default_ = QVector(), const QString &what = "__placeholder__") -{ - const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); - if (!parent.contains(key)) - { - return default_; - } - return ensureIsArrayOf(parent.value(key), default_, localWhat); -} - -// this macro part could be replaced by variadic functions that just pass on their arguments, but that wouldn't work well with IDE helpers -#define JSON_HELPERFUNCTIONS(NAME, TYPE) \ - inline TYPE require##NAME(const QJsonValue &value, const QString &what = "Value") \ - { \ - return requireIsType(value, what); \ - } \ - inline TYPE ensure##NAME(const QJsonValue &value, const TYPE default_ = TYPE(), const QString &what = "Value") \ - { \ - return ensureIsType(value, default_, what); \ - } \ - inline TYPE require##NAME(const QJsonObject &parent, const QString &key, const QString &what = "__placeholder__") \ - { \ - return requireIsType(parent, key, what); \ - } \ - inline TYPE ensure##NAME(const QJsonObject &parent, const QString &key, const TYPE default_ = TYPE(), const QString &what = "__placeholder") \ - { \ - return ensureIsType(parent, key, default_, what); \ - } - -JSON_HELPERFUNCTIONS(Array, QJsonArray) -JSON_HELPERFUNCTIONS(Object, QJsonObject) -JSON_HELPERFUNCTIONS(JsonValue, QJsonValue) -JSON_HELPERFUNCTIONS(String, QString) -JSON_HELPERFUNCTIONS(Boolean, bool) -JSON_HELPERFUNCTIONS(Double, double) -JSON_HELPERFUNCTIONS(Integer, int) -JSON_HELPERFUNCTIONS(DateTime, QDateTime) -JSON_HELPERFUNCTIONS(Url, QUrl) -JSON_HELPERFUNCTIONS(ByteArray, QByteArray) -JSON_HELPERFUNCTIONS(Dir, QDir) -JSON_HELPERFUNCTIONS(Uuid, QUuid) -JSON_HELPERFUNCTIONS(Variant, QVariant) - -#undef JSON_HELPERFUNCTIONS - -} -using JSONValidationError = Json::JsonException; diff --git a/logic/MMCStrings.cpp b/logic/MMCStrings.cpp deleted file mode 100644 index c50d596e..00000000 --- a/logic/MMCStrings.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "MMCStrings.h" - -/// TAKEN FROM Qt, because it doesn't expose it intelligently -static inline QChar getNextChar(const QString &s, int location) -{ - return (location < s.length()) ? s.at(location) : QChar(); -} - -/// TAKEN FROM Qt, because it doesn't expose it intelligently -int Strings::naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs) -{ - for (int l1 = 0, l2 = 0; l1 <= s1.count() && l2 <= s2.count(); ++l1, ++l2) - { - // skip spaces, tabs and 0's - QChar c1 = getNextChar(s1, l1); - while (c1.isSpace()) - c1 = getNextChar(s1, ++l1); - QChar c2 = getNextChar(s2, l2); - while (c2.isSpace()) - c2 = getNextChar(s2, ++l2); - - if (c1.isDigit() && c2.isDigit()) - { - while (c1.digitValue() == 0) - c1 = getNextChar(s1, ++l1); - while (c2.digitValue() == 0) - c2 = getNextChar(s2, ++l2); - - int lookAheadLocation1 = l1; - int lookAheadLocation2 = l2; - int currentReturnValue = 0; - // find the last digit, setting currentReturnValue as we go if it isn't equal - for (QChar lookAhead1 = c1, lookAhead2 = c2; - (lookAheadLocation1 <= s1.length() && lookAheadLocation2 <= s2.length()); - lookAhead1 = getNextChar(s1, ++lookAheadLocation1), - lookAhead2 = getNextChar(s2, ++lookAheadLocation2)) - { - bool is1ADigit = !lookAhead1.isNull() && lookAhead1.isDigit(); - bool is2ADigit = !lookAhead2.isNull() && lookAhead2.isDigit(); - if (!is1ADigit && !is2ADigit) - break; - if (!is1ADigit) - return -1; - if (!is2ADigit) - return 1; - if (currentReturnValue == 0) - { - if (lookAhead1 < lookAhead2) - { - currentReturnValue = -1; - } - else if (lookAhead1 > lookAhead2) - { - currentReturnValue = 1; - } - } - } - if (currentReturnValue != 0) - return currentReturnValue; - } - if (cs == Qt::CaseInsensitive) - { - if (!c1.isLower()) - c1 = c1.toLower(); - if (!c2.isLower()) - c2 = c2.toLower(); - } - int r = QString::localeAwareCompare(c1, c2); - if (r < 0) - return -1; - if (r > 0) - return 1; - } - // The two strings are the same (02 == 2) so fall back to the normal sort - return QString::compare(s1, s2, cs); -} diff --git a/logic/MMCStrings.h b/logic/MMCStrings.h deleted file mode 100644 index 5606b909..00000000 --- a/logic/MMCStrings.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -#include "multimc_logic_export.h" - -namespace Strings -{ - int MULTIMC_LOGIC_EXPORT naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs); -} diff --git a/logic/MMCZip.cpp b/logic/MMCZip.cpp deleted file mode 100644 index 0f35bc70..00000000 --- a/logic/MMCZip.cpp +++ /dev/null @@ -1,491 +0,0 @@ -/* -Copyright (C) 2010 Roberto Pompermaier -Copyright (C) 2005-2014 Sergey A. Tachenov - -Parts of this file were part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)MMCZip.h files for details. Basically it's the zlib license. -*/ - -#include -#include -#include -#include "MMCZip.h" -#include "FileSystem.h" - -#include - -bool copyData(QIODevice &inFile, QIODevice &outFile) -{ - while (!inFile.atEnd()) - { - char buf[4096]; - qint64 readLen = inFile.read(buf, 4096); - if (readLen <= 0) - return false; - if (outFile.write(buf, readLen) != readLen) - return false; - } - return true; -} - -QStringList MMCZip::extractDir(QString fileCompressed, QString dir) -{ - return JlCompress::extractDir(fileCompressed, dir); -} - -bool compressFile(QuaZip *zip, QString fileName, QString fileDest) -{ - if (!zip) - { - return false; - } - if (zip->getMode() != QuaZip::mdCreate && zip->getMode() != QuaZip::mdAppend && - zip->getMode() != QuaZip::mdAdd) - { - return false; - } - - QFile inFile; - inFile.setFileName(fileName); - if (!inFile.open(QIODevice::ReadOnly)) - { - return false; - } - - QuaZipFile outFile(zip); - if (!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) - { - return false; - } - - if (!copyData(inFile, outFile) || outFile.getZipError() != UNZ_OK) - { - return false; - } - - outFile.close(); - if (outFile.getZipError() != UNZ_OK) - { - return false; - } - inFile.close(); - - return true; -} - -bool MMCZip::compressSubDir(QuaZip* zip, QString dir, QString origDir, QSet& added, QString prefix, const SeparatorPrefixTree <'/'> * blacklist) -{ - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdCreate && zip->getMode()!=QuaZip::mdAppend && zip->getMode()!=QuaZip::mdAdd) - { - return false; - } - - QDir directory(dir); - if (!directory.exists()) - { - return false; - } - - QDir origDirectory(origDir); - if (dir != origDir) - { - QString internalDirName = origDirectory.relativeFilePath(dir); - if(!blacklist || !blacklist->covers(internalDirName)) - { - QuaZipFile dirZipFile(zip); - auto dirPrefix = FS::PathCombine(prefix, origDirectory.relativeFilePath(dir)) + "/"; - if (!dirZipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(dirPrefix, dir), 0, 0, 0)) - { - return false; - } - dirZipFile.close(); - } - } - - QFileInfoList files = directory.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden); - for (auto file: files) - { - if(!file.isDir()) - { - continue; - } - if(!compressSubDir(zip,file.absoluteFilePath(),origDir, added, prefix, blacklist)) - { - return false; - } - } - - files = directory.entryInfoList(QDir::Files); - for (auto file: files) - { - if(!file.isFile()) - { - continue; - } - - if(file.absoluteFilePath()==zip->getZipName()) - { - continue; - } - - QString filename = origDirectory.relativeFilePath(file.absoluteFilePath()); - if(blacklist && blacklist->covers(filename)) - { - continue; - } - if(prefix.size()) - { - filename = FS::PathCombine(prefix, filename); - } - added.insert(filename); - if (!compressFile(zip,file.absoluteFilePath(),filename)) - { - return false; - } - } - - return true; -} - -bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet &contained, - std::function filter) -{ - QuaZip modZip(from.filePath()); - modZip.open(QuaZip::mdUnzip); - - QuaZipFile fileInsideMod(&modZip); - QuaZipFile zipOutFile(into); - for (bool more = modZip.goToFirstFile(); more; more = modZip.goToNextFile()) - { - QString filename = modZip.getCurrentFileName(); - if (!filter(filename)) - { - qDebug() << "Skipping file " << filename << " from " - << from.fileName() << " - filtered"; - continue; - } - if (contained.contains(filename)) - { - qDebug() << "Skipping already contained file " << filename << " from " - << from.fileName(); - continue; - } - contained.insert(filename); - - if (!fileInsideMod.open(QIODevice::ReadOnly)) - { - qCritical() << "Failed to open " << filename << " from " << from.fileName(); - return false; - } - - QuaZipNewInfo info_out(fileInsideMod.getActualFileName()); - - if (!zipOutFile.open(QIODevice::WriteOnly, info_out)) - { - qCritical() << "Failed to open " << filename << " in the jar"; - fileInsideMod.close(); - return false; - } - if (!copyData(fileInsideMod, zipOutFile)) - { - zipOutFile.close(); - fileInsideMod.close(); - qCritical() << "Failed to copy data of " << filename << " into the jar"; - return false; - } - zipOutFile.close(); - fileInsideMod.close(); - } - return true; -} - -bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods) -{ - QuaZip zipOut(targetJarPath); - if (!zipOut.open(QuaZip::mdCreate)) - { - QFile::remove(targetJarPath); - qCritical() << "Failed to open the minecraft.jar for modding"; - return false; - } - // Files already added to the jar. - // These files will be skipped. - QSet addedFiles; - - // Modify the jar - QListIterator i(mods); - i.toBack(); - while (i.hasPrevious()) - { - const Mod &mod = i.previous(); - // do not merge disabled mods. - if (!mod.enabled()) - continue; - if (mod.type() == Mod::MOD_ZIPFILE) - { - if (!mergeZipFiles(&zipOut, mod.filename(), addedFiles, noFilter)) - { - zipOut.close(); - QFile::remove(targetJarPath); - qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar."; - return false; - } - } - else if (mod.type() == Mod::MOD_SINGLEFILE) - { - auto filename = mod.filename(); - if (!compressFile(&zipOut, filename.absoluteFilePath(), - filename.fileName())) - { - zipOut.close(); - QFile::remove(targetJarPath); - qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar."; - return false; - } - addedFiles.insert(filename.fileName()); - } - else if (mod.type() == Mod::MOD_FOLDER) - { - auto filename = mod.filename(); - QString what_to_zip = filename.absoluteFilePath(); - QDir dir(what_to_zip); - dir.cdUp(); - QString parent_dir = dir.absolutePath(); - if (!compressSubDir(&zipOut, what_to_zip, parent_dir, addedFiles)) - { - zipOut.close(); - QFile::remove(targetJarPath); - qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar."; - return false; - } - qDebug() << "Adding folder " << filename.fileName() << " from " - << filename.absoluteFilePath(); - } - } - - if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, metaInfFilter)) - { - zipOut.close(); - QFile::remove(targetJarPath); - qCritical() << "Failed to insert minecraft.jar contents."; - return false; - } - - // Recompress the jar - zipOut.close(); - if (zipOut.getZipError() != 0) - { - QFile::remove(targetJarPath); - qCritical() << "Failed to finalize minecraft.jar!"; - return false; - } - return true; -} - -bool MMCZip::noFilter(QString) -{ - return true; -} - -bool MMCZip::metaInfFilter(QString key) -{ - if(key.contains("META-INF")) - { - return false; - } - return true; -} - -bool MMCZip::compressDir(QString zipFile, QString dir, QString prefix, const SeparatorPrefixTree <'/'> * blacklist) -{ - QuaZip zip(zipFile); - QDir().mkpath(QFileInfo(zipFile).absolutePath()); - if(!zip.open(QuaZip::mdCreate)) - { - QFile::remove(zipFile); - return false; - } - - QSet added; - if (!compressSubDir(&zip, dir, dir, added, prefix, blacklist)) - { - QFile::remove(zipFile); - return false; - } - zip.close(); - if(zip.getZipError()!=0) - { - QFile::remove(zipFile); - return false; - } - return true; -} - -QString MMCZip::findFileInZip(QuaZip * zip, const QString & what, const QString &root) -{ - QuaZipDir rootDir(zip, root); - for(auto fileName: rootDir.entryList(QDir::Files)) - { - if(fileName == what) - return root; - } - for(auto fileName: rootDir.entryList(QDir::Dirs)) - { - QString result = findFileInZip(zip, what, root + fileName); - if(!result.isEmpty()) - { - return result; - } - } - return QString(); -} - -bool MMCZip::findFilesInZip(QuaZip * zip, const QString & what, QStringList & result, const QString &root) -{ - QuaZipDir rootDir(zip, root); - for(auto fileName: rootDir.entryList(QDir::Files)) - { - if(fileName == what) - { - result.append(root); - return true; - } - } - for(auto fileName: rootDir.entryList(QDir::Dirs)) - { - findFilesInZip(zip, what, result, root + fileName); - } - return !result.isEmpty(); -} - -bool removeFile(QStringList listFile) -{ - bool ret = true; - for (int i = 0; i < listFile.count(); i++) - { - ret &= QFile::remove(listFile.at(i)); - } - return ret; -} - -bool MMCZip::extractFile(QuaZip *zip, const QString &fileName, const QString &fileDest) -{ - if(!zip) - return false; - - if (zip->getMode() != QuaZip::mdUnzip) - return false; - - if (!fileName.isEmpty()) - zip->setCurrentFile(fileName); - - QuaZipFile inFile(zip); - if (!inFile.open(QIODevice::ReadOnly) || inFile.getZipError() != UNZ_OK) - return false; - - // Controllo esistenza cartella file risultato - QDir curDir; - if (fileDest.endsWith('/')) - { - if (!curDir.mkpath(fileDest)) - { - return false; - } - } - else - { - if (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) - { - return false; - } - } - - QuaZipFileInfo64 info; - if (!zip->getCurrentFileInfo(&info)) - return false; - - QFile::Permissions srcPerm = info.getPermissions(); - if (fileDest.endsWith('/') && QFileInfo(fileDest).isDir()) - { - if (srcPerm != 0) - { - QFile(fileDest).setPermissions(srcPerm); - } - return true; - } - - QFile outFile; - outFile.setFileName(fileDest); - if (!outFile.open(QIODevice::WriteOnly)) - return false; - - if (!copyData(inFile, outFile) || inFile.getZipError() != UNZ_OK) - { - outFile.close(); - removeFile(QStringList(fileDest)); - return false; - } - outFile.close(); - - inFile.close(); - if (inFile.getZipError() != UNZ_OK) - { - removeFile(QStringList(fileDest)); - return false; - } - - if (srcPerm != 0) - { - outFile.setPermissions(srcPerm); - } - return true; -} - -QStringList MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target) -{ - QDir directory(target); - QStringList extracted; - if (!zip->goToFirstFile()) - { - return QStringList(); - } - do - { - QString name = zip->getCurrentFileName(); - if(!name.startsWith(subdir)) - { - continue; - } - name.remove(0, subdir.size()); - QString absFilePath = directory.absoluteFilePath(name); - if(name.isEmpty()) - { - absFilePath += "/"; - } - if (!extractFile(zip, "", absFilePath)) - { - removeFile(extracted); - return QStringList(); - } - extracted.append(absFilePath); - } while (zip->goToNextFile()); - return extracted; -} diff --git a/logic/MMCZip.h b/logic/MMCZip.h deleted file mode 100644 index f350e668..00000000 --- a/logic/MMCZip.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include -#include -#include -#include "minecraft/Mod.h" -#include "SeparatorPrefixTree.h" -#include - -#include "multimc_logic_export.h" - -class QuaZip; - -namespace MMCZip -{ - /** - * Compress a subdirectory. - * \param parentZip Opened zip containing the parent directory. - * \param dir The full path to the directory to pack. - * \param parentDir The full path to the directory corresponding to the root of the ZIP. - * \param recursive Whether to pack sub-directories as well or only files. - * \return true if success, false otherwise. - */ - bool MULTIMC_LOGIC_EXPORT compressSubDir(QuaZip *zip, QString dir, QString origDir, QSet &added, - QString prefix = QString(), const SeparatorPrefixTree <'/'> * blacklist = nullptr); - - /** - * Compress a whole directory. - * \param fileCompressed The name of the archive. - * \param dir The directory to compress. - * \param recursive Whether to pack the subdirectories as well, or just regular files. - * \return true if success, false otherwise. - */ - bool MULTIMC_LOGIC_EXPORT compressDir(QString zipFile, QString dir, QString prefix = QString(), const SeparatorPrefixTree <'/'> * blacklist = nullptr); - - /// filter function for @mergeZipFiles - passthrough - bool MULTIMC_LOGIC_EXPORT noFilter(QString key); - - /// filter function for @mergeZipFiles - ignores METAINF - bool MULTIMC_LOGIC_EXPORT metaInfFilter(QString key); - - /** - * Merge two zip files, using a filter function - */ - bool MULTIMC_LOGIC_EXPORT mergeZipFiles(QuaZip *into, QFileInfo from, QSet &contained, std::function filter); - - /** - * take a source jar, add mods to it, resulting in target jar - */ - bool MULTIMC_LOGIC_EXPORT createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods); - - /** - * Extract a whole archive. - * - * \param fileCompressed The name of the archive. - * \param dir The directory to extract to, the current directory if - * left empty. - * \return The list of the full paths of the files extracted, empty on failure. - */ - QStringList MULTIMC_LOGIC_EXPORT extractDir(QString fileCompressed, QString dir = QString()); - - /** - * Find a single file in archive by file name (not path) - * - * \return the path prefix where the file is - */ - QString MULTIMC_LOGIC_EXPORT findFileInZip(QuaZip * zip, const QString & what, const QString &root = QString()); - - /** - * Find a multiple files of the same name in archive by file name - * If a file is found in a path, no deeper paths are searched - * - * \return true if anything was found - */ - bool MULTIMC_LOGIC_EXPORT findFilesInZip(QuaZip * zip, const QString & what, QStringList & result, const QString &root = QString()); - - /** - * Extract a single file to a destination - * - * \return true if it succeeds - */ - bool MULTIMC_LOGIC_EXPORT extractFile(QuaZip *zip, const QString &fileName, const QString &fileDest); - - /** - * Extract a subdirectory from an archive - */ - QStringList MULTIMC_LOGIC_EXPORT extractSubDir(QuaZip *zip, const QString & subdir, const QString &target); -} diff --git a/logic/NullInstance.h b/logic/NullInstance.h deleted file mode 100644 index fbb2d985..00000000 --- a/logic/NullInstance.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once -#include "BaseInstance.h" - -class NullInstance: public BaseInstance -{ -public: - NullInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) - :BaseInstance(globalSettings, settings, rootDir) - { - setFlag(BaseInstance::VersionBrokenFlag); - } - virtual ~NullInstance() {}; - virtual bool setIntendedVersionId(QString) override - { - return false; - } - virtual void cleanupAfterRun() override - { - } - virtual QString currentVersionId() const override - { - return "Null"; - }; - virtual QString intendedVersionId() const override - { - return "Null"; - }; - virtual void init() override - { - }; - virtual QString getStatusbarDescription() override - { - return tr("Unknown instance type"); - }; - virtual bool shouldUpdate() const override - { - return false; - }; - virtual QSet< QString > traits() override - { - return {}; - }; - virtual QString instanceConfigFolder() const override - { - return instanceRoot(); - }; - virtual std::shared_ptr createLaunchTask(AuthSessionPtr) override - { - return nullptr; - } - virtual std::shared_ptr< Task > createUpdateTask() override - { - return nullptr; - } - virtual std::shared_ptr createJarModdingTask() override - { - return nullptr; - } - virtual void setShouldUpdate(bool) override - { - }; - virtual std::shared_ptr< BaseVersionList > versionList() const override - { - return nullptr; - }; - virtual QProcessEnvironment createEnvironment() override - { - return QProcessEnvironment(); - } - virtual QMap getVariables() const override - { - return QMap(); - } - virtual IPathMatcher::Ptr getLogFileMatcher() override - { - return nullptr; - } - virtual QString getLogFileRoot() override - { - return instanceRoot(); - } - virtual QString typeName() const override - { - return "Null"; - } - bool canExport() const override - { - return false; - } -}; diff --git a/logic/QObjectPtr.h b/logic/QObjectPtr.h deleted file mode 100644 index b81b3234..00000000 --- a/logic/QObjectPtr.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include -#include - -namespace details -{ -struct DeleteQObjectLater -{ - void operator()(QObject *obj) const - { - obj->deleteLater(); - } -}; -} -/** - * A unique pointer class with unique pointer semantics intended for derivates of QObject - * Calls deleteLater() instead of destroying the contained object immediately - */ -template using unique_qobject_ptr = std::unique_ptr; - -/** - * A shared pointer class with shared pointer semantics intended for derivates of QObject - * Calls deleteLater() instead of destroying the contained object immediately - */ -template -class shared_qobject_ptr -{ -public: - shared_qobject_ptr(){} - shared_qobject_ptr(T * wrap) - { - reset(wrap); - } - shared_qobject_ptr(const shared_qobject_ptr& other) - { - m_ptr = other.m_ptr; - } - template - shared_qobject_ptr(const shared_qobject_ptr &other) - { - m_ptr = other.unwrap(); - } - -public: - void reset(T * wrap) - { - using namespace std::placeholders; - m_ptr.reset(wrap, std::bind(&QObject::deleteLater, _1)); - } - void reset() - { - m_ptr.reset(); - } - T * get() const - { - return m_ptr.get(); - } - T * operator->() const - { - return m_ptr.get(); - } - T & operator*() const - { - return *m_ptr.get(); - } - operator bool() const - { - return m_ptr.get() != nullptr; - } - const std::shared_ptr unwrap() const - { - return m_ptr; - } - -private: - std::shared_ptr m_ptr; -}; diff --git a/logic/RWStorage.h b/logic/RWStorage.h deleted file mode 100644 index b1598ca4..00000000 --- a/logic/RWStorage.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -template -class RWStorage -{ -public: - void add(K key, V value) - { - QWriteLocker l(&lock); - cache[key] = value; - stale_entries.remove(key); - } - V get(K key) - { - QReadLocker l(&lock); - if(cache.contains(key)) - { - return cache[key]; - } - else return V(); - } - bool get(K key, V& value) - { - QReadLocker l(&lock); - if(cache.contains(key)) - { - value = cache[key]; - return true; - } - else return false; - } - bool has(K key) - { - QReadLocker l(&lock); - return cache.contains(key); - } - bool stale(K key) - { - QReadLocker l(&lock); - if(!cache.contains(key)) - return true; - return stale_entries.contains(key); - } - void setStale(K key) - { - QReadLocker l(&lock); - if(cache.contains(key)) - { - stale_entries.insert(key); - } - } - void clear() - { - QWriteLocker l(&lock); - cache.clear(); - } -private: - QReadWriteLock lock; - QMap cache; - QSet stale_entries; -}; \ No newline at end of file diff --git a/logic/RecursiveFileSystemWatcher.cpp b/logic/RecursiveFileSystemWatcher.cpp deleted file mode 100644 index 59c3f0f0..00000000 --- a/logic/RecursiveFileSystemWatcher.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "RecursiveFileSystemWatcher.h" - -#include -#include - -RecursiveFileSystemWatcher::RecursiveFileSystemWatcher(QObject *parent) - : QObject(parent), m_watcher(new QFileSystemWatcher(this)) -{ - connect(m_watcher, &QFileSystemWatcher::fileChanged, this, - &RecursiveFileSystemWatcher::fileChange); - connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, - &RecursiveFileSystemWatcher::directoryChange); -} - -void RecursiveFileSystemWatcher::setRootDir(const QDir &root) -{ - bool wasEnabled = m_isEnabled; - disable(); - m_root = root; - setFiles(scanRecursive(m_root)); - if (wasEnabled) - { - enable(); - } -} -void RecursiveFileSystemWatcher::setWatchFiles(const bool watchFiles) -{ - bool wasEnabled = m_isEnabled; - disable(); - m_watchFiles = watchFiles; - if (wasEnabled) - { - enable(); - } -} - -void RecursiveFileSystemWatcher::enable() -{ - if (m_isEnabled) - { - return; - } - Q_ASSERT(m_root != QDir::root()); - addFilesToWatcherRecursive(m_root); - m_isEnabled = true; -} -void RecursiveFileSystemWatcher::disable() -{ - if (!m_isEnabled) - { - return; - } - m_isEnabled = false; - m_watcher->removePaths(m_watcher->files()); - m_watcher->removePaths(m_watcher->directories()); -} - -void RecursiveFileSystemWatcher::setFiles(const QStringList &files) -{ - if (files != m_files) - { - m_files = files; - emit filesChanged(); - } -} - -void RecursiveFileSystemWatcher::addFilesToWatcherRecursive(const QDir &dir) -{ - m_watcher->addPath(dir.absolutePath()); - for (const QString &directory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) - { - addFilesToWatcherRecursive(dir.absoluteFilePath(directory)); - } - if (m_watchFiles) - { - for (const QFileInfo &info : dir.entryInfoList(QDir::Files)) - { - m_watcher->addPath(info.absoluteFilePath()); - } - } -} -QStringList RecursiveFileSystemWatcher::scanRecursive(const QDir &directory) -{ - QStringList ret; - if(!m_matcher) - { - return {}; - } - for (const QString &dir : directory.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden)) - { - ret.append(scanRecursive(directory.absoluteFilePath(dir))); - } - for (const QString &file : directory.entryList(QDir::Files | QDir::Hidden)) - { - auto relPath = m_root.relativeFilePath(directory.absoluteFilePath(file)); - if (m_matcher->matches(relPath)) - { - ret.append(relPath); - } - } - return ret; -} - -void RecursiveFileSystemWatcher::fileChange(const QString &path) -{ - emit fileChanged(path); -} -void RecursiveFileSystemWatcher::directoryChange(const QString &path) -{ - setFiles(scanRecursive(m_root)); -} diff --git a/logic/RecursiveFileSystemWatcher.h b/logic/RecursiveFileSystemWatcher.h deleted file mode 100644 index 07bce0b9..00000000 --- a/logic/RecursiveFileSystemWatcher.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include -#include -#include "pathmatcher/IPathMatcher.h" - -#include "multimc_logic_export.h" - -class MULTIMC_LOGIC_EXPORT RecursiveFileSystemWatcher : public QObject -{ - Q_OBJECT -public: - RecursiveFileSystemWatcher(QObject *parent); - - void setRootDir(const QDir &root); - QDir rootDir() const - { - return m_root; - } - - // WARNING: setting this to true may be bad for performance - void setWatchFiles(const bool watchFiles); - bool watchFiles() const - { - return m_watchFiles; - } - - void setMatcher(IPathMatcher::Ptr matcher) - { - m_matcher = matcher; - } - - QStringList files() const - { - return m_files; - } - -signals: - void filesChanged(); - void fileChanged(const QString &path); - -public slots: - void enable(); - void disable(); - -private: - QDir m_root; - bool m_watchFiles = false; - bool m_isEnabled = false; - IPathMatcher::Ptr m_matcher; - - QFileSystemWatcher *m_watcher; - - QStringList m_files; - void setFiles(const QStringList &files); - - void addFilesToWatcherRecursive(const QDir &dir); - QStringList scanRecursive(const QDir &dir); - -private slots: - void fileChange(const QString &path); - void directoryChange(const QString &path); -}; diff --git a/logic/SeparatorPrefixTree.h b/logic/SeparatorPrefixTree.h deleted file mode 100644 index fd149af0..00000000 --- a/logic/SeparatorPrefixTree.h +++ /dev/null @@ -1,298 +0,0 @@ -#pragma once -#include -#include -#include - -template -class SeparatorPrefixTree -{ -public: - SeparatorPrefixTree(QStringList paths) - { - insert(paths); - } - - SeparatorPrefixTree(bool contained = false) - { - m_contained = contained; - } - - void insert(QStringList paths) - { - for(auto &path: paths) - { - insert(path); - } - } - - /// insert an exact path into the tree - SeparatorPrefixTree & insert(QString path) - { - auto sepIndex = path.indexOf(Tseparator); - if(sepIndex == -1) - { - children[path] = SeparatorPrefixTree(true); - return children[path]; - } - else - { - auto prefix = path.left(sepIndex); - if(!children.contains(prefix)) - { - children[prefix] = SeparatorPrefixTree(false); - } - return children[prefix].insert(path.mid(sepIndex + 1)); - } - } - - /// is the path fully contained in the tree? - bool contains(QString path) const - { - auto node = find(path); - return node != nullptr; - } - - /// does the tree cover a path? That means the prefix of the path is contained in the tree - bool covers(QString path) const - { - // if we found some valid node, it's good enough. the tree covers the path - if(m_contained) - { - return true; - } - auto sepIndex = path.indexOf(Tseparator); - if(sepIndex == -1) - { - auto found = children.find(path); - if(found == children.end()) - { - return false; - } - return (*found).covers(QString()); - } - else - { - auto prefix = path.left(sepIndex); - auto found = children.find(prefix); - if(found == children.end()) - { - return false; - } - return (*found).covers(path.mid(sepIndex + 1)); - } - } - - /// return the contained path that covers the path specified - QString cover(QString path) const - { - // if we found some valid node, it's good enough. the tree covers the path - if(m_contained) - { - return QString(""); - } - auto sepIndex = path.indexOf(Tseparator); - if(sepIndex == -1) - { - auto found = children.find(path); - if(found == children.end()) - { - return QString(); - } - auto nested = (*found).cover(QString()); - if(nested.isNull()) - { - return nested; - } - if(nested.isEmpty()) - return path; - return path + Tseparator + nested; - } - else - { - auto prefix = path.left(sepIndex); - auto found = children.find(prefix); - if(found == children.end()) - { - return QString(); - } - auto nested = (*found).cover(path.mid(sepIndex + 1)); - if(nested.isNull()) - { - return nested; - } - if(nested.isEmpty()) - return prefix; - return prefix + Tseparator + nested; - } - } - - /// Does the path-specified node exist in the tree? It does not have to be contained. - bool exists(QString path) const - { - auto sepIndex = path.indexOf(Tseparator); - if(sepIndex == -1) - { - auto found = children.find(path); - if(found == children.end()) - { - return false; - } - return true; - } - else - { - auto prefix = path.left(sepIndex); - auto found = children.find(prefix); - if(found == children.end()) - { - return false; - } - return (*found).exists(path.mid(sepIndex + 1)); - } - } - - /// find a node in the tree by name - const SeparatorPrefixTree * find(QString path) const - { - auto sepIndex = path.indexOf(Tseparator); - if(sepIndex == -1) - { - auto found = children.find(path); - if(found == children.end()) - { - return nullptr; - } - return &(*found); - } - else - { - auto prefix = path.left(sepIndex); - auto found = children.find(prefix); - if(found == children.end()) - { - return nullptr; - } - return (*found).find(path.mid(sepIndex + 1)); - } - } - - /// is this a leaf node? - bool leaf() const - { - return children.isEmpty(); - } - - /// is this node actually contained in the tree, or is it purely structural? - bool contained() const - { - return m_contained; - } - - /// Remove a path from the tree - bool remove(QString path) - { - return removeInternal(path) != Failed; - } - - /// Clear all children of this node tree node - void clear() - { - children.clear(); - } - - QStringList toStringList() const - { - QStringList collected; - // collecting these is more expensive. - auto iter = children.begin(); - while(iter != children.end()) - { - QStringList list = iter.value().toStringList(); - for(int i = 0; i < list.size(); i++) - { - list[i] = iter.key() + Tseparator + list[i]; - } - collected.append(list); - if((*iter).m_contained) - { - collected.append(iter.key()); - } - iter++; - } - return collected; - } -private: - enum Removal - { - Failed, - Succeeded, - HasChildren - }; - Removal removeInternal(QString path = QString()) - { - if(path.isEmpty()) - { - if(!m_contained) - { - // remove all children - we are removing a prefix - clear(); - return Succeeded; - } - m_contained = false; - if(children.size()) - { - return HasChildren; - } - return Succeeded; - } - Removal remStatus = Failed; - QString childToRemove; - auto sepIndex = path.indexOf(Tseparator); - if(sepIndex == -1) - { - childToRemove = path; - auto found = children.find(childToRemove); - if(found == children.end()) - { - return Failed; - } - remStatus = (*found).removeInternal(); - } - else - { - childToRemove = path.left(sepIndex); - auto found = children.find(childToRemove); - if(found == children.end()) - { - return Failed; - } - remStatus = (*found).removeInternal(path.mid(sepIndex + 1)); - } - switch (remStatus) - { - case Failed: - case HasChildren: - { - return remStatus; - } - case Succeeded: - { - children.remove(childToRemove); - if(m_contained) - { - return HasChildren; - } - if(children.size()) - { - return HasChildren; - } - return Succeeded; - } - } - return Failed; - } - -private: - QMap> children; - bool m_contained = false; -}; diff --git a/logic/TypeMagic.h b/logic/TypeMagic.h deleted file mode 100644 index fa9d12a9..00000000 --- a/logic/TypeMagic.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -namespace TypeMagic -{ -/** "Cleans" the given type T by stripping references (&) and cv-qualifiers (const, volatile) from it - * const int => int - * QString & => QString - * const unsigned long long & => unsigned long long - * - * Usage: - * using Cleaned = Detail::CleanType; - * static_assert(std::is_same, "Cleaned == int"); - */ -// the order of remove_cv and remove_reference matters! -template -using CleanType = typename std::remove_cv::type>::type; - -/// For functors (structs with operator()), including lambdas, which in **most** cases are functors -/// "Calls" Function or Function -template struct Function : public Function {}; -/// For function pointers (&function), including static members (&Class::member) -template struct Function : public Function {}; -/// Default specialization used by others. -template struct Function -{ - using ReturnType = Ret; - using Argument = Arg; -}; -/// For member functions. Also used by the lambda overload if the lambda captures [this] -template struct Function : public Function {}; -template struct Function : public Function {}; -/// Overload for references -template struct Function : public Function {}; -/// Overload for rvalues -template struct Function : public Function {}; -// for more info: https://functionalcpp.wordpress.com/2013/08/05/function-traits/ -} diff --git a/logic/Version.cpp b/logic/Version.cpp deleted file mode 100644 index 3c4727ad..00000000 --- a/logic/Version.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "Version.h" - -#include -#include -#include -#include - -Version::Version(const QString &str) : m_string(str) -{ - parse(); -} - -bool Version::operator<(const Version &other) const -{ - const int size = qMax(m_sections.size(), other.m_sections.size()); - for (int i = 0; i < size; ++i) - { - const Section sec1 = (i >= m_sections.size()) ? Section("0") : m_sections.at(i); - const Section sec2 = - (i >= other.m_sections.size()) ? Section("0") : other.m_sections.at(i); - if (sec1 != sec2) - { - return sec1 < sec2; - } - } - - return false; -} -bool Version::operator<=(const Version &other) const -{ - return *this < other || *this == other; -} -bool Version::operator>(const Version &other) const -{ - const int size = qMax(m_sections.size(), other.m_sections.size()); - for (int i = 0; i < size; ++i) - { - const Section sec1 = (i >= m_sections.size()) ? Section("0") : m_sections.at(i); - const Section sec2 = - (i >= other.m_sections.size()) ? Section("0") : other.m_sections.at(i); - if (sec1 != sec2) - { - return sec1 > sec2; - } - } - - return false; -} -bool Version::operator>=(const Version &other) const -{ - return *this > other || *this == other; -} -bool Version::operator==(const Version &other) const -{ - const int size = qMax(m_sections.size(), other.m_sections.size()); - for (int i = 0; i < size; ++i) - { - const Section sec1 = (i >= m_sections.size()) ? Section("0") : m_sections.at(i); - const Section sec2 = - (i >= other.m_sections.size()) ? Section("0") : other.m_sections.at(i); - if (sec1 != sec2) - { - return false; - } - } - - return true; -} -bool Version::operator!=(const Version &other) const -{ - return !operator==(other); -} - -void Version::parse() -{ - m_sections.clear(); - - QStringList parts = m_string.split('.'); - - for (const auto part : parts) - { - m_sections.append(Section(part)); - } -} - -bool versionIsInInterval(const QString &version, const QString &interval) -{ - return versionIsInInterval(Version(version), interval); -} -bool versionIsInInterval(const Version &version, const QString &interval) -{ - if (interval.isEmpty() || version.toString() == interval) - { - return true; - } - - // Interval notation is used - QRegularExpression exp( - "(?[\\[\\]\\(\\)])(?.*?)(,(?.*?))?(?[\\[\\]\\(\\)]),?"); - QRegularExpressionMatch match = exp.match(interval); - if (match.hasMatch()) - { - const QChar start = match.captured("start").at(0); - const QChar end = match.captured("end").at(0); - const QString bottom = match.captured("bottom"); - const QString top = match.captured("top"); - - // check if in range (bottom) - if (!bottom.isEmpty()) - { - const auto bottomVersion = Version(bottom); - if ((start == '[') && !(version >= bottomVersion)) - { - return false; - } - else if ((start == '(') && !(version > bottomVersion)) - { - return false; - } - } - - // check if in range (top) - if (!top.isEmpty()) - { - const auto topVersion = Version(top); - if ((end == ']') && !(version <= topVersion)) - { - return false; - } - else if ((end == ')') && !(version < topVersion)) - { - return false; - } - } - - return true; - } - - return false; -} diff --git a/logic/Version.h b/logic/Version.h deleted file mode 100644 index b5946ced..00000000 --- a/logic/Version.h +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include -#include - -#include "multimc_logic_export.h" - -class QUrl; - -struct MULTIMC_LOGIC_EXPORT Version -{ - Version(const QString &str); - Version() {} - - bool operator<(const Version &other) const; - bool operator<=(const Version &other) const; - bool operator>(const Version &other) const; - bool operator>=(const Version &other) const; - bool operator==(const Version &other) const; - bool operator!=(const Version &other) const; - - QString toString() const - { - return m_string; - } - -private: - QString m_string; - struct Section - { - explicit Section(const QString &fullString) - { - m_fullString = fullString; - int cutoff = m_fullString.size(); - for(int i = 0; i < m_fullString.size(); i++) - { - if(!m_fullString[i].isDigit()) - { - cutoff = i; - break; - } - } - auto numPart = m_fullString.leftRef(cutoff); - if(numPart.size()) - { - numValid = true; - m_numPart = numPart.toInt(); - } - auto stringPart = m_fullString.midRef(cutoff); - if(stringPart.size()) - { - m_stringPart = stringPart.toString(); - } - } - explicit Section() {} - bool numValid = false; - int m_numPart = 0; - QString m_stringPart; - QString m_fullString; - - inline bool operator!=(const Section &other) const - { - if(numValid && other.numValid) - { - return m_numPart != other.m_numPart || m_stringPart != other.m_stringPart; - } - else - { - return m_fullString != other.m_fullString; - } - } - inline bool operator<(const Section &other) const - { - if(numValid && other.numValid) - { - if(m_numPart < other.m_numPart) - return true; - if(m_numPart == other.m_numPart && m_stringPart < other.m_stringPart) - return true; - return false; - } - else - { - return m_fullString < other.m_fullString; - } - } - inline bool operator>(const Section &other) const - { - if(numValid && other.numValid) - { - if(m_numPart > other.m_numPart) - return true; - if(m_numPart == other.m_numPart && m_stringPart > other.m_stringPart) - return true; - return false; - } - else - { - return m_fullString > other.m_fullString; - } - } - }; - QList
m_sections; - - void parse(); -}; - -MULTIMC_LOGIC_EXPORT bool versionIsInInterval(const QString &version, const QString &interval); -MULTIMC_LOGIC_EXPORT bool versionIsInInterval(const Version &version, const QString &interval); - diff --git a/logic/icons/IconList.cpp b/logic/icons/IconList.cpp deleted file mode 100644 index 99def3b7..00000000 --- a/logic/icons/IconList.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "IconList.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_SIZE 1024 - -IconList::IconList(QString builtinPath, QString path, QObject *parent) : QAbstractListModel(parent) -{ - // add builtin icons - QDir instance_icons(builtinPath); - auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name); - for (auto file_info : file_info_list) - { - QString key = file_info.baseName(); - addIcon(key, key, file_info.absoluteFilePath(), MMCIcon::Builtin); - } - - m_watcher.reset(new QFileSystemWatcher()); - is_watching = false; - connect(m_watcher.get(), SIGNAL(directoryChanged(QString)), - SLOT(directoryChanged(QString))); - connect(m_watcher.get(), SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString))); - - directoryChanged(path); -} - -void IconList::directoryChanged(const QString &path) -{ - QDir new_dir (path); - if(m_dir.absolutePath() != new_dir.absolutePath()) - { - m_dir.setPath(path); - m_dir.refresh(); - if(is_watching) - stopWatching(); - startWatching(); - } - if(!m_dir.exists()) - if(!FS::ensureFolderPathExists(m_dir.absolutePath())) - return; - m_dir.refresh(); - auto new_list = m_dir.entryList(QDir::Files, QDir::Name); - for (auto it = new_list.begin(); it != new_list.end(); it++) - { - QString &foo = (*it); - foo = m_dir.filePath(foo); - } - auto new_set = new_list.toSet(); - QList current_list; - for (auto &it : icons) - { - if (!it.has(MMCIcon::FileBased)) - continue; - current_list.push_back(it.m_images[MMCIcon::FileBased].filename); - } - QSet current_set = current_list.toSet(); - - QSet to_remove = current_set; - to_remove -= new_set; - - QSet to_add = new_set; - to_add -= current_set; - - for (auto remove : to_remove) - { - qDebug() << "Removing " << remove; - QFileInfo rmfile(remove); - QString key = rmfile.baseName(); - int idx = getIconIndex(key); - if (idx == -1) - continue; - icons[idx].remove(MMCIcon::FileBased); - if (icons[idx].type() == MMCIcon::ToBeDeleted) - { - beginRemoveRows(QModelIndex(), idx, idx); - icons.remove(idx); - reindex(); - endRemoveRows(); - } - else - { - dataChanged(index(idx), index(idx)); - } - m_watcher->removePath(remove); - emit iconUpdated(key); - } - - for (auto add : to_add) - { - qDebug() << "Adding " << add; - QFileInfo addfile(add); - QString key = addfile.baseName(); - if (addIcon(key, QString(), addfile.filePath(), MMCIcon::FileBased)) - { - m_watcher->addPath(add); - emit iconUpdated(key); - } - } -} - -void IconList::fileChanged(const QString &path) -{ - qDebug() << "Checking " << path; - QFileInfo checkfile(path); - if (!checkfile.exists()) - return; - QString key = checkfile.baseName(); - int idx = getIconIndex(key); - if (idx == -1) - return; - QIcon icon(path); - if (!icon.availableSizes().size()) - return; - - icons[idx].m_images[MMCIcon::FileBased].icon = icon; - dataChanged(index(idx), index(idx)); - emit iconUpdated(key); -} - -void IconList::SettingChanged(const Setting &setting, QVariant value) -{ - if(setting.id() != "IconsDir") - return; - - directoryChanged(value.toString()); -} - -void IconList::startWatching() -{ - auto abs_path = m_dir.absolutePath(); - FS::ensureFolderPathExists(abs_path); - is_watching = m_watcher->addPath(abs_path); - if (is_watching) - { - qDebug() << "Started watching " << abs_path; - } - else - { - qDebug() << "Failed to start watching " << abs_path; - } -} - -void IconList::stopWatching() -{ - m_watcher->removePaths(m_watcher->files()); - m_watcher->removePaths(m_watcher->directories()); - is_watching = false; -} - -QStringList IconList::mimeTypes() const -{ - QStringList types; - types << "text/uri-list"; - return types; -} -Qt::DropActions IconList::supportedDropActions() const -{ - return Qt::CopyAction; -} - -bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, - const QModelIndex &parent) -{ - if (action == Qt::IgnoreAction) - return true; - // check if the action is supported - if (!data || !(action & supportedDropActions())) - return false; - - // files dropped from outside? - if (data->hasUrls()) - { - auto urls = data->urls(); - QStringList iconFiles; - for (auto url : urls) - { - // only local files may be dropped... - if (!url.isLocalFile()) - continue; - iconFiles += url.toLocalFile(); - } - installIcons(iconFiles); - return true; - } - return false; -} - -Qt::ItemFlags IconList::flags(const QModelIndex &index) const -{ - Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); - if (index.isValid()) - return Qt::ItemIsDropEnabled | defaultFlags; - else - return Qt::ItemIsDropEnabled | defaultFlags; -} - -QVariant IconList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - int row = index.row(); - - if (row < 0 || row >= icons.size()) - return QVariant(); - - switch (role) - { - case Qt::DecorationRole: - return icons[row].icon(); - case Qt::DisplayRole: - return icons[row].name(); - case Qt::UserRole: - return icons[row].m_key; - default: - return QVariant(); - } -} - -int IconList::rowCount(const QModelIndex &parent) const -{ - return icons.size(); -} - -void IconList::installIcons(QStringList iconFiles) -{ - for (QString file : iconFiles) - { - QFileInfo fileinfo(file); - if (!fileinfo.isReadable() || !fileinfo.isFile()) - continue; - QString target = FS::PathCombine(m_dir.dirName(), fileinfo.fileName()); - - QString suffix = fileinfo.suffix(); - if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico") - continue; - - if (!QFile::copy(file, target)) - continue; - } -} - -bool IconList::iconFileExists(QString key) -{ - auto iconEntry = icon(key); - if(!iconEntry) - { - return false; - } - return iconEntry->has(MMCIcon::FileBased); -} - -const MMCIcon *IconList::icon(QString key) -{ - int iconIdx = getIconIndex(key); - if (iconIdx == -1) - return nullptr; - return &icons[iconIdx]; -} - -bool IconList::deleteIcon(QString key) -{ - int iconIdx = getIconIndex(key); - if (iconIdx == -1) - return false; - auto &iconEntry = icons[iconIdx]; - if (iconEntry.has(MMCIcon::FileBased)) - { - return QFile::remove(iconEntry.m_images[MMCIcon::FileBased].filename); - } - return false; -} - -bool IconList::addIcon(QString key, QString name, QString path, MMCIcon::Type type) -{ - // replace the icon even? is the input valid? - QIcon icon(path); - if (!icon.availableSizes().size()) - return false; - auto iter = name_index.find(key); - if (iter != name_index.end()) - { - auto &oldOne = icons[*iter]; - oldOne.replace(type, icon, path); - dataChanged(index(*iter), index(*iter)); - return true; - } - else - { - // add a new icon - beginInsertRows(QModelIndex(), icons.size(), icons.size()); - { - MMCIcon mmc_icon; - mmc_icon.m_name = name; - mmc_icon.m_key = key; - mmc_icon.replace(type, icon, path); - icons.push_back(mmc_icon); - name_index[key] = icons.size() - 1; - } - endInsertRows(); - return true; - } -} - -void IconList::reindex() -{ - name_index.clear(); - int i = 0; - for (auto &iter : icons) - { - name_index[iter.m_key] = i; - i++; - } -} - -QIcon IconList::getIcon(QString key) -{ - int icon_index = getIconIndex(key); - - if (icon_index != -1) - return icons[icon_index].icon(); - - // Fallback for icons that don't exist. - icon_index = getIconIndex("infinity"); - - if (icon_index != -1) - return icons[icon_index].icon(); - return QIcon(); -} - -QIcon IconList::getBigIcon(QString key) -{ - int icon_index = getIconIndex(key); - - if (icon_index == -1) - key = "infinity"; - - // Fallback for icons that don't exist. - icon_index = getIconIndex(key); - - if (icon_index == -1) - return QIcon(); - - QPixmap bigone = icons[icon_index].icon().pixmap(256,256).scaled(256,256); - return QIcon(bigone); -} - -int IconList::getIconIndex(QString key) -{ - if (key == "default") - key = "infinity"; - - auto iter = name_index.find(key); - if (iter != name_index.end()) - return *iter; - - return -1; -} - -//#include "IconList.moc" diff --git a/logic/icons/IconList.h b/logic/icons/IconList.h deleted file mode 100644 index 971db824..00000000 --- a/logic/icons/IconList.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include "MMCIcon.h" -#include "settings/Setting.h" -#include "Env.h" // there is a global icon list inside Env. - -#include "multimc_logic_export.h" - -class QFileSystemWatcher; - -class MULTIMC_LOGIC_EXPORT IconList : public QAbstractListModel -{ - Q_OBJECT -public: - explicit IconList(QString builtinPath, QString path, QObject *parent = 0); - virtual ~IconList() {}; - - QIcon getIcon(QString key); - QIcon getBigIcon(QString key); - int getIconIndex(QString key); - - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - - bool addIcon(QString key, QString name, QString path, MMCIcon::Type type); - bool deleteIcon(QString key); - bool iconFileExists(QString key); - - virtual QStringList mimeTypes() const; - virtual Qt::DropActions supportedDropActions() const; - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, - const QModelIndex &parent); - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - - void installIcons(QStringList iconFiles); - - const MMCIcon * icon(QString key); - - void startWatching(); - void stopWatching(); - -signals: - void iconUpdated(QString key); - -private: - // hide copy constructor - IconList(const IconList &) = delete; - // hide assign op - IconList &operator=(const IconList &) = delete; - void reindex(); - -public slots: - void directoryChanged(const QString &path); - -protected slots: - void fileChanged(const QString &path); - void SettingChanged(const Setting & setting, QVariant value); -private: - std::shared_ptr m_watcher; - bool is_watching; - QMap name_index; - QVector icons; - QDir m_dir; -}; diff --git a/logic/icons/MMCIcon.cpp b/logic/icons/MMCIcon.cpp deleted file mode 100644 index 6b4eef39..00000000 --- a/logic/icons/MMCIcon.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "MMCIcon.h" -#include - -MMCIcon::Type operator--(MMCIcon::Type &t, int) -{ - MMCIcon::Type temp = t; - switch (t) - { - case MMCIcon::Type::Builtin: - t = MMCIcon::Type::ToBeDeleted; - break; - case MMCIcon::Type::Transient: - t = MMCIcon::Type::Builtin; - break; - case MMCIcon::Type::FileBased: - t = MMCIcon::Type::Transient; - break; - default: - { - } - } - return temp; -} - -MMCIcon::Type MMCIcon::type() const -{ - return m_current_type; -} - -QString MMCIcon::name() const -{ - if (m_name.size()) - return m_name; - return m_key; -} - -bool MMCIcon::has(MMCIcon::Type _type) const -{ - return m_images[_type].present(); -} - -QIcon MMCIcon::icon() const -{ - if (m_current_type == Type::ToBeDeleted) - return QIcon(); - return m_images[m_current_type].icon; -} - -void MMCIcon::remove(Type rm_type) -{ - m_images[rm_type].filename = QString(); - m_images[rm_type].icon = QIcon(); - for (auto iter = rm_type; iter != Type::ToBeDeleted; iter--) - { - if (m_images[iter].present()) - { - m_current_type = iter; - return; - } - } - m_current_type = Type::ToBeDeleted; -} - -void MMCIcon::replace(MMCIcon::Type new_type, QIcon icon, QString path) -{ - QFileInfo foo(path); - if (new_type > m_current_type || m_current_type == MMCIcon::ToBeDeleted) - { - m_current_type = new_type; - } - m_images[new_type].icon = icon; - m_images[new_type].changed = foo.lastModified(); - m_images[new_type].filename = path; -} diff --git a/logic/icons/MMCIcon.h b/logic/icons/MMCIcon.h deleted file mode 100644 index 753e916d..00000000 --- a/logic/icons/MMCIcon.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include -#include -#include - -#include "multimc_logic_export.h" - -struct MULTIMC_LOGIC_EXPORT MMCImage -{ - QIcon icon; - QString filename; - QDateTime changed; - bool present() const - { - return !icon.isNull(); - } -}; - -struct MULTIMC_LOGIC_EXPORT MMCIcon -{ - enum Type : unsigned - { - Builtin, - Transient, - FileBased, - ICONS_TOTAL, - ToBeDeleted - }; - QString m_key; - QString m_name; - MMCImage m_images[ICONS_TOTAL]; - Type m_current_type = ToBeDeleted; - - Type type() const; - QString name() const; - bool has(Type _type) const; - QIcon icon() const; - void remove(Type rm_type); - void replace(Type new_type, QIcon icon, QString path = QString()); -}; diff --git a/logic/java/JavaChecker.cpp b/logic/java/JavaChecker.cpp deleted file mode 100644 index 54d552a9..00000000 --- a/logic/java/JavaChecker.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "JavaChecker.h" -#include -#include -#include -#include -#include -#include -#include - -JavaChecker::JavaChecker(QObject *parent) : QObject(parent) -{ -} - -void JavaChecker::performCheck() -{ - QString checkerJar = FS::PathCombine(QCoreApplication::applicationDirPath(), "jars", "JavaCheck.jar"); - - QStringList args; - - process.reset(new QProcess()); - if(m_args.size()) - { - auto extraArgs = Commandline::splitArgs(m_args); - args.append(extraArgs); - } - if(m_minMem != 0) - { - args << QString("-Xms%1m").arg(m_minMem); - } - if(m_maxMem != 0) - { - args << QString("-Xmx%1m").arg(m_maxMem); - } - if(m_permGen != 64) - { - args << QString("-XX:PermSize=%1m").arg(m_permGen); - } - - args.append({"-jar", checkerJar}); - process->setArguments(args); - process->setProgram(m_path); - process->setProcessChannelMode(QProcess::SeparateChannels); - qDebug() << "Running java checker: " + m_path + args.join(" ");; - - connect(process.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus))); - connect(process.get(), SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError))); - connect(process.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(stdoutReady())); - connect(process.get(), SIGNAL(readyReadStandardError()), this, SLOT(stderrReady())); - connect(&killTimer, SIGNAL(timeout()), SLOT(timeout())); - killTimer.setSingleShot(true); - killTimer.start(15000); - process->start(); -} - -void JavaChecker::stdoutReady() -{ - QByteArray data = process->readAllStandardOutput(); - QString added = QString::fromLocal8Bit(data); - added.remove('\r'); - m_stdout += added; -} - -void JavaChecker::stderrReady() -{ - QByteArray data = process->readAllStandardError(); - QString added = QString::fromLocal8Bit(data); - added.remove('\r'); - m_stderr += added; -} - -void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) -{ - killTimer.stop(); - QProcessPtr _process; - _process.swap(process); - - JavaCheckResult result; - { - result.path = m_path; - result.id = m_id; - } - result.errorLog = m_stderr; - qDebug() << "STDOUT" << m_stdout; - qWarning() << "STDERR" << m_stderr; - qDebug() << "Java checker finished with status " << status << " exit code " << exitcode; - - if (status == QProcess::CrashExit || exitcode == 1) - { - qDebug() << "Java checker failed!"; - emit checkFinished(result); - return; - } - - bool success = true; - - QMap results; - QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts); - for(QString line : lines) - { - line = line.trimmed(); - - auto parts = line.split('=', QString::SkipEmptyParts); - if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty()) - { - success = false; - } - else - { - results.insert(parts[0], parts[1]); - } - } - - if(!results.contains("os.arch") || !results.contains("java.version") || !success) - { - qDebug() << "Java checker failed - couldn't extract required information."; - emit checkFinished(result); - return; - } - - auto os_arch = results["os.arch"]; - auto java_version = results["java.version"]; - bool is_64 = os_arch == "x86_64" || os_arch == "amd64"; - - - result.valid = true; - result.is_64bit = is_64; - result.mojangPlatform = is_64 ? "64" : "32"; - result.realPlatform = os_arch; - result.javaVersion = java_version; - qDebug() << "Java checker succeeded."; - emit checkFinished(result); -} - -void JavaChecker::error(QProcess::ProcessError err) -{ - if(err == QProcess::FailedToStart) - { - killTimer.stop(); - qDebug() << "Java checker has failed to start."; - JavaCheckResult result; - { - result.path = m_path; - result.id = m_id; - } - - emit checkFinished(result); - return; - } -} - -void JavaChecker::timeout() -{ - // NO MERCY. NO ABUSE. - if(process) - { - qDebug() << "Java checker has been killed by timeout."; - process->kill(); - } -} diff --git a/logic/java/JavaChecker.h b/logic/java/JavaChecker.h deleted file mode 100644 index 650e7ce3..00000000 --- a/logic/java/JavaChecker.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include -#include -#include - -#include "multimc_logic_export.h" - -#include "JavaVersion.h" - -class JavaChecker; - -struct MULTIMC_LOGIC_EXPORT JavaCheckResult -{ - QString path; - QString mojangPlatform; - QString realPlatform; - JavaVersion javaVersion; - QString errorLog; - bool valid = false; - bool is_64bit = false; - int id; -}; - -typedef std::shared_ptr QProcessPtr; -typedef std::shared_ptr JavaCheckerPtr; -class MULTIMC_LOGIC_EXPORT JavaChecker : public QObject -{ - Q_OBJECT -public: - explicit JavaChecker(QObject *parent = 0); - void performCheck(); - - QString m_path; - QString m_args; - int m_id = 0; - int m_minMem = 0; - int m_maxMem = 0; - int m_permGen = 64; - -signals: - void checkFinished(JavaCheckResult result); -private: - QProcessPtr process; - QTimer killTimer; - QString m_stdout; - QString m_stderr; -public -slots: - void timeout(); - void finished(int exitcode, QProcess::ExitStatus); - void error(QProcess::ProcessError); - void stdoutReady(); - void stderrReady(); -}; diff --git a/logic/java/JavaCheckerJob.cpp b/logic/java/JavaCheckerJob.cpp deleted file mode 100644 index 0b040e43..00000000 --- a/logic/java/JavaCheckerJob.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright 2013-2015 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 "JavaCheckerJob.h" - -#include - -void JavaCheckerJob::partFinished(JavaCheckResult result) -{ - num_finished++; - qDebug() << m_job_name.toLocal8Bit() << "progress:" << num_finished << "/" - << javacheckers.size(); - emit progress(num_finished, javacheckers.size()); - - javaresults.replace(result.id, result); - - if (num_finished == javacheckers.size()) - { - emit finished(javaresults); - } -} - -void JavaCheckerJob::executeTask() -{ - qDebug() << m_job_name.toLocal8Bit() << " started."; - m_running = true; - for (auto iter : javacheckers) - { - javaresults.append(JavaCheckResult()); - connect(iter.get(), SIGNAL(checkFinished(JavaCheckResult)), SLOT(partFinished(JavaCheckResult))); - iter->performCheck(); - } -} diff --git a/logic/java/JavaCheckerJob.h b/logic/java/JavaCheckerJob.h deleted file mode 100644 index d031c435..00000000 --- a/logic/java/JavaCheckerJob.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include "JavaChecker.h" -#include "tasks/Task.h" - -class JavaCheckerJob; -typedef std::shared_ptr JavaCheckerJobPtr; - -class JavaCheckerJob : public Task -{ - Q_OBJECT -public: - explicit JavaCheckerJob(QString job_name) : Task(), m_job_name(job_name) {}; - - bool addJavaCheckerAction(JavaCheckerPtr base) - { - javacheckers.append(base); - total_progress++; - // if this is already running, the action needs to be started right away! - if (isRunning()) - { - setProgress(current_progress, total_progress); - connect(base.get(), SIGNAL(checkFinished(JavaCheckResult)), SLOT(partFinished(JavaCheckResult))); - - base->performCheck(); - } - return true; - } - - JavaCheckerPtr operator[](int index) - { - return javacheckers[index]; - } - ; - JavaCheckerPtr first() - { - if (javacheckers.size()) - return javacheckers[0]; - return JavaCheckerPtr(); - } - int size() const - { - return javacheckers.size(); - } - virtual bool isRunning() const override - { - return m_running; - } - -signals: - void started(); - void finished(QList); - -private slots: - void partFinished(JavaCheckResult result); - -protected: - virtual void executeTask() override; - -private: - QString m_job_name; - QList javacheckers; - QList javaresults; - qint64 current_progress = 0; - qint64 total_progress = 0; - int num_finished = 0; - bool m_running = false; -}; diff --git a/logic/java/JavaInstall.cpp b/logic/java/JavaInstall.cpp deleted file mode 100644 index bb262b6e..00000000 --- a/logic/java/JavaInstall.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "JavaInstall.h" -#include - -bool JavaInstall::operator<(const JavaInstall &rhs) -{ - auto archCompare = Strings::naturalCompare(arch, rhs.arch, Qt::CaseInsensitive); - if(archCompare != 0) - return archCompare < 0; - if(id < rhs.id) - { - return true; - } - if(id > rhs.id) - { - return false; - } - return Strings::naturalCompare(path, rhs.path, Qt::CaseInsensitive) < 0; -} - -bool JavaInstall::operator==(const JavaInstall &rhs) -{ - return arch == rhs.arch && id == rhs.id && path == rhs.path; -} - -bool JavaInstall::operator>(const JavaInstall &rhs) -{ - return (!operator<(rhs)) && (!operator==(rhs)); -} diff --git a/logic/java/JavaInstall.h b/logic/java/JavaInstall.h deleted file mode 100644 index 882c7386..00000000 --- a/logic/java/JavaInstall.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "BaseVersion.h" -#include "JavaVersion.h" - -struct JavaInstall : public BaseVersion -{ - JavaInstall(){} - JavaInstall(QString id, QString arch, QString path) - : id(id), arch(arch), path(path) - { - } - virtual QString descriptor() - { - return id.toString(); - } - - virtual QString name() - { - return id.toString(); - } - - virtual QString typeString() const - { - return arch; - } - - bool operator<(const JavaInstall & rhs); - bool operator==(const JavaInstall & rhs); - bool operator>(const JavaInstall & rhs); - - JavaVersion id; - QString arch; - QString path; - bool recommended = false; -}; - -typedef std::shared_ptr JavaInstallPtr; diff --git a/logic/java/JavaInstallList.cpp b/logic/java/JavaInstallList.cpp deleted file mode 100644 index c0729227..00000000 --- a/logic/java/JavaInstallList.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* Copyright 2013-2015 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 -#include -#include - -#include - -#include "java/JavaInstallList.h" -#include "java/JavaCheckerJob.h" -#include "java/JavaUtils.h" -#include "MMCStrings.h" -#include "minecraft/VersionFilterData.h" - -JavaInstallList::JavaInstallList(QObject *parent) : BaseVersionList(parent) -{ -} - -Task *JavaInstallList::getLoadTask() -{ - return new JavaListLoadTask(this); -} - -const BaseVersionPtr JavaInstallList::at(int i) const -{ - return m_vlist.at(i); -} - -bool JavaInstallList::isLoaded() -{ - return m_loaded; -} - -int JavaInstallList::count() const -{ - return m_vlist.count(); -} - -QVariant JavaInstallList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (index.row() > count()) - return QVariant(); - - auto version = std::dynamic_pointer_cast(m_vlist[index.row()]); - switch (role) - { - case VersionPointerRole: - return qVariantFromValue(m_vlist[index.row()]); - case VersionIdRole: - return version->descriptor(); - case VersionRole: - return version->id.toString(); - case RecommendedRole: - return version->recommended; - case PathRole: - return version->path; - case ArchitectureRole: - return version->arch; - default: - return QVariant(); - } -} - -BaseVersionList::RoleList JavaInstallList::providesRoles() const -{ - return {VersionPointerRole, VersionIdRole, VersionRole, RecommendedRole, PathRole, ArchitectureRole}; -} - - -void JavaInstallList::updateListData(QList versions) -{ - beginResetModel(); - m_vlist = versions; - m_loaded = true; - sortVersions(); - if(m_vlist.size()) - { - auto best = std::dynamic_pointer_cast(m_vlist[0]); - best->recommended = true; - } - endResetModel(); -} - -bool sortJavas(BaseVersionPtr left, BaseVersionPtr right) -{ - auto rleft = std::dynamic_pointer_cast(left); - auto rright = std::dynamic_pointer_cast(right); - return (*rleft) > (*rright); -} - -void JavaInstallList::sortVersions() -{ - beginResetModel(); - std::sort(m_vlist.begin(), m_vlist.end(), sortJavas); - endResetModel(); -} - -JavaListLoadTask::JavaListLoadTask(JavaInstallList *vlist) : Task() -{ - m_list = vlist; - m_currentRecommended = NULL; -} - -JavaListLoadTask::~JavaListLoadTask() -{ -} - -void JavaListLoadTask::executeTask() -{ - setStatus(tr("Detecting Java installations...")); - - JavaUtils ju; - QList candidate_paths = ju.FindJavaPaths(); - - m_job = std::shared_ptr(new JavaCheckerJob("Java detection")); - connect(m_job.get(), SIGNAL(finished(QList)), this, SLOT(javaCheckerFinished(QList))); - connect(m_job.get(), &Task::progress, this, &Task::setProgress); - - qDebug() << "Probing the following Java paths: "; - int id = 0; - for(QString candidate : candidate_paths) - { - qDebug() << " " << candidate; - - auto candidate_checker = new JavaChecker(); - candidate_checker->m_path = candidate; - candidate_checker->m_id = id; - m_job->addJavaCheckerAction(JavaCheckerPtr(candidate_checker)); - - id++; - } - - m_job->start(); -} - -void JavaListLoadTask::javaCheckerFinished(QList results) -{ - QList candidates; - - qDebug() << "Found the following valid Java installations:"; - for(JavaCheckResult result : results) - { - if(result.valid) - { - JavaInstallPtr javaVersion(new JavaInstall()); - - javaVersion->id = result.javaVersion; - javaVersion->arch = result.mojangPlatform; - javaVersion->path = result.path; - candidates.append(javaVersion); - - qDebug() << " " << javaVersion->id.toString() << javaVersion->arch << javaVersion->path; - } - } - - QList javas_bvp; - for (auto java : candidates) - { - //qDebug() << java->id << java->arch << " at " << java->path; - BaseVersionPtr bp_java = std::dynamic_pointer_cast(java); - - if (bp_java) - { - javas_bvp.append(java); - } - } - - m_list->updateListData(javas_bvp); - emitSucceeded(); -} diff --git a/logic/java/JavaInstallList.h b/logic/java/JavaInstallList.h deleted file mode 100644 index cf0e5784..00000000 --- a/logic/java/JavaInstallList.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "BaseVersionList.h" -#include "tasks/Task.h" - -#include "JavaCheckerJob.h" -#include "JavaInstall.h" - -#include "multimc_logic_export.h" - -class JavaListLoadTask; - -class MULTIMC_LOGIC_EXPORT JavaInstallList : public BaseVersionList -{ - Q_OBJECT -public: - explicit JavaInstallList(QObject *parent = 0); - - virtual Task *getLoadTask() override; - virtual bool isLoaded() override; - virtual const BaseVersionPtr at(int i) const override; - virtual int count() const override; - virtual void sortVersions() override; - - virtual QVariant data(const QModelIndex &index, int role) const override; - virtual RoleList providesRoles() const override; - -public slots: - virtual void updateListData(QList versions) override; - -protected: - QList m_vlist; - - bool m_loaded = false; -}; - -class JavaListLoadTask : public Task -{ - Q_OBJECT - -public: - explicit JavaListLoadTask(JavaInstallList *vlist); - ~JavaListLoadTask(); - - virtual void executeTask(); -public slots: - void javaCheckerFinished(QList results); - -protected: - std::shared_ptr m_job; - JavaInstallList *m_list; - JavaInstall *m_currentRecommended; -}; diff --git a/logic/java/JavaUtils.cpp b/logic/java/JavaUtils.cpp deleted file mode 100644 index 88996e9f..00000000 --- a/logic/java/JavaUtils.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* Copyright 2013-2015 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 -#include -#include -#include - -#include - -#include -#include "java/JavaUtils.h" -#include "java/JavaCheckerJob.h" -#include "java/JavaInstallList.h" -#include "FileSystem.h" - -JavaUtils::JavaUtils() -{ -} - -JavaInstallPtr JavaUtils::MakeJavaPtr(QString path, QString id, QString arch) -{ - JavaInstallPtr javaVersion(new JavaInstall()); - - javaVersion->id = id; - javaVersion->arch = arch; - javaVersion->path = path; - - return javaVersion; -} - -JavaInstallPtr JavaUtils::GetDefaultJava() -{ - JavaInstallPtr javaVersion(new JavaInstall()); - - javaVersion->id = "java"; - javaVersion->arch = "unknown"; - javaVersion->path = "java"; - - return javaVersion; -} - -#if defined(Q_OS_WIN32) -QList JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName) -{ - QList javas; - - QString archType = "unknown"; - if (keyType == KEY_WOW64_64KEY) - archType = "64"; - else if (keyType == KEY_WOW64_32KEY) - archType = "32"; - - HKEY jreKey; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName.toStdString().c_str(), 0, - KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS) - { - // Read the current type version from the registry. - // This will be used to find any key that contains the JavaHome value. - char *value = new char[0]; - DWORD valueSz = 0; - if (RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz) == - ERROR_MORE_DATA) - { - value = new char[valueSz]; - RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz); - } - - QString recommended = value; - - TCHAR subKeyName[255]; - DWORD subKeyNameSize, numSubKeys, retCode; - - // Get the number of subkeys - RegQueryInfoKey(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, - NULL, NULL); - - // Iterate until RegEnumKeyEx fails - if (numSubKeys > 0) - { - for (int i = 0; i < numSubKeys; i++) - { - subKeyNameSize = 255; - retCode = RegEnumKeyEx(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL, - NULL); - if (retCode == ERROR_SUCCESS) - { - // Now open the registry key for the version that we just got. - QString newKeyName = keyName + "\\" + subKeyName; - - HKEY newKey; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newKeyName.toStdString().c_str(), 0, - KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS) - { - // Read the JavaHome value to find where Java is installed. - value = new char[0]; - valueSz = 0; - if (RegQueryValueEx(newKey, "JavaHome", NULL, NULL, (BYTE *)value, - &valueSz) == ERROR_MORE_DATA) - { - value = new char[valueSz]; - RegQueryValueEx(newKey, "JavaHome", NULL, NULL, (BYTE *)value, - &valueSz); - - // Now, we construct the version object and add it to the list. - JavaInstallPtr javaVersion(new JavaInstall()); - - javaVersion->id = subKeyName; - javaVersion->arch = archType; - javaVersion->path = - QDir(FS::PathCombine(value, "bin")).absoluteFilePath("javaw.exe"); - javas.append(javaVersion); - } - - RegCloseKey(newKey); - } - } - } - } - - RegCloseKey(jreKey); - } - - return javas; -} - -QList JavaUtils::FindJavaPaths() -{ - QList java_candidates; - - QList JRE64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); - QList JDK64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); - QList JRE32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); - QList JDK32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); - - java_candidates.append(JRE64s); - java_candidates.append(MakeJavaPtr("C:/Program Files/Java/jre7/bin/javaw.exe")); - java_candidates.append(MakeJavaPtr("C:/Program Files/Java/jre6/bin/javaw.exe")); - java_candidates.append(JDK64s); - java_candidates.append(JRE32s); - java_candidates.append(MakeJavaPtr("C:/Program Files (x86)/Java/jre7/bin/javaw.exe")); - java_candidates.append(MakeJavaPtr("C:/Program Files (x86)/Java/jre6/bin/javaw.exe")); - java_candidates.append(JDK32s); - java_candidates.append(MakeJavaPtr(this->GetDefaultJava()->path)); - - QList candidates; - for(JavaInstallPtr java_candidate : java_candidates) - { - if(!candidates.contains(java_candidate->path)) - { - candidates.append(java_candidate->path); - } - } - - return candidates; -} - -#elif defined(Q_OS_MAC) -QList JavaUtils::FindJavaPaths() -{ - QList javas; - javas.append(this->GetDefaultJava()->path); - javas.append("/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/MacOS/itms/java/bin/java"); - javas.append("/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java"); - javas.append("/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java"); - QDir libraryJVMDir("/Library/Java/JavaVirtualMachines/"); - QStringList libraryJVMJavas = libraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - foreach (const QString &java, libraryJVMJavas) { - javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); - javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/jre/bin/java"); - } - QDir systemLibraryJVMDir("/System/Library/Java/JavaVirtualMachines/"); - QStringList systemLibraryJVMJavas = systemLibraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - foreach (const QString &java, systemLibraryJVMJavas) { - javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); - javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java"); - } - return javas; -} - -#elif defined(Q_OS_LINUX) -QList JavaUtils::FindJavaPaths() -{ - qDebug() << "Linux Java detection incomplete - defaulting to \"java\""; - - QList javas; - javas.append(this->GetDefaultJava()->path); - javas.append("/opt/java/bin/java"); - javas.append("/usr/bin/java"); - - return javas; -} -#else -QList JavaUtils::FindJavaPaths() -{ - qDebug() << "Unknown operating system build - defaulting to \"java\""; - - QList javas; - javas.append(this->GetDefaultJava()->path); - - return javas; -} -#endif diff --git a/logic/java/JavaUtils.h b/logic/java/JavaUtils.h deleted file mode 100644 index b671d0a5..00000000 --- a/logic/java/JavaUtils.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "JavaCheckerJob.h" -#include "JavaChecker.h" -#include "JavaInstallList.h" - -#ifdef Q_OS_WIN -#include -#endif - -#include "multimc_logic_export.h" - -class MULTIMC_LOGIC_EXPORT JavaUtils : public QObject -{ - Q_OBJECT -public: - JavaUtils(); - - JavaInstallPtr MakeJavaPtr(QString path, QString id = "unknown", QString arch = "unknown"); - QList FindJavaPaths(); - JavaInstallPtr GetDefaultJava(); - -#ifdef Q_OS_WIN - QList FindJavaFromRegistryKey(DWORD keyType, QString keyName); -#endif -}; diff --git a/logic/java/JavaVersion.cpp b/logic/java/JavaVersion.cpp deleted file mode 100644 index 84fc48a4..00000000 --- a/logic/java/JavaVersion.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "JavaVersion.h" -#include - -#include -#include - -JavaVersion & JavaVersion::operator=(const QString & javaVersionString) -{ - string = javaVersionString; - - auto getCapturedInteger = [](const QRegularExpressionMatch & match, const QString &what) -> int - { - auto str = match.captured(what); - if(str.isEmpty()) - { - return 0; - } - return str.toInt(); - }; - - QRegularExpression pattern; - if(javaVersionString.startsWith("1.")) - { - pattern = QRegularExpression ("1[.](?[0-9]+)([.](?[0-9]+))?(_(?[0-9]+)?)?(-(?[a-zA-Z0-9]+))?"); - } - else - { - pattern = QRegularExpression("(?[0-9]+)([.](?[0-9]+))?([.](?[0-9]+))?(-(?[a-zA-Z0-9]+))?"); - } - - auto match = pattern.match(string); - parseable = match.hasMatch(); - major = getCapturedInteger(match, "major"); - minor = getCapturedInteger(match, "minor"); - security = getCapturedInteger(match, "security"); - prerelease = match.captured("prerelease"); - return *this; -} - -JavaVersion::JavaVersion(const QString &rhs) -{ - operator=(rhs); -} - -QString JavaVersion::toString() -{ - return string; -} - -bool JavaVersion::requiresPermGen() -{ - if(parseable) - { - return major < 8; - } - return true; -} - -bool JavaVersion::operator<(const JavaVersion &rhs) -{ - if(parseable && rhs.parseable) - { - if(major < rhs.major) - return true; - if(major > rhs.major) - return false; - if(minor < rhs.minor) - return true; - if(minor > rhs.minor) - return false; - if(security < rhs.security) - return true; - if(security > rhs.security) - return false; - - // everything else being equal, consider prerelease status - bool thisPre = !prerelease.isEmpty(); - bool rhsPre = !rhs.prerelease.isEmpty(); - if(thisPre && !rhsPre) - { - // this is a prerelease and the other one isn't -> lesser - return true; - } - else if(!thisPre && rhsPre) - { - // this isn't a prerelease and the other one is -> greater - return false; - } - else if(thisPre && rhsPre) - { - // both are prereleases - use natural compare... - return Strings::naturalCompare(prerelease, rhs.prerelease, Qt::CaseSensitive) < 0; - } - // neither is prerelease, so they are the same -> this cannot be less than rhs - return false; - } - else return Strings::naturalCompare(string, rhs.string, Qt::CaseSensitive) < 0; -} - -bool JavaVersion::operator==(const JavaVersion &rhs) -{ - if(parseable && rhs.parseable) - { - return major == rhs.major && minor == rhs.minor && security == rhs.security && prerelease == rhs.prerelease; - } - return string == rhs.string; -} - -bool JavaVersion::operator>(const JavaVersion &rhs) -{ - return (!operator<(rhs)) && (!operator==(rhs)); -} diff --git a/logic/java/JavaVersion.h b/logic/java/JavaVersion.h deleted file mode 100644 index f9a733d3..00000000 --- a/logic/java/JavaVersion.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "multimc_logic_export.h" -#include - -class MULTIMC_LOGIC_EXPORT JavaVersion -{ - friend class JavaVersionTest; -public: - JavaVersion() {}; - JavaVersion(const QString & rhs); - - JavaVersion & operator=(const QString & rhs); - - bool operator<(const JavaVersion & rhs); - bool operator==(const JavaVersion & rhs); - bool operator>(const JavaVersion & rhs); - - bool requiresPermGen(); - - QString toString(); - -private: - QString string; - int major = 0; - int minor = 0; - int security = 0; - bool parseable = false; - QString prerelease; -}; diff --git a/logic/launch/LaunchStep.cpp b/logic/launch/LaunchStep.cpp deleted file mode 100644 index 3078043b..00000000 --- a/logic/launch/LaunchStep.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright 2013-2015 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 "LaunchStep.h" -#include "LaunchTask.h" - -void LaunchStep::bind(LaunchTask *parent) -{ - m_parent = parent; - connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch); - connect(this, &LaunchStep::logLine, parent, &LaunchTask::onLogLine); - connect(this, &LaunchStep::logLines, parent, &LaunchTask::onLogLines); - connect(this, &LaunchStep::finished, parent, &LaunchTask::onStepFinished); - connect(this, &LaunchStep::progressReportingRequest, parent, &LaunchTask::onProgressReportingRequested); -} diff --git a/logic/launch/LaunchStep.h b/logic/launch/LaunchStep.h deleted file mode 100644 index ea472c0d..00000000 --- a/logic/launch/LaunchStep.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "tasks/Task.h" -#include "MessageLevel.h" - -#include - -class LaunchTask; -class LaunchStep: public Task -{ - Q_OBJECT -public: /* methods */ - explicit LaunchStep(LaunchTask *parent):Task(nullptr), m_parent(parent) - { - bind(parent); - }; - virtual ~LaunchStep() {}; - -protected: /* methods */ - virtual void bind(LaunchTask *parent); - -signals: - void logLines(QStringList lines, MessageLevel::Enum level); - void logLine(QString line, MessageLevel::Enum level); - void readyForLaunch(); - void progressReportingRequest(); - -public slots: - virtual void proceed() {}; - -protected: /* data */ - LaunchTask *m_parent; -}; \ No newline at end of file diff --git a/logic/launch/LaunchTask.cpp b/logic/launch/LaunchTask.cpp deleted file mode 100644 index 5b7ff182..00000000 --- a/logic/launch/LaunchTask.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Authors: Orochimarufan - * - * 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 "launch/LaunchTask.h" -#include "MessageLevel.h" -#include "MMCStrings.h" -#include "java/JavaChecker.h" -#include "tasks/Task.h" -#include -#include -#include -#include -#include -#include -#include - -void LaunchTask::init() -{ - m_instance->setRunning(true); -} - -std::shared_ptr LaunchTask::create(InstancePtr inst) -{ - std::shared_ptr proc(new LaunchTask(inst)); - proc->init(); - return proc; -} - -LaunchTask::LaunchTask(InstancePtr instance): m_instance(instance) -{ -} - -void LaunchTask::appendStep(std::shared_ptr step) -{ - m_steps.append(step); -} - -void LaunchTask::prependStep(std::shared_ptr step) -{ - m_steps.prepend(step); -} - -void LaunchTask::executeTask() -{ - if(!m_steps.size()) - { - state = LaunchTask::Finished; - emitSucceeded(); - } - state = LaunchTask::Running; - onStepFinished(); -} - -void LaunchTask::onReadyForLaunch() -{ - state = LaunchTask::Waiting; - emit readyForLaunch(); -} - -void LaunchTask::onStepFinished() -{ - // initial -> just start the first step - if(currentStep == -1) - { - currentStep ++; - m_steps[currentStep]->start(); - return; - } - - auto step = m_steps[currentStep]; - if(step->successful()) - { - // end? - if(currentStep == m_steps.size() - 1) - { - emitSucceeded(); - } - else - { - currentStep ++; - step = m_steps[currentStep]; - step->start(); - } - } - else - { - emitFailed(step->failReason()); - } -} - -void LaunchTask::onProgressReportingRequested() -{ - state = LaunchTask::Waiting; - emit requestProgress(m_steps[currentStep].get()); -} - -void LaunchTask::setCensorFilter(QMap filter) -{ - m_censorFilter = filter; -} - -QString LaunchTask::censorPrivateInfo(QString in) -{ - auto iter = m_censorFilter.begin(); - while (iter != m_censorFilter.end()) - { - in.replace(iter.key(), iter.value()); - iter++; - } - return in; -} - -void LaunchTask::proceed() -{ - if(state != LaunchTask::Waiting) - { - return; - } - m_steps[currentStep]->proceed(); -} - -bool LaunchTask::abort() -{ - switch(state) - { - case LaunchTask::Aborted: - case LaunchTask::Failed: - case LaunchTask::Finished: - return true; - case LaunchTask::NotStarted: - { - state = LaunchTask::Aborted; - emitFailed("Aborted"); - return true; - } - case LaunchTask::Running: - case LaunchTask::Waiting: - { - auto step = m_steps[currentStep]; - if(!step->canAbort()) - { - return false; - } - if(step->abort()) - { - state = LaunchTask::Aborted; - return true; - } - } - default: - break; - } - return false; -} - -void LaunchTask::onLogLines(const QStringList &lines, MessageLevel::Enum defaultLevel) -{ - for (auto & line: lines) - { - onLogLine(line, defaultLevel); - } -} - -void LaunchTask::onLogLine(QString line, MessageLevel::Enum level) -{ - // if the launcher part set a log level, use it - auto innerLevel = MessageLevel::fromLine(line); - if(innerLevel != MessageLevel::Unknown) - { - level = innerLevel; - } - - // If the level is still undetermined, guess level - if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) - { - level = m_instance->guessLevel(line, level); - } - - // censor private user info - line = censorPrivateInfo(line); - - emit log(line, level); -} - -void LaunchTask::emitSucceeded() -{ - m_instance->cleanupAfterRun(); - m_instance->setRunning(false); - Task::emitSucceeded(); -} - -void LaunchTask::emitFailed(QString reason) -{ - m_instance->cleanupAfterRun(); - m_instance->setRunning(false); - Task::emitFailed(reason); -} - -QString LaunchTask::substituteVariables(const QString &cmd) const -{ - QString out = cmd; - auto variables = m_instance->getVariables(); - for (auto it = variables.begin(); it != variables.end(); ++it) - { - out.replace("$" + it.key(), it.value()); - } - auto env = QProcessEnvironment::systemEnvironment(); - for (auto var : env.keys()) - { - out.replace("$" + var, env.value(var)); - } - return out; -} - diff --git a/logic/launch/LaunchTask.h b/logic/launch/LaunchTask.h deleted file mode 100644 index 447445ca..00000000 --- a/logic/launch/LaunchTask.h +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Authors: Orochimarufan - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include -#include "BaseInstance.h" -#include "MessageLevel.h" -#include "LoggedProcess.h" -#include "LaunchStep.h" - -#include "multimc_logic_export.h" - -class MULTIMC_LOGIC_EXPORT LaunchTask: public Task -{ - Q_OBJECT -protected: - explicit LaunchTask(InstancePtr instance); - void init(); - -public: - enum State - { - NotStarted, - Running, - Waiting, - Failed, - Aborted, - Finished - }; - -public: /* methods */ - static std::shared_ptr create(InstancePtr inst); - virtual ~LaunchTask() {}; - - void appendStep(std::shared_ptr step); - void prependStep(std::shared_ptr step); - void setCensorFilter(QMap filter); - - InstancePtr instance() - { - return m_instance; - } - - void setPid(qint64 pid) - { - m_pid = pid; - } - - qint64 pid() - { - return m_pid; - } - - /** - * @brief prepare the process for launch (for multi-stage launch) - */ - virtual void executeTask() override; - - /** - * @brief launch the armed instance - */ - void proceed(); - - /** - * @brief abort launch - */ - virtual bool abort() override; - -public: - QString substituteVariables(const QString &cmd) const; - QString censorPrivateInfo(QString in); - -protected: /* methods */ - virtual void emitFailed(QString reason) override; - virtual void emitSucceeded() override; - -signals: - /** - * @brief emitted when the launch preparations are done - */ - void readyForLaunch(); - - void requestProgress(Task *task); - - void requestLogging(); - - /** - * @brief emitted when we want to log something - * @param text the text to log - * @param level the level to log at - */ - void log(QString text, MessageLevel::Enum level = MessageLevel::MultiMC); - -public slots: - void onLogLines(const QStringList& lines, MessageLevel::Enum defaultLevel = MessageLevel::MultiMC); - void onLogLine(QString line, MessageLevel::Enum defaultLevel = MessageLevel::MultiMC); - void onReadyForLaunch(); - void onStepFinished(); - void onProgressReportingRequested(); - -protected: /* data */ - InstancePtr m_instance; - QList > m_steps; - QMap m_censorFilter; - int currentStep = -1; - State state = NotStarted; - qint64 m_pid = -1; -}; diff --git a/logic/launch/LoggedProcess.cpp b/logic/launch/LoggedProcess.cpp deleted file mode 100644 index 88ca40aa..00000000 --- a/logic/launch/LoggedProcess.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "LoggedProcess.h" -#include "MessageLevel.h" -#include - -LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent) -{ - // QProcess has a strange interface... let's map a lot of those into a few. - connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut); - connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr); - connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus))); - connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError))); - connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange); -} - -QStringList reprocess(const QByteArray & data, QString & leftover) -{ - QString str = leftover + QString::fromLocal8Bit(data); - - str.remove('\r'); - QStringList lines = str.split("\n"); - leftover = lines.takeLast(); - return lines; -} - -void LoggedProcess::on_stdErr() -{ - auto lines = reprocess(readAllStandardError(), m_err_leftover); - emit log(lines, MessageLevel::StdErr); -} - -void LoggedProcess::on_stdOut() -{ - auto lines = reprocess(readAllStandardOutput(), m_out_leftover); - emit log(lines, MessageLevel::StdOut); -} - -void LoggedProcess::on_exit(int exit_code, QProcess::ExitStatus status) -{ - // save the exit code - m_exit_code = exit_code; - - // Flush console window - if (!m_err_leftover.isEmpty()) - { - emit log({m_err_leftover}, MessageLevel::StdErr); - m_err_leftover.clear(); - } - if (!m_out_leftover.isEmpty()) - { - emit log({m_err_leftover}, MessageLevel::StdOut); - m_out_leftover.clear(); - } - - // based on state, send signals - if (!m_is_aborting) - { - if (status == QProcess::NormalExit) - { - //: Message displayed on instance exit - emit log({tr("Process exited with code %1.").arg(exit_code)}, MessageLevel::MultiMC); - changeState(LoggedProcess::Finished); - } - else - { - //: Message displayed on instance crashed - if(exit_code == -1) - emit log({tr("Process crashed.")}, MessageLevel::MultiMC); - else - emit log({tr("Process crashed with exitcode %1.").arg(exit_code)}, MessageLevel::MultiMC); - changeState(LoggedProcess::Crashed); - } - } - else - { - //: Message displayed after the instance exits due to kill request - emit log({tr("Process was killed by user.")}, MessageLevel::Error); - changeState(LoggedProcess::Aborted); - } -} - -void LoggedProcess::on_error(QProcess::ProcessError error) -{ - switch(error) - { - case QProcess::FailedToStart: - { - emit log({tr("The process failed to start.")}, MessageLevel::Fatal); - changeState(LoggedProcess::FailedToStart); - break; - } - // we'll just ignore those... never needed them - case QProcess::Crashed: - case QProcess::ReadError: - case QProcess::Timedout: - case QProcess::UnknownError: - case QProcess::WriteError: - break; - } -} - -void LoggedProcess::kill() -{ - m_is_aborting = true; - QProcess::kill(); -} - -int LoggedProcess::exitCode() const -{ - return m_exit_code; -} - -void LoggedProcess::changeState(LoggedProcess::State state) -{ - if(state == m_state) - return; - m_state = state; - emit stateChanged(m_state); -} - -LoggedProcess::State LoggedProcess::state() const -{ - return m_state; -} - -void LoggedProcess::on_stateChange(QProcess::ProcessState state) -{ - switch(state) - { - case QProcess::NotRunning: - break; // let's not - there are too many that handle this already. - case QProcess::Starting: - { - if(m_state != LoggedProcess::NotRunning) - { - qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Starting; - } - changeState(LoggedProcess::Starting); - return; - } - case QProcess::Running: - { - if(m_state != LoggedProcess::Starting) - { - qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Running; - } - changeState(LoggedProcess::Running); - return; - } - } -} - -#if defined Q_OS_WIN32 -#include -#endif - -qint64 LoggedProcess::processId() const -{ -#ifdef Q_OS_WIN - return pid() ? pid()->dwProcessId : 0; -#else - return pid(); -#endif -} diff --git a/logic/launch/LoggedProcess.h b/logic/launch/LoggedProcess.h deleted file mode 100644 index baa53d79..00000000 --- a/logic/launch/LoggedProcess.h +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include "MessageLevel.h" - -/* - * This is a basic process. - * It has line-based logging support and hides some of the nasty bits. - */ -class LoggedProcess : public QProcess -{ -Q_OBJECT -public: - enum State - { - NotRunning, - Starting, - FailedToStart, - Running, - Finished, - Crashed, - Aborted - }; - -public: - explicit LoggedProcess(QObject* parent = 0); - virtual ~LoggedProcess() {}; - - State state() const; - int exitCode() const; - qint64 processId() const; - -signals: - void log(QStringList lines, MessageLevel::Enum level); - void stateChanged(LoggedProcess::State state); - -public slots: - /** - * @brief kill the process - equivalent to kill -9 - */ - void kill(); - - -private slots: - void on_stdErr(); - void on_stdOut(); - void on_exit(int exit_code, QProcess::ExitStatus status); - void on_error(QProcess::ProcessError error); - void on_stateChange(QProcess::ProcessState); - -private: - void changeState(LoggedProcess::State state); - -private: - QString m_err_leftover; - QString m_out_leftover; - bool m_killed = false; - State m_state = NotRunning; - int m_exit_code = 0; - bool m_is_aborting = false; -}; diff --git a/logic/launch/MessageLevel.cpp b/logic/launch/MessageLevel.cpp deleted file mode 100644 index a5191290..00000000 --- a/logic/launch/MessageLevel.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "MessageLevel.h" - -MessageLevel::Enum MessageLevel::getLevel(const QString& levelName) -{ - if (levelName == "MultiMC") - return MessageLevel::MultiMC; - else if (levelName == "Debug") - return MessageLevel::Debug; - else if (levelName == "Info") - return MessageLevel::Info; - else if (levelName == "Message") - return MessageLevel::Message; - else if (levelName == "Warning") - return MessageLevel::Warning; - else if (levelName == "Error") - return MessageLevel::Error; - else if (levelName == "Fatal") - return MessageLevel::Fatal; - // Skip PrePost, it's not exposed to !![]! - // Also skip StdErr and StdOut - else - return MessageLevel::Unknown; -} - -MessageLevel::Enum MessageLevel::fromLine(QString &line) -{ - // Level prefix - int endmark = line.indexOf("]!"); - if (line.startsWith("!![") && endmark != -1) - { - auto level = MessageLevel::getLevel(line.left(endmark).mid(3)); - line = line.mid(endmark + 2); - return level; - } - return MessageLevel::Unknown; -} diff --git a/logic/launch/MessageLevel.h b/logic/launch/MessageLevel.h deleted file mode 100644 index 0128148d..00000000 --- a/logic/launch/MessageLevel.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -/** - * @brief the MessageLevel Enum - * defines what level a log message is - */ -namespace MessageLevel -{ -enum Enum -{ - Unknown, /**< No idea what this is or where it came from */ - StdOut, /**< Undetermined stderr messages */ - StdErr, /**< Undetermined stdout messages */ - MultiMC, /**< MultiMC Messages */ - Debug, /**< Debug Messages */ - Info, /**< Info Messages */ - Message, /**< Standard Messages */ - Warning, /**< Warnings */ - Error, /**< Errors */ - Fatal, /**< Fatal Errors */ -}; -MessageLevel::Enum getLevel(const QString &levelName); - -/* Get message level from a line. Line is modified if it was successful. */ -MessageLevel::Enum fromLine(QString &line); -} diff --git a/logic/launch/steps/CheckJava.cpp b/logic/launch/steps/CheckJava.cpp deleted file mode 100644 index a4eaa307..00000000 --- a/logic/launch/steps/CheckJava.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright 2013-2015 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 "CheckJava.h" -#include -#include -#include -#include - -void CheckJava::executeTask() -{ - auto instance = m_parent->instance(); - auto settings = instance->settings(); - m_javaPath = FS::ResolveExecutable(settings->get("JavaPath").toString()); - bool perInstance = settings->get("OverrideJava").toBool() || settings->get("OverrideJavaLocation").toBool(); - - auto realJavaPath = QStandardPaths::findExecutable(m_javaPath); - if (realJavaPath.isEmpty()) - { - if (perInstance) - { - emit logLine( - tr("The java binary \"%1\" couldn't be found. Please fix the java path " - "override in the instance's settings or disable it.").arg(m_javaPath), - MessageLevel::Warning); - } - else - { - emit logLine(tr("The java binary \"%1\" couldn't be found. Please set up java in " - "the settings.").arg(m_javaPath), - MessageLevel::Warning); - } - emitFailed(tr("Java path is not valid.")); - return; - } - else - { - emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::MultiMC); - } - - QFileInfo javaInfo(realJavaPath); - qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch(); - auto storedUnixTime = settings->get("JavaTimestamp").toLongLong(); - m_javaUnixTime = javaUnixTime; - // if they are not the same, check! - if (javaUnixTime != storedUnixTime) - { - m_JavaChecker = std::make_shared(); - QString errorLog; - QString version; - emit logLine(tr("Checking Java version..."), MessageLevel::MultiMC); - connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, - &CheckJava::checkJavaFinished); - m_JavaChecker->m_path = realJavaPath; - m_JavaChecker->performCheck(); - return; - } - emitSucceeded(); -} - -void CheckJava::checkJavaFinished(JavaCheckResult result) -{ - if (!result.valid) - { - // Error message displayed if java can't start - emit logLine(tr("Could not start java:"), MessageLevel::Error); - emit logLines(result.errorLog.split('\n'), MessageLevel::Error); - emit logLine("\nCheck your MultiMC Java settings.", MessageLevel::MultiMC); - emitFailed(tr("Could not start java!")); - } - else - { - auto instance = m_parent->instance(); - emit logLine(tr("Java version is %1!\n").arg(result.javaVersion.toString()), - MessageLevel::MultiMC); - instance->settings()->set("JavaVersion", result.javaVersion.toString()); - instance->settings()->set("JavaTimestamp", m_javaUnixTime); - emitSucceeded(); - } -} diff --git a/logic/launch/steps/CheckJava.h b/logic/launch/steps/CheckJava.h deleted file mode 100644 index b63dd4f4..00000000 --- a/logic/launch/steps/CheckJava.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -class CheckJava: public LaunchStep -{ - Q_OBJECT -public: - explicit CheckJava(LaunchTask *parent) :LaunchStep(parent){}; - virtual ~CheckJava() {}; - - virtual void executeTask(); - virtual bool canAbort() const - { - return false; - } -private slots: - void checkJavaFinished(JavaCheckResult result); - -private: - QString m_javaPath; - qlonglong m_javaUnixTime; - JavaCheckerPtr m_JavaChecker; -}; diff --git a/logic/launch/steps/LaunchMinecraft.cpp b/logic/launch/steps/LaunchMinecraft.cpp deleted file mode 100644 index 77a89f17..00000000 --- a/logic/launch/steps/LaunchMinecraft.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright 2013-2015 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 "LaunchMinecraft.h" -#include -#include -#include -#include - -LaunchMinecraft::LaunchMinecraft(LaunchTask *parent) : LaunchStep(parent) -{ - connect(&m_process, &LoggedProcess::log, this, &LaunchMinecraft::logLines); - connect(&m_process, &LoggedProcess::stateChanged, this, &LaunchMinecraft::on_state); -} - -void LaunchMinecraft::executeTask() -{ - auto instance = m_parent->instance(); - std::shared_ptr minecraftInstance = std::dynamic_pointer_cast(instance); - - m_launchScript = minecraftInstance->createLaunchScript(m_session); - - QStringList args = minecraftInstance->javaArguments(); - - // HACK: this is a workaround for MCL-3732 - 'server-resource-packs' is created. - if(!FS::ensureFolderPathExists(FS::PathCombine(minecraftInstance->minecraftRoot(), "server-resource-packs"))) - { - emit logLine(tr("Couldn't create the 'server-resource-packs' folder"), MessageLevel::Error); - } - - QString allArgs = args.join(", "); - emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC); - - auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString()); - - m_process.setProcessEnvironment(instance->createEnvironment()); - - QString wrapperCommand = instance->getWrapperCommand(); - if(!wrapperCommand.isEmpty()) - { - auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand); - if (realWrapperCommand.isEmpty()) - { - QString reason = tr("The wrapper command \"%1\" couldn't be found.").arg(wrapperCommand); - emit logLine(reason, MessageLevel::Fatal); - emitFailed(reason); - return; - } - emit logLine("Wrapper command is:\n" + wrapperCommand + "\n\n", MessageLevel::MultiMC); - args.prepend(javaPath); - m_process.start(wrapperCommand, args); - } - else - { - m_process.start(javaPath, args); - } -} - -void LaunchMinecraft::on_state(LoggedProcess::State state) -{ - switch(state) - { - case LoggedProcess::FailedToStart: - { - //: Error message displayed if instace can't start - QString reason = tr("Could not launch minecraft!"); - emit logLine(reason, MessageLevel::Fatal); - emitFailed(reason); - return; - } - case LoggedProcess::Aborted: - case LoggedProcess::Crashed: - - { - m_parent->setPid(-1); - emitFailed("Game crashed."); - return; - } - case LoggedProcess::Finished: - { - m_parent->setPid(-1); - // if the exit code wasn't 0, report this as a crash - auto exitCode = m_process.exitCode(); - if(exitCode != 0) - { - emitFailed("Game crashed."); - return; - } - //FIXME: make this work again - // m_postlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(exitCode)); - // run post-exit - emitSucceeded(); - break; - } - case LoggedProcess::Running: - emit logLine(tr("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC); - m_parent->setPid(m_process.processId()); - m_parent->instance()->setLastLaunch(); - // send the launch script to the launcher part - m_process.write(m_launchScript.toUtf8()); - - mayProceed = true; - emit readyForLaunch(); - break; - default: - break; - } -} - -void LaunchMinecraft::setWorkingDirectory(const QString &wd) -{ - m_process.setWorkingDirectory(wd); -} - -void LaunchMinecraft::proceed() -{ - if(mayProceed) - { - QString launchString("launch\n"); - m_process.write(launchString.toUtf8()); - mayProceed = false; - } -} - -bool LaunchMinecraft::abort() -{ - if(mayProceed) - { - mayProceed = false; - QString launchString("abort\n"); - m_process.write(launchString.toUtf8()); - } - else - { - auto state = m_process.state(); - if (state == LoggedProcess::Running || state == LoggedProcess::Starting) - { - m_process.kill(); - } - } - return true; -} diff --git a/logic/launch/steps/LaunchMinecraft.h b/logic/launch/steps/LaunchMinecraft.h deleted file mode 100644 index 6b9f7919..00000000 --- a/logic/launch/steps/LaunchMinecraft.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -class LaunchMinecraft: public LaunchStep -{ - Q_OBJECT -public: - explicit LaunchMinecraft(LaunchTask *parent); - virtual void executeTask(); - virtual bool abort(); - virtual void proceed(); - virtual bool canAbort() const - { - return true; - } - void setWorkingDirectory(const QString &wd); - void setAuthSession(AuthSessionPtr session) - { - m_session = session; - } -private slots: - void on_state(LoggedProcess::State state); - -private: - LoggedProcess m_process; - QString m_command; - QString m_launchScript; - AuthSessionPtr m_session; - bool mayProceed = false; -}; diff --git a/logic/launch/steps/ModMinecraftJar.cpp b/logic/launch/steps/ModMinecraftJar.cpp deleted file mode 100644 index fce2d70a..00000000 --- a/logic/launch/steps/ModMinecraftJar.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2013-2015 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 "ModMinecraftJar.h" -#include -#include - -void ModMinecraftJar::executeTask() -{ - m_jarModTask = m_parent->instance()->createJarModdingTask(); - if(m_jarModTask) - { - connect(m_jarModTask.get(), SIGNAL(finished()), this, SLOT(jarModdingFinished())); - m_jarModTask->start(); - return; - } - emitSucceeded(); -} - -void ModMinecraftJar::jarModdingFinished() -{ - if(m_jarModTask->successful()) - { - emitSucceeded(); - } - else - { - QString reason = tr("jar modding failed because: %1.\n\n").arg(m_jarModTask->failReason()); - emit logLine(reason, MessageLevel::Fatal); - emitFailed(reason); - } -} diff --git a/logic/launch/steps/ModMinecraftJar.h b/logic/launch/steps/ModMinecraftJar.h deleted file mode 100644 index b35dfafa..00000000 --- a/logic/launch/steps/ModMinecraftJar.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -// FIXME: temporary wrapper for existing task. -class ModMinecraftJar: public LaunchStep -{ - Q_OBJECT -public: - explicit ModMinecraftJar(LaunchTask *parent) : LaunchStep(parent) {}; - virtual ~ModMinecraftJar(){}; - - virtual void executeTask(); - virtual bool canAbort() const - { - return false; - } -private slots: - void jarModdingFinished(); - -private: - std::shared_ptr m_jarModTask; -}; diff --git a/logic/launch/steps/PostLaunchCommand.cpp b/logic/launch/steps/PostLaunchCommand.cpp deleted file mode 100644 index 29a45f1b..00000000 --- a/logic/launch/steps/PostLaunchCommand.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "PostLaunchCommand.h" -#include - -PostLaunchCommand::PostLaunchCommand(LaunchTask *parent) : LaunchStep(parent) -{ - auto instance = m_parent->instance(); - m_command = instance->getPostExitCommand(); - m_process.setProcessEnvironment(instance->createEnvironment()); - connect(&m_process, &LoggedProcess::log, this, &PostLaunchCommand::logLines); - connect(&m_process, &LoggedProcess::stateChanged, this, &PostLaunchCommand::on_state); -} - -void PostLaunchCommand::executeTask() -{ - QString postlaunch_cmd = m_parent->substituteVariables(m_command); - emit logLine(tr("Running Post-Launch command: %1").arg(postlaunch_cmd), MessageLevel::MultiMC); - m_process.start(postlaunch_cmd); -} - -void PostLaunchCommand::on_state(LoggedProcess::State state) -{ - auto getError = [&]() - { - return tr("Post-Launch command failed with code %1.\n\n").arg(m_process.exitCode()); - }; - switch(state) - { - case LoggedProcess::Aborted: - case LoggedProcess::Crashed: - case LoggedProcess::FailedToStart: - { - auto error = getError(); - emit logLine(error, MessageLevel::Fatal); - emitFailed(error); - return; - } - case LoggedProcess::Finished: - { - if(m_process.exitCode() != 0) - { - auto error = getError(); - emit logLine(error, MessageLevel::Fatal); - emitFailed(error); - } - else - { - emit logLine(tr("Post-Launch command ran successfully.\n\n"), MessageLevel::MultiMC); - emitSucceeded(); - } - } - default: - break; - } -} - -void PostLaunchCommand::setWorkingDirectory(const QString &wd) -{ - m_process.setWorkingDirectory(wd); -} - -bool PostLaunchCommand::abort() -{ - auto state = m_process.state(); - if (state == LoggedProcess::Running || state == LoggedProcess::Starting) - { - m_process.kill(); - } - return true; -} diff --git a/logic/launch/steps/PostLaunchCommand.h b/logic/launch/steps/PostLaunchCommand.h deleted file mode 100644 index 4d5b0a52..00000000 --- a/logic/launch/steps/PostLaunchCommand.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -class PostLaunchCommand: public LaunchStep -{ - Q_OBJECT -public: - explicit PostLaunchCommand(LaunchTask *parent); - virtual void executeTask(); - virtual bool abort(); - virtual bool canAbort() const - { - return true; - } - void setWorkingDirectory(const QString &wd); -private slots: - void on_state(LoggedProcess::State state); - -private: - LoggedProcess m_process; - QString m_command; -}; diff --git a/logic/launch/steps/PreLaunchCommand.cpp b/logic/launch/steps/PreLaunchCommand.cpp deleted file mode 100644 index 47197a82..00000000 --- a/logic/launch/steps/PreLaunchCommand.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2013-2015 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 "PreLaunchCommand.h" -#include - -PreLaunchCommand::PreLaunchCommand(LaunchTask *parent) : LaunchStep(parent) -{ - auto instance = m_parent->instance(); - m_command = instance->getPreLaunchCommand(); - m_process.setProcessEnvironment(instance->createEnvironment()); - connect(&m_process, &LoggedProcess::log, this, &PreLaunchCommand::logLines); - connect(&m_process, &LoggedProcess::stateChanged, this, &PreLaunchCommand::on_state); -} - -void PreLaunchCommand::executeTask() -{ - //FIXME: where to put this? - QString prelaunch_cmd = m_parent->substituteVariables(m_command); - emit logLine(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd), MessageLevel::MultiMC); - m_process.start(prelaunch_cmd); -} - -void PreLaunchCommand::on_state(LoggedProcess::State state) -{ - auto getError = [&]() - { - return tr("Pre-Launch command failed with code %1.\n\n").arg(m_process.exitCode()); - }; - switch(state) - { - case LoggedProcess::Aborted: - case LoggedProcess::Crashed: - case LoggedProcess::FailedToStart: - { - auto error = getError(); - emit logLine(error, MessageLevel::Fatal); - emitFailed(error); - return; - } - case LoggedProcess::Finished: - { - if(m_process.exitCode() != 0) - { - auto error = getError(); - emit logLine(error, MessageLevel::Fatal); - emitFailed(error); - } - else - { - emit logLine(tr("Pre-Launch command ran successfully.\n\n"), MessageLevel::MultiMC); - emitSucceeded(); - } - } - default: - break; - } -} - -void PreLaunchCommand::setWorkingDirectory(const QString &wd) -{ - m_process.setWorkingDirectory(wd); -} - -bool PreLaunchCommand::abort() -{ - auto state = m_process.state(); - if (state == LoggedProcess::Running || state == LoggedProcess::Starting) - { - m_process.kill(); - } - return true; -} diff --git a/logic/launch/steps/PreLaunchCommand.h b/logic/launch/steps/PreLaunchCommand.h deleted file mode 100644 index 077bdfca..00000000 --- a/logic/launch/steps/PreLaunchCommand.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -class PreLaunchCommand: public LaunchStep -{ - Q_OBJECT -public: - explicit PreLaunchCommand(LaunchTask *parent); - virtual void executeTask(); - virtual bool abort(); - virtual bool canAbort() const - { - return true; - } - void setWorkingDirectory(const QString &wd); -private slots: - void on_state(LoggedProcess::State state); - -private: - LoggedProcess m_process; - QString m_command; -}; diff --git a/logic/launch/steps/TextPrint.cpp b/logic/launch/steps/TextPrint.cpp deleted file mode 100644 index f307b1fd..00000000 --- a/logic/launch/steps/TextPrint.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "TextPrint.h" - -TextPrint::TextPrint(LaunchTask * parent, const QStringList &lines, MessageLevel::Enum level) : LaunchStep(parent) -{ - m_lines = lines; - m_level = level; -} -TextPrint::TextPrint(LaunchTask *parent, const QString &line, MessageLevel::Enum level) : LaunchStep(parent) -{ - m_lines.append(line); - m_level = level; -} - -void TextPrint::executeTask() -{ - emit logLines(m_lines, m_level); - emitSucceeded(); -} - -bool TextPrint::canAbort() const -{ - return true; -} - -bool TextPrint::abort() -{ - emitFailed("Aborted."); - return true; -} diff --git a/logic/launch/steps/TextPrint.h b/logic/launch/steps/TextPrint.h deleted file mode 100644 index fdd9014a..00000000 --- a/logic/launch/steps/TextPrint.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "multimc_logic_export.h" - -/* - * FIXME: maybe do not export - */ - -class MULTIMC_LOGIC_EXPORT TextPrint: public LaunchStep -{ - Q_OBJECT -public: - explicit TextPrint(LaunchTask *parent, const QStringList &lines, MessageLevel::Enum level); - explicit TextPrint(LaunchTask *parent, const QString &line, MessageLevel::Enum level); - virtual ~TextPrint(){}; - - virtual void executeTask(); - virtual bool canAbort() const; - virtual bool abort(); - -private: - QStringList m_lines; - MessageLevel::Enum m_level; -}; diff --git a/logic/launch/steps/Update.cpp b/logic/launch/steps/Update.cpp deleted file mode 100644 index 4901f001..00000000 --- a/logic/launch/steps/Update.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright 2013-2015 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 "Update.h" -#include - -void Update::executeTask() -{ - m_updateTask = m_parent->instance()->createUpdateTask(); - if(m_updateTask) - { - connect(m_updateTask.get(), SIGNAL(finished()), this, SLOT(updateFinished())); - connect(m_updateTask.get(), &Task::progress, this, &Task::setProgress); - connect(m_updateTask.get(), &Task::status, this, &Task::setStatus); - emit progressReportingRequest(); - return; - } - emitSucceeded(); -} - -void Update::proceed() -{ - m_updateTask->start(); -} - -void Update::updateFinished() -{ - if(m_updateTask->successful()) - { - emitSucceeded(); - } - else - { - QString reason = tr("Instance update failed because: %1.\n\n").arg(m_updateTask->failReason()); - emit logLine(reason, MessageLevel::Fatal); - emitFailed(reason); - } -} diff --git a/logic/launch/steps/Update.h b/logic/launch/steps/Update.h deleted file mode 100644 index 14928253..00000000 --- a/logic/launch/steps/Update.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -// FIXME: stupid. should be defined by the instance type? or even completely abstracted away... -class Update: public LaunchStep -{ - Q_OBJECT -public: - explicit Update(LaunchTask *parent):LaunchStep(parent) {}; - virtual ~Update() {}; - - virtual void executeTask(); - virtual bool canAbort() const - { - return false; - } - virtual void proceed(); -private slots: - void updateFinished(); - -private: - std::shared_ptr m_updateTask; -}; diff --git a/logic/minecraft/AssetsUtils.cpp b/logic/minecraft/AssetsUtils.cpp deleted file mode 100644 index 7a525abe..00000000 --- a/logic/minecraft/AssetsUtils.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* Copyright 2013-2015 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AssetsUtils.h" -#include "FileSystem.h" -#include "net/MD5EtagDownload.h" - -namespace AssetsUtils -{ - -/* - * Returns true on success, with index populated - * index is undefined otherwise - */ -bool loadAssetsIndexJson(QString assetsId, QString path, AssetsIndex *index) -{ - /* - { - "objects": { - "icons/icon_16x16.png": { - "hash": "bdf48ef6b5d0d23bbb02e17d04865216179f510a", - "size": 3665 - }, - ... - } - } - } - */ - - QFile file(path); - - // Try to open the file and fail if we can't. - // TODO: We should probably report this error to the user. - if (!file.open(QIODevice::ReadOnly)) - { - qCritical() << "Failed to read assets index file" << path; - return false; - } - index->id = assetsId; - - // Read the file and close it. - QByteArray jsonData = file.readAll(); - file.close(); - - QJsonParseError parseError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError); - - // Fail if the JSON is invalid. - if (parseError.error != QJsonParseError::NoError) - { - qCritical() << "Failed to parse assets index file:" << parseError.errorString() - << "at offset " << QString::number(parseError.offset); - return false; - } - - // Make sure the root is an object. - if (!jsonDoc.isObject()) - { - qCritical() << "Invalid assets index JSON: Root should be an array."; - return false; - } - - QJsonObject root = jsonDoc.object(); - - QJsonValue isVirtual = root.value("virtual"); - if (!isVirtual.isUndefined()) - { - index->isVirtual = isVirtual.toBool(false); - } - - QJsonValue objects = root.value("objects"); - QVariantMap map = objects.toVariant().toMap(); - - for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) - { - // qDebug() << iter.key(); - - QVariant variant = iter.value(); - QVariantMap nested_objects = variant.toMap(); - - AssetObject object; - - for (QVariantMap::const_iterator nested_iter = nested_objects.begin(); - nested_iter != nested_objects.end(); ++nested_iter) - { - // qDebug() << nested_iter.key() << nested_iter.value().toString(); - QString key = nested_iter.key(); - QVariant value = nested_iter.value(); - - if (key == "hash") - { - object.hash = value.toString(); - } - else if (key == "size") - { - object.size = value.toDouble(); - } - } - - index->objects.insert(iter.key(), object); - } - - return true; -} - -QDir reconstructAssets(QString assetsId) -{ - 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 virtualRoot; - } - - 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) - { - qDebug() << "Reconstructing virtual assets folder at" << virtualRoot.path(); - - for (QString map : index.objects.keys()) - { - AssetObject asset_object = index.objects.value(map); - QString target_path = FS::PathCombine(virtualRoot.path(), map); - QFile target(target_path); - - QString tlk = asset_object.hash.left(2); - - QString original_path = FS::PathCombine(objectDir.path(), tlk, asset_object.hash); - QFile original(original_path); - if (!original.exists()) - continue; - if (!target.exists()) - { - QFileInfo info(target_path); - QDir target_dir = info.dir(); - // qDebug() << target_dir; - if (!target_dir.exists()) - QDir("").mkpath(target_dir.path()); - - bool couldCopy = original.copy(target_path); - qDebug() << " Copying" << original_path << "to" << target_path - << QString::number(couldCopy); // << original.errorString(); - } - } - - // TODO: Write last used time to virtualRoot/.lastused - } - - return virtualRoot; -} - -} - -NetActionPtr AssetObject::getDownloadAction() -{ - QFileInfo objectFile(getLocalPath()); - if ((!objectFile.isFile()) || (objectFile.size() != size)) - { - auto objectDL = MD5EtagDownload::make(getUrl(), objectFile.filePath()); - objectDL->m_total_progress = size; - return objectDL; - } - return nullptr; -} - -QString AssetObject::getLocalPath() -{ - return "assets/objects/" + getRelPath(); -} - -QUrl AssetObject::getUrl() -{ - return QUrl("http://resources.download.minecraft.net/" + getRelPath()); -} - -QString AssetObject::getRelPath() -{ - return hash.left(2) + "/" + hash; -} - -NetJobPtr AssetsIndex::getDownloadJob() -{ - auto job = new NetJob(QObject::tr("Assets for %1").arg(id)); - for (auto &object : objects.values()) - { - auto dl = object.getDownloadAction(); - if(dl) - { - job->addNetAction(dl); - } - } - if(job->size()) - return job; - return nullptr; -} diff --git a/logic/minecraft/AssetsUtils.h b/logic/minecraft/AssetsUtils.h deleted file mode 100644 index 90251c2d..00000000 --- a/logic/minecraft/AssetsUtils.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include "net/NetAction.h" -#include "net/NetJob.h" - -struct AssetObject -{ - QString getRelPath(); - QUrl getUrl(); - QString getLocalPath(); - NetActionPtr getDownloadAction(); - - QString hash; - qint64 size; -}; - -struct AssetsIndex -{ - NetJobPtr getDownloadJob(); - - QString id; - QMap objects; - bool isVirtual = false; -}; - -namespace AssetsUtils -{ -bool loadAssetsIndexJson(QString id, QString file, AssetsIndex* index); -/// Reconstruct a virtual assets folder for the given assets ID and return the folder -QDir reconstructAssets(QString assetsId); -} diff --git a/logic/minecraft/GradleSpecifier.h b/logic/minecraft/GradleSpecifier.h deleted file mode 100644 index 18308537..00000000 --- a/logic/minecraft/GradleSpecifier.h +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include -#include -#include "DefaultVariable.h" - -struct GradleSpecifier -{ - GradleSpecifier() - { - m_valid = false; - } - GradleSpecifier(QString value) - { - operator=(value); - } - GradleSpecifier & operator =(const QString & value) - { - /* - org.gradle.test.classifiers : service : 1.0 : jdk15 @ jar - DEBUG 0 "org.gradle.test.classifiers:service:1.0:jdk15@jar" - DEBUG 1 "org.gradle.test.classifiers" - DEBUG 2 "service" - DEBUG 3 "1.0" - DEBUG 4 ":jdk15" - DEBUG 5 "jdk15" - DEBUG 6 "@jar" - DEBUG 7 "jar" - */ - QRegExp matcher("([^:@]+):([^:@]+):([^:@]+)" "(:([^:@]+))?" "(@([^:@]+))?"); - m_valid = matcher.exactMatch(value); - auto elements = matcher.capturedTexts(); - m_groupId = elements[1]; - m_artifactId = elements[2]; - m_version = elements[3]; - m_classifier = elements[5]; - if(!elements[7].isEmpty()) - { - m_extension = elements[7]; - } - return *this; - } - operator QString() const - { - if(!m_valid) - return "INVALID"; - QString retval = m_groupId + ":" + m_artifactId + ":" + m_version; - if(!m_classifier.isEmpty()) - { - retval += ":" + m_classifier; - } - if(m_extension.isExplicit()) - { - retval += "@" + m_extension; - } - return retval; - } - QString toPath() const - { - if(!m_valid) - return "INVALID"; - QString path = m_groupId; - path.replace('.', '/'); - path += '/' + m_artifactId + '/' + m_version + '/' + m_artifactId + '-' + m_version; - if(!m_classifier.isEmpty()) - { - path += "-" + m_classifier; - } - path += "." + m_extension; - return path; - } - inline bool valid() const - { - return m_valid; - } - inline QString version() const - { - return m_version; - } - inline QString groupId() const - { - return m_groupId; - } - inline QString artifactId() const - { - return m_artifactId; - } - inline void setClassifier(const QString & classifier) - { - m_classifier = classifier; - } - inline QString classifier() const - { - return m_classifier; - } - inline QString extension() const - { - return m_extension; - } - inline QString artifactPrefix() const - { - return m_groupId + ":" + m_artifactId; - } - bool matchName(const GradleSpecifier & other) const - { - return other.artifactId() == artifactId() && other.groupId() == groupId(); - } - bool operator==(const GradleSpecifier & other) const - { - if(m_groupId != other.m_groupId) - return false; - if(m_artifactId != other.m_artifactId) - return false; - if(m_version != other.m_version) - return false; - if(m_classifier != other.m_classifier) - return false; - if(m_extension != other.m_extension) - return false; - return true; - } -private: - QString m_groupId; - QString m_artifactId; - QString m_version; - QString m_classifier; - DefaultVariable m_extension = DefaultVariable("jar"); - bool m_valid = false; -}; diff --git a/logic/minecraft/JarMod.h b/logic/minecraft/JarMod.h deleted file mode 100644 index 42d05da9..00000000 --- a/logic/minecraft/JarMod.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include -#include -#include -class Jarmod; -typedef std::shared_ptr JarmodPtr; -class Jarmod -{ -public: /* data */ - QString name; - QString originalName; -}; diff --git a/logic/minecraft/Library.cpp b/logic/minecraft/Library.cpp deleted file mode 100644 index 922db84e..00000000 --- a/logic/minecraft/Library.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#include "Library.h" -#include -#include -#include -#include - -void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& native, QStringList& native32, QStringList& native64) const -{ - auto actualPath = [&](QString relPath) - { - QFileInfo out(FS::PathCombine(storagePrefix(), relPath)); - return out.absoluteFilePath(); - }; - if(m_mojangDownloads) - { - if(m_mojangDownloads->artifact) - { - auto artifact = m_mojangDownloads->artifact; - jar += actualPath(artifact->path); - } - if(!isNative()) - return; - if(m_nativeClassifiers.contains(system)) - { - auto nativeClassifier = m_nativeClassifiers[system]; - if(nativeClassifier.contains("${arch}")) - { - auto nat32Classifier = nativeClassifier; - nat32Classifier.replace("${arch}", "32"); - auto nat64Classifier = nativeClassifier; - nat64Classifier.replace("${arch}", "64"); - auto nat32info = m_mojangDownloads->getDownloadInfo(nat32Classifier); - if(nat32info) - native32 += actualPath(nat32info->path); - auto nat64info = m_mojangDownloads->getDownloadInfo(nat64Classifier); - if(nat64info) - native64 += actualPath(nat64info->path); - } - else - { - native += actualPath(m_mojangDownloads->getDownloadInfo(nativeClassifier)->path); - } - } - } - else - { - QString raw_storage = storageSuffix(system); - if(isNative()) - { - if (raw_storage.contains("${arch}")) - { - auto nat32Storage = raw_storage; - nat32Storage.replace("${arch}", "32"); - auto nat64Storage = raw_storage; - nat64Storage.replace("${arch}", "64"); - native32 += actualPath(nat32Storage); - native64 += actualPath(nat64Storage); - } - else - { - native += actualPath(raw_storage); - } - } - else - { - jar += actualPath(raw_storage); - } - } -} - -QList Library::getDownloads(OpSys system, HttpMetaCache * cache, QStringList &failedFiles) const -{ - QList out; - bool isLocal = (hint() == "local"); - bool isForge = (hint() == "forge-pack-xz"); - - auto add_download = [&](QString storage, QString dl) - { - auto entry = cache->resolveEntry("libraries", storage); - if (!entry->isStale()) - return true; - if(isLocal) - { - QFileInfo fileinfo(entry->getFullPath()); - if(!fileinfo.exists()) - { - failedFiles.append(entry->getFullPath()); - return false; - } - return true; - } - if (isForge) - { - out.append(ForgeXzDownload::make(storage, entry)); - } - else - { - out.append(CacheDownload::make(dl, entry)); - } - return true; - }; - - if(m_mojangDownloads) - { - if(m_mojangDownloads->artifact) - { - auto artifact = m_mojangDownloads->artifact; - add_download(artifact->path, artifact->url); - } - if(m_nativeClassifiers.contains(system)) - { - auto nativeClassifier = m_nativeClassifiers[system]; - if(nativeClassifier.contains("${arch}")) - { - auto nat32Classifier = nativeClassifier; - nat32Classifier.replace("${arch}", "32"); - auto nat64Classifier = nativeClassifier; - nat64Classifier.replace("${arch}", "64"); - auto nat32info = m_mojangDownloads->getDownloadInfo(nat32Classifier); - if(nat32info) - add_download(nat32info->path, nat32info->url); - auto nat64info = m_mojangDownloads->getDownloadInfo(nat64Classifier); - if(nat64info) - add_download(nat64info->path, nat64info->url); - } - else - { - auto info = m_mojangDownloads->getDownloadInfo(nativeClassifier); - if(info) - { - add_download(info->path, info->url); - } - } - } - } - else - { - QString raw_storage = storageSuffix(system); - auto raw_dl = [&](){ - if (!m_absoluteURL.isEmpty()) - { - return m_absoluteURL; - } - - if (m_repositoryURL.isEmpty()) - { - return QString("https://" + URLConstants::LIBRARY_BASE) + raw_storage; - } - - if(m_repositoryURL.endsWith('/')) - { - return m_repositoryURL + raw_storage; - } - else - { - return m_repositoryURL + QChar('/') + raw_storage; - } - }(); - if (raw_storage.contains("${arch}")) - { - QString cooked_storage = raw_storage; - QString cooked_dl = raw_dl; - add_download(cooked_storage.replace("${arch}", "32"), cooked_dl.replace("${arch}", "32")); - cooked_storage = raw_storage; - cooked_dl = raw_dl; - add_download(cooked_storage.replace("${arch}", "64"), cooked_dl.replace("${arch}", "64")); - } - else - { - add_download(raw_storage, raw_dl); - } - } - return out; -} - -bool Library::isActive() const -{ - bool result = true; - if (m_rules.empty()) - { - result = true; - } - else - { - RuleAction ruleResult = Disallow; - for (auto rule : m_rules) - { - RuleAction temp = rule->apply(this); - if (temp != Defer) - ruleResult = temp; - } - result = result && (ruleResult == Allow); - } - if (isNative()) - { - result = result && m_nativeClassifiers.contains(currentSystem); - } - return result; -} - -void Library::setStoragePrefix(QString prefix) -{ - m_storagePrefix = prefix; -} - -QString Library::defaultStoragePrefix() -{ - return "libraries/"; -} - -QString Library::storagePrefix() const -{ - if(m_storagePrefix.isEmpty()) - { - return defaultStoragePrefix(); - } - return m_storagePrefix; -} - -QString Library::storageSuffix(OpSys system) const -{ - // non-native? use only the gradle specifier - if (!isNative()) - { - return m_name.toPath(); - } - - // otherwise native, override classifiers. Mojang HACK! - GradleSpecifier nativeSpec = m_name; - if (m_nativeClassifiers.contains(system)) - { - nativeSpec.setClassifier(m_nativeClassifiers[system]); - } - else - { - nativeSpec.setClassifier("INVALID"); - } - return nativeSpec.toPath(); -} diff --git a/logic/minecraft/Library.h b/logic/minecraft/Library.h deleted file mode 100644 index fdce93f3..00000000 --- a/logic/minecraft/Library.h +++ /dev/null @@ -1,184 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Rule.h" -#include "minecraft/OpSys.h" -#include "GradleSpecifier.h" -#include "net/URLConstants.h" -#include "MojangDownloadInfo.h" - -#include "multimc_logic_export.h" - -class Library; - -typedef std::shared_ptr LibraryPtr; - -class MULTIMC_LOGIC_EXPORT Library -{ - friend class OneSixVersionFormat; - friend class MojangVersionFormat; - friend class LibraryTest; -public: - Library() - { - } - Library(const QString &name) - { - m_name = name; - } - /// limited copy without some data. TODO: why? - static LibraryPtr limitedCopy(LibraryPtr base) - { - auto newlib = std::make_shared(); - newlib->m_name = base->m_name; - newlib->m_repositoryURL = base->m_repositoryURL; - newlib->m_hint = base->m_hint; - newlib->m_absoluteURL = base->m_absoluteURL; - newlib->m_extractExcludes = base->m_extractExcludes; - newlib->m_nativeClassifiers = base->m_nativeClassifiers; - newlib->m_rules = base->m_rules; - newlib->m_storagePrefix = base->m_storagePrefix; - newlib->m_mojangDownloads = base->m_mojangDownloads; - return newlib; - } - -public: /* methods */ - /// Returns the raw name field - const GradleSpecifier & rawName() const - { - return m_name; - } - - void setRawName(const GradleSpecifier & spec) - { - m_name = spec; - } - - void setClassifier(const QString & spec) - { - m_name.setClassifier(spec); - } - - /// returns the full group and artifact prefix - QString artifactPrefix() const - { - return m_name.artifactPrefix(); - } - - /// get the artifact ID - QString artifactId() const - { - return m_name.artifactId(); - } - - /// get the artifact version - QString version() const - { - return m_name.version(); - } - - /// Returns true if the library is native - bool isNative() const - { - return m_nativeClassifiers.size() != 0; - } - - void setStoragePrefix(QString prefix = QString()); - - /// Set the url base for downloads - void setRepositoryURL(const QString &base_url) - { - m_repositoryURL = base_url; - } - - void getApplicableFiles(OpSys system, QStringList & jar, QStringList & native, QStringList & native32, QStringList & native64) const; - - void setAbsoluteUrl(const QString &absolute_url) - { - m_absoluteURL = absolute_url; - } - - void setMojangDownloadInfo(MojangLibraryDownloadInfo::Ptr info) - { - m_mojangDownloads = info; - } - - void setHint(const QString &hint) - { - m_hint = hint; - } - - /// Set the load rules - void setRules(QList> rules) - { - m_rules = rules; - } - - /// Returns true if the library should be loaded (or extracted, in case of natives) - bool isActive() const; - - // Get a list of downloads for this library - QList getDownloads(OpSys system, class HttpMetaCache * cache, QStringList &failedFiles) const; - -private: /* methods */ - /// the default storage prefix used by MultiMC - static QString defaultStoragePrefix(); - - /// Get the prefix - root of the storage to be used - QString storagePrefix() const; - - /// Get the relative path where the library should be saved - QString storageSuffix(OpSys system) const; - - QString hint() const - { - return m_hint; - } - -protected: /* data */ - /// the basic gradle dependency specifier. - GradleSpecifier m_name; - - /// DEPRECATED URL prefix of the maven repo where the file can be downloaded - QString m_repositoryURL; - - /// DEPRECATED: MultiMC-specific absolute URL. takes precedence over the implicit maven repo URL, if defined - QString m_absoluteURL; - - /** - * MultiMC-specific type hint - modifies how the library is treated - */ - QString m_hint; - - /** - * storage - by default the local libraries folder in multimc, but could be elsewhere - * MultiMC specific, because of FTB. - */ - QString m_storagePrefix; - - /// true if the library had an extract/excludes section (even empty) - bool m_hasExcludes = false; - - /// a list of files that shouldn't be extracted from the library - QStringList m_extractExcludes; - - /// native suffixes per OS - QMap m_nativeClassifiers; - - /// true if the library had a rules section (even empty) - bool applyRules = false; - - /// rules associated with the library - QList> m_rules; - - /// MOJANG: container with Mojang style download info - MojangLibraryDownloadInfo::Ptr m_mojangDownloads; -}; diff --git a/logic/minecraft/MinecraftInstance.cpp b/logic/minecraft/MinecraftInstance.cpp deleted file mode 100644 index 405ccd26..00000000 --- a/logic/minecraft/MinecraftInstance.cpp +++ /dev/null @@ -1,369 +0,0 @@ -#include "MinecraftInstance.h" -#include -#include "settings/SettingsObject.h" -#include "Env.h" -#include "minecraft/MinecraftVersionList.h" -#include -#include -#include -#include -#include - -#define IBUS "@im=ibus" - -// all of this because keeping things compatible with deprecated old settings -// if either of the settings {a, b} is true, this also resolves to true -class OrSetting : public Setting -{ - Q_OBJECT -public: - OrSetting(QString id, std::shared_ptr a, std::shared_ptr b) - :Setting({id}, false), m_a(a), m_b(b) - { - } - virtual QVariant get() const - { - bool a = m_a->get().toBool(); - bool b = m_b->get().toBool(); - return a || b; - } - virtual void reset() {} - virtual void set(QVariant value) {} -private: - std::shared_ptr m_a; - std::shared_ptr m_b; -}; - -MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir) - : BaseInstance(globalSettings, settings, rootDir) -{ - // Java Settings - auto javaOverride = m_settings->registerSetting("OverrideJava", false); - auto locationOverride = m_settings->registerSetting("OverrideJavaLocation", false); - auto argsOverride = m_settings->registerSetting("OverrideJavaArgs", false); - - // combinations - auto javaOrLocation = std::make_shared("JavaOrLocationOverride", javaOverride, locationOverride); - auto javaOrArgs = std::make_shared("JavaOrArgsOverride", javaOverride, argsOverride); - - m_settings->registerOverride(globalSettings->getSetting("JavaPath"), javaOrLocation); - m_settings->registerOverride(globalSettings->getSetting("JvmArgs"), javaOrArgs); - - // special! - m_settings->registerPassthrough(globalSettings->getSetting("JavaTimestamp"), javaOrLocation); - m_settings->registerPassthrough(globalSettings->getSetting("JavaVersion"), javaOrLocation); - - // Window Size - auto windowSetting = m_settings->registerSetting("OverrideWindow", false); - m_settings->registerOverride(globalSettings->getSetting("LaunchMaximized"), windowSetting); - m_settings->registerOverride(globalSettings->getSetting("MinecraftWinWidth"), windowSetting); - m_settings->registerOverride(globalSettings->getSetting("MinecraftWinHeight"), windowSetting); - - // Memory - auto memorySetting = m_settings->registerSetting("OverrideMemory", false); - m_settings->registerOverride(globalSettings->getSetting("MinMemAlloc"), memorySetting); - m_settings->registerOverride(globalSettings->getSetting("MaxMemAlloc"), memorySetting); - m_settings->registerOverride(globalSettings->getSetting("PermGen"), memorySetting); -} - -QString MinecraftInstance::minecraftRoot() const -{ - QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft")); - QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft")); - - if (dotMCDir.exists() && !mcDir.exists()) - return dotMCDir.filePath(); - else - return mcDir.filePath(); -} - -std::shared_ptr< BaseVersionList > MinecraftInstance::versionList() const -{ - return ENV.getVersionList("net.minecraft"); -} - -QStringList MinecraftInstance::javaArguments() const -{ - QStringList args; - - // custom args go first. we want to override them if we have our own here. - args.append(extraArguments()); - - // OSX dock icon and name -#ifdef Q_OS_MAC - args << "-Xdock:icon=icon.png"; - args << QString("-Xdock:name=\"%1\"").arg(windowTitle()); -#endif - - // HACK: Stupid hack for Intel drivers. See: https://mojang.atlassian.net/browse/MCL-767 -#ifdef Q_OS_WIN32 - args << QString("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_" - "minecraft.exe.heapdump"); -#endif - - args << QString("-Xms%1m").arg(settings()->get("MinMemAlloc").toInt()); - args << QString("-Xmx%1m").arg(settings()->get("MaxMemAlloc").toInt()); - - // No PermGen in newer java. - JavaVersion javaVersion(settings()->get("JavaVersion").toString()); - if(javaVersion.requiresPermGen()) - { - auto permgen = settings()->get("PermGen").toInt(); - if (permgen != 64) - { - args << QString("-XX:PermSize=%1m").arg(permgen); - } - } - - args << "-Duser.language=en"; - args << "-jar" << FS::PathCombine(QCoreApplication::applicationDirPath(), "jars", "NewLaunch.jar"); - - return args; -} - -QMap MinecraftInstance::getVariables() const -{ - QMap out; - out.insert("INST_NAME", name()); - out.insert("INST_ID", id()); - out.insert("INST_DIR", QDir(instanceRoot()).absolutePath()); - out.insert("INST_MC_DIR", QDir(minecraftRoot()).absolutePath()); - out.insert("INST_JAVA", settings()->get("JavaPath").toString()); - out.insert("INST_JAVA_ARGS", javaArguments().join(' ')); - return out; -} - -static QString processLD_LIBRARY_PATH(const QString & LD_LIBRARY_PATH) -{ - QDir mmcBin(QCoreApplication::applicationDirPath()); - auto items = LD_LIBRARY_PATH.split(':'); - QStringList final; - for(auto & item: items) - { - QDir test(item); - if(test == mmcBin) - { - qDebug() << "Env:LD_LIBRARY_PATH ignoring path" << item; - continue; - } - final.append(item); - } - return final.join(':'); -} - -QProcessEnvironment MinecraftInstance::createEnvironment() -{ - // prepare the process environment - QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment(); - QProcessEnvironment env; - - QStringList ignored = - { - "JAVA_ARGS", - "CLASSPATH", - "CONFIGPATH", - "JAVA_HOME", - "JRE_HOME", - "_JAVA_OPTIONS", - "JAVA_OPTIONS", - "JAVA_TOOL_OPTIONS" - }; - for(auto key: rawenv.keys()) - { - auto value = rawenv.value(key); - // filter out dangerous java crap - if(ignored.contains(key)) - { - qDebug() << "Env: ignoring" << key << value; - continue; - } - // filter MultiMC-related things - if(key.startsWith("QT_")) - { - qDebug() << "Env: ignoring" << key << value; - continue; - } -#ifdef Q_OS_LINUX - // Do not pass LD_* variables to java. They were intended for MultiMC - if(key.startsWith("LD_")) - { - qDebug() << "Env: ignoring" << key << value; - continue; - } - // Strip IBus - // IBus is a Linux IME framework. For some reason, it breaks MC? - if (key == "XMODIFIERS" && value.contains(IBUS)) - { - QString save = value; - value.replace(IBUS, ""); - qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value; - } - if(key == "GAME_PRELOAD") - { - env.insert("LD_PRELOAD", value); - continue; - } - if(key == "GAME_LIBRARY_PATH") - { - env.insert("LD_LIBRARY_PATH", processLD_LIBRARY_PATH(value)); - continue; - } -#endif - qDebug() << "Env: " << key << value; - env.insert(key, value); - } -#ifdef Q_OS_LINUX - // HACK: Workaround for QTBUG42500 - if(!env.contains("LD_LIBRARY_PATH")) - { - env.insert("LD_LIBRARY_PATH", ""); - } -#endif - - // export some infos - auto variables = getVariables(); - for (auto it = variables.begin(); it != variables.end(); ++it) - { - env.insert(it.key(), it.value()); - } - return env; -} - -QMap MinecraftInstance::createCensorFilterFromSession(AuthSessionPtr session) -{ - if(!session) - { - return QMap(); - } - auto & sessionRef = *session.get(); - QMap filter; - auto addToFilter = [&filter](QString key, QString value) - { - if(key.trimmed().size()) - { - filter[key] = value; - } - }; - if (sessionRef.session != "-") - { - addToFilter(sessionRef.session, tr("")); - } - addToFilter(sessionRef.access_token, tr("")); - addToFilter(sessionRef.client_token, tr("")); - addToFilter(sessionRef.uuid, tr("")); - addToFilter(sessionRef.player_name, tr("")); - - auto i = sessionRef.u.properties.begin(); - while (i != sessionRef.u.properties.end()) - { - addToFilter(i.value(), "<" + i.key().toUpper() + ">"); - ++i; - } - return filter; -} - -MessageLevel::Enum MinecraftInstance::guessLevel(const QString &line, MessageLevel::Enum level) -{ - QRegularExpression re("\\[(?[0-9:]+)\\] \\[[^/]+/(?[^\\]]+)\\]"); - auto match = re.match(line); - if(match.hasMatch()) - { - // New style logs from log4j - QString timestamp = match.captured("timestamp"); - QString levelStr = match.captured("level"); - if(levelStr == "INFO") - level = MessageLevel::Message; - if(levelStr == "WARN") - level = MessageLevel::Warning; - if(levelStr == "ERROR") - level = MessageLevel::Error; - if(levelStr == "FATAL") - level = MessageLevel::Fatal; - if(levelStr == "TRACE" || levelStr == "DEBUG") - level = MessageLevel::Debug; - } - else - { - // Old style forge logs - if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || - line.contains("[FINER]") || line.contains("[FINEST]")) - level = MessageLevel::Message; - if (line.contains("[SEVERE]") || line.contains("[STDERR]")) - level = MessageLevel::Error; - if (line.contains("[WARNING]")) - level = MessageLevel::Warning; - if (line.contains("[DEBUG]")) - level = MessageLevel::Debug; - } - if (line.contains("overwriting existing")) - return MessageLevel::Fatal; - //NOTE: this diverges from the real regexp. no unicode, the first section is + instead of * - static const QString javaSymbol = "([a-zA-Z_$][a-zA-Z\\d_$]*\\.)+[a-zA-Z_$][a-zA-Z\\d_$]*"; - if (line.contains("Exception in thread") - || line.contains(QRegularExpression("\\s+at " + javaSymbol)) - || line.contains(QRegularExpression("Caused by: " + javaSymbol)) - || line.contains(QRegularExpression("([a-zA-Z_$][a-zA-Z\\d_$]*\\.)+[a-zA-Z_$]?[a-zA-Z\\d_$]*(Exception|Error|Throwable)")) - || line.contains(QRegularExpression("... \\d+ more$")) - ) - return MessageLevel::Error; - return level; -} - -IPathMatcher::Ptr MinecraftInstance::getLogFileMatcher() -{ - auto combined = std::make_shared(); - combined->add(std::make_shared(".*\\.log(\\.[0-9]*)?(\\.gz)?$")); - combined->add(std::make_shared("crash-.*\\.txt")); - combined->add(std::make_shared("IDMap dump.*\\.txt$")); - combined->add(std::make_shared("ModLoader\\.txt(\\..*)?$")); - return combined; -} - -QString MinecraftInstance::getLogFileRoot() -{ - return minecraftRoot(); -} - -QString MinecraftInstance::prettifyTimeDuration(int64_t duration) -{ - int seconds = (int) (duration % 60); - duration /= 60; - int minutes = (int) (duration % 60); - duration /= 60; - int hours = (int) (duration % 24); - int days = (int) (duration / 24); - if((hours == 0)&&(days == 0)) - { - return tr("%1m %2s").arg(minutes).arg(seconds); - } - if (days == 0) - { - return tr("%1h %2m").arg(hours).arg(minutes); - } - return tr("%1d %2h %3m").arg(days).arg(hours).arg(minutes); -} - -QString MinecraftInstance::getStatusbarDescription() -{ - QStringList traits; - if (flags() & VersionBrokenFlag) - { - traits.append(tr("broken")); - } - - QString description; - description.append(tr("Minecraft %1 (%2)").arg(intendedVersionId()).arg(typeName())); - if(totalTimePlayed() > 0) - { - description.append(tr(", played for %1").arg(prettifyTimeDuration(totalTimePlayed()))); - } - /* - if(traits.size()) - { - description.append(QString(" (%1)").arg(traits.join(", "))); - } - */ - return description; -} - -#include "MinecraftInstance.moc" diff --git a/logic/minecraft/MinecraftInstance.h b/logic/minecraft/MinecraftInstance.h deleted file mode 100644 index cd3a8d90..00000000 --- a/logic/minecraft/MinecraftInstance.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include "BaseInstance.h" -#include "minecraft/Mod.h" -#include - -#include "multimc_logic_export.h" - -class ModList; -class WorldList; - -class MULTIMC_LOGIC_EXPORT MinecraftInstance: public BaseInstance -{ -public: - MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir); - virtual ~MinecraftInstance() {}; - - /// Path to the instance's minecraft directory. - QString minecraftRoot() const; - - ////// Mod Lists ////// - virtual std::shared_ptr resourcePackList() const - { - return nullptr; - } - virtual std::shared_ptr texturePackList() const - { - return nullptr; - } - virtual std::shared_ptr worldList() const - { - return nullptr; - } - /// get all jar mods applicable to this instance's jar - virtual QList getJarMods() const - { - return QList(); - } - - /// get the launch script to be used with this - virtual QString createLaunchScript(AuthSessionPtr session) = 0; - - //FIXME: nuke? - virtual std::shared_ptr versionList() const override; - - /// get arguments passed to java - QStringList javaArguments() const; - - /// get variables for launch command variable substitution/environment - virtual QMap getVariables() const override; - - /// create an environment for launching processes - virtual QProcessEnvironment createEnvironment() override; - - /// guess log level from a line of minecraft log - virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level) override; - - virtual IPathMatcher::Ptr getLogFileMatcher() override; - - virtual QString getLogFileRoot() override; - - virtual QString getStatusbarDescription() override; - -protected: - QMap createCensorFilterFromSession(AuthSessionPtr session); -private: - QString prettifyTimeDuration(int64_t duration); -}; - -typedef std::shared_ptr MinecraftInstancePtr; diff --git a/logic/minecraft/MinecraftProfile.cpp b/logic/minecraft/MinecraftProfile.cpp deleted file mode 100644 index 70d0cee4..00000000 --- a/logic/minecraft/MinecraftProfile.cpp +++ /dev/null @@ -1,610 +0,0 @@ -/* Copyright 2013-2015 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 -#include -#include -#include -#include -#include -#include - -#include "minecraft/MinecraftProfile.h" -#include "ProfileUtils.h" -#include "ProfileStrategy.h" -#include "Exception.h" - -MinecraftProfile::MinecraftProfile(ProfileStrategy *strategy) - : QAbstractListModel() -{ - setStrategy(strategy); - clear(); -} - -void MinecraftProfile::setStrategy(ProfileStrategy* strategy) -{ - Q_ASSERT(strategy != nullptr); - - if(m_strategy != nullptr) - { - delete m_strategy; - m_strategy = nullptr; - } - m_strategy = strategy; - m_strategy->profile = this; -} - -ProfileStrategy* MinecraftProfile::strategy() -{ - return m_strategy; -} - -void MinecraftProfile::reload() -{ - beginResetModel(); - m_strategy->load(); - reapplyPatches(); - endResetModel(); -} - -void MinecraftProfile::clear() -{ - m_minecraftVersion.clear(); - m_minecraftVersionType.clear(); - m_minecraftAssets.reset(); - m_minecraftArguments.clear(); - m_tweakers.clear(); - m_mainClass.clear(); - m_appletClass.clear(); - m_libraries.clear(); - m_traits.clear(); - m_jarMods.clear(); - mojangDownloads.clear(); - m_problemSeverity = ProblemSeverity::PROBLEM_NONE; -} - -void MinecraftProfile::clearPatches() -{ - beginResetModel(); - m_patches.clear(); - endResetModel(); -} - -void MinecraftProfile::appendPatch(ProfilePatchPtr patch) -{ - int index = m_patches.size(); - beginInsertRows(QModelIndex(), index, index); - m_patches.append(patch); - endInsertRows(); -} - -bool MinecraftProfile::remove(const int index) -{ - auto patch = versionPatch(index); - if (!patch->isRemovable()) - { - qDebug() << "Patch" << patch->getID() << "is non-removable"; - return false; - } - - if(!m_strategy->removePatch(patch)) - { - qCritical() << "Patch" << patch->getID() << "could not be removed"; - return false; - } - - beginRemoveRows(QModelIndex(), index, index); - m_patches.removeAt(index); - endRemoveRows(); - reapplyPatches(); - saveCurrentOrder(); - return true; -} - -bool MinecraftProfile::remove(const QString id) -{ - int i = 0; - for (auto patch : m_patches) - { - if (patch->getID() == id) - { - return remove(i); - } - i++; - } - return false; -} - -bool MinecraftProfile::customize(int index) -{ - auto patch = versionPatch(index); - if (!patch->isCustomizable()) - { - qDebug() << "Patch" << patch->getID() << "is not customizable"; - return false; - } - if(!m_strategy->customizePatch(patch)) - { - qCritical() << "Patch" << patch->getID() << "could not be customized"; - return false; - } - reapplyPatches(); - saveCurrentOrder(); - // FIXME: maybe later in unstable - // emit dataChanged(createIndex(index, 0), createIndex(index, columnCount(QModelIndex()) - 1)); - return true; -} - -bool MinecraftProfile::revertToBase(int index) -{ - auto patch = versionPatch(index); - if (!patch->isRevertible()) - { - qDebug() << "Patch" << patch->getID() << "is not revertible"; - return false; - } - if(!m_strategy->revertPatch(patch)) - { - qCritical() << "Patch" << patch->getID() << "could not be reverted"; - return false; - } - reapplyPatches(); - saveCurrentOrder(); - // FIXME: maybe later in unstable - // emit dataChanged(createIndex(index, 0), createIndex(index, columnCount(QModelIndex()) - 1)); - return true; -} - -ProfilePatchPtr MinecraftProfile::versionPatch(const QString &id) -{ - for (auto file : m_patches) - { - if (file->getID() == id) - { - return file; - } - } - return nullptr; -} - -ProfilePatchPtr MinecraftProfile::versionPatch(int index) -{ - if(index < 0 || index >= m_patches.size()) - return nullptr; - return m_patches[index]; -} - -bool MinecraftProfile::isVanilla() -{ - for(auto patchptr: m_patches) - { - if(patchptr->isCustom()) - return false; - } - return true; -} - -bool MinecraftProfile::revertToVanilla() -{ - // remove patches, if present - auto VersionPatchesCopy = m_patches; - for(auto & it: VersionPatchesCopy) - { - if (!it->isCustom()) - { - continue; - } - if(it->isRevertible() || it->isRemovable()) - { - if(!remove(it->getID())) - { - qWarning() << "Couldn't remove" << it->getID() << "from profile!"; - reapplyPatches(); - saveCurrentOrder(); - return false; - } - } - } - reapplyPatches(); - saveCurrentOrder(); - return true; -} - -QVariant MinecraftProfile::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - int row = index.row(); - int column = index.column(); - - if (row < 0 || row >= m_patches.size()) - return QVariant(); - - auto patch = m_patches.at(row); - - if (role == Qt::DisplayRole) - { - switch (column) - { - case 0: - return m_patches.at(row)->getName(); - case 1: - { - if(patch->isCustom()) - { - return QString("%1 (Custom)").arg(patch->getVersion()); - } - else - { - return patch->getVersion(); - } - } - default: - return QVariant(); - } - } - if(role == Qt::DecorationRole) - { - switch(column) - { - case 0: - { - auto severity = patch->getProblemSeverity(); - switch (severity) - { - case PROBLEM_WARNING: - return "warning"; - case PROBLEM_ERROR: - return "error"; - default: - return QVariant(); - } - } - default: - { - return QVariant(); - } - } - } - return QVariant(); -} -QVariant MinecraftProfile::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation == Qt::Horizontal) - { - if (role == Qt::DisplayRole) - { - switch (section) - { - case 0: - return tr("Name"); - case 1: - return tr("Version"); - default: - return QVariant(); - } - } - } - return QVariant(); -} -Qt::ItemFlags MinecraftProfile::flags(const QModelIndex &index) const -{ - if (!index.isValid()) - return Qt::NoItemFlags; - return Qt::ItemIsSelectable | Qt::ItemIsEnabled; -} - -int MinecraftProfile::rowCount(const QModelIndex &parent) const -{ - return m_patches.size(); -} - -int MinecraftProfile::columnCount(const QModelIndex &parent) const -{ - return 2; -} - -void MinecraftProfile::saveCurrentOrder() const -{ - ProfileUtils::PatchOrder order; - for(auto item: m_patches) - { - if(!item->isMoveable()) - continue; - order.append(item->getID()); - } - m_strategy->saveOrder(order); -} - -void MinecraftProfile::move(const int index, const MoveDirection direction) -{ - int theirIndex; - if (direction == MoveUp) - { - theirIndex = index - 1; - } - else - { - theirIndex = index + 1; - } - - if (index < 0 || index >= m_patches.size()) - return; - if (theirIndex >= rowCount()) - theirIndex = rowCount() - 1; - if (theirIndex == -1) - theirIndex = rowCount() - 1; - if (index == theirIndex) - return; - int togap = theirIndex > index ? theirIndex + 1 : theirIndex; - - auto from = versionPatch(index); - auto to = versionPatch(theirIndex); - - if (!from || !to || !to->isMoveable() || !from->isMoveable()) - { - return; - } - beginMoveRows(QModelIndex(), index, index, QModelIndex(), togap); - m_patches.swap(index, theirIndex); - endMoveRows(); - reapplyPatches(); - saveCurrentOrder(); -} -void MinecraftProfile::resetOrder() -{ - m_strategy->resetOrder(); - reload(); -} - -bool MinecraftProfile::reapplyPatches() -{ - try - { - clear(); - for(auto file: m_patches) - { - file->applyTo(this); - } - } - catch (Exception & error) - { - clear(); - qWarning() << "Couldn't apply profile patches because: " << error.cause(); - return false; - } - return true; -} - -static void applyString(const QString & from, QString & to) -{ - if(from.isEmpty()) - return; - to = from; -} - -void MinecraftProfile::applyMinecraftVersion(const QString& id) -{ - applyString(id, this->m_minecraftVersion); -} - -void MinecraftProfile::applyAppletClass(const QString& appletClass) -{ - applyString(appletClass, this->m_appletClass); -} - -void MinecraftProfile::applyMainClass(const QString& mainClass) -{ - applyString(mainClass, this->m_mainClass); -} - -void MinecraftProfile::applyMinecraftArguments(const QString& minecraftArguments) -{ - applyString(minecraftArguments, this->m_minecraftArguments); -} - -void MinecraftProfile::applyMinecraftVersionType(const QString& type) -{ - applyString(type, this->m_minecraftVersionType); -} - -void MinecraftProfile::applyMinecraftAssets(MojangAssetIndexInfo::Ptr assets) -{ - if(assets) - { - m_minecraftAssets = assets; - } -} - -void MinecraftProfile::applyMojangDownload(const QString &key, MojangDownloadInfo::Ptr download) -{ - if(download) - { - mojangDownloads[key] = download; - } - else - { - mojangDownloads.remove(key); - } -} - -void MinecraftProfile::applyTraits(const QSet& traits) -{ - this->m_traits.unite(traits); -} - -void MinecraftProfile::applyTweakers(const QStringList& tweakers) -{ - // FIXME: check for dupes? - // FIXME: does order matter? - for (auto tweaker : tweakers) - { - this->m_tweakers += tweaker; - } -} - -void MinecraftProfile::applyJarMods(const QList& jarMods) -{ - this->m_jarMods.append(jarMods); -} - -static int findLibraryByName(QList haystack, const GradleSpecifier &needle) -{ - int retval = -1; - for (int i = 0; i < haystack.size(); ++i) - { - if (haystack.at(i)->rawName().matchName(needle)) - { - // only one is allowed. - if (retval != -1) - return -1; - retval = i; - } - } - return retval; -} - -void MinecraftProfile::applyLibrary(LibraryPtr library) -{ - if(!library->isActive()) - { - return; - } - // find the library by name. - const int index = findLibraryByName(m_libraries, library->rawName()); - // library not found? just add it. - if (index < 0) - { - m_libraries.append(Library::limitedCopy(library)); - return; - } - auto existingLibrary = m_libraries.at(index); - // if we are higher it means we should update - if (Version(library->version()) > Version(existingLibrary->version())) - { - auto libraryCopy = Library::limitedCopy(library); - m_libraries.replace(index, libraryCopy); - } -} - -void MinecraftProfile::applyProblemSeverity(ProblemSeverity severity) -{ - if (m_problemSeverity < severity) - { - m_problemSeverity = severity; - } -} - - -QString MinecraftProfile::getMinecraftVersion() const -{ - return m_minecraftVersion; -} - -QString MinecraftProfile::getAppletClass() const -{ - return m_appletClass; -} - -QString MinecraftProfile::getMainClass() const -{ - return m_mainClass; -} - -const QSet &MinecraftProfile::getTraits() const -{ - return m_traits; -} - -const QStringList & MinecraftProfile::getTweakers() const -{ - return m_tweakers; -} - -bool MinecraftProfile::hasTrait(const QString& trait) const -{ - return m_traits.contains(trait); -} - -ProblemSeverity MinecraftProfile::getProblemSeverity() const -{ - return m_problemSeverity; -} - -QString MinecraftProfile::getMinecraftVersionType() const -{ - return m_minecraftVersionType; -} - -std::shared_ptr MinecraftProfile::getMinecraftAssets() const -{ - if(!m_minecraftAssets) - { - return std::make_shared("legacy"); - } - return m_minecraftAssets; -} - -QString MinecraftProfile::getMinecraftArguments() const -{ - return m_minecraftArguments; -} - -const QList & MinecraftProfile::getJarMods() const -{ - return m_jarMods; -} - -const QList & MinecraftProfile::getLibraries() const -{ - return m_libraries; -} - -QString MinecraftProfile::getMainJarUrl() const -{ - auto iter = mojangDownloads.find("client"); - if(iter != mojangDownloads.end()) - { - // current - return iter.value()->url; - } - else - { - // legacy fallback - return URLConstants::getLegacyJarUrl(getMinecraftVersion()); - } -} - -void MinecraftProfile::installJarMods(QStringList selectedFiles) -{ - m_strategy->installJarMods(selectedFiles); -} - -/* - * TODO: get rid of this. Get rid of all order numbers. - */ -int MinecraftProfile::getFreeOrderNumber() -{ - int largest = 100; - // yes, I do realize this is dumb. The order thing itself is dumb. and to be removed next. - for(auto thing: m_patches) - { - int order = thing->getOrder(); - if(order > largest) - largest = order; - } - return largest + 1; -} diff --git a/logic/minecraft/MinecraftProfile.h b/logic/minecraft/MinecraftProfile.h deleted file mode 100644 index ca9288ad..00000000 --- a/logic/minecraft/MinecraftProfile.h +++ /dev/null @@ -1,200 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include -#include -#include - -#include "Library.h" -#include "VersionFile.h" -#include "JarMod.h" -#include "MojangDownloadInfo.h" - -#include "multimc_logic_export.h" - -class ProfileStrategy; -class OneSixInstance; - - -class MULTIMC_LOGIC_EXPORT MinecraftProfile : public QAbstractListModel -{ - Q_OBJECT - -public: - explicit MinecraftProfile(ProfileStrategy *strategy); - - void setStrategy(ProfileStrategy * strategy); - ProfileStrategy *strategy(); - - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; - virtual int columnCount(const QModelIndex &parent) const override; - virtual Qt::ItemFlags flags(const QModelIndex &index) const override; - - /// is this version unchanged by the user? - bool isVanilla(); - - /// remove any customizations on top of whatever 'vanilla' means - bool revertToVanilla(); - - /// install more jar mods - void installJarMods(QStringList selectedFiles); - - /// DEPRECATED, remove ASAP - int getFreeOrderNumber(); - - enum MoveDirection { MoveUp, MoveDown }; - /// move patch file # up or down the list - void move(const int index, const MoveDirection direction); - - /// remove patch file # - including files/records - bool remove(const int index); - - /// remove patch file by id - including files/records - bool remove(const QString id); - - bool customize(int index); - - bool revertToBase(int index); - - void resetOrder(); - - /// reload all profile patches from storage, clear the profile and apply the patches - void reload(); - - /// clear the profile - void clear(); - - /// apply the patches. Catches all the errors and returns true/false for success/failure - bool reapplyPatches(); - -public: /* application of profile variables from patches */ - void applyMinecraftVersion(const QString& id); - void applyMainClass(const QString& mainClass); - void applyAppletClass(const QString& appletClass); - void applyMinecraftArguments(const QString& minecraftArguments); - void applyMinecraftVersionType(const QString& type); - void applyMinecraftAssets(MojangAssetIndexInfo::Ptr assets); - void applyTraits(const QSet &traits); - void applyTweakers(const QStringList &tweakers); - void applyJarMods(const QList &jarMods); - void applyLibrary(LibraryPtr library); - void applyProblemSeverity(ProblemSeverity severity); - void applyMojangDownload(const QString & key, MojangDownloadInfo::Ptr download); - -public: /* getters for profile variables */ - QString getMinecraftVersion() const; - QString getMainClass() const; - QString getAppletClass() const; - QString getMinecraftVersionType() const; - MojangAssetIndexInfo::Ptr getMinecraftAssets() const; - QString getMinecraftArguments() const; - const QSet & getTraits() const; - const QStringList & getTweakers() const; - const QList & getJarMods() const; - const QList & getLibraries() const; - QString getMainJarUrl() const; - bool hasTrait(const QString & trait) const; - ProblemSeverity getProblemSeverity() const; - -public: - /// get the profile patch by id - ProfilePatchPtr versionPatch(const QString &id); - - /// get the profile patch by index - ProfilePatchPtr versionPatch(int index); - - /// save the current patch order - void saveCurrentOrder() const; - - /// Remove all the patches - void clearPatches(); - - /// Add the patch object to the internal list of patches - void appendPatch(ProfilePatchPtr patch); - -private: /* data */ - /// the version of Minecraft - jar to use - QString m_minecraftVersion; - - /// Release type - "release" or "snapshot" - QString m_minecraftVersionType; - - /// Assets type - "legacy" or a version ID - MojangAssetIndexInfo::Ptr m_minecraftAssets; - - // Mojang: list of 'downloads' - client jar, server jar, windows server exe, maybe more. - QMap > mojangDownloads; - - /** - * arguments that should be used for launching minecraft - * - * ex: "--username ${auth_player_name} --session ${auth_session} - * --version ${version_name} --gameDir ${game_directory} --assetsDir ${game_assets}" - */ - QString m_minecraftArguments; - - /// A list of all tweaker classes - QStringList m_tweakers; - - /// The main class to load first - QString m_mainClass; - - /// The applet class, for some very old minecraft releases - QString m_appletClass; - - /// the list of libraries - QList m_libraries; - - /// traits, collected from all the version files (version files can only add) - QSet m_traits; - - /// A list of jar mods. version files can add those. - QList m_jarMods; - - ProblemSeverity m_problemSeverity = PROBLEM_NONE; - - /* - FIXME: add support for those rules here? Looks like a pile of quick hacks to me though. - - "rules": [ - { - "action": "allow" - }, - { - "action": "disallow", - "os": { - "name": "osx", - "version": "^10\\.5\\.\\d$" - } - } - ], - "incompatibilityReason": "There is a bug in LWJGL which makes it incompatible with OSX - 10.5.8. Please go to New Profile and use 1.5.2 for now. Sorry!" - } - */ - // QList rules; - - /// list of attached profile patches - QList m_patches; - - /// strategy used for profile operations - ProfileStrategy *m_strategy = nullptr; -}; diff --git a/logic/minecraft/MinecraftVersion.cpp b/logic/minecraft/MinecraftVersion.cpp deleted file mode 100644 index 1e1d273c..00000000 --- a/logic/minecraft/MinecraftVersion.cpp +++ /dev/null @@ -1,215 +0,0 @@ -#include "MinecraftVersion.h" -#include "MinecraftProfile.h" -#include "VersionBuildError.h" -#include "ProfileUtils.h" -#include "settings/SettingsObject.h" -#include "minecraft/VersionFilterData.h" - -bool MinecraftVersion::usesLegacyLauncher() -{ - return getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate; -} - - -QString MinecraftVersion::descriptor() -{ - return m_version; -} - -QString MinecraftVersion::name() -{ - return m_version; -} - -QString MinecraftVersion::typeString() const -{ - if(m_type == "snapshot") - { - return QObject::tr("Snapshot"); - } - else if (m_type == "release") - { - return QObject::tr("Regular release"); - } - else if (m_type == "old_alpha") - { - return QObject::tr("Alpha"); - } - else if (m_type == "old_beta") - { - return QObject::tr("Beta"); - } - else - { - return QString(); - } -} - -VersionSource MinecraftVersion::getVersionSource() -{ - return m_versionSource; -} - -bool MinecraftVersion::hasJarMods() -{ - return false; -} - -bool MinecraftVersion::isMinecraftVersion() -{ - return true; -} - -void MinecraftVersion::applyFileTo(MinecraftProfile *profile) -{ - if(m_versionSource == Local && getVersionFile()) - { - getVersionFile()->applyTo(profile); - } - else - { - throw VersionIncomplete(QObject::tr("Can't apply incomplete/builtin Minecraft version %1").arg(m_version)); - } -} - -QString MinecraftVersion::getUrl() const -{ - // legacy fallback - if(m_versionFileURL.isEmpty()) - { - return QString("http://") + URLConstants::AWS_DOWNLOAD_VERSIONS + m_version + "/" + m_version + ".json"; - } - // current - return m_versionFileURL; -} - -VersionFilePtr MinecraftVersion::getVersionFile() -{ - QFileInfo versionFile(QString("versions/%1/%1.dat").arg(m_version)); - m_problems.clear(); - if(!versionFile.exists()) - { - if(m_loadedVersionFile) - { - m_loadedVersionFile.reset(); - } - addProblem(PROBLEM_WARNING, QObject::tr("The patch file doesn't exist locally. It's possible it just needs to be downloaded.")); - } - else - { - try - { - if(versionFile.lastModified() != m_loadedVersionFileTimestamp) - { - auto loadedVersionFile = ProfileUtils::parseBinaryJsonFile(versionFile); - loadedVersionFile->name = "Minecraft"; - loadedVersionFile->setCustomizable(true); - m_loadedVersionFileTimestamp = versionFile.lastModified(); - m_loadedVersionFile = loadedVersionFile; - } - } - catch(Exception e) - { - m_loadedVersionFile.reset(); - addProblem(PROBLEM_ERROR, QObject::tr("The patch file couldn't be read:\n%1").arg(e.cause())); - } - } - return m_loadedVersionFile; -} - -bool MinecraftVersion::isCustomizable() -{ - switch(m_versionSource) - { - case Local: - case Remote: - // locally cached file, or a remote file that we can acquire can be customized - return true; - default: - // Everything else is undefined and therefore not customizable. - return false; - } - return false; -} - -const QList &MinecraftVersion::getProblems() -{ - if(getVersionFile()) - { - return getVersionFile()->getProblems(); - } - return ProfilePatch::getProblems(); -} - -ProblemSeverity MinecraftVersion::getProblemSeverity() -{ - if(getVersionFile()) - { - return getVersionFile()->getProblemSeverity(); - } - return ProfilePatch::getProblemSeverity(); -} - -void MinecraftVersion::applyTo(MinecraftProfile *profile) -{ - // do we have this one cached? - if (m_versionSource == Local) - { - applyFileTo(profile); - return; - } - throw VersionIncomplete(QObject::tr("Minecraft version %1 could not be applied: version files are missing.").arg(m_version)); -} - -int MinecraftVersion::getOrder() -{ - return order; -} - -void MinecraftVersion::setOrder(int order) -{ - this->order = order; -} - -QList MinecraftVersion::getJarMods() -{ - return QList(); -} - -QString MinecraftVersion::getName() -{ - return "Minecraft"; -} -QString MinecraftVersion::getVersion() -{ - return m_version; -} -QString MinecraftVersion::getID() -{ - return "net.minecraft"; -} -QString MinecraftVersion::getFilename() -{ - return QString(); -} -QDateTime MinecraftVersion::getReleaseDateTime() -{ - return m_releaseTime; -} - - -bool MinecraftVersion::needsUpdate() -{ - return m_versionSource == Remote || hasUpdate(); -} - -bool MinecraftVersion::hasUpdate() -{ - return m_versionSource == Remote || (m_versionSource == Local && upstreamUpdate); -} - -bool MinecraftVersion::isCustom() -{ - // if we add any other source types, this will evaluate to false for them. - return m_versionSource != Local && m_versionSource != Remote; -} diff --git a/logic/minecraft/MinecraftVersion.h b/logic/minecraft/MinecraftVersion.h deleted file mode 100644 index b21427d9..00000000 --- a/logic/minecraft/MinecraftVersion.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "BaseVersion.h" -#include "ProfilePatch.h" -#include "VersionFile.h" - -#include "multimc_logic_export.h" - -class MinecraftProfile; -class MinecraftVersion; -typedef std::shared_ptr MinecraftVersionPtr; - -class MULTIMC_LOGIC_EXPORT MinecraftVersion : public BaseVersion, public ProfilePatch -{ -friend class MinecraftVersionList; - -public: /* methods */ - // FIXME: nuke this. - bool usesLegacyLauncher(); - - virtual QString descriptor() override; - virtual QString name() override; - virtual QString typeString() const override; - virtual bool hasJarMods() override; - virtual bool isMinecraftVersion() override; - virtual void applyTo(MinecraftProfile *profile) override; - virtual int getOrder() override; - virtual void setOrder(int order) override; - virtual QList getJarMods() override; - virtual QString getID() override; - virtual QString getVersion() override; - virtual QString getName() override; - virtual QString getFilename() override; - QDateTime getReleaseDateTime() override; - VersionSource getVersionSource() override; - - bool needsUpdate(); - bool hasUpdate(); - virtual bool isCustom() override; - virtual bool isMoveable() override - { - return false; - } - virtual bool isCustomizable() override; - virtual bool isRemovable() override - { - return false; - } - virtual bool isRevertible() override - { - return false; - } - virtual bool isEditable() override - { - return false; - } - virtual bool isVersionChangeable() override - { - return true; - } - - virtual VersionFilePtr getVersionFile() override; - - // virtual QJsonDocument toJson(bool saveOrder) override; - - QString getUrl() const; - - virtual const QList &getProblems() override; - virtual ProblemSeverity getProblemSeverity() override; - -private: /* methods */ - void applyFileTo(MinecraftProfile *profile); - -protected: /* data */ - VersionSource m_versionSource = Remote; - - /// The URL that this version will be downloaded from. - QString m_versionFileURL; - - /// the human readable version name - QString m_version; - - /// The type of this release - QString m_type; - - /// the time this version was actually released by Mojang - QDateTime m_releaseTime; - - /// the time this version was last updated by Mojang - QDateTime m_updateTime; - - /// order of this file... default = -2 - int order = -2; - - /// an update available from Mojang - MinecraftVersionPtr upstreamUpdate; - - QDateTime m_loadedVersionFileTimestamp; - mutable VersionFilePtr m_loadedVersionFile; -}; diff --git a/logic/minecraft/MinecraftVersionList.cpp b/logic/minecraft/MinecraftVersionList.cpp deleted file mode 100644 index a5cc3a39..00000000 --- a/logic/minecraft/MinecraftVersionList.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/* Copyright 2013-2015 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 -#include "Json.h" -#include -#include - -#include "Env.h" -#include "Exception.h" - -#include "MinecraftVersionList.h" -#include "net/URLConstants.h" - -#include "ParseUtils.h" -#include "ProfileUtils.h" -#include "VersionFilterData.h" -#include "onesix/OneSixVersionFormat.h" -#include "MojangVersionFormat.h" -#include - -static const char * localVersionCache = "versions/versions.dat"; - -class MCVListLoadTask : public Task -{ - Q_OBJECT - -public: - explicit MCVListLoadTask(MinecraftVersionList *vlist); - virtual ~MCVListLoadTask() override{}; - - virtual void executeTask() override; - -protected -slots: - void list_downloaded(); - -protected: - QNetworkReply *vlistReply; - MinecraftVersionList *m_list; - MinecraftVersion *m_currentStable; -}; - -class MCVListVersionUpdateTask : public Task -{ - Q_OBJECT - -public: - explicit MCVListVersionUpdateTask(MinecraftVersionList *vlist, std::shared_ptr updatedVersion); - virtual ~MCVListVersionUpdateTask() override{}; - virtual void executeTask() override; - -protected -slots: - void json_downloaded(); - -protected: - NetJobPtr specificVersionDownloadJob; - std::shared_ptr updatedVersion; - MinecraftVersionList *m_list; -}; - -class ListLoadError : public Exception -{ -public: - ListLoadError(QString cause) : Exception(cause) {}; - virtual ~ListLoadError() noexcept - { - } -}; - -MinecraftVersionList::MinecraftVersionList(QObject *parent) : BaseVersionList(parent) -{ - loadCachedList(); -} - -Task *MinecraftVersionList::getLoadTask() -{ - return new MCVListLoadTask(this); -} - -bool MinecraftVersionList::isLoaded() -{ - return m_loaded; -} - -const BaseVersionPtr MinecraftVersionList::at(int i) const -{ - return m_vlist.at(i); -} - -int MinecraftVersionList::count() const -{ - return m_vlist.count(); -} - -static bool cmpVersions(BaseVersionPtr first, BaseVersionPtr second) -{ - auto left = std::dynamic_pointer_cast(first); - auto right = std::dynamic_pointer_cast(second); - return left->getReleaseDateTime() > right->getReleaseDateTime(); -} - -void MinecraftVersionList::sortInternal() -{ - qSort(m_vlist.begin(), m_vlist.end(), cmpVersions); -} - -void MinecraftVersionList::loadCachedList() -{ - QFile localIndex(localVersionCache); - if (!localIndex.exists()) - { - return; - } - if (!localIndex.open(QIODevice::ReadOnly)) - { - // FIXME: this is actually a very bad thing! How do we deal with this? - qCritical() << "The minecraft version cache can't be read."; - return; - } - auto data = localIndex.readAll(); - try - { - localIndex.close(); - QJsonDocument jsonDoc = QJsonDocument::fromBinaryData(data); - if (jsonDoc.isNull()) - { - throw ListLoadError(tr("Error reading the version list.")); - } - loadList(jsonDoc, Local); - } - catch (Exception &e) - { - // the cache has gone bad for some reason... flush it. - qCritical() << "The minecraft version cache is corrupted. Flushing cache."; - localIndex.remove(); - return; - } - m_hasLocalIndex = true; -} - -void MinecraftVersionList::loadList(QJsonDocument jsonDoc, VersionSource source) -{ - qDebug() << "Loading" << ((source == Remote) ? "remote" : "local") << "version list."; - - if (!jsonDoc.isObject()) - { - throw ListLoadError(tr("Error parsing version list JSON: jsonDoc is not an object")); - } - - QJsonObject root = jsonDoc.object(); - - try - { - QJsonObject latest = Json::requireObject(root.value("latest")); - m_latestReleaseID = Json::requireString(latest.value("release")); - m_latestSnapshotID = Json::requireString(latest.value("snapshot")); - } - catch (Exception &err) - { - qCritical() - << tr("Error parsing version list JSON: couldn't determine latest versions"); - } - - // Now, get the array of versions. - if (!root.value("versions").isArray()) - { - throw ListLoadError(tr("Error parsing version list JSON: version list object is " - "missing 'versions' array")); - } - QJsonArray versions = root.value("versions").toArray(); - - QList tempList; - for (auto version : versions) - { - // Load the version info. - if (!version.isObject()) - { - qCritical() << "Error while parsing version list : invalid JSON structure"; - continue; - } - - QJsonObject versionObj = version.toObject(); - QString versionID = versionObj.value("id").toString(""); - if (versionID.isEmpty()) - { - qCritical() << "Error while parsing version : version ID is missing"; - continue; - } - - if (g_VersionFilterData.legacyBlacklist.contains(versionID)) - { - qWarning() << "Blacklisted legacy version ignored: " << versionID; - continue; - } - - // Now, we construct the version object and add it to the list. - std::shared_ptr mcVersion(new MinecraftVersion()); - mcVersion->m_version = versionID; - - mcVersion->m_releaseTime = timeFromS3Time(versionObj.value("releaseTime").toString("")); - mcVersion->m_updateTime = timeFromS3Time(versionObj.value("time").toString("")); - - // depends on where we load the version from -- network request or local file? - mcVersion->m_versionSource = source; - mcVersion->m_versionFileURL = versionObj.value("url").toString(""); - QString versionTypeStr = versionObj.value("type").toString(""); - if (versionTypeStr.isEmpty()) - { - qCritical() << "Ignoring" << versionID - << "because it doesn't have the version type set."; - continue; - } - // OneSix or Legacy. use filter to determine type - if (versionTypeStr == "release") - { - } - else if (versionTypeStr == "snapshot") // It's a snapshot... yay - { - } - else if (versionTypeStr == "old_alpha") - { - } - else if (versionTypeStr == "old_beta") - { - } - else - { - qCritical() << "Ignoring" << versionID - << "because it has an invalid version type."; - continue; - } - mcVersion->m_type = versionTypeStr; - qDebug() << "Loaded version" << versionID << "from" - << ((source == Remote) ? "remote" : "local") << "version list."; - tempList.append(mcVersion); - } - updateListData(tempList); - if(source == Remote) - { - m_loaded = true; - } -} - -void MinecraftVersionList::sortVersions() -{ - beginResetModel(); - sortInternal(); - endResetModel(); -} - -QVariant MinecraftVersionList::data(const QModelIndex& index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (index.row() > count()) - return QVariant(); - - auto version = std::dynamic_pointer_cast(m_vlist[index.row()]); - switch (role) - { - case VersionPointerRole: - return qVariantFromValue(m_vlist[index.row()]); - - case VersionRole: - return version->name(); - - case VersionIdRole: - return version->descriptor(); - - case RecommendedRole: - return version->descriptor() == m_latestReleaseID; - - case LatestRole: - { - if(version->descriptor() != m_latestSnapshotID) - return false; - MinecraftVersionPtr latestRelease = std::dynamic_pointer_cast(getLatestStable()); - /* - if(latestRelease && latestRelease->m_releaseTime > version->m_releaseTime) - { - return false; - } - */ - return true; - } - - case TypeRole: - return version->typeString(); - - default: - return QVariant(); - } -} - -BaseVersionList::RoleList MinecraftVersionList::providesRoles() const -{ - return {VersionPointerRole, VersionRole, VersionIdRole, RecommendedRole, LatestRole, TypeRole}; -} - -BaseVersionPtr MinecraftVersionList::getLatestStable() const -{ - if(m_lookup.contains(m_latestReleaseID)) - return m_lookup[m_latestReleaseID]; - return BaseVersionPtr(); -} - -BaseVersionPtr MinecraftVersionList::getRecommended() const -{ - return getLatestStable(); -} - -void MinecraftVersionList::updateListData(QList versions) -{ - beginResetModel(); - for (auto version : versions) - { - auto descr = version->descriptor(); - - if (!m_lookup.contains(descr)) - { - m_lookup[version->descriptor()] = version; - m_vlist.append(version); - continue; - } - auto orig = std::dynamic_pointer_cast(m_lookup[descr]); - auto added = std::dynamic_pointer_cast(version); - // updateListData is called after Mojang list loads. those can be local or remote - // remote comes always after local - // any other options are ignored - if (orig->m_versionSource != Local || added->m_versionSource != Remote) - { - continue; - } - // alright, it's an update. put it inside the original, for further processing. - orig->upstreamUpdate = added; - } - sortInternal(); - endResetModel(); -} - -MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist) -{ - m_list = vlist; - m_currentStable = NULL; - vlistReply = nullptr; -} - -void MCVListLoadTask::executeTask() -{ - setStatus(tr("Loading instance version list...")); - auto worker = ENV.qnam(); - vlistReply = worker->get(QNetworkRequest(QUrl("https://launchermeta.mojang.com/mc/game/version_manifest.json"))); - connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded())); -} - -void MCVListLoadTask::list_downloaded() -{ - if (vlistReply->error() != QNetworkReply::NoError) - { - vlistReply->deleteLater(); - emitFailed("Failed to load Minecraft main version list" + vlistReply->errorString()); - return; - } - - auto data = vlistReply->readAll(); - vlistReply->deleteLater(); - try - { - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); - if (jsonError.error != QJsonParseError::NoError) - { - throw ListLoadError( - tr("Error parsing version list JSON: %1").arg(jsonError.errorString())); - } - m_list->loadList(jsonDoc, Remote); - } - catch (Exception &e) - { - emitFailed(e.cause()); - return; - } - - emitSucceeded(); - return; -} - -MCVListVersionUpdateTask::MCVListVersionUpdateTask(MinecraftVersionList *vlist, std::shared_ptr updatedVersion) - : Task() -{ - m_list = vlist; - this->updatedVersion = updatedVersion; -} - -void MCVListVersionUpdateTask::executeTask() -{ - auto job = new NetJob("Version index"); - job->addNetAction(ByteArrayDownload::make(QUrl(updatedVersion->getUrl()))); - specificVersionDownloadJob.reset(job); - connect(specificVersionDownloadJob.get(), SIGNAL(succeeded()), SLOT(json_downloaded())); - connect(specificVersionDownloadJob.get(), SIGNAL(failed(QString)), SIGNAL(failed(QString))); - connect(specificVersionDownloadJob.get(), SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64))); - specificVersionDownloadJob->start(); -} - -void MCVListVersionUpdateTask::json_downloaded() -{ - NetActionPtr DlJob = specificVersionDownloadJob->first(); - auto data = std::dynamic_pointer_cast(DlJob)->m_data; - specificVersionDownloadJob.reset(); - - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); - - if (jsonError.error != QJsonParseError::NoError) - { - emitFailed(tr("The download version file is not valid.")); - return; - } - VersionFilePtr file; - try - { - file = MojangVersionFormat::versionFileFromJson(jsonDoc, "net.minecraft.json"); - } - catch (Exception &e) - { - emitFailed(tr("Couldn't process version file: %1").arg(e.cause())); - return; - } - - // Strip LWJGL from the version file. We use our own. - ProfileUtils::removeLwjglFromPatch(file); - - file->fileId = "net.minecraft"; - - // now dump the file to disk - auto doc = OneSixVersionFormat::versionFileToJson(file, false); - auto newdata = doc.toBinaryData(); - auto id = updatedVersion->descriptor(); - QString targetPath = "versions/" + id + "/" + id + ".dat"; - FS::ensureFilePathExists(targetPath); - QSaveFile vfile1(targetPath); - if (!vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly)) - { - emitFailed(tr("Can't open %1 for writing.").arg(targetPath)); - return; - } - qint64 actual = 0; - if ((actual = vfile1.write(newdata)) != newdata.size()) - { - emitFailed(tr("Failed to write into %1. Written %2 out of %3.") - .arg(targetPath) - .arg(actual) - .arg(newdata.size())); - return; - } - if (!vfile1.commit()) - { - emitFailed(tr("Can't commit changes to %1").arg(targetPath)); - return; - } - - m_list->finalizeUpdate(id); - emitSucceeded(); -} - -std::shared_ptr MinecraftVersionList::createUpdateTask(QString version) -{ - auto iter = m_lookup.find(version); - if(iter == m_lookup.end()) - return nullptr; - - auto mcversion = std::dynamic_pointer_cast(*iter); - if(!mcversion) - { - return nullptr; - } - - return std::shared_ptr(new MCVListVersionUpdateTask(this, mcversion)); -} - -void MinecraftVersionList::saveCachedList() -{ - // FIXME: throw. - if (!FS::ensureFilePathExists(localVersionCache)) - return; - QSaveFile tfile(localVersionCache); - if (!tfile.open(QIODevice::WriteOnly | QIODevice::Truncate)) - return; - QJsonObject toplevel; - QJsonArray entriesArr; - for (auto version : m_vlist) - { - auto mcversion = std::dynamic_pointer_cast(version); - // do not save the remote versions. - if (mcversion->m_versionSource != Local) - continue; - QJsonObject entryObj; - - entryObj.insert("id", mcversion->descriptor()); - entryObj.insert("version", mcversion->descriptor()); - entryObj.insert("time", timeToS3Time(mcversion->m_updateTime)); - entryObj.insert("releaseTime", timeToS3Time(mcversion->m_releaseTime)); - entryObj.insert("url", mcversion->m_versionFileURL); - entryObj.insert("type", mcversion->m_type); - entriesArr.append(entryObj); - } - toplevel.insert("versions", entriesArr); - - { - bool someLatest = false; - QJsonObject latestObj; - if(!m_latestReleaseID.isNull()) - { - latestObj.insert("release", m_latestReleaseID); - someLatest = true; - } - if(!m_latestSnapshotID.isNull()) - { - latestObj.insert("snapshot", m_latestSnapshotID); - someLatest = true; - } - if(someLatest) - { - toplevel.insert("latest", latestObj); - } - } - - QJsonDocument doc(toplevel); - QByteArray jsonData = doc.toBinaryData(); - qint64 result = tfile.write(jsonData); - if (result == -1) - return; - if (result != jsonData.size()) - return; - tfile.commit(); -} - -void MinecraftVersionList::finalizeUpdate(QString version) -{ - int idx = -1; - for (int i = 0; i < m_vlist.size(); i++) - { - if (version == m_vlist[i]->descriptor()) - { - idx = i; - break; - } - } - if (idx == -1) - { - return; - } - - auto updatedVersion = std::dynamic_pointer_cast(m_vlist[idx]); - - // if we have an update for the version, replace it, make the update local - if (updatedVersion->upstreamUpdate) - { - auto updatedWith = updatedVersion->upstreamUpdate; - updatedWith->m_versionSource = Local; - m_vlist[idx] = updatedWith; - m_lookup[version] = updatedWith; - } - else - { - // otherwise, just set the version as local; - updatedVersion->m_versionSource = Local; - } - - dataChanged(index(idx), index(idx)); - - saveCachedList(); -} - -#include "MinecraftVersionList.moc" diff --git a/logic/minecraft/MinecraftVersionList.h b/logic/minecraft/MinecraftVersionList.h deleted file mode 100644 index 0fca02a7..00000000 --- a/logic/minecraft/MinecraftVersionList.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "BaseVersionList.h" -#include "tasks/Task.h" -#include "minecraft/MinecraftVersion.h" -#include - -#include "multimc_logic_export.h" - -class MCVListLoadTask; -class MCVListVersionUpdateTask; - -class MULTIMC_LOGIC_EXPORT MinecraftVersionList : public BaseVersionList -{ - Q_OBJECT -private: - void sortInternal(); - void loadList(QJsonDocument jsonDoc, VersionSource source); - void loadCachedList(); - void saveCachedList(); - void finalizeUpdate(QString version); -public: - friend class MCVListLoadTask; - friend class MCVListVersionUpdateTask; - - explicit MinecraftVersionList(QObject *parent = 0); - - std::shared_ptr createUpdateTask(QString version); - - virtual Task *getLoadTask() override; - virtual bool isLoaded() override; - virtual const BaseVersionPtr at(int i) const override; - virtual int count() const override; - virtual void sortVersions() override; - virtual QVariant data(const QModelIndex & index, int role) const override; - virtual RoleList providesRoles() const override; - - virtual BaseVersionPtr getLatestStable() const override; - virtual BaseVersionPtr getRecommended() const override; - -protected: - QList m_vlist; - QMap m_lookup; - - bool m_loaded = false; - bool m_hasLocalIndex = false; - QString m_latestReleaseID = "INVALID"; - QString m_latestSnapshotID = "INVALID"; - -protected -slots: - virtual void updateListData(QList versions) override; -}; diff --git a/logic/minecraft/Mod.cpp b/logic/minecraft/Mod.cpp deleted file mode 100644 index 9b9f76f9..00000000 --- a/logic/minecraft/Mod.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* Copyright 2013-2015 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 -#include -#include -#include -#include -#include -#include -#include - -#include "Mod.h" -#include "settings/INIFile.h" -#include -#include - -Mod::Mod(const QFileInfo &file) -{ - repath(file); -} - -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(); -} diff --git a/logic/minecraft/Mod.h b/logic/minecraft/Mod.h deleted file mode 100644 index 19f4c740..00000000 --- a/logic/minecraft/Mod.h +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include - -class Mod -{ -public: - enum ModType - { - MOD_UNKNOWN, //!< Indicates an unspecified mod type. - MOD_ZIPFILE, //!< The mod is a zip file containing the mod's class files. - MOD_SINGLEFILE, //!< The mod is a single file (not a zip file). - MOD_FOLDER, //!< The mod is in a folder on the filesystem. - MOD_LITEMOD, //!< The mod is a litemod - }; - - Mod(const QFileInfo &file); - - QFileInfo filename() const - { - return m_file; - } - QString mmc_id() const - { - return m_mmc_id; - } - QString mod_id() const - { - return m_mod_id; - } - ModType type() const - { - return m_type; - } - QString mcversion() const - { - return m_mcversion; - } - ; - bool valid() - { - return m_type != MOD_UNKNOWN; - } - QString name() const - { - if(m_name.trimmed().isEmpty()) - { - return m_mmc_id; - } - return m_name; - } - - QString version() const; - - QString homeurl() const - { - return m_homeurl; - } - - QString description() const - { - return m_description; - } - - QString authors() const - { - return m_authors; - } - - QString credits() const - { - return m_credits; - } - - bool enabled() const - { - return m_enabled; - } - - bool enable(bool value); - - // delete all the files of this mod - bool destroy(); - // replace this mod with a copy of the other - bool replace(Mod &with); - // change the mod's filesystem path (used by mod lists for *MAGIC* purposes) - void repath(const QFileInfo &file); - - // WEAK compare operator - used for replacing mods - bool operator==(const Mod &other) const; - bool strongCompare(const Mod &other) const; - -private: - void ReadMCModInfo(QByteArray contents); - void ReadForgeInfo(QByteArray contents); - void ReadLiteModInfo(QByteArray contents); - -protected: - - // FIXME: what do do with those? HMM... - /* - void ReadModInfoData(QString info); - void ReadForgeInfoData(QString infoFileData); - */ - - QFileInfo m_file; - QString m_mmc_id; - QString m_mod_id; - bool m_enabled = true; - QString m_name; - QString m_version; - QString m_mcversion; - QString m_homeurl; - QString m_updateurl; - QString m_description; - QString m_authors; - QString m_credits; - - ModType m_type; -}; diff --git a/logic/minecraft/ModList.cpp b/logic/minecraft/ModList.cpp deleted file mode 100644 index d9ed4886..00000000 --- a/logic/minecraft/ModList.cpp +++ /dev/null @@ -1,616 +0,0 @@ -/* Copyright 2013-2015 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 "ModList.h" -#include -#include -#include -#include -#include -#include -#include - -ModList::ModList(const QString &dir, const QString &list_file) - : QAbstractListModel(), m_dir(dir), m_list_file(list_file) -{ - FS::ensureFolderPathExists(m_dir.absolutePath()); - m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs | - QDir::NoSymLinks); - m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); - m_list_id = QUuid::createUuid().toString(); - m_watcher = new QFileSystemWatcher(this); - is_watching = false; - connect(m_watcher, SIGNAL(directoryChanged(QString)), this, - SLOT(directoryChanged(QString))); -} - -void ModList::startWatching() -{ - update(); - is_watching = m_watcher->addPath(m_dir.absolutePath()); - if (is_watching) - { - qDebug() << "Started watching " << m_dir.absolutePath(); - } - else - { - qDebug() << "Failed to start watching " << m_dir.absolutePath(); - } -} - -void ModList::stopWatching() -{ - is_watching = !m_watcher->removePath(m_dir.absolutePath()); - if (!is_watching) - { - qDebug() << "Stopped watching " << m_dir.absolutePath(); - } - else - { - qDebug() << "Failed to stop watching " << m_dir.absolutePath(); - } -} - -void ModList::internalSort(QList &what) -{ - auto predicate = [](const Mod &left, const Mod &right) - { - if (left.name() == right.name()) - { - return left.mmc_id().localeAwareCompare(right.mmc_id()) < 0; - } - return left.name().localeAwareCompare(right.name()) < 0; - }; - std::sort(what.begin(), what.end(), predicate); -} - -bool ModList::update() -{ - if (!isValid()) - return false; - - QList orderedMods; - QList newMods; - m_dir.refresh(); - auto folderContents = m_dir.entryInfoList(); - bool orderOrStateChanged = false; - - // first, process the ordered items (if any) - OrderList listOrder = readListFile(); - for (auto item : listOrder) - { - QFileInfo infoEnabled(m_dir.filePath(item.id)); - QFileInfo infoDisabled(m_dir.filePath(item.id + ".disabled")); - int idxEnabled = folderContents.indexOf(infoEnabled); - int idxDisabled = folderContents.indexOf(infoDisabled); - bool isEnabled; - // if both enabled and disabled versions are present, it's a special case... - if (idxEnabled >= 0 && idxDisabled >= 0) - { - // we only process the one we actually have in the order file. - // and exactly as we have it. - // THIS IS A CORNER CASE - isEnabled = item.enabled; - } - else - { - // only one is present. - // we pick the one that we found. - // we assume the mod was enabled/disabled by external means - isEnabled = idxEnabled >= 0; - } - int idx = isEnabled ? idxEnabled : idxDisabled; - QFileInfo &info = isEnabled ? infoEnabled : infoDisabled; - // if the file from the index file exists - if (idx != -1) - { - // remove from the actual folder contents list - folderContents.takeAt(idx); - // append the new mod - orderedMods.append(Mod(info)); - if (isEnabled != item.enabled) - orderOrStateChanged = true; - } - else - { - orderOrStateChanged = true; - } - } - // if there are any untracked files... - if (folderContents.size()) - { - // the order surely changed! - for (auto entry : folderContents) - { - newMods.append(Mod(entry)); - } - internalSort(newMods); - orderedMods.append(newMods); - orderOrStateChanged = true; - } - // otherwise, if we were already tracking some mods - else if (mods.size()) - { - // if the number doesn't match, order changed. - if (mods.size() != orderedMods.size()) - orderOrStateChanged = true; - // if it does match, compare the mods themselves - else - for (int i = 0; i < mods.size(); i++) - { - if (!mods[i].strongCompare(orderedMods[i])) - { - orderOrStateChanged = true; - break; - } - } - } - beginResetModel(); - mods.swap(orderedMods); - endResetModel(); - if (orderOrStateChanged && !m_list_file.isEmpty()) - { - qDebug() << "Mod list " << m_list_file << " changed!"; - saveListFile(); - emit changed(); - } - return true; -} - -void ModList::directoryChanged(QString path) -{ - update(); -} - -ModList::OrderList ModList::readListFile() -{ - OrderList itemList; - if (m_list_file.isNull() || m_list_file.isEmpty()) - return itemList; - - QFile textFile(m_list_file); - if (!textFile.open(QIODevice::ReadOnly | QIODevice::Text)) - return OrderList(); - - QTextStream textStream; - textStream.setAutoDetectUnicode(true); - textStream.setDevice(&textFile); - while (true) - { - QString line = textStream.readLine(); - if (line.isNull() || line.isEmpty()) - break; - else - { - OrderItem it; - it.enabled = !line.endsWith(".disabled"); - if (!it.enabled) - { - line.chop(9); - } - it.id = line; - itemList.append(it); - } - } - textFile.close(); - return itemList; -} - -bool ModList::saveListFile() -{ - if (m_list_file.isNull() || m_list_file.isEmpty()) - return false; - QFile textFile(m_list_file); - if (!textFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) - return false; - QTextStream textStream; - textStream.setGenerateByteOrderMark(true); - textStream.setCodec("UTF-8"); - textStream.setDevice(&textFile); - for (auto mod : mods) - { - textStream << mod.mmc_id(); - if (!mod.enabled()) - textStream << ".disabled"; - textStream << endl; - } - textFile.close(); - return false; -} - -bool ModList::isValid() -{ - return m_dir.exists() && m_dir.isReadable(); -} - -bool ModList::installMod(const QString &filename, int index) -{ - // NOTE: fix for GH-1178: remove trailing slash to avoid issues with using the empty result of QFileInfo::fileName - QFileInfo fileinfo(FS::NormalizePath(filename)); - - qDebug() << "installing: " << fileinfo.absoluteFilePath(); - - if (!fileinfo.exists() || !fileinfo.isReadable() || index < 0) - { - return false; - } - Mod m(fileinfo); - if (!m.valid()) - return false; - - // if it's already there, replace the original mod (in place) - int idx = mods.indexOf(m); - if (idx != -1) - { - int idx2 = mods.indexOf(m, idx + 1); - if (idx2 != -1) - return false; - if (mods[idx].replace(m)) - { - - auto left = this->index(index); - auto right = this->index(index, columnCount(QModelIndex()) - 1); - emit dataChanged(left, right); - saveListFile(); - update(); - return true; - } - return false; - } - - auto type = m.type(); - if (type == Mod::MOD_UNKNOWN) - return false; - if (type == Mod::MOD_SINGLEFILE || type == Mod::MOD_ZIPFILE || type == Mod::MOD_LITEMOD) - { - QString newpath = FS::PathCombine(m_dir.path(), fileinfo.fileName()); - if (!QFile::copy(fileinfo.filePath(), newpath)) - return false; - m.repath(newpath); - beginInsertRows(QModelIndex(), index, index); - mods.insert(index, m); - endInsertRows(); - saveListFile(); - update(); - return true; - } - else if (type == Mod::MOD_FOLDER) - { - - QString from = fileinfo.filePath(); - QString to = FS::PathCombine(m_dir.path(), fileinfo.fileName()); - if (!FS::copy(from, to)()) - return false; - m.repath(to); - beginInsertRows(QModelIndex(), index, index); - mods.insert(index, m); - endInsertRows(); - saveListFile(); - update(); - return true; - } - return false; -} - -bool ModList::deleteMod(int index) -{ - if (index >= mods.size() || index < 0) - return false; - Mod &m = mods[index]; - if (m.destroy()) - { - beginRemoveRows(QModelIndex(), index, index); - mods.removeAt(index); - endRemoveRows(); - saveListFile(); - emit changed(); - return true; - } - return false; -} - -bool ModList::deleteMods(int first, int last) -{ - for (int i = first; i <= last; i++) - { - Mod &m = mods[i]; - m.destroy(); - } - beginRemoveRows(QModelIndex(), first, last); - mods.erase(mods.begin() + first, mods.begin() + last + 1); - endRemoveRows(); - saveListFile(); - emit changed(); - return true; -} - -bool ModList::moveModTo(int from, int to) -{ - if (from < 0 || from >= mods.size()) - return false; - if (to >= rowCount()) - to = rowCount() - 1; - if (to == -1) - to = rowCount() - 1; - if (from == to) - return false; - int togap = to > from ? to + 1 : to; - beginMoveRows(QModelIndex(), from, from, QModelIndex(), togap); - mods.move(from, to); - endMoveRows(); - saveListFile(); - emit changed(); - return true; -} - -bool ModList::moveModUp(int from) -{ - if (from > 0) - return moveModTo(from, from - 1); - return false; -} - -bool ModList::moveModsUp(int first, int last) -{ - if (first == 0) - return false; - - beginMoveRows(QModelIndex(), first, last, QModelIndex(), first - 1); - mods.move(first - 1, last); - endMoveRows(); - saveListFile(); - emit changed(); - return true; -} - -bool ModList::moveModDown(int from) -{ - if (from < 0) - return false; - if (from < mods.size() - 1) - return moveModTo(from, from + 1); - return false; -} - -bool ModList::moveModsDown(int first, int last) -{ - if (last == mods.size() - 1) - return false; - - beginMoveRows(QModelIndex(), first, last, QModelIndex(), last + 2); - mods.move(last + 1, first); - endMoveRows(); - saveListFile(); - emit changed(); - return true; -} - -int ModList::columnCount(const QModelIndex &parent) const -{ - return 3; -} - -QVariant ModList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - int row = index.row(); - int column = index.column(); - - if (row < 0 || row >= mods.size()) - return QVariant(); - - switch (role) - { - case Qt::DisplayRole: - switch (column) - { - case NameColumn: - return mods[row].name(); - case VersionColumn: - return mods[row].version(); - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - return mods[row].mmc_id(); - - case Qt::CheckStateRole: - switch (column) - { - case ActiveColumn: - return mods[row].enabled() ? Qt::Checked : Qt::Unchecked; - default: - return QVariant(); - } - default: - return QVariant(); - } -} - -bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) -{ - if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid()) - { - return false; - } - - if (role == Qt::CheckStateRole) - { - auto &mod = mods[index.row()]; - if (mod.enable(!mod.enabled())) - { - emit dataChanged(index, index); - return true; - } - } - return false; -} - -QVariant ModList::headerData(int section, Qt::Orientation orientation, int role) const -{ - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case ActiveColumn: - return QString(); - case NameColumn: - return tr("Name"); - case VersionColumn: - return tr("Version"); - default: - return QVariant(); - } - - case Qt::ToolTipRole: - switch (section) - { - case ActiveColumn: - return tr("Is the mod enabled?"); - case NameColumn: - return tr("The name of the mod."); - case VersionColumn: - return tr("The version of the mod."); - default: - return QVariant(); - } - default: - return QVariant(); - } - return QVariant(); -} - -Qt::ItemFlags ModList::flags(const QModelIndex &index) const -{ - Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); - if (index.isValid()) - return Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | - defaultFlags; - else - return Qt::ItemIsDropEnabled | defaultFlags; -} - -QStringList ModList::mimeTypes() const -{ - QStringList types; - types << "text/uri-list"; - types << "text/plain"; - return types; -} - -Qt::DropActions ModList::supportedDropActions() const -{ - // copy from outside, move from within and other mod lists - return Qt::CopyAction | Qt::MoveAction; -} - -Qt::DropActions ModList::supportedDragActions() const -{ - // move to other mod lists or VOID - return Qt::MoveAction; -} - -QMimeData *ModList::mimeData(const QModelIndexList &indexes) const -{ - QMimeData *data = new QMimeData(); - - if (indexes.size() == 0) - return data; - - auto idx = indexes[0]; - int row = idx.row(); - if (row < 0 || row >= mods.size()) - return data; - - QStringList params; - params << m_list_id << QString::number(row); - data->setText(params.join('|')); - return data; -} - -bool ModList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, - const QModelIndex &parent) -{ - if (action == Qt::IgnoreAction) - return true; - // check if the action is supported - if (!data || !(action & supportedDropActions())) - return false; - if (parent.isValid()) - { - row = parent.row(); - column = parent.column(); - } - - if (row > rowCount()) - row = rowCount(); - if (row == -1) - row = rowCount(); - if (column == -1) - column = 0; - qDebug() << "Drop row: " << row << " column: " << column; - - // files dropped from outside? - if (data->hasUrls()) - { - bool was_watching = is_watching; - if (was_watching) - stopWatching(); - auto urls = data->urls(); - for (auto url : urls) - { - // only local files may be dropped... - if (!url.isLocalFile()) - continue; - QString filename = url.toLocalFile(); - installMod(filename, row); - // if there is no ordering, re-sort the list - if (m_list_file.isEmpty()) - { - beginResetModel(); - internalSort(mods); - endResetModel(); - } - } - if (was_watching) - startWatching(); - return true; - } - else if (data->hasText()) - { - QString sourcestr = data->text(); - auto list = sourcestr.split('|'); - if (list.size() != 2) - return false; - QString remoteId = list[0]; - int remoteIndex = list[1].toInt(); - qDebug() << "move: " << sourcestr; - // no moving of things between two lists - if (remoteId != m_list_id) - return false; - // no point moving to the same place... - if (row == remoteIndex) - return false; - // otherwise, move the mod :D - moveModTo(remoteIndex, row); - return true; - } - return false; -} diff --git a/logic/minecraft/ModList.h b/logic/minecraft/ModList.h deleted file mode 100644 index 05ada8ee..00000000 --- a/logic/minecraft/ModList.h +++ /dev/null @@ -1,160 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include "minecraft/Mod.h" - -#include "multimc_logic_export.h" - -class LegacyInstance; -class BaseInstance; -class QFileSystemWatcher; - -/** - * A legacy mod list. - * Backed by a folder. - */ -class MULTIMC_LOGIC_EXPORT ModList : public QAbstractListModel -{ - Q_OBJECT -public: - enum Columns - { - ActiveColumn = 0, - NameColumn, - VersionColumn - }; - ModList(const QString &dir, const QString &list_file = QString()); - - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, - int role = Qt::EditRole); - - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const - { - return size(); - } - ; - virtual QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - virtual int columnCount(const QModelIndex &parent) const; - - size_t size() const - { - return mods.size(); - } - ; - bool empty() const - { - return size() == 0; - } - Mod &operator[](size_t index) - { - return mods[index]; - } - - /// Reloads the mod list and returns true if the list changed. - virtual bool update(); - - /** - * Adds the given mod to the list at the given index - if the list supports custom ordering - */ - virtual bool installMod(const QString & filename, int index = 0); - - /// Deletes the mod at the given index. - virtual bool deleteMod(int index); - - /// Deletes all the selected mods - virtual bool deleteMods(int first, int last); - - /** - * move the mod at index to the position N - * 0 is the beginning of the list, length() is the end of the list. - */ - virtual bool moveModTo(int from, int to); - - /** - * move the mod at index one position upwards - */ - virtual bool moveModUp(int from); - virtual bool moveModsUp(int first, int last); - - /** - * move the mod at index one position downwards - */ - virtual bool moveModDown(int from); - virtual bool moveModsDown(int first, int last); - - /// flags, mostly to support drag&drop - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - /// get data for drag action - virtual QMimeData *mimeData(const QModelIndexList &indexes) const; - /// get the supported mime types - virtual QStringList mimeTypes() const; - /// process data from drop action - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, - const QModelIndex &parent); - /// what drag actions do we support? - virtual Qt::DropActions supportedDragActions() const; - - /// what drop actions do we support? - virtual Qt::DropActions supportedDropActions() const; - - void startWatching(); - void stopWatching(); - - virtual bool isValid(); - - QDir dir() - { - return m_dir; - } - - const QList & allMods() - { - return mods; - } - -private: - void internalSort(QList & what); - struct OrderItem - { - QString id; - bool enabled = false; - }; - typedef QList OrderList; - OrderList readListFile(); - bool saveListFile(); -private -slots: - void directoryChanged(QString path); - -signals: - void changed(); - -protected: - QFileSystemWatcher *m_watcher; - bool is_watching; - QDir m_dir; - QString m_list_file; - QString m_list_id; - QList mods; -}; diff --git a/logic/minecraft/MojangDownloadInfo.h b/logic/minecraft/MojangDownloadInfo.h deleted file mode 100644 index 1f3306e0..00000000 --- a/logic/minecraft/MojangDownloadInfo.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -#include -#include -#include - -struct MojangDownloadInfo -{ - // types - typedef std::shared_ptr Ptr; - - // data - /// Local filesystem path. WARNING: not used, only here so we can pass through mojang files unmolested! - QString path; - /// absolute URL of this file - QString url; - /// sha-1 checksum of the file - QString sha1; - /// size of the file in bytes - int size; -}; - - - -struct MojangLibraryDownloadInfo -{ - MojangLibraryDownloadInfo(MojangDownloadInfo::Ptr artifact): artifact(artifact) {}; - MojangLibraryDownloadInfo() {}; - - // types - typedef std::shared_ptr Ptr; - - // methods - MojangDownloadInfo *getDownloadInfo(QString classifier) - { - if (classifier.isNull()) - { - return artifact.get(); - } - - return classifiers[classifier].get(); - } - - // data - MojangDownloadInfo::Ptr artifact; - QMap classifiers; -}; - - - -struct MojangAssetIndexInfo : public MojangDownloadInfo -{ - // types - typedef std::shared_ptr Ptr; - - // methods - MojangAssetIndexInfo() - { - } - - MojangAssetIndexInfo(QString id) - { - this->id = id; - url = "https://s3.amazonaws.com/Minecraft.Download/indexes/" + id + ".json"; - known = false; - } - - // data - int totalSize; - QString id; - bool known = true; -}; diff --git a/logic/minecraft/MojangVersionFormat.cpp b/logic/minecraft/MojangVersionFormat.cpp deleted file mode 100644 index 34129c9e..00000000 --- a/logic/minecraft/MojangVersionFormat.cpp +++ /dev/null @@ -1,381 +0,0 @@ -#include "MojangVersionFormat.h" -#include "onesix/OneSixVersionFormat.h" -#include "MinecraftVersion.h" -#include "VersionBuildError.h" -#include "MojangDownloadInfo.h" - -#include "Json.h" -using namespace Json; -#include "ParseUtils.h" - -static const int CURRENT_MINIMUM_LAUNCHER_VERSION = 18; - -static MojangAssetIndexInfo::Ptr assetIndexFromJson (const QJsonObject &obj); -static MojangDownloadInfo::Ptr downloadInfoFromJson (const QJsonObject &obj); -static MojangLibraryDownloadInfo::Ptr libDownloadInfoFromJson (const QJsonObject &libObj); -static QJsonObject assetIndexToJson (MojangAssetIndexInfo::Ptr assetidxinfo); -static QJsonObject libDownloadInfoToJson (MojangLibraryDownloadInfo::Ptr libinfo); -static QJsonObject downloadInfoToJson (MojangDownloadInfo::Ptr info); - -namespace Bits -{ -static void readString(const QJsonObject &root, const QString &key, QString &variable) -{ - if (root.contains(key)) - { - variable = requireString(root.value(key)); - } -} - -static void readDownloadInfo(MojangDownloadInfo::Ptr out, const QJsonObject &obj) -{ - // optional, not used - readString(obj, "path", out->path); - // required! - out->sha1 = requireString(obj, "sha1"); - out->url = requireString(obj, "url"); - out->size = requireInteger(obj, "size"); -} - -static void readAssetIndex(MojangAssetIndexInfo::Ptr out, const QJsonObject &obj) -{ - out->totalSize = requireInteger(obj, "totalSize"); - out->id = requireString(obj, "id"); - // out->known = true; -} -} - -MojangDownloadInfo::Ptr downloadInfoFromJson(const QJsonObject &obj) -{ - auto out = std::make_shared(); - Bits::readDownloadInfo(out, obj); - return out; -} - -MojangAssetIndexInfo::Ptr assetIndexFromJson(const QJsonObject &obj) -{ - auto out = std::make_shared(); - Bits::readDownloadInfo(out, obj); - Bits::readAssetIndex(out, obj); - return out; -} - -QJsonObject downloadInfoToJson(MojangDownloadInfo::Ptr info) -{ - QJsonObject out; - if(!info->path.isNull()) - { - out.insert("path", info->path); - } - out.insert("sha1", info->sha1); - out.insert("size", info->size); - out.insert("url", info->url); - return out; -} - -MojangLibraryDownloadInfo::Ptr libDownloadInfoFromJson(const QJsonObject &libObj) -{ - auto out = std::make_shared(); - auto dlObj = requireObject(libObj.value("downloads")); - if(dlObj.contains("artifact")) - { - out->artifact = downloadInfoFromJson(requireObject(dlObj, "artifact")); - } - if(dlObj.contains("classifiers")) - { - auto classifiersObj = requireObject(dlObj, "classifiers"); - for(auto iter = classifiersObj.begin(); iter != classifiersObj.end(); iter++) - { - auto classifier = iter.key(); - auto classifierObj = requireObject(iter.value()); - out->classifiers[classifier] = downloadInfoFromJson(classifierObj); - } - } - return out; -} - -QJsonObject libDownloadInfoToJson(MojangLibraryDownloadInfo::Ptr libinfo) -{ - QJsonObject out; - if(libinfo->artifact) - { - out.insert("artifact", downloadInfoToJson(libinfo->artifact)); - } - if(libinfo->classifiers.size()) - { - QJsonObject classifiersOut; - for(auto iter = libinfo->classifiers.begin(); iter != libinfo->classifiers.end(); iter++) - { - classifiersOut.insert(iter.key(), downloadInfoToJson(iter.value())); - } - out.insert("classifiers", classifiersOut); - } - return out; -} - -QJsonObject assetIndexToJson(MojangAssetIndexInfo::Ptr info) -{ - QJsonObject out; - if(!info->path.isNull()) - { - out.insert("path", info->path); - } - out.insert("sha1", info->sha1); - out.insert("size", info->size); - out.insert("url", info->url); - out.insert("totalSize", info->totalSize); - out.insert("id", info->id); - return out; -} - -void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFile *out) -{ - Bits::readString(in, "id", out->minecraftVersion); - Bits::readString(in, "mainClass", out->mainClass); - Bits::readString(in, "minecraftArguments", out->minecraftArguments); - if(out->minecraftArguments.isEmpty()) - { - QString processArguments; - Bits::readString(in, "processArguments", processArguments); - QString toCompare = processArguments.toLower(); - if (toCompare == "legacy") - { - out->minecraftArguments = " ${auth_player_name} ${auth_session}"; - } - else if (toCompare == "username_session") - { - out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}"; - } - else if (toCompare == "username_session_version") - { - out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}"; - } - else if (!toCompare.isEmpty()) - { - out->addProblem(PROBLEM_ERROR, QObject::tr("processArguments is set to unknown value '%1'").arg(processArguments)); - } - } - Bits::readString(in, "type", out->type); - - Bits::readString(in, "assets", out->assets); - if(in.contains("assetIndex")) - { - out->mojangAssetIndex = assetIndexFromJson(requireObject(in, "assetIndex")); - } - else if (!out->assets.isNull()) - { - out->mojangAssetIndex = std::make_shared(out->assets); - } - - out->m_releaseTime = timeFromS3Time(in.value("releaseTime").toString("")); - out->m_updateTime = timeFromS3Time(in.value("time").toString("")); - - if (in.contains("minimumLauncherVersion")) - { - out->minimumLauncherVersion = requireInteger(in.value("minimumLauncherVersion")); - if (out->minimumLauncherVersion > CURRENT_MINIMUM_LAUNCHER_VERSION) - { - out->addProblem( - PROBLEM_WARNING, - QObject::tr("The 'minimumLauncherVersion' value of this version (%1) is higher than supported by MultiMC (%2). It might not work properly!") - .arg(out->minimumLauncherVersion) - .arg(CURRENT_MINIMUM_LAUNCHER_VERSION)); - } - } - if(in.contains("downloads")) - { - auto downloadsObj = requireObject(in, "downloads"); - for(auto iter = downloadsObj.begin(); iter != downloadsObj.end(); iter++) - { - auto classifier = iter.key(); - auto classifierObj = requireObject(iter.value()); - out->mojangDownloads[classifier] = downloadInfoFromJson(classifierObj); - } - } -} - -VersionFilePtr MojangVersionFormat::versionFileFromJson(const QJsonDocument &doc, const QString &filename) -{ - VersionFilePtr out(new VersionFile()); - if (doc.isEmpty() || doc.isNull()) - { - throw JSONValidationError(filename + " is empty or null"); - } - if (!doc.isObject()) - { - throw JSONValidationError(filename + " is not an object"); - } - - QJsonObject root = doc.object(); - - readVersionProperties(root, out.get()); - - out->name = "Minecraft"; - out->fileId = "net.minecraft"; - out->version = out->minecraftVersion; - out->filename = filename; - - - if (root.contains("libraries")) - { - for (auto libVal : requireArray(root.value("libraries"))) - { - auto libObj = requireObject(libVal); - - auto lib = MojangVersionFormat::libraryFromJson(libObj, filename); - out->libraries.append(lib); - } - } - return out; -} - -void MojangVersionFormat::writeVersionProperties(const VersionFile* in, QJsonObject& out) -{ - writeString(out, "id", in->minecraftVersion); - writeString(out, "mainClass", in->mainClass); - writeString(out, "minecraftArguments", in->minecraftArguments); - writeString(out, "type", in->type); - if(!in->m_releaseTime.isNull()) - { - writeString(out, "releaseTime", timeToS3Time(in->m_releaseTime)); - } - if(!in->m_updateTime.isNull()) - { - writeString(out, "time", timeToS3Time(in->m_updateTime)); - } - if(in->minimumLauncherVersion != -1) - { - out.insert("minimumLauncherVersion", in->minimumLauncherVersion); - } - writeString(out, "assets", in->assets); - if(in->mojangAssetIndex && in->mojangAssetIndex->known) - { - out.insert("assetIndex", assetIndexToJson(in->mojangAssetIndex)); - } - if(in->mojangDownloads.size()) - { - QJsonObject downloadsOut; - for(auto iter = in->mojangDownloads.begin(); iter != in->mojangDownloads.end(); iter++) - { - downloadsOut.insert(iter.key(), downloadInfoToJson(iter.value())); - } - out.insert("downloads", downloadsOut); - } -} - -QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr &patch) -{ - QJsonObject root; - writeVersionProperties(patch.get(), root); - if (!patch->libraries.isEmpty()) - { - QJsonArray array; - for (auto value: patch->libraries) - { - array.append(MojangVersionFormat::libraryToJson(value.get())); - } - root.insert("libraries", array); - } - - // write the contents to a json document. - { - QJsonDocument out; - out.setObject(root); - return out; - } -} - -LibraryPtr MojangVersionFormat::libraryFromJson(const QJsonObject &libObj, const QString &filename) -{ - LibraryPtr out(new Library()); - if (!libObj.contains("name")) - { - throw JSONValidationError(filename + "contains a library that doesn't have a 'name' field"); - } - out->m_name = libObj.value("name").toString(); - - Bits::readString(libObj, "url", out->m_repositoryURL); - if (libObj.contains("extract")) - { - out->m_hasExcludes = true; - auto extractObj = requireObject(libObj.value("extract")); - for (auto excludeVal : requireArray(extractObj.value("exclude"))) - { - out->m_extractExcludes.append(requireString(excludeVal)); - } - } - if (libObj.contains("natives")) - { - QJsonObject nativesObj = requireObject(libObj.value("natives")); - for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it) - { - if (!it.value().isString()) - { - qWarning() << filename << "contains an invalid native (skipping)"; - } - OpSys opSys = OpSys_fromString(it.key()); - if (opSys != Os_Other) - { - out->m_nativeClassifiers[opSys] = it.value().toString(); - } - } - } - if (libObj.contains("rules")) - { - out->applyRules = true; - out->m_rules = rulesFromJsonV4(libObj); - } - if (libObj.contains("downloads")) - { - out->m_mojangDownloads = libDownloadInfoFromJson(libObj); - } - return out; -} - -QJsonObject MojangVersionFormat::libraryToJson(Library *library) -{ - QJsonObject libRoot; - libRoot.insert("name", (QString)library->m_name); - if (!library->m_repositoryURL.isEmpty()) - { - libRoot.insert("url", library->m_repositoryURL); - } - if (library->isNative()) - { - QJsonObject nativeList; - auto iter = library->m_nativeClassifiers.begin(); - while (iter != library->m_nativeClassifiers.end()) - { - nativeList.insert(OpSys_toString(iter.key()), iter.value()); - iter++; - } - libRoot.insert("natives", nativeList); - if (library->m_extractExcludes.size()) - { - QJsonArray excludes; - QJsonObject extract; - for (auto exclude : library->m_extractExcludes) - { - excludes.append(exclude); - } - extract.insert("exclude", excludes); - libRoot.insert("extract", extract); - } - } - if (library->m_rules.size()) - { - QJsonArray allRules; - for (auto &rule : library->m_rules) - { - QJsonObject ruleObj = rule->toJson(); - allRules.append(ruleObj); - } - libRoot.insert("rules", allRules); - } - if(library->m_mojangDownloads) - { - auto downloadsObj = libDownloadInfoToJson(library->m_mojangDownloads); - libRoot.insert("downloads", downloadsObj); - } - return libRoot; -} diff --git a/logic/minecraft/MojangVersionFormat.h b/logic/minecraft/MojangVersionFormat.h deleted file mode 100644 index 4e141088..00000000 --- a/logic/minecraft/MojangVersionFormat.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "multimc_logic_export.h" - -class MULTIMC_LOGIC_EXPORT MojangVersionFormat -{ -friend class OneSixVersionFormat; -protected: - // does not include libraries - static void readVersionProperties(const QJsonObject& in, VersionFile* out); - // does not include libraries - static void writeVersionProperties(const VersionFile* in, QJsonObject& out); -public: - // version files / profile patches - static VersionFilePtr versionFileFromJson(const QJsonDocument &doc, const QString &filename); - static QJsonDocument versionFileToJson(const VersionFilePtr &patch); - - // libraries - static LibraryPtr libraryFromJson(const QJsonObject &libObj, const QString &filename); - static QJsonObject libraryToJson(Library *library); -}; diff --git a/logic/minecraft/OpSys.cpp b/logic/minecraft/OpSys.cpp deleted file mode 100644 index 4c2a236d..00000000 --- a/logic/minecraft/OpSys.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright 2013-2015 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 "OpSys.h" - -OpSys OpSys_fromString(QString name) -{ - if (name == "linux") - return Os_Linux; - if (name == "windows") - return Os_Windows; - if (name == "osx") - return Os_OSX; - return Os_Other; -} - -QString OpSys_toString(OpSys name) -{ - switch (name) - { - case Os_Linux: - return "linux"; - case Os_OSX: - return "osx"; - case Os_Windows: - return "windows"; - default: - return "other"; - } -} \ No newline at end of file diff --git a/logic/minecraft/OpSys.h b/logic/minecraft/OpSys.h deleted file mode 100644 index 9ebea3de..00000000 --- a/logic/minecraft/OpSys.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include -enum OpSys -{ - Os_Windows, - Os_Linux, - Os_OSX, - Os_Other -}; - -OpSys OpSys_fromString(QString); -QString OpSys_toString(OpSys); - -#ifdef Q_OS_WIN32 -#define currentSystem Os_Windows -#else -#ifdef Q_OS_MAC -#define currentSystem Os_OSX -#else -#define currentSystem Os_Linux -#endif -#endif \ No newline at end of file diff --git a/logic/minecraft/ParseUtils.cpp b/logic/minecraft/ParseUtils.cpp deleted file mode 100644 index ca188432..00000000 --- a/logic/minecraft/ParseUtils.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include "ParseUtils.h" -#include -#include - -QDateTime timeFromS3Time(QString str) -{ - return QDateTime::fromString(str, Qt::ISODate); -} - -QString timeToS3Time(QDateTime time) -{ - // this all because Qt can't format timestamps right. - int offsetRaw = time.offsetFromUtc(); - bool negative = offsetRaw < 0; - int offsetAbs = std::abs(offsetRaw); - - int offsetSeconds = offsetAbs % 60; - offsetAbs -= offsetSeconds; - - int offsetMinutes = offsetAbs % 3600; - offsetAbs -= offsetMinutes; - offsetMinutes /= 60; - - int offsetHours = offsetAbs / 3600; - - QString raw = time.toString("yyyy-MM-ddTHH:mm:ss"); - raw += (negative ? QChar('-') : QChar('+')); - raw += QString("%1").arg(offsetHours, 2, 10, QChar('0')); - raw += ":"; - raw += QString("%1").arg(offsetMinutes, 2, 10, QChar('0')); - return raw; -} diff --git a/logic/minecraft/ParseUtils.h b/logic/minecraft/ParseUtils.h deleted file mode 100644 index 2b367a10..00000000 --- a/logic/minecraft/ParseUtils.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include -#include - -#include "multimc_logic_export.h" - -/// take the timestamp used by S3 and turn it into QDateTime -MULTIMC_LOGIC_EXPORT QDateTime timeFromS3Time(QString str); - -/// take a timestamp and convert it into an S3 timestamp -MULTIMC_LOGIC_EXPORT QString timeToS3Time(QDateTime); diff --git a/logic/minecraft/ProfilePatch.h b/logic/minecraft/ProfilePatch.h deleted file mode 100644 index f0c65360..00000000 --- a/logic/minecraft/ProfilePatch.h +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include "JarMod.h" - -class MinecraftProfile; - -enum ProblemSeverity -{ - PROBLEM_NONE, - PROBLEM_WARNING, - PROBLEM_ERROR -}; - -/// where is a version from? -enum VersionSource -{ - Local, //!< version loaded from a file in the cache. - Remote, //!< incomplete version on a remote server. -}; - -class PatchProblem -{ -public: - PatchProblem(ProblemSeverity severity, const QString & description) - { - m_severity = severity; - m_description = description; - } - const QString & getDescription() const - { - return m_description; - } - const ProblemSeverity getSeverity() const - { - return m_severity; - } -private: - ProblemSeverity m_severity; - QString m_description; -}; - -class ProfilePatch : public std::enable_shared_from_this -{ -public: - virtual ~ProfilePatch(){}; - virtual void applyTo(MinecraftProfile *profile) = 0; - - virtual bool isMinecraftVersion() = 0; - virtual bool hasJarMods() = 0; - virtual QList getJarMods() = 0; - - virtual bool isMoveable() = 0; - virtual bool isCustomizable() = 0; - virtual bool isRevertible() = 0; - virtual bool isRemovable() = 0; - virtual bool isCustom() = 0; - virtual bool isEditable() = 0; - virtual bool isVersionChangeable() = 0; - - virtual void setOrder(int order) = 0; - virtual int getOrder() = 0; - - virtual QString getID() = 0; - virtual QString getName() = 0; - virtual QString getVersion() = 0; - virtual QDateTime getReleaseDateTime() = 0; - - virtual QString getFilename() = 0; - - virtual VersionSource getVersionSource() = 0; - - virtual std::shared_ptr getVersionFile() = 0; - - virtual const QList& getProblems() - { - return m_problems; - } - virtual void addProblem(ProblemSeverity severity, const QString &description) - { - if(severity > m_problemSeverity) - { - m_problemSeverity = severity; - } - m_problems.append(PatchProblem(severity, description)); - } - virtual ProblemSeverity getProblemSeverity() - { - return m_problemSeverity; - } - virtual bool hasFailed() - { - return getProblemSeverity() == PROBLEM_ERROR; - } - -protected: - QList m_problems; - ProblemSeverity m_problemSeverity = PROBLEM_NONE; -}; - -typedef std::shared_ptr ProfilePatchPtr; diff --git a/logic/minecraft/ProfileStrategy.h b/logic/minecraft/ProfileStrategy.h deleted file mode 100644 index b4dfc4b3..00000000 --- a/logic/minecraft/ProfileStrategy.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "ProfileUtils.h" - -class MinecraftProfile; - -class ProfileStrategy -{ - friend class MinecraftProfile; -public: - virtual ~ProfileStrategy(){}; - - /// load the patch files into the profile - virtual void load() = 0; - - /// reset the order of patches - virtual bool resetOrder() = 0; - - /// save the order of patches, given the order - virtual bool saveOrder(ProfileUtils::PatchOrder order) = 0; - - /// install a list of jar mods into the instance - virtual bool installJarMods(QStringList filepaths) = 0; - - /// remove any files or records that constitute the version patch - virtual bool removePatch(ProfilePatchPtr jarMod) = 0; - - /// make the patch custom, if possible - virtual bool customizePatch(ProfilePatchPtr patch) = 0; - - /// revert the custom patch to 'vanilla', if possible - virtual bool revertPatch(ProfilePatchPtr patch) = 0; -protected: - MinecraftProfile *profile; -}; diff --git a/logic/minecraft/ProfileUtils.cpp b/logic/minecraft/ProfileUtils.cpp deleted file mode 100644 index ef9b3b28..00000000 --- a/logic/minecraft/ProfileUtils.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "ProfileUtils.h" -#include "minecraft/VersionFilterData.h" -#include "minecraft/onesix/OneSixVersionFormat.h" -#include "Json.h" -#include - -#include -#include -#include -#include - -namespace ProfileUtils -{ - -static const int currentOrderFileVersion = 1; - -bool writeOverrideOrders(QString path, const PatchOrder &order) -{ - QJsonObject obj; - obj.insert("version", currentOrderFileVersion); - QJsonArray orderArray; - for(auto str: order) - { - orderArray.append(str); - } - obj.insert("order", orderArray); - QSaveFile orderFile(path); - if (!orderFile.open(QFile::WriteOnly)) - { - qCritical() << "Couldn't open" << orderFile.fileName() - << "for writing:" << orderFile.errorString(); - return false; - } - auto data = QJsonDocument(obj).toJson(QJsonDocument::Indented); - if(orderFile.write(data) != data.size()) - { - qCritical() << "Couldn't write all the data into" << orderFile.fileName() - << "because:" << orderFile.errorString(); - return false; - } - if(!orderFile.commit()) - { - qCritical() << "Couldn't save" << orderFile.fileName() - << "because:" << orderFile.errorString(); - } - return true; -} - -bool readOverrideOrders(QString path, PatchOrder &order) -{ - QFile orderFile(path); - if (!orderFile.exists()) - { - qWarning() << "Order file doesn't exist. Ignoring."; - return false; - } - if (!orderFile.open(QFile::ReadOnly)) - { - qCritical() << "Couldn't open" << orderFile.fileName() - << " for reading:" << orderFile.errorString(); - qWarning() << "Ignoring overriden order"; - return false; - } - - // and it's valid JSON - QJsonParseError error; - QJsonDocument doc = QJsonDocument::fromJson(orderFile.readAll(), &error); - if (error.error != QJsonParseError::NoError) - { - qCritical() << "Couldn't parse" << orderFile.fileName() << ":" << error.errorString(); - qWarning() << "Ignoring overriden order"; - return false; - } - - // and then read it and process it if all above is true. - try - { - auto obj = Json::requireObject(doc); - // check order file version. - auto version = Json::requireInteger(obj.value("version")); - if (version != currentOrderFileVersion) - { - throw JSONValidationError(QObject::tr("Invalid order file version, expected %1") - .arg(currentOrderFileVersion)); - } - auto orderArray = Json::requireArray(obj.value("order")); - for(auto item: orderArray) - { - order.append(Json::requireString(item)); - } - } - catch (JSONValidationError &err) - { - qCritical() << "Couldn't parse" << orderFile.fileName() << ": bad file format"; - qWarning() << "Ignoring overriden order"; - order.clear(); - return false; - } - return true; -} - -static VersionFilePtr createErrorVersionFile(QString fileId, QString filepath, QString error) -{ - auto outError = std::make_shared(); - outError->fileId = outError->name = fileId; - outError->filename = filepath; - outError->addProblem(PROBLEM_ERROR, error); - return outError; -} - -static VersionFilePtr guardedParseJson(const QJsonDocument & doc,const QString &fileId,const QString &filepath,const bool &requireOrder) -{ - try - { - return OneSixVersionFormat::versionFileFromJson(doc, filepath, requireOrder); - } - catch (Exception & e) - { - return createErrorVersionFile(fileId, filepath, e.cause()); - } -} - -VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder) -{ - QFile file(fileInfo.absoluteFilePath()); - if (!file.open(QFile::ReadOnly)) - { - auto errorStr = QObject::tr("Unable to open the version file %1: %2.").arg(fileInfo.fileName(), file.errorString()); - return createErrorVersionFile(fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), errorStr); - } - QJsonParseError error; - auto data = file.readAll(); - QJsonDocument doc = QJsonDocument::fromJson(data, &error); - file.close(); - if (error.error != QJsonParseError::NoError) - { - int line = 1; - int column = 0; - for(int i = 0; i < error.offset; i++) - { - if(data[i] == '\n') - { - line++; - column = 0; - continue; - } - column++; - } - auto errorStr = QObject::tr("Unable to process the version file %1: %2 at line %3 column %4.") - .arg(fileInfo.fileName(), error.errorString()) - .arg(line).arg(column); - return createErrorVersionFile(fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), errorStr); - } - return guardedParseJson(doc, fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), requireOrder); -} - -VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo) -{ - QFile file(fileInfo.absoluteFilePath()); - if (!file.open(QFile::ReadOnly)) - { - auto errorStr = QObject::tr("Unable to open the version file %1: %2.").arg(fileInfo.fileName(), file.errorString()); - return createErrorVersionFile(fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), errorStr); - } - QJsonDocument doc = QJsonDocument::fromBinaryData(file.readAll()); - file.close(); - if (doc.isNull()) - { - file.remove(); - throw JSONValidationError(QObject::tr("Unable to process the version file %1.").arg(fileInfo.fileName())); - } - return guardedParseJson(doc, fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), false); -} - -void removeLwjglFromPatch(VersionFilePtr patch) -{ - auto filter = [](QList& libs) - { - QList filteredLibs; - for (auto lib : libs) - { - if (!g_VersionFilterData.lwjglWhitelist.contains(lib->artifactPrefix())) - { - filteredLibs.append(lib); - } - } - libs = filteredLibs; - }; - filter(patch->libraries); -} -} diff --git a/logic/minecraft/ProfileUtils.h b/logic/minecraft/ProfileUtils.h deleted file mode 100644 index 267fd42b..00000000 --- a/logic/minecraft/ProfileUtils.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "Library.h" -#include "VersionFile.h" - -namespace ProfileUtils -{ -typedef QStringList PatchOrder; - -/// Read and parse a OneSix format order file -bool readOverrideOrders(QString path, PatchOrder &order); - -/// Write a OneSix format order file -bool writeOverrideOrders(QString path, const PatchOrder &order); - - -/// Parse a version file in JSON format -VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder); - -/// Parse a version file in binary JSON format -VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo); - -/// Remove LWJGL from a patch file. This is applied to all Mojang-like profile files. -void removeLwjglFromPatch(VersionFilePtr patch); - -} diff --git a/logic/minecraft/Rule.cpp b/logic/minecraft/Rule.cpp deleted file mode 100644 index c8ba297b..00000000 --- a/logic/minecraft/Rule.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright 2013-2015 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 -#include - -#include "Rule.h" - -RuleAction RuleAction_fromString(QString name) -{ - if (name == "allow") - return Allow; - if (name == "disallow") - return Disallow; - return Defer; -} - -QList> rulesFromJsonV4(const QJsonObject &objectWithRules) -{ - QList> rules; - auto rulesVal = objectWithRules.value("rules"); - if (!rulesVal.isArray()) - return rules; - - QJsonArray ruleList = rulesVal.toArray(); - for (auto ruleVal : ruleList) - { - std::shared_ptr rule; - if (!ruleVal.isObject()) - continue; - auto ruleObj = ruleVal.toObject(); - auto actionVal = ruleObj.value("action"); - if (!actionVal.isString()) - continue; - auto action = RuleAction_fromString(actionVal.toString()); - if (action == Defer) - continue; - - auto osVal = ruleObj.value("os"); - if (!osVal.isObject()) - { - // add a new implicit action rule - rules.append(ImplicitRule::create(action)); - continue; - } - - auto osObj = osVal.toObject(); - auto osNameVal = osObj.value("name"); - if (!osNameVal.isString()) - continue; - OpSys requiredOs = OpSys_fromString(osNameVal.toString()); - QString versionRegex = osObj.value("version").toString(); - // add a new OS rule - rules.append(OsRule::create(action, requiredOs, versionRegex)); - } - return rules; -} - -QJsonObject ImplicitRule::toJson() -{ - QJsonObject ruleObj; - ruleObj.insert("action", m_result == Allow ? QString("allow") : QString("disallow")); - return ruleObj; -} - -QJsonObject OsRule::toJson() -{ - QJsonObject ruleObj; - ruleObj.insert("action", m_result == Allow ? QString("allow") : QString("disallow")); - QJsonObject osObj; - { - osObj.insert("name", OpSys_toString(m_system)); - if(!m_version_regexp.isEmpty()) - { - osObj.insert("version", m_version_regexp); - } - } - ruleObj.insert("os", osObj); - return ruleObj; -} - diff --git a/logic/minecraft/Rule.h b/logic/minecraft/Rule.h deleted file mode 100644 index c8bf6eaa..00000000 --- a/logic/minecraft/Rule.h +++ /dev/null @@ -1,101 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include "OpSys.h" - -class Library; -class Rule; - -enum RuleAction -{ - Allow, - Disallow, - Defer -}; - -QList> rulesFromJsonV4(const QJsonObject &objectWithRules); - -class Rule -{ -protected: - RuleAction m_result; - virtual bool applies(const Library *parent) = 0; - -public: - Rule(RuleAction result) : m_result(result) - { - } - virtual ~Rule() {}; - virtual QJsonObject toJson() = 0; - RuleAction apply(const Library *parent) - { - if (applies(parent)) - return m_result; - else - return Defer; - } -}; - -class OsRule : public Rule -{ -private: - // the OS - OpSys m_system; - // the OS version regexp - QString m_version_regexp; - -protected: - virtual bool applies(const Library *) - { - return (m_system == currentSystem); - } - OsRule(RuleAction result, OpSys system, QString version_regexp) - : Rule(result), m_system(system), m_version_regexp(version_regexp) - { - } - -public: - virtual QJsonObject toJson(); - static std::shared_ptr create(RuleAction result, OpSys system, - QString version_regexp) - { - return std::shared_ptr(new OsRule(result, system, version_regexp)); - } -}; - -class ImplicitRule : public Rule -{ -protected: - virtual bool applies(const Library *) - { - return true; - } - ImplicitRule(RuleAction result) : Rule(result) - { - } - -public: - virtual QJsonObject toJson(); - static std::shared_ptr create(RuleAction result) - { - return std::shared_ptr(new ImplicitRule(result)); - } -}; diff --git a/logic/minecraft/SkinUtils.cpp b/logic/minecraft/SkinUtils.cpp deleted file mode 100644 index e6e513a5..00000000 --- a/logic/minecraft/SkinUtils.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2013-2015 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 "minecraft/SkinUtils.h" -#include "net/HttpMetaCache.h" -#include "Env.h" - -#include -#include -#include -#include - -namespace SkinUtils -{ -/* - * Given a username, return a pixmap of the cached skin (if it exists), QPixmap() otherwise - */ -QPixmap getFaceFromCache(QString username, int height, int width) -{ - QFile fskin(ENV.metacache() - ->resolveEntry("skins", username + ".png") - ->getFullPath()); - - if (fskin.exists()) - { - QPixmap skin(fskin.fileName()); - if(!skin.isNull()) - { - return skin.copy(8, 8, 8, 8).scaled(height, width, Qt::KeepAspectRatio); - } - } - - return QPixmap(); -} -} diff --git a/logic/minecraft/SkinUtils.h b/logic/minecraft/SkinUtils.h deleted file mode 100644 index 5f5b1897..00000000 --- a/logic/minecraft/SkinUtils.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include "multimc_logic_export.h" - -namespace SkinUtils -{ -QPixmap MULTIMC_LOGIC_EXPORT getFaceFromCache(QString id, int height = 64, int width = 64); -} diff --git a/logic/minecraft/VersionBuildError.h b/logic/minecraft/VersionBuildError.h deleted file mode 100644 index fda453e5..00000000 --- a/logic/minecraft/VersionBuildError.h +++ /dev/null @@ -1,58 +0,0 @@ -#include "Exception.h" - -class VersionBuildError : public Exception -{ -public: - explicit VersionBuildError(QString cause) : Exception(cause) {} - virtual ~VersionBuildError() noexcept - { - } -}; - -/** - * the base version file was meant for a newer version of the vanilla launcher than we support - */ -class LauncherVersionError : public VersionBuildError -{ -public: - LauncherVersionError(int actual, int supported) - : VersionBuildError(QObject::tr( - "The base version file of this instance was meant for a newer (%1) " - "version of the vanilla launcher than this version of MultiMC supports (%2).") - .arg(actual) - .arg(supported)) {}; - virtual ~LauncherVersionError() noexcept - { - } -}; - -/** - * some patch was intended for a different version of minecraft - */ -class MinecraftVersionMismatch : public VersionBuildError -{ -public: - MinecraftVersionMismatch(QString fileId, QString mcVersion, QString parentMcVersion) - : VersionBuildError(QObject::tr("The patch %1 is for a different version of Minecraft " - "(%2) than that of the instance (%3).") - .arg(fileId) - .arg(mcVersion) - .arg(parentMcVersion)) {}; - virtual ~MinecraftVersionMismatch() noexcept - { - } -}; - -/** - * files required for the version are not (yet?) present - */ -class VersionIncomplete : public VersionBuildError -{ -public: - VersionIncomplete(QString missingPatch) - : VersionBuildError(QObject::tr("Version is incomplete: missing %1.") - .arg(missingPatch)) {}; - virtual ~VersionIncomplete() noexcept - { - } -}; diff --git a/logic/minecraft/VersionFile.cpp b/logic/minecraft/VersionFile.cpp deleted file mode 100644 index 573c4cb4..00000000 --- a/logic/minecraft/VersionFile.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include - -#include - -#include "minecraft/VersionFile.h" -#include "minecraft/Library.h" -#include "minecraft/MinecraftProfile.h" -#include "minecraft/JarMod.h" -#include "ParseUtils.h" - -#include "VersionBuildError.h" -#include - -bool VersionFile::isMinecraftVersion() -{ - return fileId == "net.minecraft"; -} - -bool VersionFile::hasJarMods() -{ - return !jarMods.isEmpty(); -} - -void VersionFile::applyTo(MinecraftProfile *profile) -{ - auto theirVersion = profile->getMinecraftVersion(); - if (!theirVersion.isNull() && !dependsOnMinecraftVersion.isNull()) - { - if (QRegExp(dependsOnMinecraftVersion, Qt::CaseInsensitive, QRegExp::Wildcard).indexIn(theirVersion) == -1) - { - throw MinecraftVersionMismatch(fileId, dependsOnMinecraftVersion, theirVersion); - } - } - profile->applyMinecraftVersion(minecraftVersion); - profile->applyMainClass(mainClass); - profile->applyAppletClass(appletClass); - profile->applyMinecraftArguments(minecraftArguments); - if (isMinecraftVersion()) - { - profile->applyMinecraftVersionType(type); - } - profile->applyMinecraftAssets(mojangAssetIndex); - profile->applyTweakers(addTweakers); - - profile->applyJarMods(jarMods); - profile->applyTraits(traits); - - for (auto library : libraries) - { - profile->applyLibrary(library); - } - profile->applyProblemSeverity(getProblemSeverity()); - auto iter = mojangDownloads.begin(); - while(iter != mojangDownloads.end()) - { - profile->applyMojangDownload(iter.key(), iter.value()); - iter++; - } -} diff --git a/logic/minecraft/VersionFile.h b/logic/minecraft/VersionFile.h deleted file mode 100644 index 1b692f0f..00000000 --- a/logic/minecraft/VersionFile.h +++ /dev/null @@ -1,195 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include "minecraft/OpSys.h" -#include "minecraft/Rule.h" -#include "ProfilePatch.h" -#include "Library.h" -#include "JarMod.h" - -class MinecraftProfile; -class VersionFile; -struct MojangDownloadInfo; -struct MojangAssetIndexInfo; - -typedef std::shared_ptr VersionFilePtr; -class VersionFile : public ProfilePatch -{ - friend class MojangVersionFormat; - friend class OneSixVersionFormat; -public: /* methods */ - virtual void applyTo(MinecraftProfile *profile) override; - virtual bool isMinecraftVersion() override; - virtual bool hasJarMods() override; - virtual int getOrder() override - { - return order; - } - virtual void setOrder(int order) override - { - this->order = order; - } - virtual QList getJarMods() override - { - return jarMods; - } - virtual QString getID() override - { - return fileId; - } - virtual QString getName() override - { - return name; - } - virtual QString getVersion() override - { - return version; - } - virtual QString getFilename() override - { - return filename; - } - virtual QDateTime getReleaseDateTime() override - { - return m_releaseTime; - } - VersionSource getVersionSource() override - { - return Local; - } - - std::shared_ptr getVersionFile() override - { - return std::dynamic_pointer_cast(shared_from_this()); - } - - virtual bool isCustom() override - { - return !m_isVanilla; - }; - virtual bool isCustomizable() override - { - return m_isCustomizable; - } - virtual bool isRemovable() override - { - return m_isRemovable; - } - virtual bool isRevertible() override - { - return m_isRevertible; - } - virtual bool isMoveable() override - { - return m_isMovable; - } - virtual bool isEditable() override - { - return isCustom(); - } - virtual bool isVersionChangeable() override - { - return false; - } - - void setVanilla (bool state) - { - m_isVanilla = state; - } - void setRemovable (bool state) - { - m_isRemovable = state; - } - void setRevertible (bool state) - { - m_isRevertible = state; - } - void setCustomizable (bool state) - { - m_isCustomizable = state; - } - void setMovable (bool state) - { - m_isMovable = state; - } - - -public: /* data */ - /// MultiMC: order hint for this version file if no explicit order is set - int order = 0; - - // Flags for UI and version file manipulation in general - bool m_isVanilla = false; - bool m_isRemovable = false; - bool m_isRevertible = false; - bool m_isCustomizable = false; - bool m_isMovable = false; - - /// MultiMC: filename of the file this was loaded from - QString filename; - - /// MultiMC: human readable name of this package - QString name; - - /// MultiMC: package ID of this package - QString fileId; - - /// MultiMC: version of this package - QString version; - - /// MultiMC: dependency on a Minecraft version - QString dependsOnMinecraftVersion; - - /// Mojang: used to version the Mojang version format - int minimumLauncherVersion = -1; - - /// Mojang: version of Minecraft this is - QString minecraftVersion; - - /// Mojang: class to launch Minecraft with - QString mainClass; - - /// MultiMC: DEPRECATED class to launch legacy Minecraft with (ambed in a custom window) - QString appletClass; - - /// Mojang: Minecraft launch arguments (may contain placeholders for variable substitution) - QString minecraftArguments; - - /// Mojang: type of the Minecraft version - QString type; - - /// Mojang: the time this version was actually released by Mojang - QDateTime m_releaseTime; - - /// Mojang: the time this version was last updated by Mojang - QDateTime m_updateTime; - - /// Mojang: DEPRECATED asset group to be used with Minecraft - QString assets; - - /// MultiMC: list of tweaker mod arguments for launchwrapper - QStringList addTweakers; - - /// Mojang: list of libraries to add to the version - QList libraries; - - /// MultiMC: list of attached traits of this version file - used to enable features - QSet traits; - - /// MultiMC: list of jar mods added to this version - QList jarMods; - -public: - // Mojang: list of 'downloads' - client jar, server jar, windows server exe, maybe more. - QMap > mojangDownloads; - - // Mojang: extended asset index download information - std::shared_ptr mojangAssetIndex; -}; - - diff --git a/logic/minecraft/VersionFilterData.cpp b/logic/minecraft/VersionFilterData.cpp deleted file mode 100644 index 0c4a6e3d..00000000 --- a/logic/minecraft/VersionFilterData.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "VersionFilterData.h" -#include "ParseUtils.h" - -VersionFilterData g_VersionFilterData = VersionFilterData(); - -VersionFilterData::VersionFilterData() -{ - // 1.3.* - auto libs13 = - QList{{"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b", false}, - {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f", false}, - {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82", false}}; - - fmlLibsMapping["1.3.2"] = libs13; - - // 1.4.* - auto libs14 = QList{ - {"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b", false}, - {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f", false}, - {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82", false}, - {"bcprov-jdk15on-147.jar", "b6f5d9926b0afbde9f4dbe3db88c5247be7794bb", false}}; - - fmlLibsMapping["1.4"] = libs14; - fmlLibsMapping["1.4.1"] = libs14; - fmlLibsMapping["1.4.2"] = libs14; - fmlLibsMapping["1.4.3"] = libs14; - fmlLibsMapping["1.4.4"] = libs14; - fmlLibsMapping["1.4.5"] = libs14; - fmlLibsMapping["1.4.6"] = libs14; - fmlLibsMapping["1.4.7"] = libs14; - - // 1.5 - fmlLibsMapping["1.5"] = QList{ - {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false}, - {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false}, - {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false}, - {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true}, - {"deobfuscation_data_1.5.zip", "5f7c142d53776f16304c0bbe10542014abad6af8", false}, - {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}}; - - // 1.5.1 - fmlLibsMapping["1.5.1"] = QList{ - {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false}, - {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false}, - {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false}, - {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true}, - {"deobfuscation_data_1.5.1.zip", "22e221a0d89516c1f721d6cab056a7e37471d0a6", false}, - {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}}; - - // 1.5.2 - fmlLibsMapping["1.5.2"] = QList{ - {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false}, - {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false}, - {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false}, - {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true}, - {"deobfuscation_data_1.5.2.zip", "446e55cd986582c70fcf12cb27bc00114c5adfd9", false}, - {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}}; - - // don't use installers for those. - forgeInstallerBlacklist = QSet({"1.5.2"}); - // these won't show up in version lists because they are extremely bad and dangerous - legacyBlacklist = QSet({"rd-160052"}); - /* - * nothing older than this will be accepted from Mojang servers - * (these versions need to be tested by us first) - */ - legacyCutoffDate = timeFromS3Time("2013-06-25T15:08:56+02:00"); - lwjglWhitelist = - QSet{"net.java.jinput:jinput", "net.java.jinput:jinput-platform", - "net.java.jutils:jutils", "org.lwjgl.lwjgl:lwjgl", - "org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform"}; - - // Version list magic - recommendedMinecraftVersion = "1.7.10"; -} diff --git a/logic/minecraft/VersionFilterData.h b/logic/minecraft/VersionFilterData.h deleted file mode 100644 index f7d4ebe7..00000000 --- a/logic/minecraft/VersionFilterData.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include -#include -#include -#include - -#include "multimc_logic_export.h" - -struct FMLlib -{ - QString filename; - QString checksum; - bool ours; -}; - -struct VersionFilterData -{ - VersionFilterData(); - // mapping between minecraft versions and FML libraries required - QMap> fmlLibsMapping; - // set of minecraft versions for which using forge installers is blacklisted - QSet forgeInstallerBlacklist; - // set of 'legacy' versions that will not show up in the version lists. - QSet legacyBlacklist; - // no new versions below this date will be accepted from Mojang servers - QDateTime legacyCutoffDate; - // Libraries that belong to LWJGL - QSet lwjglWhitelist; - // Currently recommended minecraft version - QString recommendedMinecraftVersion; -}; -extern VersionFilterData MULTIMC_LOGIC_EXPORT g_VersionFilterData; diff --git a/logic/minecraft/World.cpp b/logic/minecraft/World.cpp deleted file mode 100644 index 6081a8ec..00000000 --- a/logic/minecraft/World.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* Copyright 2015 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 -#include -#include -#include -#include "World.h" - -#include "GZip.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -std::unique_ptr parseLevelDat(QByteArray data) -{ - QByteArray output; - if(!GZip::unzip(data, output)) - { - return nullptr; - } - std::istringstream foo(std::string(output.constData(), output.size())); - auto pair = nbt::io::read_compound(foo); - - if(pair.first != "") - return nullptr; - - if(pair.second == nullptr) - return nullptr; - - return std::move(pair.second); -} - -QByteArray serializeLevelDat(nbt::tag_compound * levelInfo) -{ - std::ostringstream s; - nbt::io::write_tag("", *levelInfo, s); - QByteArray val( s.str().data(), (int) s.str().size() ); - return val; -} - -QString getLevelDatFromFS(const QFileInfo &file) -{ - QDir worldDir(file.filePath()); - if(!file.isDir() || !worldDir.exists("level.dat")) - { - return QString(); - } - return worldDir.absoluteFilePath("level.dat"); -} - -QByteArray getLevelDatDataFromFS(const QFileInfo &file) -{ - auto fullFilePath = getLevelDatFromFS(file); - if(fullFilePath.isNull()) - { - return QByteArray(); - } - QFile f(fullFilePath); - if(!f.open(QIODevice::ReadOnly)) - { - return QByteArray(); - } - return f.readAll(); -} - -bool putLevelDatDataToFS(const QFileInfo &file, QByteArray & data) -{ - auto fullFilePath = getLevelDatFromFS(file); - if(fullFilePath.isNull()) - { - return false; - } - QSaveFile f(fullFilePath); - if(!f.open(QIODevice::WriteOnly)) - { - return false; - } - QByteArray compressed; - if(!GZip::zip(data, compressed)) - { - return false; - } - if(f.write(compressed) != compressed.size()) - { - f.cancelWriting(); - return false; - } - return f.commit(); -} - -World::World(const QFileInfo &file) -{ - repath(file); -} - -void World::repath(const QFileInfo &file) -{ - m_containerFile = file; - m_folderName = file.fileName(); - if(file.isFile() && file.suffix() == "zip") - { - readFromZip(file); - } - else if(file.isDir()) - { - readFromFS(file); - } -} - -void World::readFromFS(const QFileInfo &file) -{ - auto bytes = getLevelDatDataFromFS(file); - if(bytes.isEmpty()) - { - is_valid = false; - return; - } - loadFromLevelDat(bytes); - levelDatTime = file.lastModified(); -} - -void World::readFromZip(const QFileInfo &file) -{ - QuaZip zip(file.absoluteFilePath()); - is_valid = zip.open(QuaZip::mdUnzip); - if (!is_valid) - { - return; - } - auto location = MMCZip::findFileInZip(&zip, "level.dat"); - is_valid = !location.isEmpty(); - if (!is_valid) - { - return; - } - m_containerOffsetPath = location; - QuaZipFile zippedFile(&zip); - // read the install profile - is_valid = zip.setCurrentFile(location + "level.dat"); - if (!is_valid) - { - return; - } - is_valid = zippedFile.open(QIODevice::ReadOnly); - QuaZipFileInfo64 levelDatInfo; - zippedFile.getFileInfo(&levelDatInfo); - auto modTime = levelDatInfo.getNTFSmTime(); - if(!modTime.isValid()) - { - modTime = levelDatInfo.dateTime; - } - levelDatTime = modTime; - if (!is_valid) - { - return; - } - loadFromLevelDat(zippedFile.readAll()); - zippedFile.close(); -} - -bool World::install(const QString &to, const QString &name) -{ - auto finalPath = FS::PathCombine(to, FS::DirNameFromString(m_actualName, to)); - if(!FS::ensureFolderPathExists(finalPath)) - { - return false; - } - bool ok = false; - if(m_containerFile.isFile()) - { - QuaZip zip(m_containerFile.absoluteFilePath()); - if (!zip.open(QuaZip::mdUnzip)) - { - return false; - } - ok = !MMCZip::extractSubDir(&zip, m_containerOffsetPath, finalPath).isEmpty(); - } - else if(m_containerFile.isDir()) - { - QString from = m_containerFile.filePath(); - ok = FS::copy(from, finalPath)(); - } - - if(ok && !name.isEmpty() && m_actualName != name) - { - World newWorld(finalPath); - if(newWorld.isValid()) - { - newWorld.rename(name); - } - } - return ok; -} - -bool World::rename(const QString &newName) -{ - if(m_containerFile.isFile()) - { - return false; - } - - auto data = getLevelDatDataFromFS(m_containerFile); - if(data.isEmpty()) - { - return false; - } - - auto worldData = parseLevelDat(data); - if(!worldData) - { - return false; - } - auto &val = worldData->at("Data"); - if(val.get_type() != nbt::tag_type::Compound) - { - return false; - } - auto &dataCompound = val.as(); - dataCompound.put("LevelName", nbt::value_initializer(newName.toUtf8().data())); - data = serializeLevelDat(worldData.get()); - - putLevelDatDataToFS(m_containerFile, data); - - m_actualName = newName; - - QDir parentDir(m_containerFile.absoluteFilePath()); - parentDir.cdUp(); - QFile container(m_containerFile.absoluteFilePath()); - auto dirName = FS::DirNameFromString(m_actualName, parentDir.absolutePath()); - container.rename(parentDir.absoluteFilePath(dirName)); - - return true; -} - -static QString read_string (nbt::value& parent, const char * name, const QString & fallback = QString()) -{ - try - { - auto &namedValue = parent.at(name); - if(namedValue.get_type() != nbt::tag_type::String) - { - return fallback; - } - auto & tag_str = namedValue.as(); - return QString::fromStdString(tag_str.get()); - } - catch(std::out_of_range e) - { - // fallback for old world formats - qWarning() << "String NBT tag" << name << "could not be found. Defaulting to" << fallback; - return fallback; - } - catch(std::bad_cast e) - { - // type mismatch - qWarning() << "NBT tag" << name << "could not be converted to string. Defaulting to" << fallback; - return fallback; - } -}; - -static int64_t read_long (nbt::value& parent, const char * name, const int64_t & fallback = 0) -{ - try - { - auto &namedValue = parent.at(name); - if(namedValue.get_type() != nbt::tag_type::Long) - { - return fallback; - } - auto & tag_str = namedValue.as(); - return tag_str.get(); - } - catch(std::out_of_range e) - { - // fallback for old world formats - qWarning() << "Long NBT tag" << name << "could not be found. Defaulting to" << fallback; - return fallback; - } - catch(std::bad_cast e) - { - // type mismatch - qWarning() << "NBT tag" << name << "could not be converted to long. Defaulting to" << fallback; - return fallback; - } -}; - -void World::loadFromLevelDat(QByteArray data) -{ - try - { - auto levelData = parseLevelDat(data); - if(!levelData) - { - is_valid = false; - return; - } - - auto &val = levelData->at("Data"); - is_valid = val.get_type() == nbt::tag_type::Compound; - if(!is_valid) - return; - - m_actualName = read_string(val, "LevelName", m_folderName); - - - int64_t temp = read_long(val, "LastPlayed", 0); - if(temp == 0) - { - m_lastPlayed = levelDatTime; - } - else - { - m_lastPlayed = QDateTime::fromMSecsSinceEpoch(temp); - } - - m_randomSeed = read_long(val, "RandomSeed", 0); - - qDebug() << "World Name:" << m_actualName; - qDebug() << "Last Played:" << m_lastPlayed.toString(); - qDebug() << "Seed:" << m_randomSeed; - } - catch (nbt::io::input_error e) - { - qWarning() << "Unable to load" << m_folderName << ":" << e.what(); - is_valid = false; - return; - } -} - -bool World::replace(World &with) -{ - if (!destroy()) - return false; - bool success = FS::copy(with.m_containerFile.filePath(), m_containerFile.path())(); - if (success) - { - m_folderName = with.m_folderName; - m_containerFile.refresh(); - } - return success; -} - -bool World::destroy() -{ - if(!is_valid) return false; - if (m_containerFile.isDir()) - { - QDir d(m_containerFile.filePath()); - return d.removeRecursively(); - } - else if(m_containerFile.isFile()) - { - QFile file(m_containerFile.absoluteFilePath()); - return file.remove(); - } - return true; -} - -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(); -} diff --git a/logic/minecraft/World.h b/logic/minecraft/World.h deleted file mode 100644 index 3cde5ea4..00000000 --- a/logic/minecraft/World.h +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright 2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include -#include - -#include "multimc_logic_export.h" - -class MULTIMC_LOGIC_EXPORT World -{ -public: - World(const QFileInfo &file); - QString folderName() const - { - return m_folderName; - } - QString name() const - { - return m_actualName; - } - QDateTime lastPlayed() const - { - return m_lastPlayed; - } - int64_t seed() const - { - return m_randomSeed; - } - bool isValid() const - { - return is_valid; - } - bool isOnFS() const - { - return m_containerFile.isDir(); - } - QFileInfo container() const - { - return m_containerFile; - } - // delete all the files of this world - bool destroy(); - // replace this world with a copy of the other - bool replace(World &with); - // change the world's filesystem path (used by world lists for *MAGIC* purposes) - void repath(const QFileInfo &file); - - bool rename(const QString &to); - bool install(const QString &to, const QString &name= QString()); - - // 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); - void readFromFS(const QFileInfo &file); - void loadFromLevelDat(QByteArray data); - -protected: - - QFileInfo m_containerFile; - QString m_containerOffsetPath; - QString m_folderName; - QString m_actualName; - QDateTime levelDatTime; - QDateTime m_lastPlayed; - int64_t m_randomSeed = 0; - bool is_valid = false; -}; diff --git a/logic/minecraft/WorldList.cpp b/logic/minecraft/WorldList.cpp deleted file mode 100644 index 42c8a3e6..00000000 --- a/logic/minecraft/WorldList.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/* Copyright 2015 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 "WorldList.h" -#include -#include -#include -#include -#include -#include -#include - -WorldList::WorldList(const QString &dir) - : QAbstractListModel(), m_dir(dir) -{ - FS::ensureFolderPathExists(m_dir.absolutePath()); - m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs | - QDir::NoSymLinks); - m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); - m_watcher = new QFileSystemWatcher(this); - is_watching = false; - connect(m_watcher, SIGNAL(directoryChanged(QString)), this, - SLOT(directoryChanged(QString))); -} - -void WorldList::startWatching() -{ - update(); - is_watching = m_watcher->addPath(m_dir.absolutePath()); - if (is_watching) - { - qDebug() << "Started watching " << m_dir.absolutePath(); - } - else - { - qDebug() << "Failed to start watching " << m_dir.absolutePath(); - } -} - -void WorldList::stopWatching() -{ - is_watching = !m_watcher->removePath(m_dir.absolutePath()); - if (!is_watching) - { - qDebug() << "Stopped watching " << m_dir.absolutePath(); - } - else - { - qDebug() << "Failed to stop watching " << m_dir.absolutePath(); - } -} - -bool WorldList::update() -{ - if (!isValid()) - return false; - - QList newWorlds; - m_dir.refresh(); - auto folderContents = m_dir.entryInfoList(); - // if there are any untracked files... - for (QFileInfo entry : folderContents) - { - if(!entry.isDir()) - continue; - - World w(entry); - if(w.isValid()) - { - newWorlds.append(w); - } - } - beginResetModel(); - worlds.swap(newWorlds); - endResetModel(); - return true; -} - -void WorldList::directoryChanged(QString path) -{ - update(); -} - -bool WorldList::isValid() -{ - return m_dir.exists() && m_dir.isReadable(); -} - -bool WorldList::deleteWorld(int index) -{ - if (index >= worlds.size() || index < 0) - return false; - World &m = worlds[index]; - if (m.destroy()) - { - beginRemoveRows(QModelIndex(), index, index); - worlds.removeAt(index); - endRemoveRows(); - emit changed(); - return true; - } - return false; -} - -bool WorldList::deleteWorlds(int first, int last) -{ - for (int i = first; i <= last; i++) - { - World &m = worlds[i]; - m.destroy(); - } - beginRemoveRows(QModelIndex(), first, last); - worlds.erase(worlds.begin() + first, worlds.begin() + last + 1); - endRemoveRows(); - emit changed(); - return true; -} - -int WorldList::columnCount(const QModelIndex &parent) const -{ - return 2; -} - -QVariant WorldList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - int row = index.row(); - int column = index.column(); - - if (row < 0 || row >= worlds.size()) - return QVariant(); - - auto & world = worlds[row]; - switch (role) - { - case Qt::DisplayRole: - switch (column) - { - case NameColumn: - return world.name(); - - case LastPlayedColumn: - return world.lastPlayed(); - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - { - return world.folderName(); - } - case ObjectRole: - { - return QVariant::fromValue((void *)&world); - } - case FolderRole: - { - return QDir::toNativeSeparators(dir().absoluteFilePath(world.folderName())); - } - case SeedRole: - { - return qVariantFromValue(world.seed()); - } - case NameRole: - { - return world.name(); - } - case LastPlayedRole: - { - return world.lastPlayed(); - } - default: - return QVariant(); - } -} - -QVariant WorldList::headerData(int section, Qt::Orientation orientation, int role) const -{ - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case NameColumn: - return tr("Name"); - case LastPlayedColumn: - return tr("Last Played"); - default: - return QVariant(); - } - - case Qt::ToolTipRole: - switch (section) - { - case NameColumn: - return tr("The name of the world."); - case LastPlayedColumn: - return tr("Date and time the world was last played."); - default: - return QVariant(); - } - default: - return QVariant(); - } - return QVariant(); -} - -QStringList WorldList::mimeTypes() const -{ - QStringList types; - types << "text/uri-list"; - return types; -} - -class WorldMimeData : public QMimeData -{ -Q_OBJECT - -public: - WorldMimeData(QList worlds) - { - m_worlds = worlds; - - } - QStringList formats() const - { - return QMimeData::formats() << "text/uri-list"; - } - -protected: - QVariant retrieveData(const QString &mimetype, QVariant::Type type) const - { - QList urls; - for(auto &world: m_worlds) - { - if(!world.isValid() || !world.isOnFS()) - continue; - QString worldPath = world.container().absoluteFilePath(); - qDebug() << worldPath; - urls.append(QUrl::fromLocalFile(worldPath)); - } - const_cast(this)->setUrls(urls); - return QMimeData::retrieveData(mimetype, type); - } -private: - QList m_worlds; -}; - -QMimeData *WorldList::mimeData(const QModelIndexList &indexes) const -{ - if (indexes.size() == 0) - return new QMimeData(); - - QList worlds; - for(auto idx : indexes) - { - if(idx.column() != 0) - continue; - int row = idx.row(); - if (row < 0 || row >= this->worlds.size()) - continue; - worlds.append(this->worlds[row]); - } - if(!worlds.size()) - { - return new QMimeData(); - } - return new WorldMimeData(worlds); -} - -Qt::ItemFlags WorldList::flags(const QModelIndex &index) const -{ - Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); - if (index.isValid()) - return Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | - defaultFlags; - else - return Qt::ItemIsDropEnabled | defaultFlags; -} - -Qt::DropActions WorldList::supportedDragActions() const -{ - // move to other mod lists or VOID - return Qt::MoveAction; -} - -Qt::DropActions WorldList::supportedDropActions() const -{ - // copy from outside, move from within and other mod lists - return Qt::CopyAction | Qt::MoveAction; -} - -void WorldList::installWorld(QFileInfo filename) -{ - qDebug() << "installing: " << filename.absoluteFilePath(); - World w(filename); - if(!w.isValid()) - { - return; - } - w.install(m_dir.absolutePath()); -} - -bool WorldList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, - const QModelIndex &parent) -{ - if (action == Qt::IgnoreAction) - return true; - // check if the action is supported - if (!data || !(action & supportedDropActions())) - return false; - // files dropped from outside? - if (data->hasUrls()) - { - bool was_watching = is_watching; - if (was_watching) - stopWatching(); - auto urls = data->urls(); - for (auto url : urls) - { - // only local files may be dropped... - if (!url.isLocalFile()) - continue; - QString filename = url.toLocalFile(); - - QFileInfo worldInfo(filename); - - if(!m_dir.entryInfoList().contains(worldInfo)) - { - installWorld(worldInfo); - } - } - if (was_watching) - startWatching(); - return true; - } - return false; -} - -#include "WorldList.moc" diff --git a/logic/minecraft/WorldList.h b/logic/minecraft/WorldList.h deleted file mode 100644 index 34b30e9c..00000000 --- a/logic/minecraft/WorldList.h +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright 2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include "minecraft/World.h" - -#include "multimc_logic_export.h" - -class QFileSystemWatcher; - -class MULTIMC_LOGIC_EXPORT WorldList : public QAbstractListModel -{ - Q_OBJECT -public: - enum Columns - { - NameColumn, - LastPlayedColumn - }; - - enum Roles - { - ObjectRole = Qt::UserRole + 1, - FolderRole, - SeedRole, - NameRole, - LastPlayedRole - }; - - WorldList(const QString &dir); - - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const - { - return size(); - }; - virtual QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - virtual int columnCount(const QModelIndex &parent) const; - - size_t size() const - { - return worlds.size(); - }; - bool empty() const - { - return size() == 0; - } - World &operator[](size_t index) - { - return worlds[index]; - } - - /// Reloads the mod list and returns true if the list changed. - virtual bool update(); - - /// Install a world from location - void installWorld(QFileInfo filename); - - /// Deletes the mod at the given index. - virtual bool deleteWorld(int index); - - /// Deletes all the selected mods - virtual bool deleteWorlds(int first, int last); - - /// flags, mostly to support drag&drop - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - /// get data for drag action - virtual QMimeData *mimeData(const QModelIndexList &indexes) const; - /// get the supported mime types - virtual QStringList mimeTypes() const; - /// process data from drop action - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); - /// what drag actions do we support? - virtual Qt::DropActions supportedDragActions() const; - - /// what drop actions do we support? - virtual Qt::DropActions supportedDropActions() const; - - void startWatching(); - void stopWatching(); - - virtual bool isValid(); - - QDir dir() const - { - return m_dir; - } - - const QList &allWorlds() const - { - return worlds; - } - -private slots: - void directoryChanged(QString path); - -signals: - void changed(); - -protected: - QFileSystemWatcher *m_watcher; - bool is_watching; - QDir m_dir; - QList worlds; -}; diff --git a/logic/minecraft/auth/AuthSession.cpp b/logic/minecraft/auth/AuthSession.cpp deleted file mode 100644 index 8758bfbd..00000000 --- a/logic/minecraft/auth/AuthSession.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "AuthSession.h" -#include -#include -#include -#include - -QString AuthSession::serializeUserProperties() -{ - QJsonObject userAttrs; - for (auto key : u.properties.keys()) - { - auto array = QJsonArray::fromStringList(u.properties.values(key)); - userAttrs.insert(key, array); - } - QJsonDocument value(userAttrs); - return value.toJson(QJsonDocument::Compact); - -} - -bool AuthSession::MakeOffline(QString offline_playername) -{ - if (status != PlayableOffline && status != PlayableOnline) - { - return false; - } - session = "-"; - player_name = offline_playername; - status = PlayableOffline; - return true; -} diff --git a/logic/minecraft/auth/AuthSession.h b/logic/minecraft/auth/AuthSession.h deleted file mode 100644 index dede90a9..00000000 --- a/logic/minecraft/auth/AuthSession.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "multimc_logic_export.h" - -struct User -{ - QString id; - QMultiMap properties; -}; - -struct MULTIMC_LOGIC_EXPORT AuthSession -{ - bool MakeOffline(QString offline_playername); - - QString serializeUserProperties(); - - enum Status - { - Undetermined, - RequiresPassword, - PlayableOffline, - PlayableOnline - } status = Undetermined; - - User u; - - // client token - QString client_token; - // account user name - QString username; - // combined session ID - QString session; - // volatile auth token - QString access_token; - // profile name - QString player_name; - // profile ID - QString uuid; - // 'legacy' or 'mojang', depending on account type - QString user_type; - // Did the auth server reply? - bool auth_server_online = false; - // Did the user request online mode? - bool wants_online = true; -}; - -typedef std::shared_ptr AuthSessionPtr; diff --git a/logic/minecraft/auth/MojangAccount.cpp b/logic/minecraft/auth/MojangAccount.cpp deleted file mode 100644 index 69a24c09..00000000 --- a/logic/minecraft/auth/MojangAccount.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Authors: Orochimarufan - * - * 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 "MojangAccount.h" -#include "flows/RefreshTask.h" -#include "flows/AuthenticateTask.h" - -#include -#include -#include -#include -#include -#include - -#include - -MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object) -{ - // The JSON object must at least have a username for it to be valid. - if (!object.value("username").isString()) - { - qCritical() << "Can't load Mojang account info from JSON object. Username field is " - "missing or of the wrong type."; - return nullptr; - } - - QString username = object.value("username").toString(""); - QString clientToken = object.value("clientToken").toString(""); - QString accessToken = object.value("accessToken").toString(""); - - QJsonArray profileArray = object.value("profiles").toArray(); - if (profileArray.size() < 1) - { - qCritical() << "Can't load Mojang account with username \"" << username - << "\". No profiles found."; - return nullptr; - } - - QList profiles; - for (QJsonValue profileVal : profileArray) - { - QJsonObject profileObject = profileVal.toObject(); - QString id = profileObject.value("id").toString(""); - QString name = profileObject.value("name").toString(""); - bool legacy = profileObject.value("legacy").toBool(false); - if (id.isEmpty() || name.isEmpty()) - { - qWarning() << "Unable to load a profile because it was missing an ID or a name."; - continue; - } - profiles.append({id, name, legacy}); - } - - MojangAccountPtr account(new MojangAccount()); - if (object.value("user").isObject()) - { - User u; - QJsonObject userStructure = object.value("user").toObject(); - u.id = userStructure.value("id").toString(); - /* - QJsonObject propMap = userStructure.value("properties").toObject(); - for(auto key: propMap.keys()) - { - auto values = propMap.operator[](key).toArray(); - for(auto value: values) - u.properties.insert(key, value.toString()); - } - */ - account->m_user = u; - } - account->m_username = username; - account->m_clientToken = clientToken; - account->m_accessToken = accessToken; - account->m_profiles = profiles; - - // Get the currently selected profile. - QString currentProfile = object.value("activeProfile").toString(""); - if (!currentProfile.isEmpty()) - account->setCurrentProfile(currentProfile); - - return account; -} - -MojangAccountPtr MojangAccount::createFromUsername(const QString &username) -{ - MojangAccountPtr account(new MojangAccount()); - account->m_clientToken = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); - account->m_username = username; - return account; -} - -QJsonObject MojangAccount::saveToJson() const -{ - QJsonObject json; - json.insert("username", m_username); - json.insert("clientToken", m_clientToken); - json.insert("accessToken", m_accessToken); - - QJsonArray profileArray; - for (AccountProfile profile : m_profiles) - { - QJsonObject profileObj; - profileObj.insert("id", profile.id); - profileObj.insert("name", profile.name); - profileObj.insert("legacy", profile.legacy); - profileArray.append(profileObj); - } - json.insert("profiles", profileArray); - - QJsonObject userStructure; - { - userStructure.insert("id", m_user.id); - /* - QJsonObject userAttrs; - for(auto key: m_user.properties.keys()) - { - auto array = QJsonArray::fromStringList(m_user.properties.values(key)); - userAttrs.insert(key, array); - } - userStructure.insert("properties", userAttrs); - */ - } - json.insert("user", userStructure); - - if (m_currentProfile != -1) - json.insert("activeProfile", currentProfile()->id); - - return json; -} - -bool MojangAccount::setCurrentProfile(const QString &profileId) -{ - for (int i = 0; i < m_profiles.length(); i++) - { - if (m_profiles[i].id == profileId) - { - m_currentProfile = i; - return true; - } - } - return false; -} - -const AccountProfile *MojangAccount::currentProfile() const -{ - if (m_currentProfile == -1) - return nullptr; - return &m_profiles[m_currentProfile]; -} - -AccountStatus MojangAccount::accountStatus() const -{ - if (m_accessToken.isEmpty()) - return NotVerified; - else - return Verified; -} - -std::shared_ptr MojangAccount::login(AuthSessionPtr session, - QString password) -{ - Q_ASSERT(m_currentTask.get() == nullptr); - - // take care of the true offline status - if (accountStatus() == NotVerified && password.isEmpty()) - { - if (session) - { - session->status = AuthSession::RequiresPassword; - fillSession(session); - } - return nullptr; - } - - if (password.isEmpty()) - { - m_currentTask.reset(new RefreshTask(this)); - } - else - { - m_currentTask.reset(new AuthenticateTask(this, password)); - } - m_currentTask->assignSession(session); - - connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded())); - connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString))); - return m_currentTask; -} - -void MojangAccount::authSucceeded() -{ - auto session = m_currentTask->getAssignedSession(); - if (session) - { - session->status = - session->wants_online ? AuthSession::PlayableOnline : AuthSession::PlayableOffline; - fillSession(session); - session->auth_server_online = true; - } - m_currentTask.reset(); - emit changed(); -} - -void MojangAccount::authFailed(QString reason) -{ - auto session = m_currentTask->getAssignedSession(); - // This is emitted when the yggdrasil tasks time out or are cancelled. - // -> we treat the error as no-op - if (m_currentTask->state() == YggdrasilTask::STATE_FAILED_SOFT) - { - if (session) - { - session->status = accountStatus() == Verified ? AuthSession::PlayableOffline - : AuthSession::RequiresPassword; - session->auth_server_online = false; - fillSession(session); - } - } - else - { - m_accessToken = QString(); - emit changed(); - if (session) - { - session->status = AuthSession::RequiresPassword; - session->auth_server_online = true; - fillSession(session); - } - } - m_currentTask.reset(); -} - -void MojangAccount::fillSession(AuthSessionPtr session) -{ - // the user name. you have to have an user name - session->username = m_username; - // volatile auth token - session->access_token = m_accessToken; - // the semi-permanent client token - session->client_token = m_clientToken; - if (currentProfile()) - { - // profile name - session->player_name = currentProfile()->name; - // profile ID - session->uuid = currentProfile()->id; - // 'legacy' or 'mojang', depending on account type - session->user_type = currentProfile()->legacy ? "legacy" : "mojang"; - if (!session->access_token.isEmpty()) - { - session->session = "token:" + m_accessToken + ":" + m_profiles[m_currentProfile].id; - } - else - { - session->session = "-"; - } - } - else - { - session->player_name = "Player"; - session->session = "-"; - } - session->u = user(); -} diff --git a/logic/minecraft/auth/MojangAccount.h b/logic/minecraft/auth/MojangAccount.h deleted file mode 100644 index 2de0c19c..00000000 --- a/logic/minecraft/auth/MojangAccount.h +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include "AuthSession.h" - -#include "multimc_logic_export.h" - -class Task; -class YggdrasilTask; -class MojangAccount; - -typedef std::shared_ptr MojangAccountPtr; -Q_DECLARE_METATYPE(MojangAccountPtr) - -/** - * A profile within someone's Mojang account. - * - * Currently, the profile system has not been implemented by Mojang yet, - * but we might as well add some things for it in MultiMC right now so - * we don't have to rip the code to pieces to add it later. - */ -struct AccountProfile -{ - QString id; - QString name; - bool legacy; -}; - -enum AccountStatus -{ - NotVerified, - Verified -}; - -/** - * Object that stores information about a certain Mojang account. - * - * Said information may include things such as that account's username, client token, and access - * token if the user chose to stay logged in. - */ -class MULTIMC_LOGIC_EXPORT MojangAccount : public QObject -{ - Q_OBJECT -public: /* construction */ - //! Do not copy accounts. ever. - explicit MojangAccount(const MojangAccount &other, QObject *parent) = delete; - - //! Default constructor - explicit MojangAccount(QObject *parent = 0) : QObject(parent) {}; - - //! Creates an empty account for the specified user name. - static MojangAccountPtr createFromUsername(const QString &username); - - //! Loads a MojangAccount from the given JSON object. - static MojangAccountPtr loadFromJson(const QJsonObject &json); - - //! Saves a MojangAccount to a JSON object and returns it. - QJsonObject saveToJson() const; - -public: /* manipulation */ - /** - * Sets the currently selected profile to the profile with the given ID string. - * If profileId is not in the list of available profiles, the function will simply return - * false. - */ - bool setCurrentProfile(const QString &profileId); - - /** - * Attempt to login. Empty password means we use the token. - * If the attempt fails because we already are performing some task, it returns false. - */ - std::shared_ptr login(AuthSessionPtr session, - QString password = QString()); - -public: /* queries */ - const QString &username() const - { - return m_username; - } - - const QString &clientToken() const - { - return m_clientToken; - } - - const QString &accessToken() const - { - return m_accessToken; - } - - const QList &profiles() const - { - return m_profiles; - } - - const User &user() - { - return m_user; - } - - //! Returns the currently selected profile (if none, returns nullptr) - const AccountProfile *currentProfile() const; - - //! Returns whether the account is NotVerified, Verified or Online - AccountStatus accountStatus() const; - -signals: - /** - * This signal is emitted when the account changes - */ - void changed(); - - // TODO: better signalling for the various possible state changes - especially errors - -protected: /* variables */ - QString m_username; - - // Used to identify the client - the user can have multiple clients for the same account - // Think: different launchers, all connecting to the same account/profile - QString m_clientToken; - - // Blank if not logged in. - QString m_accessToken; - - // Index of the selected profile within the list of available - // profiles. -1 if nothing is selected. - int m_currentProfile = -1; - - // List of available profiles. - QList m_profiles; - - // the user structure, whatever it is. - User m_user; - - // current task we are executing here - std::shared_ptr m_currentTask; - -private -slots: - void authSucceeded(); - void authFailed(QString reason); - -private: - void fillSession(AuthSessionPtr session); - -public: - friend class YggdrasilTask; - friend class AuthenticateTask; - friend class ValidateTask; - friend class RefreshTask; -}; diff --git a/logic/minecraft/auth/MojangAccountList.cpp b/logic/minecraft/auth/MojangAccountList.cpp deleted file mode 100644 index 26cbc81a..00000000 --- a/logic/minecraft/auth/MojangAccountList.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/* Copyright 2013-2015 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 "MojangAccountList.h" -#include "MojangAccount.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#define ACCOUNT_LIST_FORMAT_VERSION 2 - -MojangAccountList::MojangAccountList(QObject *parent) : QAbstractListModel(parent) -{ -} - -MojangAccountPtr MojangAccountList::findAccount(const QString &username) const -{ - for (int i = 0; i < count(); i++) - { - MojangAccountPtr account = at(i); - if (account->username() == username) - return account; - } - return nullptr; -} - -const MojangAccountPtr MojangAccountList::at(int i) const -{ - return MojangAccountPtr(m_accounts.at(i)); -} - -void MojangAccountList::addAccount(const MojangAccountPtr account) -{ - beginResetModel(); - connect(account.get(), SIGNAL(changed()), SLOT(accountChanged())); - m_accounts.append(account); - endResetModel(); - onListChanged(); -} - -void MojangAccountList::removeAccount(const QString &username) -{ - beginResetModel(); - for (auto account : m_accounts) - { - if (account->username() == username) - { - m_accounts.removeOne(account); - return; - } - } - endResetModel(); - onListChanged(); -} - -void MojangAccountList::removeAccount(QModelIndex index) -{ - beginResetModel(); - m_accounts.removeAt(index.row()); - endResetModel(); - onListChanged(); -} - -MojangAccountPtr MojangAccountList::activeAccount() const -{ - return m_activeAccount; -} - -void MojangAccountList::setActiveAccount(const QString &username) -{ - beginResetModel(); - if (username.isEmpty()) - { - m_activeAccount = nullptr; - } - else - { - for (MojangAccountPtr account : m_accounts) - { - if (account->username() == username) - m_activeAccount = account; - } - } - endResetModel(); - onActiveChanged(); -} - -void MojangAccountList::accountChanged() -{ - // the list changed. there is no doubt. - onListChanged(); -} - -void MojangAccountList::onListChanged() -{ - if (m_autosave) - // TODO: Alert the user if this fails. - saveList(); - - emit listChanged(); -} - -void MojangAccountList::onActiveChanged() -{ - if (m_autosave) - saveList(); - - emit activeAccountChanged(); -} - -int MojangAccountList::count() const -{ - return m_accounts.count(); -} - -QVariant MojangAccountList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (index.row() > count()) - return QVariant(); - - MojangAccountPtr account = at(index.row()); - - switch (role) - { - case Qt::DisplayRole: - switch (index.column()) - { - case NameColumn: - return account->username(); - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - return account->username(); - - case PointerRole: - return qVariantFromValue(account); - - case Qt::CheckStateRole: - switch (index.column()) - { - case ActiveColumn: - return account == m_activeAccount; - } - - default: - return QVariant(); - } -} - -QVariant MojangAccountList::headerData(int section, Qt::Orientation orientation, int role) const -{ - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case ActiveColumn: - return tr("Active?"); - - case NameColumn: - return tr("Name"); - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - switch (section) - { - case NameColumn: - return tr("The name of the version."); - - default: - return QVariant(); - } - - default: - return QVariant(); - } -} - -int MojangAccountList::rowCount(const QModelIndex &parent) const -{ - // Return count - return count(); -} - -int MojangAccountList::columnCount(const QModelIndex &parent) const -{ - return 2; -} - -Qt::ItemFlags MojangAccountList::flags(const QModelIndex &index) const -{ - if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid()) - { - return Qt::NoItemFlags; - } - - return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -bool MojangAccountList::setData(const QModelIndex &index, const QVariant &value, int role) -{ - if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid()) - { - return false; - } - - if(role == Qt::CheckStateRole) - { - if(value == Qt::Checked) - { - MojangAccountPtr account = this->at(index.row()); - this->setActiveAccount(account->username()); - } - } - - emit dataChanged(index, index); - return true; -} - -void MojangAccountList::updateListData(QList versions) -{ - beginResetModel(); - m_accounts = versions; - endResetModel(); -} - -bool MojangAccountList::loadList(const QString &filePath) -{ - QString path = filePath; - if (path.isEmpty()) - path = m_listFilePath; - if (path.isEmpty()) - { - qCritical() << "Can't load Mojang account list. No file path given and no default set."; - return false; - } - - QFile file(path); - - // Try to open the file and fail if we can't. - // TODO: We should probably report this error to the user. - if (!file.open(QIODevice::ReadOnly)) - { - qCritical() << QString("Failed to read the account list file (%1).").arg(path).toUtf8(); - return false; - } - - // Read the file and close it. - QByteArray jsonData = file.readAll(); - file.close(); - - QJsonParseError parseError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError); - - // Fail if the JSON is invalid. - if (parseError.error != QJsonParseError::NoError) - { - qCritical() << QString("Failed to parse account list file: %1 at offset %2") - .arg(parseError.errorString(), QString::number(parseError.offset)) - .toUtf8(); - return false; - } - - // Make sure the root is an object. - if (!jsonDoc.isObject()) - { - qCritical() << "Invalid account list JSON: Root should be an array."; - return false; - } - - QJsonObject root = jsonDoc.object(); - - // Make sure the format version matches. - if (root.value("formatVersion").toVariant().toInt() != ACCOUNT_LIST_FORMAT_VERSION) - { - QString newName = "accounts-old.json"; - qWarning() << "Format version mismatch when loading account list. Existing one will be renamed to" - << newName; - - // Attempt to rename the old version. - file.rename(newName); - return false; - } - - // Now, load the accounts array. - beginResetModel(); - QJsonArray accounts = root.value("accounts").toArray(); - for (QJsonValue accountVal : accounts) - { - QJsonObject accountObj = accountVal.toObject(); - MojangAccountPtr account = MojangAccount::loadFromJson(accountObj); - if (account.get() != nullptr) - { - connect(account.get(), SIGNAL(changed()), SLOT(accountChanged())); - m_accounts.append(account); - } - else - { - qWarning() << "Failed to load an account."; - } - } - // Load the active account. - m_activeAccount = findAccount(root.value("activeAccount").toString("")); - endResetModel(); - return true; -} - -bool MojangAccountList::saveList(const QString &filePath) -{ - QString path(filePath); - if (path.isEmpty()) - path = m_listFilePath; - if (path.isEmpty()) - { - qCritical() << "Can't save Mojang account list. No file path given and no default set."; - return false; - } - - // make sure the parent folder exists - if(!FS::ensureFilePathExists(path)) - return false; - - // make sure the file wasn't overwritten with a folder before (fixes a bug) - QFileInfo finfo(path); - if(finfo.isDir()) - { - QDir badDir(path); - badDir.removeRecursively(); - } - - qDebug() << "Writing account list to" << path; - - qDebug() << "Building JSON data structure."; - // Build the JSON document to write to the list file. - QJsonObject root; - - root.insert("formatVersion", ACCOUNT_LIST_FORMAT_VERSION); - - // Build a list of accounts. - qDebug() << "Building account array."; - QJsonArray accounts; - for (MojangAccountPtr account : m_accounts) - { - QJsonObject accountObj = account->saveToJson(); - accounts.append(accountObj); - } - - // Insert the account list into the root object. - root.insert("accounts", accounts); - - if(m_activeAccount) - { - // Save the active account. - root.insert("activeAccount", m_activeAccount->username()); - } - - // Create a JSON document object to convert our JSON to bytes. - QJsonDocument doc(root); - - // Now that we're done building the JSON object, we can write it to the file. - qDebug() << "Writing account list to file."; - QFile file(path); - - // Try to open the file and fail if we can't. - // TODO: We should probably report this error to the user. - if (!file.open(QIODevice::WriteOnly)) - { - qCritical() << QString("Failed to read the account list file (%1).").arg(path).toUtf8(); - return false; - } - - // Write the JSON to the file. - file.write(doc.toJson()); - file.setPermissions(QFile::ReadOwner|QFile::WriteOwner|QFile::ReadUser|QFile::WriteUser); - file.close(); - - qDebug() << "Saved account list to" << path; - - return true; -} - -void MojangAccountList::setListFilePath(QString path, bool autosave) -{ - m_listFilePath = path; - m_autosave = autosave; -} - -bool MojangAccountList::anyAccountIsValid() -{ - for(auto account:m_accounts) - { - if(account->accountStatus() != NotVerified) - return true; - } - return false; -} diff --git a/logic/minecraft/auth/MojangAccountList.h b/logic/minecraft/auth/MojangAccountList.h deleted file mode 100644 index c40fa6a3..00000000 --- a/logic/minecraft/auth/MojangAccountList.h +++ /dev/null @@ -1,201 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "MojangAccount.h" - -#include -#include -#include -#include - -#include "multimc_logic_export.h" - -/*! - * \brief List of available Mojang accounts. - * This should be loaded in the background by MultiMC on startup. - * - * This class also inherits from QAbstractListModel. Methods from that - * class determine how this list shows up in a list view. Said methods - * all have a default implementation, but they can be overridden by subclasses to - * change the behavior of the list. - */ -class MULTIMC_LOGIC_EXPORT MojangAccountList : public QAbstractListModel -{ - Q_OBJECT -public: - enum ModelRoles - { - PointerRole = 0x34B1CB48 - }; - - enum VListColumns - { - // TODO: Add icon column. - - // First column - Active? - ActiveColumn = 0, - - // Second column - Name - NameColumn, - }; - - explicit MojangAccountList(QObject *parent = 0); - - //! Gets the account at the given index. - virtual const MojangAccountPtr at(int i) const; - - //! Returns the number of accounts in the list. - virtual int count() const; - - //////// List Model Functions //////// - virtual QVariant data(const QModelIndex &index, int role) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; - virtual int rowCount(const QModelIndex &parent) const; - virtual int columnCount(const QModelIndex &parent) const; - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role); - - /*! - * Adds a the given Mojang account to the account list. - */ - virtual void addAccount(const MojangAccountPtr account); - - /*! - * Removes the mojang account with the given username from the account list. - */ - virtual void removeAccount(const QString &username); - - /*! - * Removes the account at the given QModelIndex. - */ - virtual void removeAccount(QModelIndex index); - - /*! - * \brief Finds an account by its username. - * \param The username of the account to find. - * \return A const pointer to the account with the given username. NULL if - * one doesn't exist. - */ - virtual MojangAccountPtr findAccount(const QString &username) const; - - /*! - * Sets the default path to save the list file to. - * If autosave is true, this list will automatically save to the given path whenever it changes. - * THIS FUNCTION DOES NOT LOAD THE LIST. If you set autosave, be sure to call loadList() immediately - * after calling this function to ensure an autosaved change doesn't overwrite the list you intended - * to load. - */ - virtual void setListFilePath(QString path, bool autosave = false); - - /*! - * \brief Loads the account list from the given file path. - * If the given file is an empty string (default), will load from the default account list file. - * \return True if successful, otherwise false. - */ - virtual bool loadList(const QString &file = ""); - - /*! - * \brief Saves the account list to the given file. - * If the given file is an empty string (default), will save from the default account list file. - * \return True if successful, otherwise false. - */ - virtual bool saveList(const QString &file = ""); - - /*! - * \brief Gets a pointer to the account that the user has selected as their "active" account. - * Which account is active can be overridden on a per-instance basis, but this will return the one that - * is set as active globally. - * \return The currently active MojangAccount. If there isn't an active account, returns a null pointer. - */ - virtual MojangAccountPtr activeAccount() const; - - /*! - * Sets the given account as the current active account. - * If the username given is an empty string, sets the active account to nothing. - */ - virtual void setActiveAccount(const QString &username); - - /*! - * Returns true if any of the account is at least Validated - */ - bool anyAccountIsValid(); - -signals: - /*! - * Signal emitted to indicate that the account list has changed. - * This will also fire if the value of an element in the list changes (will be implemented - * later). - */ - void listChanged(); - - /*! - * Signal emitted to indicate that the active account has changed. - */ - void activeAccountChanged(); - -public -slots: - /** - * This is called when one of the accounts changes and the list needs to be updated - */ - void accountChanged(); - -protected: - /*! - * Called whenever the list changes. - * This emits the listChanged() signal and autosaves the list (if autosave is enabled). - */ - void onListChanged(); - - /*! - * Called whenever the active account changes. - * Emits the activeAccountChanged() signal and autosaves the list if enabled. - */ - void onActiveChanged(); - - QList m_accounts; - - /*! - * Account that is currently active. - */ - MojangAccountPtr m_activeAccount; - - //! Path to the account list file. Empty string if there isn't one. - QString m_listFilePath; - - /*! - * If true, the account list will automatically save to the account list path when it changes. - * Ignored if m_listFilePath is blank. - */ - bool m_autosave = false; - -protected -slots: - /*! - * Updates this list with the given list of accounts. - * This is done by copying each account in the given list and inserting it - * into this one. - * We need to do this so that we can set the parents of the accounts are set to this - * account list. This can't be done in the load task, because the accounts the load - * task creates are on the load task's thread and Qt won't allow their parents - * to be set to something created on another thread. - * To get around that problem, we invoke this method on the GUI thread, which - * then copies the accounts and sets their parents correctly. - * \param accounts List of accounts whose parents should be set. - */ - virtual void updateListData(QList versions); -}; diff --git a/logic/minecraft/auth/YggdrasilTask.cpp b/logic/minecraft/auth/YggdrasilTask.cpp deleted file mode 100644 index c6971c9f..00000000 --- a/logic/minecraft/auth/YggdrasilTask.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* Copyright 2013-2015 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 "YggdrasilTask.h" -#include "MojangAccount.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -YggdrasilTask::YggdrasilTask(MojangAccount *account, QObject *parent) - : Task(parent), m_account(account) -{ - changeState(STATE_CREATED); -} - -void YggdrasilTask::executeTask() -{ - changeState(STATE_SENDING_REQUEST); - - // Get the content of the request we're going to send to the server. - QJsonDocument doc(getRequestContent()); - - auto worker = ENV.qnam(); - QUrl reqUrl("https://" + URLConstants::AUTH_BASE + getEndpoint()); - QNetworkRequest netRequest(reqUrl); - netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - - QByteArray requestData = doc.toJson(); - m_netReply = worker->post(netRequest, requestData); - connect(m_netReply, &QNetworkReply::finished, this, &YggdrasilTask::processReply); - connect(m_netReply, &QNetworkReply::uploadProgress, this, &YggdrasilTask::refreshTimers); - connect(m_netReply, &QNetworkReply::downloadProgress, this, &YggdrasilTask::refreshTimers); - connect(m_netReply, &QNetworkReply::sslErrors, this, &YggdrasilTask::sslErrors); - timeout_keeper.setSingleShot(true); - timeout_keeper.start(timeout_max); - counter.setSingleShot(false); - counter.start(time_step); - progress(0, timeout_max); - connect(&timeout_keeper, &QTimer::timeout, this, &YggdrasilTask::abortByTimeout); - connect(&counter, &QTimer::timeout, this, &YggdrasilTask::heartbeat); -} - -void YggdrasilTask::refreshTimers(qint64, qint64) -{ - timeout_keeper.stop(); - timeout_keeper.start(timeout_max); - progress(count = 0, timeout_max); -} -void YggdrasilTask::heartbeat() -{ - count += time_step; - progress(count, timeout_max); -} - -bool YggdrasilTask::abort() -{ - progress(timeout_max, timeout_max); - // TODO: actually use this in a meaningful way - m_aborted = YggdrasilTask::BY_USER; - m_netReply->abort(); - return true; -} - -void YggdrasilTask::abortByTimeout() -{ - progress(timeout_max, timeout_max); - // TODO: actually use this in a meaningful way - m_aborted = YggdrasilTask::BY_TIMEOUT; - m_netReply->abort(); -} - -void YggdrasilTask::sslErrors(QList errors) -{ - int i = 1; - for (auto error : errors) - { - qCritical() << "LOGIN SSL Error #" << i << " : " << error.errorString(); - auto cert = error.certificate(); - qCritical() << "Certificate in question:\n" << cert.toText(); - i++; - } -} - -void YggdrasilTask::processReply() -{ - changeState(STATE_PROCESSING_RESPONSE); - - switch (m_netReply->error()) - { - case QNetworkReply::NoError: - break; - case QNetworkReply::TimeoutError: - changeState(STATE_FAILED_SOFT, tr("Authentication operation timed out.")); - return; - case QNetworkReply::OperationCanceledError: - changeState(STATE_FAILED_SOFT, tr("Authentication operation cancelled.")); - return; - case QNetworkReply::SslHandshakeFailedError: - changeState( - STATE_FAILED_SOFT, - tr("SSL Handshake failed.
There might be a few causes for it:
" - "
    " - "
  • You use Windows XP and need to update " - "your root certificates
  • " - "
  • Some device on your network is interfering with SSL traffic. In that case, " - "you have bigger worries than Minecraft not starting.
  • " - "
  • Possibly something else. Check the MultiMC log file for details
  • " - "
")); - return; - // used for invalid credentials and similar errors. Fall through. - case QNetworkReply::ContentOperationNotPermittedError: - break; - default: - changeState(STATE_FAILED_SOFT, - tr("Authentication operation failed due to a network error: %1 (%2)") - .arg(m_netReply->errorString()).arg(m_netReply->error())); - return; - } - - // Try to parse the response regardless of the response code. - // Sometimes the auth server will give more information and an error code. - QJsonParseError jsonError; - QByteArray replyData = m_netReply->readAll(); - QJsonDocument doc = QJsonDocument::fromJson(replyData, &jsonError); - // Check the response code. - int responseCode = m_netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (responseCode == 200) - { - // If the response code was 200, then there shouldn't be an error. Make sure - // anyways. - // Also, sometimes an empty reply indicates success. If there was no data received, - // pass an empty json object to the processResponse function. - if (jsonError.error == QJsonParseError::NoError || replyData.size() == 0) - { - processResponse(replyData.size() > 0 ? doc.object() : QJsonObject()); - return; - } - else - { - changeState(STATE_FAILED_SOFT, tr("Failed to parse authentication server response " - "JSON response: %1 at offset %2.") - .arg(jsonError.errorString()) - .arg(jsonError.offset)); - qCritical() << replyData; - } - return; - } - - // If the response code was not 200, then Yggdrasil may have given us information - // about the error. - // If we can parse the response, then get information from it. Otherwise just say - // there was an unknown error. - if (jsonError.error == QJsonParseError::NoError) - { - // We were able to parse the server's response. Woo! - // Call processError. If a subclass has overridden it then they'll handle their - // stuff there. - qDebug() << "The request failed, but the server gave us an error message. " - "Processing error."; - processError(doc.object()); - } - else - { - // The server didn't say anything regarding the error. Give the user an unknown - // error. - qDebug() - << "The request failed and the server gave no error message. Unknown error."; - changeState(STATE_FAILED_SOFT, - tr("An unknown error occurred when trying to communicate with the " - "authentication server: %1").arg(m_netReply->errorString())); - } -} - -void YggdrasilTask::processError(QJsonObject responseData) -{ - QJsonValue errorVal = responseData.value("error"); - QJsonValue errorMessageValue = responseData.value("errorMessage"); - QJsonValue causeVal = responseData.value("cause"); - - if (errorVal.isString() && errorMessageValue.isString()) - { - m_error = std::shared_ptr(new Error{ - errorVal.toString(""), errorMessageValue.toString(""), causeVal.toString("")}); - changeState(STATE_FAILED_HARD, m_error->m_errorMessageVerbose); - } - else - { - // Error is not in standard format. Don't set m_error and return unknown error. - changeState(STATE_FAILED_HARD, tr("An unknown Yggdrasil error occurred.")); - } -} - -QString YggdrasilTask::getStateMessage() const -{ - switch (m_state) - { - case STATE_CREATED: - return "Waiting..."; - case STATE_SENDING_REQUEST: - return tr("Sending request to auth servers..."); - case STATE_PROCESSING_RESPONSE: - return tr("Processing response from servers..."); - case STATE_SUCCEEDED: - return tr("Authentication task succeeded."); - case STATE_FAILED_SOFT: - return tr("Failed to contact the authentication server."); - case STATE_FAILED_HARD: - return tr("Failed to authenticate."); - default: - return tr("..."); - } -} - -void YggdrasilTask::changeState(YggdrasilTask::State newState, QString reason) -{ - m_state = newState; - setStatus(getStateMessage()); - if (newState == STATE_SUCCEEDED) - { - emitSucceeded(); - } - else if (newState == STATE_FAILED_HARD || newState == STATE_FAILED_SOFT) - { - emitFailed(reason); - } -} - -YggdrasilTask::State YggdrasilTask::state() -{ - return m_state; -} diff --git a/logic/minecraft/auth/YggdrasilTask.h b/logic/minecraft/auth/YggdrasilTask.h deleted file mode 100644 index c84cfc06..00000000 --- a/logic/minecraft/auth/YggdrasilTask.h +++ /dev/null @@ -1,150 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include -#include -#include -#include - -#include "MojangAccount.h" - -class QNetworkReply; - -/** - * A Yggdrasil task is a task that performs an operation on a given mojang account. - */ -class YggdrasilTask : public Task -{ - Q_OBJECT -public: - explicit YggdrasilTask(MojangAccount * account, QObject *parent = 0); - - /** - * assign a session to this task. the session will be filled with required infomration - * upon completion - */ - void assignSession(AuthSessionPtr session) - { - m_session = session; - } - - /// get the assigned session for filling with information. - AuthSessionPtr getAssignedSession() - { - return m_session; - } - - /** - * Class describing a Yggdrasil error response. - */ - struct Error - { - QString m_errorMessageShort; - QString m_errorMessageVerbose; - QString m_cause; - }; - - enum AbortedBy - { - BY_NOTHING, - BY_USER, - BY_TIMEOUT - } m_aborted = BY_NOTHING; - - /** - * Enum for describing the state of the current task. - * Used by the getStateMessage function to determine what the status message should be. - */ - enum State - { - STATE_CREATED, - STATE_SENDING_REQUEST, - STATE_PROCESSING_RESPONSE, - STATE_FAILED_SOFT, //!< soft failure. this generally means the user auth details haven't been invalidated - STATE_FAILED_HARD, //!< hard failure. auth is invalid - STATE_SUCCEEDED - } m_state = STATE_CREATED; - -protected: - - virtual void executeTask() override; - - /** - * Gets the JSON object that will be sent to the authentication server. - * Should be overridden by subclasses. - */ - virtual QJsonObject getRequestContent() const = 0; - - /** - * Gets the endpoint to POST to. - * No leading slash. - */ - virtual QString getEndpoint() const = 0; - - /** - * Processes the response received from the server. - * If an error occurred, this should emit a failed signal and return false. - * If Yggdrasil gave an error response, it should call setError() first, and then return false. - * Otherwise, it should return true. - * Note: If the response from the server was blank, and the HTTP code was 200, this function is called with - * an empty QJsonObject. - */ - virtual void processResponse(QJsonObject responseData) = 0; - - /** - * Processes an error response received from the server. - * The default implementation will read data from Yggdrasil's standard error response format and set it as this task's Error. - * \returns a QString error message that will be passed to emitFailed. - */ - virtual void processError(QJsonObject responseData); - - /** - * Returns the state message for the given state. - * Used to set the status message for the task. - * Should be overridden by subclasses that want to change messages for a given state. - */ - virtual QString getStateMessage() const; - -protected -slots: - void processReply(); - void refreshTimers(qint64, qint64); - void heartbeat(); - void sslErrors(QList); - - void changeState(State newState, QString reason=QString()); -public -slots: - virtual bool abort() override; - void abortByTimeout(); - State state(); -protected: - // FIXME: segfault disaster waiting to happen - MojangAccount *m_account = nullptr; - QNetworkReply *m_netReply = nullptr; - std::shared_ptr m_error; - QTimer timeout_keeper; - QTimer counter; - int count = 0; // num msec since time reset - - const int timeout_max = 30000; - const int time_step = 50; - - AuthSessionPtr m_session; -}; diff --git a/logic/minecraft/auth/flows/AuthenticateTask.cpp b/logic/minecraft/auth/flows/AuthenticateTask.cpp deleted file mode 100644 index 8d136f0b..00000000 --- a/logic/minecraft/auth/flows/AuthenticateTask.cpp +++ /dev/null @@ -1,202 +0,0 @@ - -/* Copyright 2013-2015 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 "AuthenticateTask.h" -#include "../MojangAccount.h" - -#include -#include -#include -#include - -#include -#include - -AuthenticateTask::AuthenticateTask(MojangAccount * account, const QString &password, - QObject *parent) - : YggdrasilTask(account, parent), m_password(password) -{ -} - -QJsonObject AuthenticateTask::getRequestContent() const -{ - /* - * { - * "agent": { // optional - * "name": "Minecraft", // So far this is the only encountered value - * "version": 1 // This number might be increased - * // by the vanilla client in the future - * }, - * "username": "mojang account name", // Can be an email address or player name for - // unmigrated accounts - * "password": "mojang account password", - * "clientToken": "client identifier" // optional - * "requestUser": true/false // request the user structure - * } - */ - QJsonObject req; - - { - QJsonObject agent; - // C++ makes string literals void* for some stupid reason, so we have to tell it - // QString... Thanks Obama. - agent.insert("name", QString("Minecraft")); - agent.insert("version", 1); - req.insert("agent", agent); - } - - req.insert("username", m_account->username()); - req.insert("password", m_password); - req.insert("requestUser", true); - - // If we already have a client token, give it to the server. - // Otherwise, let the server give us one. - - if(m_account->m_clientToken.isEmpty()) - { - auto uuid = QUuid::createUuid(); - auto uuidString = uuid.toString().remove('{').remove('-').remove('}'); - m_account->m_clientToken = uuidString; - } - req.insert("clientToken", m_account->m_clientToken); - - return req; -} - -void AuthenticateTask::processResponse(QJsonObject responseData) -{ - // Read the response data. We need to get the client token, access token, and the selected - // profile. - qDebug() << "Processing authentication response."; - // qDebug() << responseData; - // If we already have a client token, make sure the one the server gave us matches our - // existing one. - qDebug() << "Getting client token."; - QString clientToken = responseData.value("clientToken").toString(""); - if (clientToken.isEmpty()) - { - // Fail if the server gave us an empty client token - changeState(STATE_FAILED_HARD, tr("Authentication server didn't send a client token.")); - return; - } - if (!m_account->m_clientToken.isEmpty() && clientToken != m_account->m_clientToken) - { - changeState(STATE_FAILED_HARD, tr("Authentication server attempted to change the client token. This isn't supported.")); - return; - } - // Set the client token. - m_account->m_clientToken = clientToken; - - // Now, we set the access token. - qDebug() << "Getting access token."; - QString accessToken = responseData.value("accessToken").toString(""); - if (accessToken.isEmpty()) - { - // Fail if the server didn't give us an access token. - changeState(STATE_FAILED_HARD, tr("Authentication server didn't send an access token.")); - return; - } - // Set the access token. - m_account->m_accessToken = accessToken; - - // Now we load the list of available profiles. - // Mojang hasn't yet implemented the profile system, - // but we might as well support what's there so we - // don't have trouble implementing it later. - qDebug() << "Loading profile list."; - QJsonArray availableProfiles = responseData.value("availableProfiles").toArray(); - QList loadedProfiles; - for (auto iter : availableProfiles) - { - QJsonObject profile = iter.toObject(); - // Profiles are easy, we just need their ID and name. - QString id = profile.value("id").toString(""); - QString name = profile.value("name").toString(""); - bool legacy = profile.value("legacy").toBool(false); - - if (id.isEmpty() || name.isEmpty()) - { - // This should never happen, but we might as well - // warn about it if it does so we can debug it easily. - // You never know when Mojang might do something truly derpy. - qWarning() << "Found entry in available profiles list with missing ID or name " - "field. Ignoring it."; - } - - // Now, add a new AccountProfile entry to the list. - loadedProfiles.append({id, name, legacy}); - } - // Put the list of profiles we loaded into the MojangAccount object. - m_account->m_profiles = loadedProfiles; - - // Finally, we set the current profile to the correct value. This is pretty simple. - // We do need to make sure that the current profile that the server gave us - // is actually in the available profiles list. - // If it isn't, we'll just fail horribly (*shouldn't* ever happen, but you never know). - qDebug() << "Setting current profile."; - QJsonObject currentProfile = responseData.value("selectedProfile").toObject(); - QString currentProfileId = currentProfile.value("id").toString(""); - if (currentProfileId.isEmpty()) - { - changeState(STATE_FAILED_HARD, tr("Authentication server didn't specify a currently selected profile. The account exists, but likely isn't premium.")); - return; - } - if (!m_account->setCurrentProfile(currentProfileId)) - { - changeState(STATE_FAILED_HARD, tr("Authentication server specified a selected profile that wasn't in the available profiles list.")); - return; - } - - // this is what the vanilla launcher passes to the userProperties launch param - if (responseData.contains("user")) - { - User u; - auto obj = responseData.value("user").toObject(); - u.id = obj.value("id").toString(); - auto propArray = obj.value("properties").toArray(); - for (auto prop : propArray) - { - auto propTuple = prop.toObject(); - auto name = propTuple.value("name").toString(); - auto value = propTuple.value("value").toString(); - u.properties.insert(name, value); - } - m_account->m_user = u; - } - - // We've made it through the minefield of possible errors. Return true to indicate that - // we've succeeded. - qDebug() << "Finished reading authentication response."; - changeState(STATE_SUCCEEDED); -} - -QString AuthenticateTask::getEndpoint() const -{ - return "authenticate"; -} - -QString AuthenticateTask::getStateMessage() const -{ - switch (m_state) - { - case STATE_SENDING_REQUEST: - return tr("Authenticating: Sending request..."); - case STATE_PROCESSING_RESPONSE: - return tr("Authenticating: Processing response..."); - default: - return YggdrasilTask::getStateMessage(); - } -} diff --git a/logic/minecraft/auth/flows/AuthenticateTask.h b/logic/minecraft/auth/flows/AuthenticateTask.h deleted file mode 100644 index 398fab98..00000000 --- a/logic/minecraft/auth/flows/AuthenticateTask.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "../YggdrasilTask.h" - -#include -#include -#include - -/** - * The authenticate task takes a MojangAccount with no access token and password and attempts to - * authenticate with Mojang's servers. - * If successful, it will set the MojangAccount's access token. - */ -class AuthenticateTask : public YggdrasilTask -{ - Q_OBJECT -public: - AuthenticateTask(MojangAccount *account, const QString &password, QObject *parent = 0); - -protected: - virtual QJsonObject getRequestContent() const override; - - virtual QString getEndpoint() const override; - - virtual void processResponse(QJsonObject responseData) override; - - virtual QString getStateMessage() const override; - -private: - QString m_password; -}; diff --git a/logic/minecraft/auth/flows/RefreshTask.cpp b/logic/minecraft/auth/flows/RefreshTask.cpp deleted file mode 100644 index a0fb2e48..00000000 --- a/logic/minecraft/auth/flows/RefreshTask.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* Copyright 2013-2015 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 "RefreshTask.h" -#include "../MojangAccount.h" - -#include -#include -#include -#include - -#include - -RefreshTask::RefreshTask(MojangAccount *account) : YggdrasilTask(account) -{ -} - -QJsonObject RefreshTask::getRequestContent() const -{ - /* - * { - * "clientToken": "client identifier" - * "accessToken": "current access token to be refreshed" - * "selectedProfile": // specifying this causes errors - * { - * "id": "profile ID" - * "name": "profile name" - * } - * "requestUser": true/false // request the user structure - * } - */ - QJsonObject req; - req.insert("clientToken", m_account->m_clientToken); - req.insert("accessToken", m_account->m_accessToken); - /* - { - auto currentProfile = m_account->currentProfile(); - QJsonObject profile; - profile.insert("id", currentProfile->id()); - profile.insert("name", currentProfile->name()); - req.insert("selectedProfile", profile); - } - */ - req.insert("requestUser", true); - - return req; -} - -void RefreshTask::processResponse(QJsonObject responseData) -{ - // Read the response data. We need to get the client token, access token, and the selected - // profile. - qDebug() << "Processing authentication response."; - - // qDebug() << responseData; - // If we already have a client token, make sure the one the server gave us matches our - // existing one. - QString clientToken = responseData.value("clientToken").toString(""); - if (clientToken.isEmpty()) - { - // Fail if the server gave us an empty client token - changeState(STATE_FAILED_HARD, tr("Authentication server didn't send a client token.")); - return; - } - if (!m_account->m_clientToken.isEmpty() && clientToken != m_account->m_clientToken) - { - changeState(STATE_FAILED_HARD, tr("Authentication server attempted to change the client token. This isn't supported.")); - return; - } - - // Now, we set the access token. - qDebug() << "Getting new access token."; - QString accessToken = responseData.value("accessToken").toString(""); - if (accessToken.isEmpty()) - { - // Fail if the server didn't give us an access token. - changeState(STATE_FAILED_HARD, tr("Authentication server didn't send an access token.")); - return; - } - - // we validate that the server responded right. (our current profile = returned current - // profile) - QJsonObject currentProfile = responseData.value("selectedProfile").toObject(); - QString currentProfileId = currentProfile.value("id").toString(""); - if (m_account->currentProfile()->id != currentProfileId) - { - changeState(STATE_FAILED_HARD, tr("Authentication server didn't specify the same prefile as expected.")); - return; - } - - // this is what the vanilla launcher passes to the userProperties launch param - if (responseData.contains("user")) - { - User u; - auto obj = responseData.value("user").toObject(); - u.id = obj.value("id").toString(); - auto propArray = obj.value("properties").toArray(); - for (auto prop : propArray) - { - auto propTuple = prop.toObject(); - auto name = propTuple.value("name").toString(); - auto value = propTuple.value("value").toString(); - u.properties.insert(name, value); - } - m_account->m_user = u; - } - - // We've made it through the minefield of possible errors. Return true to indicate that - // we've succeeded. - qDebug() << "Finished reading refresh response."; - // Reset the access token. - m_account->m_accessToken = accessToken; - changeState(STATE_SUCCEEDED); -} - -QString RefreshTask::getEndpoint() const -{ - return "refresh"; -} - -QString RefreshTask::getStateMessage() const -{ - switch (m_state) - { - case STATE_SENDING_REQUEST: - return tr("Refreshing login token..."); - case STATE_PROCESSING_RESPONSE: - return tr("Refreshing login token: Processing response..."); - default: - return YggdrasilTask::getStateMessage(); - } -} diff --git a/logic/minecraft/auth/flows/RefreshTask.h b/logic/minecraft/auth/flows/RefreshTask.h deleted file mode 100644 index 17714b4f..00000000 --- a/logic/minecraft/auth/flows/RefreshTask.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "../YggdrasilTask.h" - -#include -#include -#include - -/** - * The authenticate task takes a MojangAccount with a possibly timed-out access token - * and attempts to authenticate with Mojang's servers. - * If successful, it will set the new access token. The token is considered validated. - */ -class RefreshTask : public YggdrasilTask -{ - Q_OBJECT -public: - RefreshTask(MojangAccount * account); - -protected: - virtual QJsonObject getRequestContent() const override; - - virtual QString getEndpoint() const override; - - virtual void processResponse(QJsonObject responseData) override; - - virtual QString getStateMessage() const override; -}; - diff --git a/logic/minecraft/auth/flows/ValidateTask.cpp b/logic/minecraft/auth/flows/ValidateTask.cpp deleted file mode 100644 index 4deceb6a..00000000 --- a/logic/minecraft/auth/flows/ValidateTask.cpp +++ /dev/null @@ -1,61 +0,0 @@ - -/* Copyright 2013-2015 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 "ValidateTask.h" -#include "../MojangAccount.h" - -#include -#include -#include -#include - -#include - -ValidateTask::ValidateTask(MojangAccount * account, QObject *parent) - : YggdrasilTask(account, parent) -{ -} - -QJsonObject ValidateTask::getRequestContent() const -{ - QJsonObject req; - req.insert("accessToken", m_account->m_accessToken); - return req; -} - -void ValidateTask::processResponse(QJsonObject responseData) -{ - // Assume that if processError wasn't called, then the request was successful. - changeState(YggdrasilTask::STATE_SUCCEEDED); -} - -QString ValidateTask::getEndpoint() const -{ - return "validate"; -} - -QString ValidateTask::getStateMessage() const -{ - switch (m_state) - { - case YggdrasilTask::STATE_SENDING_REQUEST: - return tr("Validating access token: Sending request..."); - case YggdrasilTask::STATE_PROCESSING_RESPONSE: - return tr("Validating access token: Processing response..."); - default: - return YggdrasilTask::getStateMessage(); - } -} diff --git a/logic/minecraft/auth/flows/ValidateTask.h b/logic/minecraft/auth/flows/ValidateTask.h deleted file mode 100644 index 77d628a0..00000000 --- a/logic/minecraft/auth/flows/ValidateTask.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2013-2015 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. - */ - -/* - * :FIXME: DEAD CODE, DEAD CODE, DEAD CODE! :FIXME: - */ - -#pragma once - -#include "../YggdrasilTask.h" - -#include -#include -#include - -/** - * The validate task takes a MojangAccount and checks to make sure its access token is valid. - */ -class ValidateTask : public YggdrasilTask -{ - Q_OBJECT -public: - ValidateTask(MojangAccount *account, QObject *parent = 0); - -protected: - virtual QJsonObject getRequestContent() const override; - - virtual QString getEndpoint() const override; - - virtual void processResponse(QJsonObject responseData) override; - - virtual QString getStateMessage() const override; - -private: -}; diff --git a/logic/minecraft/forge/ForgeInstaller.cpp b/logic/minecraft/forge/ForgeInstaller.cpp deleted file mode 100644 index 353328ab..00000000 --- a/logic/minecraft/forge/ForgeInstaller.cpp +++ /dev/null @@ -1,458 +0,0 @@ -/* Copyright 2013-2015 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 "ForgeInstaller.h" -#include "ForgeVersionList.h" - -#include "minecraft/MinecraftProfile.h" -#include "minecraft/GradleSpecifier.h" -#include "net/HttpMetaCache.h" -#include "tasks/Task.h" -#include "minecraft/onesix/OneSixInstance.h" -#include -#include "minecraft/VersionFilterData.h" -#include "minecraft/MinecraftVersion.h" -#include "Env.h" -#include "Exception.h" -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -ForgeInstaller::ForgeInstaller() : BaseInstaller() -{ -} - -void ForgeInstaller::prepare(const QString &filename, const QString &universalUrl) -{ - VersionFilePtr newVersion; - m_universal_url = universalUrl; - - QuaZip zip(filename); - if (!zip.open(QuaZip::mdUnzip)) - return; - - QuaZipFile file(&zip); - - // read the install profile - if (!zip.setCurrentFile("install_profile.json")) - return; - - QJsonParseError jsonError; - if (!file.open(QIODevice::ReadOnly)) - return; - QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll(), &jsonError); - file.close(); - if (jsonError.error != QJsonParseError::NoError) - return; - - if (!jsonDoc.isObject()) - return; - - QJsonObject root = jsonDoc.object(); - - auto installVal = root.value("install"); - auto versionInfoVal = root.value("versionInfo"); - if (!installVal.isObject() || !versionInfoVal.isObject()) - return; - - try - { - newVersion = OneSixVersionFormat::versionFileFromJson(QJsonDocument(versionInfoVal.toObject()), QString(), false); - } - catch(Exception &err) - { - qWarning() << "Forge: Fatal error while parsing version file:" << err.what(); - return; - } - - for(auto problem: newVersion->getProblems()) - { - qWarning() << "Forge: Problem found: " << problem.getDescription(); - } - if(newVersion->getProblemSeverity() == ProblemSeverity::PROBLEM_ERROR) - { - qWarning() << "Forge: Errors found while parsing version file"; - return; - } - - QJsonObject installObj = installVal.toObject(); - QString libraryName = installObj.value("path").toString(); - internalPath = installObj.value("filePath").toString(); - m_forgeVersionString = installObj.value("version").toString().remove("Forge", Qt::CaseInsensitive).trimmed(); - - // where do we put the library? decode the mojang path - GradleSpecifier lib(libraryName); - - auto cacheentry = ENV.metacache()->resolveEntry("libraries", lib.toPath()); - finalPath = "libraries/" + lib.toPath(); - if (!FS::ensureFilePathExists(finalPath)) - return; - - if (!zip.setCurrentFile(internalPath)) - return; - if (!file.open(QIODevice::ReadOnly)) - return; - { - QByteArray data = file.readAll(); - // extract file - QSaveFile extraction(finalPath); - if (!extraction.open(QIODevice::WriteOnly)) - return; - if (extraction.write(data) != data.size()) - return; - if (!extraction.commit()) - return; - QCryptographicHash md5sum(QCryptographicHash::Md5); - md5sum.addData(data); - - cacheentry->setStale(false); - cacheentry->setMD5Sum(md5sum.result().toHex().constData()); - ENV.metacache()->updateEntry(cacheentry); - } - file.close(); - - m_forge_json = newVersion; -} - -bool ForgeInstaller::add(OneSixInstance *to) -{ - if (!BaseInstaller::add(to)) - { - return false; - } - - if (!m_forge_json) - { - return false; - } - - // A blacklist - QSet blacklist{"authlib", "realms"}; - QList xzlist{"org.scala-lang", "com.typesafe"}; - - // get the minecraft version from the instance - VersionFilePtr minecraft; - auto minecraftPatch = to->getMinecraftProfile()->versionPatch("net.minecraft"); - if(minecraftPatch) - { - minecraft = std::dynamic_pointer_cast(minecraftPatch); - if(!minecraft) - { - auto mcWrap = std::dynamic_pointer_cast(minecraftPatch); - if(mcWrap) - { - minecraft = mcWrap->getVersionFile(); - } - } - } - - // for each library in the version we are adding (except for the blacklisted) - QMutableListIterator iter(m_forge_json->libraries); - while (iter.hasNext()) - { - auto library = iter.next(); - QString libName = library->artifactId(); - QString libVersion = library->version(); - QString rawName = library->rawName(); - - // ignore lwjgl libraries. - if (g_VersionFilterData.lwjglWhitelist.contains(library->artifactPrefix())) - { - iter.remove(); - continue; - } - // ignore other blacklisted (realms, authlib) - if (blacklist.contains(libName)) - { - iter.remove(); - continue; - } - // if minecraft version was found, ignore everything that is already in the minecraft version - if(minecraft) - { - bool found = false; - for (auto & lib: minecraft->libraries) - { - if(library->artifactPrefix() == lib->artifactPrefix() && library->version() == lib->version()) - { - found = true; - break; - } - } - if (found) - continue; - } - - // if this is the actual forge lib, set an absolute url for the download - if (m_forge_version->type == ForgeVersion::Gradle) - { - if (libName == "forge") - { - library->setClassifier("universal"); - } - else if (libName == "minecraftforge") - { - QString forgeCoord("net.minecraftforge:forge:%1:universal"); - // using insane form of the MC version... - QString longVersion = m_forge_version->mcver + "-" + m_forge_version->jobbuildver; - GradleSpecifier spec(forgeCoord.arg(longVersion)); - library->setRawName(spec); - } - } - else - { - if (libName.contains("minecraftforge")) - { - library->setAbsoluteUrl(m_universal_url); - } - } - - // mark bad libraries based on the xzlist above - for (auto entry : xzlist) - { - qDebug() << "Testing " << rawName << " : " << entry; - if (rawName.startsWith(entry)) - { - library->setHint("forge-pack-xz"); - break; - } - } - } - QString &args = m_forge_json->minecraftArguments; - QStringList tweakers; - { - QRegularExpression expression("--tweakClass ([a-zA-Z0-9\\.]*)"); - QRegularExpressionMatch match = expression.match(args); - while (match.hasMatch()) - { - tweakers.append(match.captured(1)); - args.remove(match.capturedStart(), match.capturedLength()); - match = expression.match(args); - } - if(tweakers.size()) - { - args.operator=(args.trimmed()); - m_forge_json->addTweakers = tweakers; - } - } - if(minecraft && args == minecraft->minecraftArguments) - { - args.clear(); - } - - m_forge_json->name = "Forge"; - m_forge_json->fileId = id(); - m_forge_json->version = m_forgeVersionString; - m_forge_json->dependsOnMinecraftVersion = to->intendedVersionId(); - m_forge_json->order = 5; - - // reset some things we do not want to be passed along. - m_forge_json->m_releaseTime = QDateTime(); - m_forge_json->m_updateTime = QDateTime(); - m_forge_json->minimumLauncherVersion = -1; - m_forge_json->type.clear(); - m_forge_json->minecraftArguments.clear(); - m_forge_json->minecraftVersion.clear(); - - QSaveFile file(filename(to->instanceRoot())); - if (!file.open(QFile::WriteOnly)) - { - qCritical() << "Error opening" << file.fileName() - << "for reading:" << file.errorString(); - return false; - } - file.write(OneSixVersionFormat::versionFileToJson(m_forge_json, true).toJson()); - file.commit(); - - return true; -} - -bool ForgeInstaller::addLegacy(OneSixInstance *to) -{ - if (!BaseInstaller::add(to)) - { - return false; - } - auto entry = ENV.metacache()->resolveEntry("minecraftforge", m_forge_version->filename()); - finalPath = FS::PathCombine(to->jarModsDir(), m_forge_version->filename()); - if (!FS::ensureFilePathExists(finalPath)) - { - return false; - } - if (!QFile::copy(entry->getFullPath(), finalPath)) - { - return false; - } - QJsonObject obj; - obj.insert("order", 5); - { - QJsonArray jarmodsPlus; - { - QJsonObject libObj; - libObj.insert("name", m_forge_version->universal_filename); - jarmodsPlus.append(libObj); - } - obj.insert("+jarMods", jarmodsPlus); - } - - obj.insert("name", QString("Forge")); - obj.insert("fileId", id()); - obj.insert("version", m_forge_version->jobbuildver); - obj.insert("mcVersion", to->intendedVersionId()); - if (g_VersionFilterData.fmlLibsMapping.contains(m_forge_version->mcver)) - { - QJsonArray traitsPlus; - traitsPlus.append(QString("legacyFML")); - obj.insert("+traits", traitsPlus); - } - auto fullversion = to->getMinecraftProfile(); - fullversion->remove("net.minecraftforge"); - - QFile file(filename(to->instanceRoot())); - if (!file.open(QFile::WriteOnly)) - { - qCritical() << "Error opening" << file.fileName() - << "for reading:" << file.errorString(); - return false; - } - file.write(QJsonDocument(obj).toJson()); - file.close(); - return true; -} - -class ForgeInstallTask : public Task -{ - Q_OBJECT -public: - ForgeInstallTask(ForgeInstaller *installer, OneSixInstance *instance, - BaseVersionPtr version, QObject *parent = 0) - : Task(parent), m_installer(installer), m_instance(instance), m_version(version) - { - } - -protected: - void executeTask() override - { - setStatus(tr("Installing Forge...")); - ForgeVersionPtr forgeVersion = std::dynamic_pointer_cast(m_version); - if (!forgeVersion) - { - emitFailed(tr("Unknown error occured")); - return; - } - prepare(forgeVersion); - } - void prepare(ForgeVersionPtr forgeVersion) - { - auto entry = ENV.metacache()->resolveEntry("minecraftforge", forgeVersion->filename()); - auto installFunction = [this, entry, forgeVersion]() - { - if (!install(entry, forgeVersion)) - { - qCritical() << "Failure installing Forge"; - emitFailed(tr("Failure to install Forge")); - } - else - { - reload(); - } - }; - - /* - * HACK IF the local non-stale file is too small, mark is as stale - * - * This fixes some problems with bad files acquired because of unhandled HTTP redirects - * in old versions of MultiMC. - */ - if (!entry->isStale()) - { - QFileInfo localFile(entry->getFullPath()); - if (localFile.size() <= 0x4000) - { - entry->setStale(true); - } - } - - if (entry->isStale()) - { - NetJob *fjob = new NetJob("Forge download"); - fjob->addNetAction(CacheDownload::make(forgeVersion->url(), entry)); - connect(fjob, &NetJob::progress, this, &Task::setProgress); - connect(fjob, &NetJob::status, this, &Task::setStatus); - connect(fjob, &NetJob::failed, [this](QString reason) - { emitFailed(tr("Failure to download Forge:\n%1").arg(reason)); }); - connect(fjob, &NetJob::succeeded, installFunction); - fjob->start(); - } - else - { - installFunction(); - } - } - bool install(const std::shared_ptr &entry, const ForgeVersionPtr &forgeVersion) - { - if (forgeVersion->usesInstaller()) - { - QString forgePath = entry->getFullPath(); - m_installer->prepare(forgePath, forgeVersion->universal_url); - return m_installer->add(m_instance); - } - else - return m_installer->addLegacy(m_instance); - } - void reload() - { - try - { - m_instance->reloadProfile(); - emitSucceeded(); - } - catch (Exception &e) - { - emitFailed(e.cause()); - } - catch (...) - { - emitFailed(tr("Failed to load the version description file for reasons unknown.")); - } - } - -private: - ForgeInstaller *m_installer; - OneSixInstance *m_instance; - BaseVersionPtr m_version; -}; - -Task *ForgeInstaller::createInstallTask(OneSixInstance *instance, - BaseVersionPtr version, QObject *parent) -{ - if (!version) - { - return nullptr; - } - m_forge_version = std::dynamic_pointer_cast(version); - return new ForgeInstallTask(this, instance, version, parent); -} - -#include "ForgeInstaller.moc" diff --git a/logic/minecraft/forge/ForgeInstaller.h b/logic/minecraft/forge/ForgeInstaller.h deleted file mode 100644 index 499a6fb3..00000000 --- a/logic/minecraft/forge/ForgeInstaller.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "BaseInstaller.h" - -#include -#include - -#include "multimc_logic_export.h" - -class VersionFile; -class ForgeInstallTask; -struct ForgeVersion; - -class MULTIMC_LOGIC_EXPORT ForgeInstaller : public BaseInstaller -{ - friend class ForgeInstallTask; -public: - ForgeInstaller(); - virtual ~ForgeInstaller(){} - virtual Task *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) override; - virtual QString id() const override { return "net.minecraftforge"; } - -protected: - void prepare(const QString &filename, const QString &universalUrl); - bool add(OneSixInstance *to) override; - bool addLegacy(OneSixInstance *to); - -private: - // the parsed version json, read from the installer - std::shared_ptr m_forge_json; - // the actual forge version - std::shared_ptr m_forge_version; - QString internalPath; - QString finalPath; - QString m_forgeVersionString; - QString m_universal_url; -}; diff --git a/logic/minecraft/forge/ForgeVersion.cpp b/logic/minecraft/forge/ForgeVersion.cpp deleted file mode 100644 index b859a28c..00000000 --- a/logic/minecraft/forge/ForgeVersion.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "ForgeVersion.h" -#include "minecraft/VersionFilterData.h" -#include - -QString ForgeVersion::name() -{ - return "Forge " + jobbuildver; -} - -QString ForgeVersion::descriptor() -{ - return universal_filename; -} - -QString ForgeVersion::typeString() const -{ - if (is_recommended) - return QObject::tr("Recommended"); - return QString(); -} - -bool ForgeVersion::operator<(BaseVersion &a) -{ - ForgeVersion *pa = dynamic_cast(&a); - if (!pa) - return true; - return m_buildnr < pa->m_buildnr; -} - -bool ForgeVersion::operator>(BaseVersion &a) -{ - ForgeVersion *pa = dynamic_cast(&a); - if (!pa) - return false; - return m_buildnr > pa->m_buildnr; -} - -bool ForgeVersion::usesInstaller() -{ - if(installer_url.isEmpty()) - return false; - if(g_VersionFilterData.forgeInstallerBlacklist.contains(mcver)) - return false; - return true; -} - -QString ForgeVersion::filename() -{ - return usesInstaller() ? installer_filename : universal_filename; -} - -QString ForgeVersion::url() -{ - return usesInstaller() ? installer_url : universal_url; -} diff --git a/logic/minecraft/forge/ForgeVersion.h b/logic/minecraft/forge/ForgeVersion.h deleted file mode 100644 index e77d32f1..00000000 --- a/logic/minecraft/forge/ForgeVersion.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include -#include -#include "BaseVersion.h" - -struct ForgeVersion; -typedef std::shared_ptr ForgeVersionPtr; - -struct ForgeVersion : public BaseVersion -{ - virtual QString descriptor() override; - virtual QString name() override; - virtual QString typeString() const override; - virtual bool operator<(BaseVersion &a) override; - virtual bool operator>(BaseVersion &a) override; - - QString filename(); - QString url(); - - enum - { - Invalid, - Legacy, - Gradle - } type = Invalid; - - bool usesInstaller(); - - int m_buildnr = 0; - QString branch; - QString universal_url; - QString changelog_url; - QString installer_url; - QString jobbuildver; - QString mcver; - QString mcver_sane; - QString universal_filename; - QString installer_filename; - bool is_recommended = false; -}; - -Q_DECLARE_METATYPE(ForgeVersionPtr) diff --git a/logic/minecraft/forge/ForgeVersionList.cpp b/logic/minecraft/forge/ForgeVersionList.cpp deleted file mode 100644 index de185e5f..00000000 --- a/logic/minecraft/forge/ForgeVersionList.cpp +++ /dev/null @@ -1,450 +0,0 @@ -/* Copyright 2013-2015 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 "ForgeVersionList.h" -#include "ForgeVersion.h" - -#include "net/NetJob.h" -#include "net/URLConstants.h" -#include "Env.h" - -#include -#include -#include - -#include - -ForgeVersionList::ForgeVersionList(QObject *parent) : BaseVersionList(parent) -{ -} - -Task *ForgeVersionList::getLoadTask() -{ - return new ForgeListLoadTask(this); -} - -bool ForgeVersionList::isLoaded() -{ - return m_loaded; -} - -const BaseVersionPtr ForgeVersionList::at(int i) const -{ - return m_vlist.at(i); -} - -int ForgeVersionList::count() const -{ - return m_vlist.count(); -} - -int ForgeVersionList::columnCount(const QModelIndex &parent) const -{ - return 1; -} - -QVariant ForgeVersionList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (index.row() > count()) - return QVariant(); - - auto version = std::dynamic_pointer_cast(m_vlist[index.row()]); - switch (role) - { - case VersionPointerRole: - return qVariantFromValue(m_vlist[index.row()]); - - case VersionRole: - return version->name(); - - case VersionIdRole: - return version->descriptor(); - - case ParentGameVersionRole: - return version->mcver_sane; - - case RecommendedRole: - return version->is_recommended; - - case BranchRole: - return version->branch; - - default: - return QVariant(); - } -} - -BaseVersionList::RoleList ForgeVersionList::providesRoles() const -{ - return {VersionPointerRole, VersionRole, VersionIdRole, ParentGameVersionRole, RecommendedRole, BranchRole}; -} - -BaseVersionPtr ForgeVersionList::getLatestStable() const -{ - return BaseVersionPtr(); -} - -void ForgeVersionList::updateListData(QList versions) -{ - beginResetModel(); - m_vlist = versions; - m_loaded = true; - endResetModel(); - // NOW SORT!! - // sort(); -} - -void ForgeVersionList::sortVersions() -{ - // NO-OP for now -} - -ForgeListLoadTask::ForgeListLoadTask(ForgeVersionList *vlist) : Task() -{ - m_list = vlist; -} - -void ForgeListLoadTask::executeTask() -{ - setStatus(tr("Fetching Forge version lists...")); - auto job = new NetJob("Version index"); - // we do not care if the version is stale or not. - auto forgeListEntry = ENV.metacache()->resolveEntry("minecraftforge", "list.json"); - auto gradleForgeListEntry = ENV.metacache()->resolveEntry("minecraftforge", "json"); - - // verify by poking the server. - forgeListEntry->setStale(true); - gradleForgeListEntry->setStale(true); - - job->addNetAction(listDownload = CacheDownload::make(QUrl(URLConstants::FORGE_LEGACY_URL), - forgeListEntry)); - job->addNetAction(gradleListDownload = CacheDownload::make( - QUrl(URLConstants::FORGE_GRADLE_URL), gradleForgeListEntry)); - - connect(listDownload.get(), SIGNAL(failed(int)), SLOT(listFailed())); - connect(gradleListDownload.get(), SIGNAL(failed(int)), SLOT(gradleListFailed())); - - listJob.reset(job); - connect(listJob.get(), SIGNAL(succeeded()), SLOT(listDownloaded())); - connect(listJob.get(), SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64))); - listJob->start(); -} - -bool ForgeListLoadTask::abort() -{ - return listJob->abort(); -} - -bool ForgeListLoadTask::parseForgeList(QList &out) -{ - QByteArray data; - { - auto dlJob = listDownload; - auto filename = std::dynamic_pointer_cast(dlJob)->getTargetFilepath(); - QFile listFile(filename); - if (!listFile.open(QIODevice::ReadOnly)) - { - return false; - } - data = listFile.readAll(); - dlJob.reset(); - } - - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); - - if (jsonError.error != QJsonParseError::NoError) - { - emitFailed("Error parsing version list JSON:" + jsonError.errorString()); - return false; - } - - if (!jsonDoc.isObject()) - { - emitFailed("Error parsing version list JSON: JSON root is not an object"); - return false; - } - - QJsonObject root = jsonDoc.object(); - - // Now, get the array of versions. - if (!root.value("builds").isArray()) - { - emitFailed( - "Error parsing version list JSON: version list object is missing 'builds' array"); - return false; - } - QJsonArray builds = root.value("builds").toArray(); - - for (int i = 0; i < builds.count(); i++) - { - // Load the version info. - if (!builds[i].isObject()) - { - // FIXME: log this somewhere - continue; - } - QJsonObject obj = builds[i].toObject(); - int build_nr = obj.value("build").toDouble(0); - if (!build_nr) - continue; - QJsonArray files = obj.value("files").toArray(); - QString url, jobbuildver, mcver, buildtype, universal_filename; - QString changelog_url, installer_url; - QString installer_filename; - bool valid = false; - for (int j = 0; j < files.count(); j++) - { - if (!files[j].isObject()) - { - continue; - } - QJsonObject file = files[j].toObject(); - buildtype = file.value("buildtype").toString(); - if ((buildtype == "client" || buildtype == "universal") && !valid) - { - mcver = file.value("mcver").toString(); - url = file.value("url").toString(); - jobbuildver = file.value("jobbuildver").toString(); - int lastSlash = url.lastIndexOf('/'); - universal_filename = url.mid(lastSlash + 1); - valid = true; - } - else if (buildtype == "changelog") - { - QString ext = file.value("ext").toString(); - if (ext.isEmpty()) - { - continue; - } - changelog_url = file.value("url").toString(); - } - else if (buildtype == "installer") - { - installer_url = file.value("url").toString(); - int lastSlash = installer_url.lastIndexOf('/'); - installer_filename = installer_url.mid(lastSlash + 1); - } - } - if (valid) - { - // Now, we construct the version object and add it to the list. - std::shared_ptr fVersion(new ForgeVersion()); - fVersion->universal_url = url; - fVersion->changelog_url = changelog_url; - fVersion->installer_url = installer_url; - fVersion->jobbuildver = jobbuildver; - fVersion->mcver = fVersion->mcver_sane = mcver; - fVersion->installer_filename = installer_filename; - fVersion->universal_filename = universal_filename; - fVersion->m_buildnr = build_nr; - fVersion->type = ForgeVersion::Legacy; - out.append(fVersion); - } - } - - return true; -} - -bool ForgeListLoadTask::parseForgeGradleList(QList &out) -{ - QMap> lookup; - QByteArray data; - { - auto dlJob = gradleListDownload; - auto filename = std::dynamic_pointer_cast(dlJob)->getTargetFilepath(); - QFile listFile(filename); - if (!listFile.open(QIODevice::ReadOnly)) - { - return false; - } - data = listFile.readAll(); - dlJob.reset(); - } - - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); - - if (jsonError.error != QJsonParseError::NoError) - { - emitFailed("Error parsing gradle version list JSON:" + jsonError.errorString()); - return false; - } - - if (!jsonDoc.isObject()) - { - emitFailed("Error parsing gradle version list JSON: JSON root is not an object"); - return false; - } - - QJsonObject root = jsonDoc.object(); - - // we probably could hard code these, but it might still be worth doing it this way - const QString webpath = root.value("webpath").toString(); - const QString artifact = root.value("artifact").toString(); - - QJsonObject numbers = root.value("number").toObject(); - for (auto it = numbers.begin(); it != numbers.end(); ++it) - { - QJsonObject number = it.value().toObject(); - std::shared_ptr fVersion(new ForgeVersion()); - fVersion->m_buildnr = number.value("build").toDouble(); - if(fVersion->m_buildnr >= 953 && fVersion->m_buildnr <= 965) - { - qDebug() << fVersion->m_buildnr; - } - fVersion->jobbuildver = number.value("version").toString(); - fVersion->branch = number.value("branch").toString(""); - fVersion->mcver = number.value("mcversion").toString(); - fVersion->universal_filename = ""; - fVersion->installer_filename = ""; - // HACK: here, we fix the minecraft version used by forge. - // HACK: this will inevitably break (later) - // FIXME: replace with a dictionary - fVersion->mcver_sane = fVersion->mcver; - fVersion->mcver_sane.replace("_pre", "-pre"); - - QString universal_filename, installer_filename; - QJsonArray files = number.value("files").toArray(); - for (auto fIt = files.begin(); fIt != files.end(); ++fIt) - { - // TODO with gradle we also get checksums, use them - QJsonArray file = (*fIt).toArray(); - if (file.size() < 3) - { - continue; - } - - QString extension = file.at(0).toString(); - QString part = file.at(1).toString(); - QString checksum = file.at(2).toString(); - - // insane form of mcver is used here - QString longVersion = fVersion->mcver + "-" + fVersion->jobbuildver; - if (!fVersion->branch.isEmpty()) - { - longVersion = longVersion + "-" + fVersion->branch; - } - QString filename = artifact + "-" + longVersion + "-" + part + "." + extension; - - QString url = QString("%1/%2/%3") - .arg(webpath) - .arg(longVersion) - .arg(filename); - - if (part == "installer") - { - fVersion->installer_url = url; - installer_filename = filename; - } - else if (part == "universal") - { - fVersion->universal_url = url; - universal_filename = filename; - } - else if (part == "changelog") - { - fVersion->changelog_url = url; - } - } - if (fVersion->installer_url.isEmpty() && fVersion->universal_url.isEmpty()) - { - continue; - } - fVersion->universal_filename = universal_filename; - fVersion->installer_filename = installer_filename; - fVersion->type = ForgeVersion::Gradle; - out.append(fVersion); - lookup[fVersion->m_buildnr] = fVersion; - } - QJsonObject promos = root.value("promos").toObject(); - for (auto it = promos.begin(); it != promos.end(); ++it) - { - QString key = it.key(); - int build = it.value().toInt(); - QRegularExpression regexp("^(?[0-9]+(.[0-9]+)*)-(?