2021-11-20 15:22:22 +00:00
# include "Application.h"
2014-04-06 01:59:37 +00:00
# include "BuildConfig.h"
2019-07-21 19:12:05 +00:00
2021-11-22 02:55:16 +00:00
# include "ui/MainWindow.h"
# include "ui/InstanceWindow.h"
2019-07-21 19:12:05 +00:00
2021-11-22 02:55:16 +00:00
# include "ui/instanceview/AccessibleInstanceView.h"
2016-10-21 07:07:26 +00:00
2021-11-22 02:55:16 +00:00
# include "ui/pages/BasePageProvider.h"
# include "ui/pages/global/LauncherPage.h"
# include "ui/pages/global/MinecraftPage.h"
# include "ui/pages/global/JavaPage.h"
# include "ui/pages/global/LanguagePage.h"
# include "ui/pages/global/ProxyPage.h"
# include "ui/pages/global/ExternalToolsPage.h"
# include "ui/pages/global/AccountListPage.h"
# include "ui/pages/global/PasteEEPage.h"
# include "ui/pages/global/CustomCommandsPage.h"
# include "ui/themes/ITheme.h"
# include "ui/themes/SystemTheme.h"
# include "ui/themes/DarkTheme.h"
# include "ui/themes/BrightTheme.h"
# include "ui/themes/CustomTheme.h"
# include "ui/setupwizard/SetupWizard.h"
# include "ui/setupwizard/LanguageWizardPage.h"
# include "ui/setupwizard/JavaWizardPage.h"
# include "ui/setupwizard/AnalyticsWizardPage.h"
# include "ui/dialogs/CustomMessageBox.h"
2021-10-31 20:42:06 +00:00
2021-11-22 02:55:16 +00:00
# include "ui/pagedialog/PageDialog.h"
# include "ApplicationMessage.h"
2016-12-01 01:17:27 +00:00
2013-09-07 02:00:58 +00:00
# include <iostream>
2021-11-22 02:55:16 +00:00
# include <QAccessible>
2013-09-07 02:00:58 +00:00
# include <QDir>
2013-12-06 18:59:58 +00:00
# include <QFileInfo>
2013-09-07 02:00:58 +00:00
# include <QNetworkAccessManager>
2013-09-08 21:43:19 +00:00
# include <QTranslator>
# include <QLibraryInfo>
2020-02-04 23:29:23 +00:00
# include <QList>
2013-12-06 18:59:58 +00:00
# include <QStringList>
2015-02-02 01:14:14 +00:00
# include <QDebug>
2016-10-21 23:43:36 +00:00
# include <QStyleFactory>
2013-09-07 02:00:58 +00:00
2015-02-09 00:51:14 +00:00
# include "InstanceList.h"
2016-10-02 22:55:54 +00:00
2021-07-26 19:44:11 +00:00
# include <minecraft/auth/AccountList.h>
2015-02-09 00:51:14 +00:00
# include "icons/IconList.h"
# include "net/HttpMetaCache.h"
2013-09-07 02:00:58 +00:00
2015-02-09 00:51:14 +00:00
# include "java/JavaUtils.h"
2013-10-06 22:44:34 +00:00
2015-02-09 00:51:14 +00:00
# include "updater/UpdateChecker.h"
2013-10-06 22:44:34 +00:00
2015-02-09 00:51:14 +00:00
# include "tools/JProfiler.h"
# include "tools/JVisualVM.h"
# include "tools/MCEditTool.h"
2014-02-15 13:19:35 +00:00
2015-03-01 21:20:57 +00:00
# include <xdgicon.h>
2015-02-09 00:51:14 +00:00
# include "settings/INISettingsObject.h"
# include "settings/Setting.h"
2015-02-02 01:14:14 +00:00
2016-12-05 01:29:08 +00:00
# include "translations/TranslationsModel.h"
2021-11-21 22:21:12 +00:00
# include "meta/Index.h"
2013-09-07 02:00:58 +00:00
2015-10-04 23:47:27 +00:00
# include <Commandline.h>
# include <FileSystem.h>
2016-01-05 06:32:52 +00:00
# include <DesktopServices.h>
2016-10-30 01:37:38 +00:00
# include <LocalPeer.h>
2016-11-22 01:02:49 +00:00
2016-11-20 19:40:59 +00:00
# include <ganalytics.h>
2016-11-22 01:02:49 +00:00
# include <sys.h>
2015-10-04 23:47:27 +00:00
2021-11-20 15:22:22 +00:00
# include <Secrets.h>
2020-10-13 19:46:09 +00:00
# include "ApplicationSettings.h"
# include "jreclient/JREClientDialog.h"
2019-06-01 10:28:53 +00:00
2018-02-16 23:00:06 +00:00
2017-05-12 23:24:15 +00:00
# define STRINGIFY(x) #x
# define TOSTRING(x) STRINGIFY(x)
2016-11-18 15:04:08 +00:00
static const QLatin1String liveCheckFile ( " live.check " ) ;
2015-10-04 23:47:27 +00:00
using namespace Commandline ;
2013-09-07 02:00:58 +00:00
2023-05-24 08:05:52 +00:00
# define MACOS_HINT "If you are on macOS Sierra or newer, you might have to move the app to your / Applications or ~ / Applications folder. "\
2018-07-15 12:51:05 +00:00
" This usually fixes the problem and you can move the application elsewhere afterwards. \n " \
" \n "
2017-01-14 15:51:08 +00:00
2021-09-04 19:27:09 +00:00
namespace {
void appDebugOutput ( QtMsgType type , const QMessageLogContext & context , const QString & msg )
2017-07-05 16:02:49 +00:00
{
2018-07-15 12:51:05 +00:00
const char * levels = " DWCFIS " ;
const QString format ( " %1 %2 %3 \n " ) ;
2021-11-20 15:22:22 +00:00
qint64 msecstotal = APPLICATION - > timeSinceStart ( ) ;
2018-07-15 12:51:05 +00:00
qint64 seconds = msecstotal / 1000 ;
qint64 msecs = msecstotal % 1000 ;
QString foo ;
char buf [ 1025 ] = { 0 } ;
: : snprintf ( buf , 1024 , " %5lld.%03lld " , seconds , msecs ) ;
QString out = format . arg ( buf ) . arg ( levels [ type ] ) . arg ( msg ) ;
2021-11-20 15:22:22 +00:00
APPLICATION - > logFile - > write ( out . toUtf8 ( ) ) ;
APPLICATION - > logFile - > flush ( ) ;
2018-07-15 12:51:05 +00:00
QTextStream ( stderr ) < < out . toLocal8Bit ( ) ;
fflush ( stderr ) ;
2017-07-05 16:02:49 +00:00
}
2021-09-04 19:27:09 +00:00
QString getIdealPlatform ( QString currentPlatform ) {
auto info = Sys : : getKernelInfo ( ) ;
switch ( info . kernelType ) {
case Sys : : KernelType : : Darwin : {
if ( info . kernelMajor > = 17 ) {
// macOS 10.13 or newer
return " osx64-5.15.2 " ;
}
else {
// macOS 10.12 or older
return " osx64 " ;
}
}
case Sys : : KernelType : : Windows : {
2021-09-04 21:51:57 +00:00
// FIXME: 5.15.2 is not stable on Windows, due to a large number of completely unpredictable and hard to reproduce issues
break ;
/*
2021-09-04 19:27:09 +00:00
if ( info . kernelMajor = = 6 & & info . kernelMinor > = 1 ) {
// Windows 7
return " win32-5.15.2 " ;
}
else if ( info . kernelMajor > 6 ) {
// Above Windows 7
return " win32-5.15.2 " ;
}
else {
// Below Windows 7
return " win32 " ;
}
2021-09-04 21:51:57 +00:00
*/
2021-09-04 19:27:09 +00:00
}
case Sys : : KernelType : : Undetermined :
case Sys : : KernelType : : Linux : {
break ;
}
}
return currentPlatform ;
}
}
2021-11-20 15:22:22 +00:00
Application : : Application ( int & argc , char * * argv ) : QApplication ( argc , argv )
2013-09-07 02:00:58 +00:00
{
2021-10-17 22:47:02 +00:00
setOrganizationName ( BuildConfig . LAUNCHER_NAME ) ;
setOrganizationDomain ( BuildConfig . LAUNCHER_DOMAIN ) ;
setApplicationName ( BuildConfig . LAUNCHER_NAME ) ;
setApplicationDisplayName ( BuildConfig . LAUNCHER_DISPLAYNAME ) ;
2018-07-15 12:51:05 +00:00
setApplicationVersion ( BuildConfig . printableVersionString ( ) ) ;
startTime = QDateTime : : currentDateTime ( ) ;
2020-05-28 21:17:50 +00:00
# ifdef Q_OS_LINUX
{
QFile osrelease ( " /proc/sys/kernel/osrelease " ) ;
if ( osrelease . open ( QFile : : ReadOnly | QFile : : Text ) ) {
QTextStream in ( & osrelease ) ;
auto contents = in . readAll ( ) ;
if (
contents . contains ( " WSL " , Qt : : CaseInsensitive ) | |
2020-05-28 21:31:50 +00:00
contents . contains ( " Microsoft " , Qt : : CaseInsensitive )
2020-05-28 21:17:50 +00:00
) {
showFatalErrorMessage (
" Unsupported system detected! " ,
2020-05-28 21:59:54 +00:00
" Linux-on-Windows distributions are not supported. \n \n "
2021-10-17 22:47:02 +00:00
" Please use the Windows binary when playing on Windows. "
2020-05-28 21:17:50 +00:00
) ;
return ;
}
}
}
# endif
2018-07-15 12:51:05 +00:00
// Don't quit on hiding the last window
this - > setQuitOnLastWindowClosed ( false ) ;
// Commandline parsing
QHash < QString , QVariant > args ;
{
Parser parser ( FlagStyle : : GNU , ArgumentStyle : : SpaceAndEquals ) ;
// --help
parser . addSwitch ( " help " ) ;
parser . addShortOpt ( " help " , ' h ' ) ;
2019-09-15 03:31:13 +00:00
parser . addDocumentation ( " help " , " Display this help and exit. " ) ;
2018-07-15 12:51:05 +00:00
// --version
parser . addSwitch ( " version " ) ;
parser . addShortOpt ( " version " , ' V ' ) ;
2019-09-15 03:31:13 +00:00
parser . addDocumentation ( " version " , " Display program version and exit. " ) ;
2018-07-15 12:51:05 +00:00
// --dir
parser . addOption ( " dir " ) ;
parser . addShortOpt ( " dir " , ' d ' ) ;
2021-10-31 20:42:06 +00:00
parser . addDocumentation ( " dir " , " Use the supplied folder as application root instead of the binary location (use '.' for current) " ) ;
2018-07-15 12:51:05 +00:00
// --launch
parser . addOption ( " launch " ) ;
parser . addShortOpt ( " launch " , ' l ' ) ;
2019-09-15 03:31:13 +00:00
parser . addDocumentation ( " launch " , " Launch the specified instance (by instance ID) " ) ;
2021-05-23 12:42:20 +00:00
// --server
parser . addOption ( " server " ) ;
parser . addShortOpt ( " server " , ' s ' ) ;
2023-04-08 17:03:20 +00:00
parser . addDocumentation ( " server " , " Join the specified server on launch (only valid in combination with --launch, mutually exclusive with --world) " ) ;
// --world
parser . addOption ( " world " ) ;
parser . addShortOpt ( " world " , ' w ' ) ;
parser . addDocumentation ( " world " , " Join the singleplayer world with the specified folder name on launch (only valid in combination with --launch, mutually exclusive with --server, only works with Minecraft 23w14a and later) " ) ;
2021-10-31 20:42:06 +00:00
// --profile
parser . addOption ( " profile " ) ;
parser . addShortOpt ( " profile " , ' a ' ) ;
parser . addDocumentation ( " profile " , " Use the account specified by its profile name (only valid in combination with --launch) " ) ;
2022-06-09 21:46:28 +00:00
// --offline
parser . addSwitch ( " offline " ) ;
parser . addShortOpt ( " offline " , ' o ' ) ;
parser . addDocumentation ( " offline " , " Launch offline (only valid in combination with --launch) " ) ;
// --name
parser . addOption ( " name " ) ;
parser . addShortOpt ( " name " , ' n ' ) ;
parser . addDocumentation ( " name " , " When launching offline, use specified name (only makes sense in combination with --launch and --offline) " ) ;
2018-07-15 12:51:05 +00:00
// --alive
parser . addSwitch ( " alive " ) ;
2021-10-17 22:47:02 +00:00
parser . addDocumentation ( " alive " , " Write a small ' " + liveCheckFile + " ' file after the launcher starts " ) ;
2020-02-04 23:29:23 +00:00
// --import
parser . addOption ( " import " ) ;
parser . addShortOpt ( " import " , ' I ' ) ;
parser . addDocumentation ( " import " , " Import instance from specified zip (local path or URL) " ) ;
2018-07-15 12:51:05 +00:00
// parse the arguments
try
{
args = parser . parse ( arguments ( ) ) ;
}
catch ( const ParsingError & e )
{
std : : cerr < < " CommandLineError: " < < e . what ( ) < < std : : endl ;
2021-01-17 20:52:54 +00:00
if ( argc > 0 )
2021-10-17 22:47:02 +00:00
std : : cerr < < " Try ' " < < argv [ 0 ] < < " -h' to get help on command line parameters. "
2021-01-17 20:52:54 +00:00
< < std : : endl ;
2021-11-20 15:22:22 +00:00
m_status = Application : : Failed ;
2018-07-15 12:51:05 +00:00
return ;
}
// display help and exit
if ( args [ " help " ] . toBool ( ) )
{
std : : cout < < qPrintable ( parser . compileHelp ( arguments ( ) [ 0 ] ) ) ;
2021-11-20 15:22:22 +00:00
m_status = Application : : Succeeded ;
2018-07-15 12:51:05 +00:00
return ;
}
// display version and exit
if ( args [ " version " ] . toBool ( ) )
{
std : : cout < < " Version " < < BuildConfig . printableVersionString ( ) . toStdString ( ) < < std : : endl ;
std : : cout < < " Git " < < BuildConfig . GIT_COMMIT . toStdString ( ) < < std : : endl ;
2021-11-20 15:22:22 +00:00
m_status = Application : : Succeeded ;
2018-07-15 12:51:05 +00:00
return ;
}
}
m_instanceIdToLaunch = args [ " launch " ] . toString ( ) ;
2021-05-23 12:42:20 +00:00
m_serverToJoin = args [ " server " ] . toString ( ) ;
2023-04-08 17:03:20 +00:00
m_worldToJoin = args [ " world " ] . toString ( ) ;
2021-10-31 20:42:06 +00:00
m_profileToUse = args [ " profile " ] . toString ( ) ;
2022-06-09 21:46:28 +00:00
if ( args [ " offline " ] . toBool ( ) ) {
m_offline = true ;
m_offlineName = args [ " name " ] . toString ( ) ;
}
2018-07-15 12:51:05 +00:00
m_liveCheck = args [ " alive " ] . toBool ( ) ;
2020-02-04 23:29:23 +00:00
m_zipToImport = args [ " import " ] . toUrl ( ) ;
2018-07-15 12:51:05 +00:00
QString origcwdPath = QDir : : currentPath ( ) ;
QString binPath = applicationDirPath ( ) ;
QString adjustedBy ;
QString dataPath ;
// change folder
2023-05-24 08:05:52 +00:00
// FIXME: Actually implement portable installs again in some way...
constexpr bool portableInstall = false ;
2018-07-15 12:51:05 +00:00
QString dirParam = args [ " dir " ] . toString ( ) ;
if ( ! dirParam . isEmpty ( ) )
{
// the dir param. it makes multimc data path point to whatever the user specified
// on command line
adjustedBy + = " Command line " + dirParam ;
dataPath = dirParam ;
}
2023-05-24 08:05:52 +00:00
else if ( portableInstall )
2018-07-15 12:51:05 +00:00
{
2021-10-17 22:47:02 +00:00
# if defined(Q_OS_MAC)
2021-07-01 23:19:55 +00:00
QDir foo ( FS : : PathCombine ( applicationDirPath ( ) , " ../../Data " ) ) ;
dataPath = foo . absolutePath ( ) ;
2017-05-12 23:24:15 +00:00
# else
2018-07-15 12:51:05 +00:00
dataPath = applicationDirPath ( ) ;
2017-05-12 23:24:15 +00:00
# endif
2023-05-24 08:05:52 +00:00
adjustedBy + = " Portable binary path " + dataPath ;
}
else {
auto dataLocation = QStandardPaths : : writableLocation ( QStandardPaths : : StandardLocation : : GenericDataLocation ) ;
dataPath = FS : : PathCombine ( dataLocation , BuildConfig . LAUNCHER_FSNAME ) ;
adjustedBy + = " Standard data path " + dataPath ;
2018-07-15 12:51:05 +00:00
}
if ( ! FS : : ensureFolderPathExists ( dataPath ) )
{
showFatalErrorMessage (
2021-10-17 22:47:02 +00:00
" The launcher data folder could not be created. " ,
2021-12-14 23:46:35 +00:00
QString (
" The launcher data folder could not be created. \n "
" \n "
2017-01-14 15:51:08 +00:00
# if defined(Q_OS_MAC)
2021-12-14 23:46:35 +00:00
MACOS_HINT
2017-01-14 15:51:08 +00:00
# endif
2021-12-14 23:46:35 +00:00
" Make sure you have the right permissions to the launcher data folder and any folder needed to access it. \n "
" (%1) \n "
" \n "
" The launcher cannot continue until you fix this problem. "
2021-12-19 18:12:43 +00:00
) . arg ( dataPath )
2018-07-15 12:51:05 +00:00
) ;
return ;
}
if ( ! QDir : : setCurrent ( dataPath ) )
{
showFatalErrorMessage (
2021-10-17 22:47:02 +00:00
" The launcher data folder could not be opened. " ,
2021-12-14 23:46:35 +00:00
QString (
" The launcher data folder could not be opened. \n "
" \n "
2017-01-14 15:51:08 +00:00
# if defined(Q_OS_MAC)
2021-12-14 23:46:35 +00:00
MACOS_HINT
2017-01-14 15:51:08 +00:00
# endif
2021-12-14 23:46:35 +00:00
" Make sure you have the right permissions to the launcher data folder. \n "
" (%1) \n "
" \n "
" The launcher cannot continue until you fix this problem. "
2021-12-19 18:12:43 +00:00
) . arg ( dataPath )
2018-07-15 12:51:05 +00:00
) ;
return ;
}
2023-04-08 17:03:20 +00:00
// --world and --server can't be used together
if ( ! m_worldToJoin . isEmpty ( ) & & ! m_serverToJoin . isEmpty ( ) )
{
std : : cerr < < " --server and --world are mutually exclusive! " < < std : : endl ;
m_status = Application : : Failed ;
return ;
}
2022-06-09 21:46:28 +00:00
// all the things invalid when NOT trying to --launch
if ( m_instanceIdToLaunch . isEmpty ( ) ) {
if ( ! m_serverToJoin . isEmpty ( ) )
{
std : : cerr < < " --server can only be used in combination with --launch! " < < std : : endl ;
m_status = Application : : Failed ;
return ;
}
2021-05-23 12:42:20 +00:00
2023-04-08 17:03:20 +00:00
if ( ! m_worldToJoin . isEmpty ( ) )
{
std : : cerr < < " --world can only be used in combination with --launch! " < < std : : endl ;
m_status = Application : : Failed ;
return ;
}
2022-06-09 21:46:28 +00:00
if ( ! m_profileToUse . isEmpty ( ) )
{
std : : cerr < < " --account can only be used in combination with --launch! " < < std : : endl ;
m_status = Application : : Failed ;
return ;
}
if ( m_offline )
{
std : : cerr < < " --offline can only be used in combination with --launch! " < < std : : endl ;
m_status = Application : : Failed ;
return ;
}
if ( ! m_offlineName . isEmpty ( ) )
{
std : : cerr < < " --offlineName can only be used in combination with --launch and --offline! " < < std : : endl ;
m_status = Application : : Failed ;
return ;
}
}
else {
// all the things invalid when trying to --launch
// online, and offline name is set
if ( ! m_offline & & ! m_offlineName . isEmpty ( ) ) {
std : : cerr < < " --offlineName can only be used in combination with --launch and --offline! " < < std : : endl ;
m_status = Application : : Failed ;
return ;
}
2021-10-31 20:42:06 +00:00
}
2018-07-15 12:51:05 +00:00
/*
* Establish the mechanism for communication with an already running MultiMC that uses the same data path .
* If there is one , tell it what the user actually wanted to do and exit .
* We want to initialize this before logging to avoid messing with the log of a potential already running copy .
*/
auto appID = ApplicationId : : fromPathAndVersion ( QDir : : currentPath ( ) , BuildConfig . printableVersionString ( ) ) ;
{
// FIXME: you can run the same binaries with multiple data dirs and they won't clash. This could cause issues for updates.
m_peerInstance = new LocalPeer ( this , appID ) ;
2021-11-20 15:22:22 +00:00
connect ( m_peerInstance , & LocalPeer : : messageReceived , this , & Application : : messageReceived ) ;
2021-10-31 20:42:06 +00:00
if ( m_peerInstance - > isClient ( ) ) {
2020-02-04 23:29:23 +00:00
int timeout = 2000 ;
2018-07-15 12:51:05 +00:00
if ( m_instanceIdToLaunch . isEmpty ( ) )
{
2021-11-20 15:22:22 +00:00
ApplicationMessage activate ;
2021-10-31 20:42:06 +00:00
activate . command = " activate " ;
m_peerInstance - > sendMessage ( activate . serialize ( ) , timeout ) ;
2020-02-04 23:29:23 +00:00
if ( ! m_zipToImport . isEmpty ( ) )
{
2021-11-20 15:22:22 +00:00
ApplicationMessage import ;
2021-10-31 20:42:06 +00:00
import . command = " import " ;
import . args . insert ( " path " , m_zipToImport . toString ( ) ) ;
m_peerInstance - > sendMessage ( import . serialize ( ) , timeout ) ;
2020-02-04 23:29:23 +00:00
}
2018-07-15 12:51:05 +00:00
}
else
{
2021-11-20 15:22:22 +00:00
ApplicationMessage launch ;
2021-10-31 20:42:06 +00:00
launch . command = " launch " ;
launch . args [ " id " ] = m_instanceIdToLaunch ;
2021-05-23 12:42:20 +00:00
if ( ! m_serverToJoin . isEmpty ( ) )
{
2021-10-31 20:42:06 +00:00
launch . args [ " server " ] = m_serverToJoin ;
2021-05-23 12:42:20 +00:00
}
2023-04-08 17:03:20 +00:00
if ( ! m_worldToJoin . isEmpty ( ) )
{
launch . args [ " world " ] = m_worldToJoin ;
}
2021-10-31 20:42:06 +00:00
if ( ! m_profileToUse . isEmpty ( ) )
2021-05-23 12:42:20 +00:00
{
2021-10-31 20:42:06 +00:00
launch . args [ " profile " ] = m_profileToUse ;
2021-05-23 12:42:20 +00:00
}
2022-06-09 21:46:28 +00:00
if ( m_offline ) {
launch . args [ " offline_enabled " ] = " true " ;
launch . args [ " offline_name " ] = m_offlineName ;
}
2021-10-31 20:42:06 +00:00
m_peerInstance - > sendMessage ( launch . serialize ( ) , timeout ) ;
2018-07-15 12:51:05 +00:00
}
2021-11-20 15:22:22 +00:00
m_status = Application : : Succeeded ;
2018-07-15 12:51:05 +00:00
return ;
}
}
// init the logger
{
2021-10-17 22:47:02 +00:00
static const QString logBase = BuildConfig . LAUNCHER_NAME + " -%0.log " ;
2018-07-15 12:51:05 +00:00
auto moveFile = [ ] ( const QString & oldName , const QString & newName )
{
QFile : : remove ( newName ) ;
QFile : : copy ( oldName , newName ) ;
QFile : : remove ( oldName ) ;
} ;
moveFile ( logBase . arg ( 3 ) , logBase . arg ( 4 ) ) ;
moveFile ( logBase . arg ( 2 ) , logBase . arg ( 3 ) ) ;
moveFile ( logBase . arg ( 1 ) , logBase . arg ( 2 ) ) ;
moveFile ( logBase . arg ( 0 ) , logBase . arg ( 1 ) ) ;
logFile = std : : unique_ptr < QFile > ( new QFile ( logBase . arg ( 0 ) ) ) ;
if ( ! logFile - > open ( QIODevice : : WriteOnly | QIODevice : : Text | QIODevice : : Truncate ) )
{
showFatalErrorMessage (
2021-10-17 22:47:02 +00:00
" The launcher data folder is not writable! " ,
2021-12-14 23:46:35 +00:00
QString (
" The launcher couldn't create a log file - the data folder is not writable. \n "
" \n "
2018-07-15 12:51:05 +00:00
# if defined(Q_OS_MAC)
2021-12-14 23:46:35 +00:00
MACOS_HINT
2018-07-15 12:51:05 +00:00
# endif
2021-12-14 23:46:35 +00:00
" Make sure you have write permissions to the data folder. \n "
" (%1) \n "
" \n "
" The launcher cannot continue until you fix this problem. "
2021-12-19 18:12:43 +00:00
) . arg ( dataPath )
2018-07-15 12:51:05 +00:00
) ;
return ;
}
qInstallMessageHandler ( appDebugOutput ) ;
qDebug ( ) < < " <> Log initialized. " ;
}
// Set up paths
{
// Root path is used for updates.
2021-12-12 00:35:46 +00:00
# if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
2018-07-15 12:51:05 +00:00
QDir foo ( FS : : PathCombine ( binPath , " .. " ) ) ;
m_rootPath = foo . absolutePath ( ) ;
2014-07-27 13:50:03 +00:00
# elif defined(Q_OS_WIN32)
2018-07-15 12:51:05 +00:00
m_rootPath = binPath ;
2014-07-27 13:50:03 +00:00
# elif defined(Q_OS_MAC)
2018-07-15 12:51:05 +00:00
QDir foo ( FS : : PathCombine ( binPath , " ../.. " ) ) ;
m_rootPath = foo . absolutePath ( ) ;
// on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
FS : : updateTimestamp ( m_rootPath ) ;
2014-07-27 13:50:03 +00:00
# endif
2013-09-22 22:23:50 +00:00
2023-02-03 22:30:59 +00:00
qDebug ( ) < < BuildConfig . LAUNCHER_DISPLAYNAME < < " , (c) 2013-2023 " < < BuildConfig . LAUNCHER_COPYRIGHT ;
2018-07-15 12:51:05 +00:00
qDebug ( ) < < " Version : " < < BuildConfig . printableVersionString ( ) ;
qDebug ( ) < < " Git commit : " < < BuildConfig . GIT_COMMIT ;
qDebug ( ) < < " Git refspec : " < < BuildConfig . GIT_REFSPEC ;
if ( adjustedBy . size ( ) )
{
qDebug ( ) < < " Work dir before adjustment : " < < origcwdPath ;
qDebug ( ) < < " Work dir after adjustment : " < < QDir : : currentPath ( ) ;
qDebug ( ) < < " Adjusted by : " < < adjustedBy ;
}
else
{
qDebug ( ) < < " Work dir : " < < QDir : : currentPath ( ) ;
}
qDebug ( ) < < " Binary path : " < < binPath ;
qDebug ( ) < < " Application root path : " < < m_rootPath ;
if ( ! m_instanceIdToLaunch . isEmpty ( ) )
{
qDebug ( ) < < " ID of instance to launch : " < < m_instanceIdToLaunch ;
}
2021-05-23 12:42:20 +00:00
if ( ! m_serverToJoin . isEmpty ( ) )
{
qDebug ( ) < < " Address of server to join : " < < m_serverToJoin ;
}
2023-04-08 17:03:20 +00:00
if ( ! m_worldToJoin . isEmpty ( ) )
{
qDebug ( ) < < " Name of world to join : " < < m_worldToJoin ;
}
2018-07-15 12:51:05 +00:00
qDebug ( ) < < " <> Paths set. " ;
}
do // once
{
if ( m_liveCheck )
{
QFile check ( liveCheckFile ) ;
if ( ! check . open ( QIODevice : : WriteOnly | QIODevice : : Truncate ) )
{
qWarning ( ) < < " Could not open " < < liveCheckFile < < " for writing! " ;
break ;
}
auto payload = appID . toString ( ) . toUtf8 ( ) ;
if ( check . write ( payload ) ! = payload . size ( ) )
{
2019-09-15 03:31:13 +00:00
qWarning ( ) < < " Could not write into " < < liveCheckFile < < " ! " ;
2018-07-15 12:51:05 +00:00
check . remove ( ) ;
break ;
}
check . close ( ) ;
}
} while ( false ) ;
2020-10-13 19:46:09 +00:00
initializeSettings ( ) ;
2018-07-15 12:51:05 +00:00
2019-10-01 12:28:06 +00:00
# ifndef QT_NO_ACCESSIBILITY
2019-07-21 19:12:05 +00:00
QAccessible : : installFactory ( groupViewAccessibleFactory ) ;
2019-10-01 12:28:06 +00:00
# endif /* !QT_NO_ACCESSIBILITY */
2019-07-21 19:12:05 +00:00
2021-11-21 22:21:12 +00:00
// initialize network access and proxy setup
{
m_network = new QNetworkAccessManager ( ) ;
QString proxyTypeStr = settings ( ) - > get ( " ProxyType " ) . toString ( ) ;
QString addr = settings ( ) - > get ( " ProxyAddr " ) . toString ( ) ;
int port = settings ( ) - > get ( " ProxyPort " ) . value < qint16 > ( ) ;
QString user = settings ( ) - > get ( " ProxyUser " ) . toString ( ) ;
QString pass = settings ( ) - > get ( " ProxyPass " ) . toString ( ) ;
updateProxySettings ( proxyTypeStr , addr , port , user , pass ) ;
qDebug ( ) < < " <> Network done. " ;
}
2018-07-15 12:51:05 +00:00
// load translations
{
m_translations . reset ( new TranslationsModel ( " translations " ) ) ;
auto bcp47Name = m_settings - > get ( " Language " ) . toString ( ) ;
m_translations - > selectLanguage ( bcp47Name ) ;
qDebug ( ) < < " Your language is " < < bcp47Name ;
qDebug ( ) < < " <> Translations loaded. " ;
}
// initialize the updater
if ( BuildConfig . UPDATER_ENABLED )
{
2021-09-04 19:27:09 +00:00
auto platform = getIdealPlatform ( BuildConfig . BUILD_PLATFORM ) ;
auto channelUrl = BuildConfig . UPDATER_BASE + platform + " /channels.json " ;
qDebug ( ) < < " Initializing updater with platform: " < < platform < < " -- " < < channelUrl ;
2023-02-03 22:05:27 +00:00
m_updateChecker . reset ( new UpdateChecker ( m_network , channelUrl , BuildConfig . VERSION_BUILD ) ) ;
2018-07-15 12:51:05 +00:00
qDebug ( ) < < " <> Updater started. " ;
}
// Instance icons
{
2021-11-20 15:22:22 +00:00
auto setting = APPLICATION - > settings ( ) - > getSetting ( " IconsDir " ) ;
2018-07-15 12:51:05 +00:00
QStringList instFolders =
{
" :/icons/multimc/32x32/instances/ " ,
" :/icons/multimc/50x50/instances/ " ,
2019-05-31 22:59:02 +00:00
" :/icons/multimc/128x128/instances/ " ,
" :/icons/multimc/scalable/instances/ "
2018-07-15 12:51:05 +00:00
} ;
m_icons . reset ( new IconList ( instFolders , setting - > get ( ) . toString ( ) ) ) ;
connect ( setting . get ( ) , & Setting : : SettingChanged , [ & ] ( const Setting & , QVariant value )
{
m_icons - > directoryChanged ( value . toString ( ) ) ;
} ) ;
qDebug ( ) < < " <> Instance icons intialized. " ;
}
// Icon themes
{
// TODO: icon themes and instance icons do not mesh well together. Rearrange and fix discrepancies!
// set icon theme search path!
auto searchPaths = QIcon : : themeSearchPaths ( ) ;
searchPaths . append ( " iconthemes " ) ;
QIcon : : setThemeSearchPaths ( searchPaths ) ;
qDebug ( ) < < " <> Icon themes initialized. " ;
}
// Initialize widget themes
{
auto insertTheme = [ this ] ( ITheme * theme )
{
m_themes . insert ( std : : make_pair ( theme - > id ( ) , std : : unique_ptr < ITheme > ( theme ) ) ) ;
} ;
auto darkTheme = new DarkTheme ( ) ;
insertTheme ( new SystemTheme ( ) ) ;
insertTheme ( darkTheme ) ;
insertTheme ( new BrightTheme ( ) ) ;
insertTheme ( new CustomTheme ( darkTheme , " custom " ) ) ;
qDebug ( ) < < " <> Widget themes initialized. " ;
}
// initialize and load all instances
{
auto InstDirSetting = m_settings - > getSetting ( " InstanceDir " ) ;
// instance path: check for problems with '!' in instance path and warn the user in the log
2019-09-15 03:31:13 +00:00
// and remember that we have to show him a dialog when the gui starts (if it does so)
2018-07-15 12:51:05 +00:00
QString instDir = InstDirSetting - > get ( ) . toString ( ) ;
qDebug ( ) < < " Instance path : " < < instDir ;
if ( FS : : checkProblemticPathJava ( QDir ( instDir ) ) )
{
2019-09-15 03:31:13 +00:00
qWarning ( ) < < " Your instance path contains \' ! \' and this is known to cause java problems! " ;
2018-07-15 12:51:05 +00:00
}
2018-07-23 23:24:06 +00:00
m_instances . reset ( new InstanceList ( m_settings , instDir , this ) ) ;
connect ( InstDirSetting . get ( ) , & Setting : : SettingChanged , m_instances . get ( ) , & InstanceList : : on_InstFolderChanged ) ;
2018-07-15 12:51:05 +00:00
qDebug ( ) < < " Loading Instances... " ;
2018-07-23 22:11:24 +00:00
m_instances - > loadList ( ) ;
2018-07-15 12:51:05 +00:00
qDebug ( ) < < " <> Instances loaded. " ;
}
// and accounts
{
2021-07-26 19:44:11 +00:00
m_accounts . reset ( new AccountList ( this ) ) ;
2018-07-15 12:51:05 +00:00
qDebug ( ) < < " Loading accounts... " ;
m_accounts - > setListFilePath ( " accounts.json " , true ) ;
m_accounts - > loadList ( ) ;
2021-12-04 00:18:05 +00:00
m_accounts - > fillQueue ( ) ;
2018-07-15 12:51:05 +00:00
qDebug ( ) < < " <> Accounts loaded. " ;
}
// init the http meta cache
{
2021-11-21 22:21:12 +00:00
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 ( " ATLauncherPacks " , QDir ( " cache/ATLauncherPacks " ) . absolutePath ( ) ) ;
m_metacache - > addBase ( " FTBPacks " , QDir ( " cache/FTBPacks " ) . absolutePath ( ) ) ;
m_metacache - > addBase ( " TechnicPacks " , QDir ( " cache/TechnicPacks " ) . absolutePath ( ) ) ;
2022-05-15 22:25:36 +00:00
m_metacache - > addBase ( " ModrinthPacks " , QDir ( " cache/ModrinthPacks " ) . absolutePath ( ) ) ;
2021-11-21 22:21:12 +00:00
m_metacache - > addBase ( " root " , QDir : : currentPath ( ) ) ;
m_metacache - > addBase ( " translations " , QDir ( " translations " ) . absolutePath ( ) ) ;
m_metacache - > addBase ( " icons " , QDir ( " cache/icons " ) . absolutePath ( ) ) ;
m_metacache - > addBase ( " meta " , QDir ( " meta " ) . absolutePath ( ) ) ;
m_metacache - > Load ( ) ;
2018-07-15 12:51:05 +00:00
qDebug ( ) < < " <> Cache initialized. " ;
}
// now we have network, download translation updates
m_translations - > downloadIndex ( ) ;
//FIXME: what to do with these?
m_profilers . insert ( " jprofiler " , std : : shared_ptr < BaseProfilerFactory > ( new JProfilerFactory ( ) ) ) ;
m_profilers . insert ( " jvisualvm " , std : : shared_ptr < BaseProfilerFactory > ( new JVisualVMFactory ( ) ) ) ;
for ( auto profiler : m_profilers . values ( ) )
{
profiler - > registerSettings ( m_settings ) ;
}
// Create the MCEdit thing... why is this here?
{
m_mcedit . reset ( new MCEditTool ( m_settings ) ) ;
}
2021-11-20 15:22:22 +00:00
connect ( this , & Application : : aboutToQuit , [ this ] ( ) {
2018-07-15 12:51:05 +00:00
if ( m_instances )
{
// save any remaining instance state
m_instances - > saveNow ( ) ;
}
if ( logFile )
{
logFile - > flush ( ) ;
logFile - > close ( ) ;
}
} ) ;
{
setIconTheme ( settings ( ) - > get ( " IconTheme " ) . toString ( ) ) ;
qDebug ( ) < < " <> Icon theme set. " ;
setApplicationTheme ( settings ( ) - > get ( " ApplicationTheme " ) . toString ( ) , true ) ;
qDebug ( ) < < " <> Application theme set. " ;
}
2023-09-02 22:26:58 +00:00
// TODO: rework analytics to not use google
2018-07-15 12:51:05 +00:00
// Initialize analytics
2023-09-02 22:26:58 +00:00
// initializeAnalytics();
2018-07-15 12:51:05 +00:00
2020-10-13 19:46:09 +00:00
if ( createSetupWizard ( ) )
{
return ;
}
performMainStartupAction ( ) ;
}
2018-07-15 12:51:05 +00:00
2020-10-13 19:46:09 +00:00
void Application : : initializeAnalytics ( )
{
const int analyticsVersion = 2 ;
if ( BuildConfig . ANALYTICS_ID . isEmpty ( ) )
{
return ;
}
2018-07-15 12:51:05 +00:00
2020-10-13 19:46:09 +00:00
auto analyticsSetting = m_settings - > getSetting ( " Analytics " ) ;
connect ( analyticsSetting . get ( ) , & Setting : : SettingChanged , this , & Application : : analyticsSettingChanged ) ;
QString clientID = m_settings - > get ( " AnalyticsClientID " ) . toString ( ) ;
if ( clientID . isEmpty ( ) )
{
clientID = QUuid : : createUuid ( ) . toString ( ) ;
clientID . remove ( QLatin1Char ( ' { ' ) ) ;
clientID . remove ( QLatin1Char ( ' } ' ) ) ;
m_settings - > set ( " AnalyticsClientID " , clientID ) ;
}
m_analytics = new GAnalytics ( BuildConfig . ANALYTICS_ID , clientID , analyticsVersion , this ) ;
m_analytics - > setLogLevel ( GAnalytics : : Debug ) ;
m_analytics - > setAnonymizeIPs ( true ) ;
// FIXME: the ganalytics library has no idea about our fancy shared pointers...
m_analytics - > setNetworkAccessManager ( network ( ) . get ( ) ) ;
2018-07-15 12:51:05 +00:00
2020-10-13 19:46:09 +00:00
if ( m_settings - > get ( " AnalyticsSeen " ) . toInt ( ) < m_analytics - > version ( ) )
2018-07-15 12:51:05 +00:00
{
2020-10-13 19:46:09 +00:00
qDebug ( ) < < " Analytics info not seen by user yet (or old version). " ;
2018-07-15 12:51:05 +00:00
return ;
}
2020-10-13 19:46:09 +00:00
if ( ! m_settings - > get ( " Analytics " ) . toBool ( ) )
{
qDebug ( ) < < " Analytics disabled by user. " ;
return ;
}
m_analytics - > enable ( ) ;
qDebug ( ) < < " <> Initialized analytics with tid " < < BuildConfig . ANALYTICS_ID ;
2017-01-21 17:18:53 +00:00
}
2020-10-13 19:46:09 +00:00
void Application : : initializeSettings ( )
{
// Initialize application settings
m_settings . reset ( new ApplicationSettings ( BuildConfig . LAUNCHER_CONFIGFILE , this ) ) ;
// Init page provider
{
m_globalSettingsProvider = std : : make_shared < GenericPageProvider > ( tr ( " Settings " ) ) ;
m_globalSettingsProvider - > addPage < LauncherPage > ( ) ;
m_globalSettingsProvider - > addPage < MinecraftPage > ( ) ;
m_globalSettingsProvider - > addPage < JavaPage > ( ) ;
m_globalSettingsProvider - > addPage < LanguagePage > ( ) ;
m_globalSettingsProvider - > addPage < CustomCommandsPage > ( ) ;
m_globalSettingsProvider - > addPage < ProxyPage > ( ) ;
m_globalSettingsProvider - > addPage < ExternalToolsPage > ( ) ;
m_globalSettingsProvider - > addPage < AccountListPage > ( ) ;
m_globalSettingsProvider - > addPage < PasteEEPage > ( ) ;
}
qDebug ( ) < < " <> Settings loaded. " ;
}
2021-11-20 15:22:22 +00:00
bool Application : : createSetupWizard ( )
2017-01-21 17:18:53 +00:00
{
2018-07-15 12:51:05 +00:00
bool javaRequired = [ & ] ( )
{
QString currentHostName = QHostInfo : : localHostName ( ) ;
QString oldHostName = settings ( ) - > get ( " LastHostname " ) . toString ( ) ;
if ( currentHostName ! = oldHostName )
{
settings ( ) - > set ( " LastHostname " , currentHostName ) ;
return true ;
}
QString currentJavaPath = settings ( ) - > get ( " JavaPath " ) . toString ( ) ;
QString actualPath = FS : : ResolveExecutable ( currentJavaPath ) ;
if ( actualPath . isNull ( ) )
{
return true ;
}
return false ;
} ( ) ;
2023-09-02 22:26:58 +00:00
bool analyticsRequired = [ & ] ( ) {
if ( ! m_analytics ) {
2018-07-15 12:51:05 +00:00
return false ;
}
2023-09-02 22:26:58 +00:00
if ( BuildConfig . ANALYTICS_ID . isEmpty ( ) ) {
2018-07-15 12:51:05 +00:00
return false ;
}
2023-09-02 22:26:58 +00:00
if ( ! settings ( ) - > get ( " Analytics " ) . toBool ( ) ) {
return false ;
}
if ( settings ( ) - > get ( " AnalyticsSeen " ) . toInt ( ) < analytics ( ) - > version ( ) ) {
2018-07-15 12:51:05 +00:00
return true ;
}
return false ;
} ( ) ;
bool languageRequired = [ & ] ( )
{
if ( settings ( ) - > get ( " Language " ) . toString ( ) . isEmpty ( ) )
return true ;
return false ;
} ( ) ;
bool wizardRequired = javaRequired | | analyticsRequired | | languageRequired ;
if ( wizardRequired )
{
m_setupWizard = new SetupWizard ( nullptr ) ;
if ( languageRequired )
{
m_setupWizard - > addPage ( new LanguageWizardPage ( m_setupWizard ) ) ;
}
if ( javaRequired )
{
m_setupWizard - > addPage ( new JavaWizardPage ( m_setupWizard ) ) ;
}
if ( analyticsRequired )
{
m_setupWizard - > addPage ( new AnalyticsWizardPage ( m_setupWizard ) ) ;
}
2021-11-20 15:22:22 +00:00
connect ( m_setupWizard , & QDialog : : finished , this , & Application : : setupWizardFinished ) ;
2018-07-15 12:51:05 +00:00
m_setupWizard - > show ( ) ;
return true ;
}
return false ;
2017-01-06 05:08:45 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : setupWizardFinished ( int status )
2017-01-06 05:08:45 +00:00
{
2018-07-15 12:51:05 +00:00
qDebug ( ) < < " Wizard result = " < < status ;
performMainStartupAction ( ) ;
2017-01-06 05:08:45 +00:00
}
2016-12-01 01:17:27 +00:00
2021-11-20 15:22:22 +00:00
void Application : : performMainStartupAction ( )
2017-01-06 05:08:45 +00:00
{
2021-11-20 15:22:22 +00:00
m_status = Application : : Initialized ;
2018-07-15 12:51:05 +00:00
if ( ! m_instanceIdToLaunch . isEmpty ( ) )
{
auto inst = instances ( ) - > getInstanceById ( m_instanceIdToLaunch ) ;
if ( inst )
{
2023-04-08 17:03:20 +00:00
QuickPlayTargetPtr serverOrWorldToJoin = nullptr ;
2021-10-31 20:42:06 +00:00
MinecraftAccountPtr accountToUse = nullptr ;
2022-06-09 21:46:28 +00:00
bool offline = m_offline ;
2021-05-23 12:42:20 +00:00
2021-10-31 20:42:06 +00:00
qDebug ( ) < < " <> Instance " < < m_instanceIdToLaunch < < " launching " ;
2021-05-23 12:42:20 +00:00
if ( ! m_serverToJoin . isEmpty ( ) )
{
2021-10-31 20:42:06 +00:00
// FIXME: validate the server string
2023-04-08 17:03:20 +00:00
serverOrWorldToJoin . reset ( new QuickPlayTarget ( QuickPlayTarget : : parseMultiplayer ( m_serverToJoin ) ) ) ;
2021-10-31 20:42:06 +00:00
qDebug ( ) < < " Launching with server " < < m_serverToJoin ;
2021-05-23 12:42:20 +00:00
}
2021-10-31 20:42:06 +00:00
2023-04-08 17:03:20 +00:00
if ( ! m_worldToJoin . isEmpty ( ) )
{
serverOrWorldToJoin . reset ( new QuickPlayTarget ( QuickPlayTarget : : parseSingleplayer ( m_worldToJoin ) ) ) ;
qDebug ( ) < < " Launching with world " < < m_worldToJoin ;
}
2021-10-31 20:42:06 +00:00
if ( ! m_profileToUse . isEmpty ( ) )
2021-05-23 12:42:20 +00:00
{
2021-10-31 20:42:06 +00:00
accountToUse = accounts ( ) - > getAccountByProfileName ( m_profileToUse ) ;
if ( ! accountToUse ) {
return ;
}
qDebug ( ) < < " Launching with account " < < m_profileToUse ;
2021-05-23 12:42:20 +00:00
}
2023-04-08 17:03:20 +00:00
launch ( inst , ! offline , nullptr , serverOrWorldToJoin , accountToUse , m_offlineName ) ;
2018-07-15 12:51:05 +00:00
return ;
}
}
if ( ! m_mainWindow )
{
// normal main window
showMainWindow ( false ) ;
qDebug ( ) < < " <> Main window shown. " ;
}
2020-02-04 23:29:23 +00:00
if ( ! m_zipToImport . isEmpty ( ) )
{
qDebug ( ) < < " <> Importing instance from zip: " < < m_zipToImport ;
m_mainWindow - > droppedURLs ( { m_zipToImport } ) ;
}
2013-09-07 02:00:58 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : showFatalErrorMessage ( const QString & title , const QString & content )
2017-01-14 14:47:58 +00:00
{
2021-11-20 15:22:22 +00:00
m_status = Application : : Failed ;
2018-07-15 12:51:05 +00:00
auto dialog = CustomMessageBox : : selectable ( nullptr , title , content , QMessageBox : : Critical ) ;
dialog - > exec ( ) ;
2017-01-14 14:47:58 +00:00
}
2021-11-20 15:22:22 +00:00
Application : : ~ Application ( )
2013-09-07 02:00:58 +00:00
{
2018-07-15 12:51:05 +00:00
// Shut down logger by setting the logger function to nothing
qInstallMessageHandler ( nullptr ) ;
2013-09-07 02:00:58 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : messageReceived ( const QByteArray & message )
2016-10-30 01:37:38 +00:00
{
2018-07-15 12:51:05 +00:00
if ( status ( ) ! = Initialized )
{
qDebug ( ) < < " Received message " < < message < < " while still initializing. It will be ignored. " ;
return ;
}
2020-02-04 23:29:23 +00:00
2021-11-20 15:22:22 +00:00
ApplicationMessage received ;
2021-10-31 20:42:06 +00:00
received . parse ( message ) ;
auto & command = received . command ;
2020-02-04 23:29:23 +00:00
if ( command = = " activate " )
2018-07-15 12:51:05 +00:00
{
showMainWindow ( ) ;
}
2020-02-04 23:29:23 +00:00
else if ( command = = " import " )
{
2021-10-31 20:42:06 +00:00
QString path = received . args [ " path " ] ;
if ( path . isEmpty ( ) )
2020-02-04 23:29:23 +00:00
{
qWarning ( ) < < " Received " < < command < < " message without a zip path/URL. " ;
return ;
}
2021-10-31 20:42:06 +00:00
m_mainWindow - > droppedURLs ( { QUrl ( path ) } ) ;
2020-02-04 23:29:23 +00:00
}
else if ( command = = " launch " )
2018-07-15 12:51:05 +00:00
{
2021-10-31 20:42:06 +00:00
QString id = received . args [ " id " ] ;
QString server = received . args [ " server " ] ;
2023-04-10 20:14:12 +00:00
QString world = received . args [ " world " ] ;
2021-10-31 20:42:06 +00:00
QString profile = received . args [ " profile " ] ;
2022-06-09 21:46:28 +00:00
bool offline = received . args [ " offline_enabled " ] = = " true " ;
QString offlineName = received . args [ " offline_name " ] ;
2021-10-31 20:42:06 +00:00
InstancePtr instance ;
if ( ! id . isEmpty ( ) ) {
instance = instances ( ) - > getInstanceById ( id ) ;
if ( ! instance ) {
qWarning ( ) < < " Launch command requires an valid instance ID. " < < id < < " resolves to nothing. " ;
return ;
}
2018-07-15 12:51:05 +00:00
}
2021-10-31 20:42:06 +00:00
else {
qWarning ( ) < < " Launch command called without an instance ID... " ;
2021-05-23 12:42:20 +00:00
return ;
}
2021-10-31 20:42:06 +00:00
2023-04-10 20:14:12 +00:00
QuickPlayTargetPtr quickPlayTarget = nullptr ;
2021-10-31 20:42:06 +00:00
if ( ! server . isEmpty ( ) ) {
2023-04-10 20:14:12 +00:00
quickPlayTarget = std : : make_shared < QuickPlayTarget > ( QuickPlayTarget : : parseMultiplayer ( server ) ) ;
} else if ( ! world . isEmpty ( ) ) {
quickPlayTarget = std : : make_shared < QuickPlayTarget > ( QuickPlayTarget : : parseSingleplayer ( world ) ) ;
2021-05-23 12:42:20 +00:00
}
2021-10-31 20:42:06 +00:00
MinecraftAccountPtr accountObject ;
if ( ! profile . isEmpty ( ) ) {
accountObject = accounts ( ) - > getAccountByProfileName ( profile ) ;
if ( ! accountObject ) {
qWarning ( ) < < " Launch command requires the specified profile to be valid. " < < profile < < " does not resolve to any account. " ;
return ;
}
2021-05-23 12:42:20 +00:00
}
2021-10-31 20:42:06 +00:00
launch (
instance ,
2022-06-09 21:46:28 +00:00
! offline ,
2021-10-31 20:42:06 +00:00
nullptr ,
2023-04-10 20:14:12 +00:00
quickPlayTarget ,
2022-06-09 21:46:28 +00:00
accountObject ,
offlineName
2021-10-31 20:42:06 +00:00
) ;
2021-05-23 12:42:20 +00:00
}
2020-02-04 23:29:23 +00:00
else
{
qWarning ( ) < < " Received invalid message " < < message ;
}
2016-10-30 01:37:38 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : analyticsSettingChanged ( const Setting & , QVariant value )
2016-11-24 03:10:07 +00:00
{
2018-07-15 12:51:05 +00:00
if ( ! m_analytics )
return ;
bool enabled = value . toBool ( ) ;
if ( enabled )
{
qDebug ( ) < < " Analytics enabled by user. " ;
}
else
{
qDebug ( ) < < " Analytics disabled by user. " ;
}
m_analytics - > enable ( enabled ) ;
2016-11-24 03:10:07 +00:00
}
2021-11-20 15:22:22 +00:00
std : : shared_ptr < TranslationsModel > Application : : translations ( )
2016-12-05 01:29:08 +00:00
{
2018-07-15 12:51:05 +00:00
return m_translations ;
2016-12-05 01:29:08 +00:00
}
2021-11-20 15:22:22 +00:00
std : : shared_ptr < JavaInstallList > Application : : javalist ( )
2013-10-14 01:59:21 +00:00
{
2018-07-15 12:51:05 +00:00
if ( ! m_javalist )
{
m_javalist . reset ( new JavaInstallList ( ) ) ;
}
return m_javalist ;
2013-10-14 01:59:21 +00:00
}
2021-11-20 15:22:22 +00:00
std : : vector < ITheme * > Application : : getValidApplicationThemes ( )
2016-10-21 07:07:26 +00:00
{
2018-07-15 12:51:05 +00:00
std : : vector < ITheme * > ret ;
auto iter = m_themes . cbegin ( ) ;
while ( iter ! = m_themes . cend ( ) )
{
ret . push_back ( ( * iter ) . second . get ( ) ) ;
iter + + ;
}
return ret ;
2016-10-21 07:07:26 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : setApplicationTheme ( const QString & name , bool initial )
2016-10-21 07:07:26 +00:00
{
2018-07-15 12:51:05 +00:00
auto systemPalette = qApp - > palette ( ) ;
auto themeIter = m_themes . find ( name ) ;
if ( themeIter ! = m_themes . end ( ) )
{
auto & theme = ( * themeIter ) . second ;
theme - > apply ( initial ) ;
}
else
{
qWarning ( ) < < " Tried to set invalid theme: " < < name ;
}
2016-10-21 07:07:26 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : setIconTheme ( const QString & name )
2015-03-01 21:20:57 +00:00
{
2018-07-15 12:51:05 +00:00
XdgIcon : : setThemeName ( name ) ;
2015-03-01 21:20:57 +00:00
}
2021-11-20 15:22:22 +00:00
QIcon Application : : getThemedIcon ( const QString & name )
2015-03-01 21:20:57 +00:00
{
2021-10-17 22:47:02 +00:00
if ( name = = " logo " ) {
return QIcon ( " :/logo.svg " ) ;
}
2018-07-15 12:51:05 +00:00
return XdgIcon : : fromTheme ( name ) ;
2015-03-01 21:20:57 +00:00
}
2021-11-20 15:22:22 +00:00
bool Application : : openJsonEditor ( const QString & filename )
2013-12-29 16:51:16 +00:00
{
2018-07-15 12:51:05 +00:00
const QString file = QDir : : current ( ) . absoluteFilePath ( filename ) ;
if ( m_settings - > get ( " JsonEditor " ) . toString ( ) . isEmpty ( ) )
{
return DesktopServices : : openUrl ( QUrl : : fromLocalFile ( file ) ) ;
}
else
{
//return DesktopServices::openFile(m_settings->get("JsonEditor").toString(), file);
return DesktopServices : : run ( m_settings - > get ( " JsonEditor " ) . toString ( ) , { file } ) ;
}
2013-12-29 16:51:16 +00:00
}
2013-09-07 02:00:58 +00:00
2021-11-20 15:22:22 +00:00
bool Application : : launch (
2021-05-22 16:07:08 +00:00
InstancePtr instance ,
bool online ,
BaseProfilerFactory * profiler ,
2023-04-08 17:03:20 +00:00
QuickPlayTargetPtr quickPlayTarget ,
2022-06-09 21:46:28 +00:00
MinecraftAccountPtr accountToUse ,
const QString & offlineName
2021-05-22 16:07:08 +00:00
) {
2018-07-15 12:51:05 +00:00
if ( m_updateRunning )
{
2019-09-15 03:31:13 +00:00
qDebug ( ) < < " Cannot launch instances while an update is running. Please try again when updates are completed. " ;
2018-07-15 12:51:05 +00:00
}
else if ( instance - > canLaunch ( ) )
{
auto & extras = m_instanceExtras [ instance - > id ( ) ] ;
auto & window = extras . window ;
if ( window )
{
if ( ! window - > saveAll ( ) )
{
return false ;
}
}
auto & controller = extras . controller ;
controller . reset ( new LaunchController ( ) ) ;
controller - > setInstance ( instance ) ;
controller - > setOnline ( online ) ;
controller - > setProfiler ( profiler ) ;
2023-04-08 17:03:20 +00:00
controller - > setQuickPlayTarget ( quickPlayTarget ) ;
2021-10-31 20:42:06 +00:00
controller - > setAccountToUse ( accountToUse ) ;
2022-06-09 21:46:28 +00:00
controller - > setOfflineName ( offlineName ) ;
2018-07-15 12:51:05 +00:00
if ( window )
{
controller - > setParentWidget ( window ) ;
}
else if ( m_mainWindow )
{
controller - > setParentWidget ( m_mainWindow ) ;
}
2021-11-20 15:22:22 +00:00
connect ( controller . get ( ) , & LaunchController : : succeeded , this , & Application : : controllerSucceeded ) ;
connect ( controller . get ( ) , & LaunchController : : failed , this , & Application : : controllerFailed ) ;
2018-07-15 12:51:05 +00:00
addRunningInstance ( ) ;
controller - > start ( ) ;
return true ;
}
else if ( instance - > isRunning ( ) )
{
showInstanceWindow ( instance , " console " ) ;
return true ;
}
else if ( instance - > canEdit ( ) )
{
showInstanceWindow ( instance ) ;
return true ;
}
return false ;
2016-10-30 01:37:38 +00:00
}
2021-11-20 15:22:22 +00:00
bool Application : : kill ( InstancePtr instance )
2016-11-26 17:06:08 +00:00
{
2018-07-15 12:51:05 +00:00
if ( ! instance - > isRunning ( ) )
{
2019-09-15 03:31:13 +00:00
qWarning ( ) < < " Attempted to kill instance " < < instance - > id ( ) < < " , which isn't running. " ;
2018-07-15 12:51:05 +00:00
return false ;
}
auto & extras = m_instanceExtras [ instance - > id ( ) ] ;
// NOTE: copy of the shared pointer keeps it alive
auto controller = extras . controller ;
if ( controller )
{
return controller - > abort ( ) ;
}
return true ;
2016-11-26 17:06:08 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : addRunningInstance ( )
2017-05-01 23:43:18 +00:00
{
2018-07-15 12:51:05 +00:00
m_runningInstances + + ;
if ( m_runningInstances = = 1 )
{
emit updateAllowedChanged ( false ) ;
}
2017-05-01 23:43:18 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : subRunningInstance ( )
2017-05-01 23:43:18 +00:00
{
2018-07-15 12:51:05 +00:00
if ( m_runningInstances = = 0 )
{
qCritical ( ) < < " Something went really wrong and we now have less than 0 running instances... WTF " ;
return ;
}
m_runningInstances - - ;
if ( m_runningInstances = = 0 )
{
emit updateAllowedChanged ( true ) ;
}
2017-05-01 23:43:18 +00:00
}
2021-11-20 15:22:22 +00:00
bool Application : : shouldExitNow ( ) const
2017-05-01 23:43:18 +00:00
{
2018-07-15 12:51:05 +00:00
return m_runningInstances = = 0 & & m_openWindows = = 0 ;
2017-05-01 23:43:18 +00:00
}
2021-11-20 15:22:22 +00:00
bool Application : : updatesAreAllowed ( )
2017-05-01 23:43:18 +00:00
{
2018-07-15 12:51:05 +00:00
return m_runningInstances = = 0 ;
2017-05-01 23:43:18 +00:00
}
2016-11-26 17:06:08 +00:00
2021-11-20 15:22:22 +00:00
void Application : : updateIsRunning ( bool running )
2017-05-02 21:29:47 +00:00
{
2018-07-15 12:51:05 +00:00
m_updateRunning = running ;
2017-05-02 21:29:47 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : controllerSucceeded ( )
2016-11-01 00:25:04 +00:00
{
2018-07-15 12:51:05 +00:00
auto controller = qobject_cast < LaunchController * > ( QObject : : sender ( ) ) ;
if ( ! controller )
return ;
auto id = controller - > id ( ) ;
auto & extras = m_instanceExtras [ id ] ;
// on success, do...
if ( controller - > instance ( ) - > settings ( ) - > get ( " AutoCloseConsole " ) . toBool ( ) )
{
if ( extras . window )
{
extras . window - > close ( ) ;
}
}
extras . controller . reset ( ) ;
subRunningInstance ( ) ;
// quit when there are no more windows.
if ( shouldExitNow ( ) )
{
m_status = Status : : Succeeded ;
exit ( 0 ) ;
}
2016-11-01 00:25:04 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : controllerFailed ( const QString & error )
2016-11-01 00:25:04 +00:00
{
2018-07-15 12:51:05 +00:00
Q_UNUSED ( error ) ;
auto controller = qobject_cast < LaunchController * > ( QObject : : sender ( ) ) ;
if ( ! controller )
return ;
auto id = controller - > id ( ) ;
auto & extras = m_instanceExtras [ id ] ;
// on failure, do... nothing
extras . controller . reset ( ) ;
subRunningInstance ( ) ;
// quit when there are no more windows.
if ( shouldExitNow ( ) )
{
m_status = Status : : Failed ;
exit ( 1 ) ;
}
2016-11-01 00:25:04 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : ShowGlobalSettings ( class QWidget * parent , QString open_page )
2019-06-01 10:28:53 +00:00
{
if ( ! m_globalSettingsProvider ) {
return ;
}
emit globalSettingsAboutToOpen ( ) ;
{
2021-11-20 15:22:22 +00:00
SettingsObject : : Lock lock ( APPLICATION - > settings ( ) ) ;
2019-06-01 10:28:53 +00:00
PageDialog dlg ( m_globalSettingsProvider . get ( ) , open_page , parent ) ;
dlg . exec ( ) ;
}
emit globalSettingsClosed ( ) ;
}
2020-10-13 19:46:09 +00:00
void Application : : ShowJREs ( class QWidget * parent )
{
JREClientDialog dlg ( parent ) ;
dlg . exec ( ) ;
}
2021-11-20 15:22:22 +00:00
MainWindow * Application : : showMainWindow ( bool minimized )
2016-10-30 01:37:38 +00:00
{
2018-07-15 12:51:05 +00:00
if ( m_mainWindow )
{
m_mainWindow - > setWindowState ( m_mainWindow - > windowState ( ) & ~ Qt : : WindowMinimized ) ;
m_mainWindow - > raise ( ) ;
m_mainWindow - > activateWindow ( ) ;
}
else
{
m_mainWindow = new MainWindow ( ) ;
2021-11-20 15:22:22 +00:00
m_mainWindow - > restoreState ( QByteArray : : fromBase64 ( APPLICATION - > settings ( ) - > get ( " MainWindowState " ) . toByteArray ( ) ) ) ;
m_mainWindow - > restoreGeometry ( QByteArray : : fromBase64 ( APPLICATION - > settings ( ) - > get ( " MainWindowGeometry " ) . toByteArray ( ) ) ) ;
2018-07-15 12:51:05 +00:00
if ( minimized )
{
m_mainWindow - > showMinimized ( ) ;
}
else
{
m_mainWindow - > show ( ) ;
}
m_mainWindow - > checkInstancePathForProblems ( ) ;
2021-11-20 15:22:22 +00:00
connect ( this , & Application : : updateAllowedChanged , m_mainWindow , & MainWindow : : updatesAllowedChanged ) ;
connect ( m_mainWindow , & MainWindow : : isClosing , this , & Application : : on_windowClose ) ;
2018-07-15 12:51:05 +00:00
m_openWindows + + ;
}
// FIXME: move this somewhere else...
if ( m_analytics )
{
auto windowSize = m_mainWindow - > size ( ) ;
auto sizeString = QString ( " %1x%2 " ) . arg ( windowSize . width ( ) ) . arg ( windowSize . height ( ) ) ;
qDebug ( ) < < " Viewport size " < < sizeString ;
m_analytics - > setViewportSize ( sizeString ) ;
/*
* cm1 = java min heap [ MB ]
* cm2 = java max heap [ MB ]
* cm3 = system RAM [ MB ]
*
* cd1 = java version
* cd2 = java architecture
* cd3 = system architecture
* cd4 = CPU architecture
*/
QVariantMap customValues ;
int min = m_settings - > get ( " MinMemAlloc " ) . toInt ( ) ;
int max = m_settings - > get ( " MaxMemAlloc " ) . toInt ( ) ;
if ( min < max )
{
customValues [ " cm1 " ] = min ;
customValues [ " cm2 " ] = max ;
}
else
{
customValues [ " cm1 " ] = max ;
customValues [ " cm2 " ] = min ;
}
constexpr uint64_t Mega = 1024ull * 1024ull ;
int ramSize = int ( Sys : : getSystemRam ( ) / Mega ) ;
qDebug ( ) < < " RAM size is " < < ramSize < < " MB " ;
customValues [ " cm3 " ] = ramSize ;
customValues [ " cd1 " ] = m_settings - > get ( " JavaVersion " ) ;
customValues [ " cd2 " ] = m_settings - > get ( " JavaArchitecture " ) ;
customValues [ " cd3 " ] = Sys : : isSystem64bit ( ) ? " 64 " : " 32 " ;
customValues [ " cd4 " ] = Sys : : isCPU64bit ( ) ? " 64 " : " 32 " ;
auto kernelInfo = Sys : : getKernelInfo ( ) ;
customValues [ " cd5 " ] = kernelInfo . kernelName ;
customValues [ " cd6 " ] = kernelInfo . kernelVersion ;
auto distInfo = Sys : : getDistributionInfo ( ) ;
if ( ! distInfo . distributionName . isEmpty ( ) )
{
customValues [ " cd7 " ] = distInfo . distributionName ;
}
if ( ! distInfo . distributionVersion . isEmpty ( ) )
{
customValues [ " cd8 " ] = distInfo . distributionVersion ;
}
m_analytics - > sendScreenView ( " Main Window " , customValues ) ;
}
return m_mainWindow ;
2016-10-30 01:37:38 +00:00
}
2021-11-20 15:22:22 +00:00
InstanceWindow * Application : : showInstanceWindow ( InstancePtr instance , QString page )
2016-10-30 01:37:38 +00:00
{
2018-07-15 12:51:05 +00:00
if ( ! instance )
return nullptr ;
auto id = instance - > id ( ) ;
auto & extras = m_instanceExtras [ id ] ;
auto & window = extras . window ;
if ( window )
{
window - > raise ( ) ;
window - > activateWindow ( ) ;
}
else
{
window = new InstanceWindow ( instance ) ;
m_openWindows + + ;
2021-11-20 15:22:22 +00:00
connect ( window , & InstanceWindow : : isClosing , this , & Application : : on_windowClose ) ;
2018-07-15 12:51:05 +00:00
}
if ( ! page . isEmpty ( ) )
{
window - > selectPage ( page ) ;
}
if ( extras . controller )
{
extras . controller - > setParentWidget ( window ) ;
}
return window ;
2016-10-30 01:37:38 +00:00
}
2021-11-20 15:22:22 +00:00
void Application : : on_windowClose ( )
2016-10-30 01:37:38 +00:00
{
2018-07-15 12:51:05 +00:00
m_openWindows - - ;
auto instWindow = qobject_cast < InstanceWindow * > ( QObject : : sender ( ) ) ;
if ( instWindow )
{
auto & extras = m_instanceExtras [ instWindow - > instanceId ( ) ] ;
extras . window = nullptr ;
if ( extras . controller )
{
extras . controller - > setParentWidget ( m_mainWindow ) ;
}
}
auto mainWindow = qobject_cast < MainWindow * > ( QObject : : sender ( ) ) ;
if ( mainWindow )
{
m_mainWindow = nullptr ;
}
// quit when there are no more windows.
if ( shouldExitNow ( ) )
{
exit ( 0 ) ;
}
2016-10-30 01:37:38 +00:00
}
2021-11-20 15:22:22 +00:00
QString Application : : msaClientId ( ) const {
return Secrets : : getMSAClientID ( ' - ' ) ;
}
2021-11-21 22:21:12 +00:00
void Application : : 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 ( ) ;
m_network - > 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 ( " %1:%2 " )
. arg ( proxy . hostName ( ) )
. arg ( proxy . port ( ) ) ;
qDebug ( ) < < proxyDesc ;
}
shared_qobject_ptr < HttpMetaCache > Application : : metacache ( )
{
return m_metacache ;
}
shared_qobject_ptr < QNetworkAccessManager > Application : : network ( )
{
return m_network ;
}
shared_qobject_ptr < Meta : : Index > Application : : metadataIndex ( )
{
if ( ! m_metadataIndex )
{
m_metadataIndex . reset ( new Meta : : Index ( ) ) ;
}
return m_metadataIndex ;
}
QString Application : : getJarsPath ( )
{
if ( m_jarsPath . isEmpty ( ) )
{
return FS : : PathCombine ( QCoreApplication : : applicationDirPath ( ) , " jars " ) ;
}
return m_jarsPath ;
}