mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-14 15:17:02 -04:00
Mojang + Offline account removal
Offline account is now Local account
This commit is contained in:
parent
de8a16e5c5
commit
deef6223d3
@ -108,3 +108,4 @@ Any code change should be submitted as a pull request. The description should ex
|
||||
- [xHook](https://github.com/iqiyi/xHook) (Used for exit code trapping): [MIT and BSD-style licenses](https://github.com/iqiyi/xHook/blob/master/LICENSE).
|
||||
- [libepoxy](https://github.com/anholt/libepoxy): [MIT License](https://github.com/anholt/libepoxy/blob/master/COPYING).
|
||||
- [virglrenderer](https://github.com/PojavLauncherTeam/virglrenderer): [MIT License](https://gitlab.freedesktop.org/virgl/virglrenderer/-/blob/master/COPYING).
|
||||
- Thanks to [MCHeads](https://mc-heads.net) for providing Minecraft avatars.
|
||||
|
@ -99,7 +99,22 @@ public abstract class BaseLauncherActivity extends BaseActivity {
|
||||
} else if (canBack) {
|
||||
v.setEnabled(false);
|
||||
mTask = new MinecraftDownloaderTask(this);
|
||||
mTask.execute(mProfile.selectedVersion);
|
||||
// TODO: better check!!!
|
||||
if (mProfile.accessToken.equals("0")) {
|
||||
File verJsonFile = new File(Tools.DIR_HOME_VERSION,
|
||||
mProfile.selectedVersion + "/" + mProfile.selectedVersion + ".json");
|
||||
if (verJsonFile.exists()) {
|
||||
mTask.onPostExecute(null);
|
||||
} else {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.global_error)
|
||||
.setMessage(R.string.mcl_launch_error_localmode)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
} else {
|
||||
mTask.execute(mProfile.selectedVersion);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ public class PojavLauncherActivity extends BaseLauncherActivity
|
||||
accountFaceImageView.setImageBitmap(mProfile.getSkinFace());
|
||||
|
||||
//TODO FULL BACKGROUND LOGIN
|
||||
tvConnectStatus.setText(mProfile.accessToken.equals("0") ? R.string.mcl_account_offline : R.string.mcl_account_connected);
|
||||
tvConnectStatus.setText(mProfile.accessToken.equals("0") ? R.string.mcl_account_local : R.string.mcl_account_connected);
|
||||
} catch(Exception e) {
|
||||
mProfile = new MinecraftAccount();
|
||||
Tools.showError(this, e, true);
|
||||
|
@ -43,9 +43,6 @@ import androidx.core.content.ContextCompat;
|
||||
|
||||
import net.kdt.pojavlaunch.authenticator.microsoft.MicrosoftAuthTask;
|
||||
import net.kdt.pojavlaunch.authenticator.microsoft.ui.MicrosoftLoginGUIActivity;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.InvalidateTokenTask;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.LoginListener;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.LoginTask;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener;
|
||||
import net.kdt.pojavlaunch.customcontrols.CustomControls;
|
||||
import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog;
|
||||
@ -69,9 +66,9 @@ public class PojavLoginActivity extends BaseActivity {
|
||||
private final Object mLockStoragePerm = new Object();
|
||||
private final Object mLockSelectJRE = new Object();
|
||||
|
||||
private EditText edit2, edit3;
|
||||
private EditText edit2;
|
||||
private final int REQUEST_STORAGE_REQUEST_CODE = 1;
|
||||
private CheckBox sRemember, sOffline;
|
||||
private CheckBox sRemember;
|
||||
private TextView startupTextView;
|
||||
private SharedPreferences firstLaunchPrefs;
|
||||
private MinecraftAccount mProfile = null;
|
||||
@ -237,15 +234,8 @@ public class PojavLoginActivity extends BaseActivity {
|
||||
});
|
||||
|
||||
edit2 = (EditText) findViewById(R.id.login_edit_email);
|
||||
edit3 = (EditText) findViewById(R.id.login_edit_password);
|
||||
|
||||
sRemember = findViewById(R.id.login_switch_remember);
|
||||
sOffline = findViewById(R.id.login_switch_offline);
|
||||
sOffline.setOnCheckedChangeListener((p1, p2) -> {
|
||||
// May delete later
|
||||
edit3.setEnabled(!p2);
|
||||
});
|
||||
|
||||
isSkipInit = true;
|
||||
}
|
||||
|
||||
@ -529,11 +519,9 @@ public class PojavLoginActivity extends BaseActivity {
|
||||
};
|
||||
|
||||
MinecraftAccount acc = MinecraftAccount.load(selectedAccName);
|
||||
if (acc.isMicrosoft){
|
||||
if (acc.accessToken.length() >= 5){
|
||||
new MicrosoftAuthTask(PojavLoginActivity.this, authListener)
|
||||
.execute("true", acc.msaRefreshToken);
|
||||
} else if (acc.accessToken.length() >= 5) {
|
||||
PojavProfile.updateTokens(PojavLoginActivity.this, selectedAccName, authListener);
|
||||
} else {
|
||||
accountDialog.dismiss();
|
||||
PojavProfile.launch(PojavLoginActivity.this, selectedAccName);
|
||||
@ -574,7 +562,7 @@ public class PojavLoginActivity extends BaseActivity {
|
||||
accountDialog.show();
|
||||
}
|
||||
|
||||
private MinecraftAccount loginOffline() {
|
||||
private MinecraftAccount loginLocal() {
|
||||
new File(Tools.DIR_ACCOUNT_OLD).mkdir();
|
||||
|
||||
String text = edit2.getText().toString();
|
||||
@ -584,8 +572,6 @@ public class PojavLoginActivity extends BaseActivity {
|
||||
edit2.setError(getString(R.string.login_error_invalid_username));
|
||||
} else if (new File(Tools.DIR_ACCOUNT_NEW + "/" + text + ".json").exists()) {
|
||||
edit2.setError(getString(R.string.login_error_exist_username));
|
||||
} else if (!edit3.getText().toString().isEmpty()) {
|
||||
edit3.setError(getString(R.string.login_error_offline_password));
|
||||
} else {
|
||||
MinecraftAccount builder = new MinecraftAccount();
|
||||
builder.isMicrosoft = false;
|
||||
@ -599,43 +585,8 @@ public class PojavLoginActivity extends BaseActivity {
|
||||
|
||||
public void loginMC(final View v)
|
||||
{
|
||||
|
||||
if (sOffline.isChecked()) {
|
||||
mProfile = loginOffline();
|
||||
playProfile(false);
|
||||
} else {
|
||||
ProgressBar prb = findViewById(R.id.launcherAccProgress);
|
||||
new LoginTask().setLoginListener(new LoginListener(){
|
||||
|
||||
|
||||
@Override
|
||||
public void onBeforeLogin() {
|
||||
v.setEnabled(false);
|
||||
prb.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginDone(String[] result) {
|
||||
if(result[0].equals("ERROR")){
|
||||
Tools.dialogOnUiThread(PojavLoginActivity.this,
|
||||
getResources().getString(R.string.global_error), strArrToString(result));
|
||||
} else{
|
||||
MinecraftAccount builder = new MinecraftAccount();
|
||||
builder.accessToken = result[1];
|
||||
builder.clientToken = result[2];
|
||||
builder.profileId = result[3];
|
||||
builder.username = result[4];
|
||||
builder.updateSkinFace();
|
||||
mProfile = builder;
|
||||
}
|
||||
runOnUiThread(() -> {
|
||||
v.setEnabled(true);
|
||||
prb.setVisibility(View.GONE);
|
||||
playProfile(false);
|
||||
});
|
||||
}
|
||||
}).execute(edit2.getText().toString(), edit3.getText().toString());
|
||||
}
|
||||
mProfile = loginLocal();
|
||||
playProfile(false);
|
||||
}
|
||||
|
||||
private void playProfile(boolean notOnLogin) {
|
||||
|
@ -8,8 +8,6 @@ import android.util.Log;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.RefreshTokenTask;
|
||||
import net.kdt.pojavlaunch.value.MinecraftAccount;
|
||||
|
||||
public class PojavProfile {
|
||||
@ -103,8 +101,4 @@ public class PojavProfile {
|
||||
Intent intent = new Intent(ctx, PojavLauncherActivity.class); //MCLauncherActivity.class);
|
||||
ctx.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void updateTokens(final Activity ctx, final String name, RefreshListener listen) throws Exception {
|
||||
new RefreshTokenTask(ctx, listen).execute(name);
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ public final class Tools {
|
||||
versionName = versionInfo.inheritsFrom;
|
||||
}
|
||||
|
||||
String userType = "mojang";
|
||||
String userType = "msa";
|
||||
|
||||
File gameDir = new File(strGameDir);
|
||||
gameDir.mkdirs();
|
||||
|
@ -1,7 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang;
|
||||
|
||||
public interface LoginListener
|
||||
{
|
||||
public void onBeforeLogin();
|
||||
public void onLoginDone(String[] result);
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang;
|
||||
|
||||
import android.os.*;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.yggdrasil.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
|
||||
public class LoginTask extends AsyncTask<String, Void, Void>
|
||||
{
|
||||
private YggdrasilAuthenticator authenticator = new YggdrasilAuthenticator();
|
||||
//private String TAG = "MojangAuth-login";
|
||||
private LoginListener listener;
|
||||
|
||||
public LoginTask setLoginListener(LoginListener listener) {
|
||||
this.listener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
private UUID getRandomUUID() {
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
listener.onBeforeLogin();
|
||||
|
||||
super.onPreExecute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(String[] args) {
|
||||
ArrayList<String> str = new ArrayList<String>();
|
||||
str.add("ERROR");
|
||||
try{
|
||||
try{
|
||||
AuthenticateResponse response = authenticator.authenticate(args[0], args[1], getRandomUUID());
|
||||
if (response.selectedProfile == null) {
|
||||
str.add("Can't login a demo account!\n");
|
||||
} else {
|
||||
if (new File(Tools.DIR_ACCOUNT_NEW + "/" + response.selectedProfile.name + ".json").exists()) {
|
||||
str.add("This account already exist!\n");
|
||||
} else {
|
||||
str.add(response.accessToken); // Access token
|
||||
str.add(response.clientToken.toString()); // Client token
|
||||
str.add(response.selectedProfile.id); // Profile ID
|
||||
str.add(response.selectedProfile.name); // Username
|
||||
str.set(0, "NORMAL");
|
||||
}
|
||||
}
|
||||
}
|
||||
//MainActivity.updateStatus(804);
|
||||
catch(Throwable e){
|
||||
str.add(e.getMessage());
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
str.add(e.getMessage());
|
||||
}
|
||||
|
||||
listener.onLoginDone(str.toArray(new String[0]));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
// listener.onLoginDone(result);
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang;
|
||||
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import com.google.gson.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import net.kdt.pojavlaunch.authenticator.mojang.yggdrasil.*;
|
||||
import android.app.*;
|
||||
import net.kdt.pojavlaunch.value.*;
|
||||
|
||||
public class RefreshTokenTask extends AsyncTask<String, Void, Throwable> {
|
||||
private YggdrasilAuthenticator authenticator = new YggdrasilAuthenticator();
|
||||
//private Gson gson = new Gson();
|
||||
private RefreshListener listener;
|
||||
private MinecraftAccount profilePath;
|
||||
|
||||
private final WeakReference<Context> ctx;
|
||||
private ProgressDialog build;
|
||||
|
||||
public RefreshTokenTask(Context ctx, RefreshListener listener) {
|
||||
this.ctx = new WeakReference<>(ctx);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreExecute() {
|
||||
build = new ProgressDialog(ctx.get());
|
||||
build.setMessage(ctx.get().getString(R.string.global_waiting));
|
||||
build.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
build.setCancelable(false);
|
||||
build.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable doInBackground(String... args) {
|
||||
try {
|
||||
this.profilePath = MinecraftAccount.load(args[0]);
|
||||
int responseCode = 400;
|
||||
try {
|
||||
responseCode = this.authenticator.validate(profilePath.accessToken).statusCode;
|
||||
}catch(RuntimeException e) {}
|
||||
|
||||
if (responseCode == 403) {
|
||||
RefreshResponse response = this.authenticator.refresh(profilePath.accessToken, UUID.fromString(profilePath.clientToken));
|
||||
if (response == null) {
|
||||
// Refresh when offline?
|
||||
return null;
|
||||
} else if (response.selectedProfile == null) {
|
||||
throw new IllegalArgumentException("Can't refresh a demo account!");
|
||||
}
|
||||
|
||||
profilePath.clientToken = response.clientToken.toString();
|
||||
profilePath.accessToken = response.accessToken;
|
||||
profilePath.username = response.selectedProfile.name;
|
||||
profilePath.profileId = response.selectedProfile.id;
|
||||
}
|
||||
profilePath.updateSkinFace();
|
||||
profilePath.save();
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostExecute(Throwable result) {
|
||||
build.dismiss();
|
||||
if (result == null) {
|
||||
listener.onSuccess(profilePath);
|
||||
} else {
|
||||
listener.onFailed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AuthenticateRequest {
|
||||
public AgentInfo agent = new AgentInfo();
|
||||
public UUID clientToken;
|
||||
public String password;
|
||||
public String username;
|
||||
|
||||
public static class AgentInfo {
|
||||
public String name;
|
||||
public int version;
|
||||
}
|
||||
|
||||
public AuthenticateRequest(String username, String password, UUID clientToken, String clientName, int clientVersion) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.clientToken = clientToken;
|
||||
this.agent.name = clientName;
|
||||
this.agent.version = clientVersion;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AuthenticateResponse {
|
||||
public String accessToken;
|
||||
public Profile[] availableProfiles;
|
||||
public UUID clientToken;
|
||||
public Profile selectedProfile;
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class RefreshResponse {
|
||||
public String accessToken;
|
||||
public UUID clientToken;
|
||||
public Profile selectedProfile;
|
||||
}
|
||||
|
@ -90,31 +90,6 @@ public class YggdrasilAuthenticator {
|
||||
}
|
||||
}
|
||||
|
||||
public AuthenticateResponse authenticate(String username, String password, UUID clientId) throws IOException, Throwable {
|
||||
NetworkResponse obj = makeRequest("authenticate", new AuthenticateRequest(username, password, clientId, this.clientName, this.clientVersion), AuthenticateResponse.class);
|
||||
/*
|
||||
if (obj.statusCode != 200) {
|
||||
throw new RuntimeException("Invalid username or password, status code: " + obj.statusCode);
|
||||
}
|
||||
*/
|
||||
obj.throwExceptionIfNeed();
|
||||
return (AuthenticateResponse) obj.response;
|
||||
}
|
||||
|
||||
public RefreshResponse refresh(String authToken, UUID clientId) throws IOException, Throwable {
|
||||
NetworkResponse obj = makeRequest("refresh", new RefreshRequest(authToken, clientId), RefreshResponse.class);
|
||||
if (obj == null) {
|
||||
return null;
|
||||
} else {
|
||||
obj.throwExceptionIfNeed(); // "Invalid username or password, status code: " + obj.statusCode);
|
||||
return (RefreshResponse) obj.response;
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkResponse validate(String authToken) throws Throwable {
|
||||
return makeRequest("validate", new RefreshRequest(authToken, null), null);
|
||||
}
|
||||
|
||||
public NetworkResponse invalidate(String authToken, UUID clientId) throws Throwable {
|
||||
return makeRequest("invalidate", new RefreshRequest(authToken, clientId), null);
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Throwable p1)
|
||||
public void onPostExecute(Throwable p1)
|
||||
{
|
||||
mActivity.mPlayButton.setText("Play");
|
||||
mActivity.mPlayButton.setEnabled(true);
|
||||
|
@ -82,57 +82,14 @@
|
||||
app:layout_constraintTop_toTopOf="@+id/login_menu"
|
||||
app:layout_constraintVertical_bias="0.088" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/login_online_password_hint"
|
||||
app:layout_constraintBottom_toTopOf="@+id/textInputLayout"
|
||||
app:layout_constraintStart_toStartOf="@+id/textInputLayout"
|
||||
app:layout_constraintTop_toTopOf="@+id/textInputLayout" />
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/textInputLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
|
||||
app:layout_constraintBottom_toBottomOf="@+id/login_menu"
|
||||
app:layout_constraintEnd_toEndOf="@+id/login_edit_email"
|
||||
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="@+id/login_edit_email"
|
||||
app:layout_constraintTop_toBottomOf="@+id/login_edit_email"
|
||||
app:layout_constraintVertical_bias="0.08"
|
||||
app:passwordToggleEnabled="true"
|
||||
app:passwordToggleTint="@android:color/white">
|
||||
|
||||
<com.kdt.mcgui.MineEditText
|
||||
android:id="@+id/login_edit_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/login_switch_remember"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:text="@string/login_online_check_keeplogin"
|
||||
app:layout_constraintStart_toStartOf="@+id/textInputLayout"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textInputLayout" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/login_switch_offline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:text="@string/login_offline_label"
|
||||
app:layout_constraintStart_toStartOf="@+id/login_switch_remember"
|
||||
app:layout_constraintTop_toBottomOf="@+id/login_switch_remember" />
|
||||
app:layout_constraintStart_toStartOf="@+id/login_edit_email"
|
||||
app:layout_constraintTop_toBottomOf="@+id/login_edit_email" />
|
||||
|
||||
<com.kdt.mcgui.MineButton
|
||||
android:id="@+id/mineButton"
|
||||
@ -145,8 +102,8 @@
|
||||
|
||||
android:textColor="@android:color/white"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guidelineLeft"
|
||||
app:layout_constraintStart_toStartOf="@+id/login_switch_offline"
|
||||
app:layout_constraintTop_toBottomOf="@+id/login_switch_offline" />
|
||||
app:layout_constraintStart_toStartOf="@+id/login_switch_local"
|
||||
app:layout_constraintTop_toBottomOf="@+id/login_switch_local" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/launcherAccProgress"
|
||||
@ -174,7 +131,7 @@
|
||||
android:textColor="@android:color/white"
|
||||
|
||||
app:layout_constraintBottom_toBottomOf="@+id/mineButton"
|
||||
app:layout_constraintEnd_toEndOf="@+id/textInputLayout"
|
||||
app:layout_constraintEnd_toEndOf="@+id/login_edit_email"
|
||||
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
|
||||
app:layout_constraintTop_toTopOf="@+id/mineButton" />
|
||||
|
||||
@ -190,4 +147,4 @@
|
||||
app:layout_constraintStart_toStartOf="@+id/mineButton"
|
||||
app:layout_constraintTop_toBottomOf="@+id/mineButton" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
@ -10,16 +10,12 @@
|
||||
<!-- Languages list part -->
|
||||
|
||||
<!-- Login strings -->
|
||||
<string name="login_online_username_hint">Email or username</string>
|
||||
<string name="login_online_password_hint">Password</string>
|
||||
<string name="login_online_username_hint">Local username</string>
|
||||
<string name="login_online_check_keeplogin">Keep me logged in</string>
|
||||
<string name="login_online_login_label">Login</string>
|
||||
|
||||
<string name="login_offline_label">Login as offline account</string>
|
||||
|
||||
<string name="login_error_invalid_username">Invalid username. Username must be in range of 3-16 characters, should only contains A-Z, a-z, 0-9 and underscore.</string>
|
||||
<string name="login_error_exist_username">This username already exist</string>
|
||||
<string name="login_error_offline_password">Offline account can\'t include password!</string>
|
||||
|
||||
<string name="login_microsoft">Microsoft login</string>
|
||||
|
||||
@ -58,7 +54,7 @@
|
||||
|
||||
<!-- MCLauncherActivity: Account status -->
|
||||
<string name="mcl_account_connected">Connected</string>
|
||||
<string name="mcl_account_offline">Offline</string>
|
||||
<string name="mcl_account_local">Local</string>
|
||||
|
||||
<!-- MCLauncherActivity: Strings -->
|
||||
<string name="mcl_version_msg">Ready to play Minecraft %s</string>
|
||||
@ -66,6 +62,7 @@
|
||||
<string name="mcl_launch_downloading">Downloading %s</string>
|
||||
<string name="mcl_launch_downloading_progress">"Downloading %s (%.2f MB / %.2f MB)"</string>
|
||||
<string name="mcl_launch_download_assets">Preparing to download resources</string>
|
||||
<string name="mcl_launch_error_localmode">Minecraft can\'t be legally installed when logged in with a local account. Please switch to an online account to continue.</string>
|
||||
|
||||
<string name="mcl_options">Options</string>
|
||||
<string name="mcl_option_modinstall">Launch a mod installer (Forge, LabyMod, Fabric, etc...)</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user