2016-08-11 04:14:01 +05:30
# include "LaunchController.h"
2016-08-06 19:09:29 +05:30
# include "MainWindow.h"
2016-02-28 00:28:40 +05:30
# include <minecraft/auth/MojangAccountList.h>
2015-07-05 05:24:30 +05:30
# include "MultiMC.h"
# include "dialogs/CustomMessageBox.h"
2016-08-11 04:14:01 +05:30
# include "dialogs/ProfileSelectDialog.h"
2015-07-05 05:24:30 +05:30
# include "dialogs/ProgressDialog.h"
# include "dialogs/EditAccountDialog.h"
2016-08-06 19:09:29 +05:30
# include "InstanceWindow.h"
2015-07-05 05:24:30 +05:30
# include "BuildConfig.h"
# include "JavaCommon.h"
# include <QLineEdit>
# include <QInputDialog>
# include <tasks/Task.h>
2016-02-28 00:28:40 +05:30
# include <minecraft/auth/YggdrasilTask.h>
2015-07-21 06:08:15 +05:30
# include <launch/steps/TextPrint.h>
2015-08-14 05:57:01 +05:30
# include <QStringList>
2015-07-05 05:24:30 +05:30
2015-10-24 04:27:54 +05:30
LaunchController : : LaunchController ( QObject * parent ) : Task ( parent )
2015-07-05 05:24:30 +05:30
{
}
2015-10-24 04:27:54 +05:30
void LaunchController : : executeTask ( )
2015-07-05 05:24:30 +05:30
{
2018-07-15 18:21:05 +05:30
if ( ! m_instance )
{
emitFailed ( tr ( " No instance specified " ) ) ;
return ;
}
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
login ( ) ;
2017-12-03 18:35:35 +05:30
}
// FIXME: minecraft specific
void LaunchController : : login ( )
{
2018-07-15 18:21:05 +05:30
JavaCommon : : checkJVMArgs ( m_instance - > settings ( ) - > get ( " JvmArgs " ) . toString ( ) , m_parentWidget ) ;
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
// Find an account to use.
std : : shared_ptr < MojangAccountList > accounts = MMC - > accounts ( ) ;
MojangAccountPtr account = accounts - > activeAccount ( ) ;
if ( accounts - > count ( ) < = 0 )
{
// Tell the user they need to log in at least one account in order to play.
auto reply = CustomMessageBox : : selectable (
m_parentWidget , tr ( " No Accounts " ) ,
tr ( " In order to play Minecraft, you must have at least one Mojang or Minecraft "
" account logged in to MultiMC. "
" Would you like to open the account manager to add an account now? " ) ,
QMessageBox : : Information , QMessageBox : : Yes | QMessageBox : : No ) - > exec ( ) ;
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
if ( reply = = QMessageBox : : Yes )
{
// Open the account manager.
2019-06-01 15:58:53 +05:30
MMC - > ShowGlobalSettings ( m_parentWidget , " accounts " ) ;
2018-07-15 18:21:05 +05:30
}
}
else if ( account . get ( ) = = nullptr )
{
// If no default account is set, ask the user which one to use.
ProfileSelectDialog selectDialog ( tr ( " Which profile would you like to use? " ) ,
ProfileSelectDialog : : GlobalDefaultCheckbox , m_parentWidget ) ;
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
selectDialog . exec ( ) ;
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
// Launch the instance with the selected account.
account = selectDialog . selectedAccount ( ) ;
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
// If the user said to use the account as default, do that.
if ( selectDialog . useAsGlobalDefault ( ) & & account . get ( ) ! = nullptr )
accounts - > setActiveAccount ( account - > username ( ) ) ;
}
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
// if no account is selected, we bail
if ( ! account . get ( ) )
{
emitFailed ( tr ( " No account selected for launch " ) ) ;
return ;
}
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
// we try empty password first :)
QString password ;
// we loop until the user succeeds in logging in or gives up
bool tryagain = true ;
// the failure. the default failure.
2019-09-15 08:42:23 +05:30
const QString needLoginAgain = tr ( " Your account is currently not logged in. Please enter your password to log in again. <br /> <br /> This could be caused by a password change. " ) ;
2018-07-15 18:21:05 +05:30
QString failReason = needLoginAgain ;
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
while ( tryagain )
{
m_session = std : : make_shared < AuthSession > ( ) ;
m_session - > wants_online = m_online ;
auto task = account - > login ( m_session , password ) ;
if ( task )
{
// We'll need to validate the access token to make sure the account
// is still logged in.
ProgressDialog progDialog ( m_parentWidget ) ;
if ( m_online )
{
progDialog . setSkipButton ( true , tr ( " Play Offline " ) ) ;
}
progDialog . execWithTask ( task . get ( ) ) ;
if ( ! task - > wasSuccessful ( ) )
{
auto failReasonNew = task - > failReason ( ) ;
if ( failReasonNew = = " Invalid token. " )
{
account - > invalidateClientToken ( ) ;
failReason = needLoginAgain ;
}
else failReason = failReasonNew ;
}
}
switch ( m_session - > status )
{
case AuthSession : : Undetermined :
{
qCritical ( ) < < " Received undetermined session status during login. Bye. " ;
tryagain = false ;
emitFailed ( tr ( " Received undetermined session status during login. " ) ) ;
break ;
}
case AuthSession : : RequiresPassword :
{
EditAccountDialog passDialog ( failReason , m_parentWidget , EditAccountDialog : : PasswordField ) ;
auto username = m_session - > username ;
auto chopN = [ ] ( QString toChop , int N ) - > QString
{
if ( toChop . size ( ) > N )
{
auto left = toChop . left ( N ) ;
left + = QString ( " \u25CF " ) . repeated ( toChop . size ( ) - N ) ;
return left ;
}
return toChop ;
} ;
2015-08-14 05:57:01 +05:30
2018-07-15 18:21:05 +05:30
if ( username . contains ( ' @ ' ) )
{
auto parts = username . split ( ' @ ' ) ;
auto mailbox = chopN ( parts [ 0 ] , 3 ) ;
QString domain = chopN ( parts [ 1 ] , 3 ) ;
username = mailbox + ' @ ' + domain ;
}
passDialog . setUsername ( username ) ;
if ( passDialog . exec ( ) = = QDialog : : Accepted )
{
password = passDialog . password ( ) ;
}
else
{
tryagain = false ;
}
break ;
}
case AuthSession : : PlayableOffline :
{
// we ask the user for a player name
bool ok = false ;
QString usedname = m_session - > player_name ;
QString name = QInputDialog : : getText ( m_parentWidget , tr ( " Player name " ) ,
tr ( " Choose your offline mode player name. " ) ,
QLineEdit : : Normal , m_session - > player_name , & ok ) ;
if ( ! ok )
{
tryagain = false ;
break ;
}
if ( name . length ( ) )
{
usedname = name ;
}
m_session - > MakeOffline ( usedname ) ;
// offline flavored game from here :3
}
case AuthSession : : PlayableOnline :
{
launchInstance ( ) ;
tryagain = false ;
return ;
}
}
}
emitFailed ( tr ( " Failed to launch. " ) ) ;
2015-07-05 05:24:30 +05:30
}
void LaunchController : : launchInstance ( )
{
2018-07-15 18:21:05 +05:30
Q_ASSERT_X ( m_instance ! = NULL , " launchInstance " , " instance is NULL " ) ;
Q_ASSERT_X ( m_session . get ( ) ! = nullptr , " launchInstance " , " session is NULL " ) ;
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
if ( ! m_instance - > reloadSettings ( ) )
{
QMessageBox : : critical ( m_parentWidget , tr ( " Error " ) , tr ( " Couldn't load the instance profile. " ) ) ;
emitFailed ( tr ( " Couldn't load the instance profile. " ) ) ;
return ;
}
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
m_launcher = m_instance - > createLaunchTask ( m_session ) ;
if ( ! m_launcher )
{
emitFailed ( tr ( " Couldn't instantiate a launcher. " ) ) ;
return ;
}
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
auto console = qobject_cast < InstanceWindow * > ( m_parentWidget ) ;
auto showConsole = m_instance - > settings ( ) - > get ( " ShowConsole " ) . toBool ( ) ;
if ( ! console & & showConsole )
{
MMC - > showInstanceWindow ( m_instance ) ;
}
connect ( m_launcher . get ( ) , & LaunchTask : : readyForLaunch , this , & LaunchController : : readyForLaunch ) ;
connect ( m_launcher . get ( ) , & LaunchTask : : succeeded , this , & LaunchController : : onSucceeded ) ;
connect ( m_launcher . get ( ) , & LaunchTask : : failed , this , & LaunchController : : onFailed ) ;
connect ( m_launcher . get ( ) , & LaunchTask : : requestProgress , this , & LaunchController : : onProgressRequested ) ;
2016-11-01 05:55:04 +05:30
2015-07-05 05:24:30 +05:30
2019-04-08 03:29:04 +05:30
m_launcher - > prependStep ( new TextPrint ( m_launcher . get ( ) , " MultiMC version: " + BuildConfig . printableVersionString ( ) + " \n \n " , MessageLevel : : MultiMC ) ) ;
2018-07-15 18:21:05 +05:30
m_launcher - > start ( ) ;
2015-07-05 05:24:30 +05:30
}
void LaunchController : : readyForLaunch ( )
{
2018-07-15 18:21:05 +05:30
if ( ! m_profiler )
{
m_launcher - > proceed ( ) ;
return ;
}
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
QString error ;
if ( ! m_profiler - > check ( & error ) )
{
m_launcher - > abort ( ) ;
QMessageBox : : critical ( m_parentWidget , tr ( " Error " ) , tr ( " Couldn't start profiler: %1 " ) . arg ( error ) ) ;
emitFailed ( " Profiler startup failed " ) ;
return ;
}
BaseProfiler * profilerInstance = m_profiler - > createProfiler ( m_launcher - > instance ( ) , this ) ;
2015-07-05 05:24:30 +05:30
2018-07-15 18:21:05 +05:30
connect ( profilerInstance , & BaseProfiler : : readyToLaunch , [ this ] ( const QString & message )
{
QMessageBox msg ;
msg . setText ( tr ( " The game launch is delayed until you press the "
" button. This is the right time to setup the profiler, as the "
" profiler server is running now. \n \n %1 " ) . arg ( message ) ) ;
msg . setWindowTitle ( tr ( " Waiting " ) ) ;
msg . setIcon ( QMessageBox : : Information ) ;
msg . addButton ( tr ( " Launch " ) , QMessageBox : : AcceptRole ) ;
msg . setModal ( true ) ;
msg . exec ( ) ;
m_launcher - > proceed ( ) ;
} ) ;
connect ( profilerInstance , & BaseProfiler : : abortLaunch , [ this ] ( const QString & message )
{
QMessageBox msg ;
msg . setText ( tr ( " Couldn't start the profiler: %1 " ) . arg ( message ) ) ;
msg . setWindowTitle ( tr ( " Error " ) ) ;
msg . setIcon ( QMessageBox : : Critical ) ;
msg . addButton ( QMessageBox : : Ok ) ;
msg . setModal ( true ) ;
msg . exec ( ) ;
m_launcher - > abort ( ) ;
emitFailed ( " Profiler startup failed " ) ;
} ) ;
profilerInstance - > beginProfiling ( m_launcher ) ;
2015-07-05 05:24:30 +05:30
}
2016-11-01 05:55:04 +05:30
void LaunchController : : onSucceeded ( )
{
2018-07-15 18:21:05 +05:30
emitSucceeded ( ) ;
2016-11-01 05:55:04 +05:30
}
void LaunchController : : onFailed ( QString reason )
{
2018-07-15 18:21:05 +05:30
if ( m_instance - > settings ( ) - > get ( " ShowConsoleOnError " ) . toBool ( ) )
{
MMC - > showInstanceWindow ( m_instance , " console " ) ;
}
emitFailed ( reason ) ;
2016-11-01 05:55:04 +05:30
}
void LaunchController : : onProgressRequested ( Task * task )
{
2018-07-15 18:21:05 +05:30
ProgressDialog progDialog ( m_parentWidget ) ;
progDialog . setSkipButton ( true , tr ( " Abort " ) ) ;
m_launcher - > proceed ( ) ;
progDialog . execWithTask ( task ) ;
2016-11-01 05:55:04 +05:30
}
2016-11-26 22:36:08 +05:30
bool LaunchController : : abort ( )
{
2018-07-15 18:21:05 +05:30
if ( ! m_launcher )
{
return true ;
}
if ( ! m_launcher - > canAbort ( ) )
{
return false ;
}
auto response = CustomMessageBox : : selectable (
m_parentWidget , tr ( " Kill Minecraft? " ) ,
tr ( " This can cause the instance to get corrupted and should only be used if Minecraft "
" is frozen for some reason " ) ,
QMessageBox : : Question , QMessageBox : : Yes | QMessageBox : : No , QMessageBox : : Yes ) - > exec ( ) ;
if ( response = = QMessageBox : : Yes )
{
return m_launcher - > abort ( ) ;
}
return false ;
2016-11-26 22:36:08 +05:30
}