This commit is contained in:
ayunami2000 2022-01-24 00:04:50 -05:00
parent 432521daad
commit 157b10925d
28 changed files with 3071 additions and 7 deletions

Binary file not shown.

View File

@ -0,0 +1,7 @@
package me.ratsiel.auth.abstracts;
/**
* The class Authentication token.
*/
public abstract class AuthenticationToken {
}

View File

@ -0,0 +1,23 @@
package me.ratsiel.auth.abstracts;
import me.ratsiel.json.Json;
/**
* The class Authenticator is used to log in to mojang or microsoft
*/
public abstract class Authenticator<T> {
protected final Json json = new Json();
/**
* Login string.
*
* @param email the email
* @param password the password
* @return the string
*/
public abstract T login(String email, String password);
}

View File

@ -0,0 +1,79 @@
package me.ratsiel.auth.abstracts;
/**
* The type Texture variable stores data from {@link me.ratsiel.auth.model.mojang.profile.MinecraftProfile}
*/
public abstract class TextureVariable {
private String id;
private String state;
private String url;
private String alias;
/**
* Instantiates a new Texture variable.
*/
public TextureVariable() {
}
/**
* Instantiates a new Texture variable.
*
* @param id the id
* @param state the state
* @param url the url
* @param alias the alias
*/
public TextureVariable(String id, String state, String url, String alias) {
this.id = id;
this.state = state;
this.url = url;
this.alias = alias;
}
/**
* Gets id.
*
* @return the id
*/
public String getId() {
return id;
}
/**
* Gets state.
*
* @return the state
*/
public String getState() {
return state;
}
/**
* Gets url.
*
* @return the url
*/
public String getUrl() {
return url;
}
/**
* Gets alias.
*
* @return the alias
*/
public String getAlias() {
return alias;
}
@Override
public String toString() {
return "TextureVariable{" +
"id='" + id + '\'' +
", state='" + state + '\'' +
", url='" + url + '\'' +
", alias='" + alias + '\'' +
'}';
}
}

View File

@ -0,0 +1,17 @@
package me.ratsiel.auth.abstracts.exception;
/**
* The class Authentication exception is thrown when something went wrong during authentication
*/
public class AuthenticationException extends RuntimeException {
/**
* Instantiates a new Authentication exception.
*
* @param message the message
*/
public AuthenticationException(String message) {
super(message);
}
}

View File

@ -0,0 +1,331 @@
package me.ratsiel.auth.model.microsoft;
import me.ratsiel.auth.abstracts.Authenticator;
import me.ratsiel.auth.abstracts.exception.AuthenticationException;
import me.ratsiel.json.model.JsonArray;
import me.ratsiel.json.model.JsonObject;
import me.ratsiel.json.model.JsonString;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* The class Microsoft authenticator is used to log in into microsoft account and generate mojang JWT token
*/
public class MicrosoftAuthenticator extends Authenticator<XboxToken> {
protected final String clientId = "00000000402b5328";
protected final String scopeUrl = "service::user.auth.xboxlive.com::MBI_SSL";
protected String loginUrl;
protected String loginCookie;
protected String loginPPFT;
@Override
public XboxToken login(String email, String password) {
MicrosoftToken microsoftToken = generateTokenPair(generateLoginCode(email, password));
XboxLiveToken xboxLiveToken = generateXboxTokenPair(microsoftToken);
return generateXboxTokenPair(xboxLiveToken);
}
/**
* Generate start login code from email and password
*
* @param email microsoft email
* @param password microsoft password
* @return login code
*/
private String generateLoginCode(String email, String password) {
try {
URL url = new URL("https://login.live.com/oauth20_authorize.srf?redirect_uri=https://login.live.com/oauth20_desktop.srf&scope=" + scopeUrl + "&display=touch&response_type=code&locale=en&client_id=" + clientId);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpURLConnection.getResponseCode() == 200 ? httpURLConnection.getInputStream() : httpURLConnection.getErrorStream();
loginCookie = httpURLConnection.getHeaderField("set-cookie");
String responseData = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining());
Matcher bodyMatcher = Pattern.compile("sFTTag:[ ]?'.*value=\"(.*)\"/>'").matcher(responseData);
if (bodyMatcher.find()) {
loginPPFT = bodyMatcher.group(1);
} else {
throw new AuthenticationException("Authentication error. Could not find 'LOGIN-PFTT' tag from response!");
}
bodyMatcher = Pattern.compile("urlPost:[ ]?'(.+?(?='))").matcher(responseData);
if (bodyMatcher.find()) {
loginUrl = bodyMatcher.group(1);
} else {
throw new AuthenticationException("Authentication error. Could not find 'LOGIN-URL' tag from response!");
}
if (loginCookie == null || loginPPFT == null || loginUrl == null)
throw new AuthenticationException("Authentication error. Error in authentication process!");
} catch (IOException exception) {
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
}
return sendCodeData(email, password);
}
/**
* Send code data from email and password
*
* @param email microsoft email
* @param password microsoft password
* @return login code
*/
private String sendCodeData(String email, String password) {
String authToken;
Map<String, String> requestData = new HashMap<>();
requestData.put("login", email);
requestData.put("loginfmt", email);
requestData.put("passwd", password);
requestData.put("PPFT", loginPPFT);
String postData = encodeURL(requestData);
try {
byte[] data = postData.getBytes(StandardCharsets.UTF_8);
HttpURLConnection connection = (HttpURLConnection) new URL(loginUrl).openConnection();
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
connection.setRequestProperty("Content-Length", String.valueOf(data.length));
connection.setRequestProperty("Cookie", loginCookie);
connection.setDoInput(true);
connection.setDoOutput(true);
try (OutputStream outputStream = connection.getOutputStream()) {
outputStream.write(data);
}
if (connection.getResponseCode() != 200 || connection.getURL().toString().equals(loginUrl)) {
throw new AuthenticationException("Authentication error. Username or password is not valid.");
}
Pattern pattern = Pattern.compile("[?|&]code=([\\w.-]+)");
Matcher tokenMatcher = pattern.matcher(URLDecoder.decode(connection.getURL().toString(), StandardCharsets.UTF_8.name()));
if (tokenMatcher.find()) {
authToken = tokenMatcher.group(1);
} else {
throw new AuthenticationException("Authentication error. Could not handle data from response.");
}
} catch (IOException exception) {
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
}
this.loginUrl = null;
this.loginCookie = null;
this.loginPPFT = null;
return authToken;
}
/**
* Send xbox auth request
*/
private void sendXboxRequest(HttpURLConnection httpURLConnection, JsonObject request, JsonObject properties) throws IOException {
request.add("Properties", properties);
String requestBody = request.toString();
httpURLConnection.setFixedLengthStreamingMode(requestBody.length());
httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setRequestProperty("Accept", "application/json");
httpURLConnection.connect();
try (OutputStream outputStream = httpURLConnection.getOutputStream()) {
outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII));
}
}
/**
* Generate {@link me.ratsiel.auth.model.mojang.MinecraftToken}
*
* @param authToken from {@link #generateLoginCode(String, String)}
* @return {@link me.ratsiel.auth.model.mojang.MinecraftToken}
*/
private MicrosoftToken generateTokenPair(String authToken) {
try {
Map<String, String> arguments = new HashMap<>();
arguments.put("client_id", clientId);
arguments.put("code", authToken);
arguments.put("grant_type", "authorization_code");
arguments.put("redirect_uri", "https://login.live.com/oauth20_desktop.srf");
arguments.put("scope", scopeUrl);
StringJoiner argumentBuilder = new StringJoiner("&");
for (Map.Entry<String, String> entry : arguments.entrySet()) {
argumentBuilder.add(encodeURL(entry.getKey()) + "=" + encodeURL(entry.getValue()));
}
byte[] data = argumentBuilder.toString().getBytes(StandardCharsets.UTF_8);
URL url = new URL("https://login.live.com/oauth20_token.srf");
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
httpURLConnection.setFixedLengthStreamingMode(data.length);
httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
httpURLConnection.connect();
try (OutputStream outputStream = httpURLConnection.getOutputStream()) {
outputStream.write(data);
}
JsonObject jsonObject = parseResponseData(httpURLConnection);
return new MicrosoftToken(jsonObject.get("access_token", JsonString.class).getValue(), jsonObject.get("refresh_token", JsonString.class).getValue());
} catch (IOException exception) {
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
}
}
/**
* Generate {@link XboxLiveToken} from {@link MicrosoftToken}
*
* @param microsoftToken the microsoft token
* @return the xbox live token
*/
public XboxLiveToken generateXboxTokenPair(MicrosoftToken microsoftToken) {
try {
URL url = new URL("https://user.auth.xboxlive.com/user/authenticate");
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setDoOutput(true);
JsonObject request = new JsonObject();
request.add("RelyingParty", new JsonString("http://auth.xboxlive.com"));
request.add("TokenType", new JsonString("JWT"));
JsonObject properties = new JsonObject();
properties.add("AuthMethod", new JsonString("RPS"));
properties.add("SiteName", new JsonString("user.auth.xboxlive.com"));
properties.add("RpsTicket", new JsonString(microsoftToken.getToken()));
sendXboxRequest(httpURLConnection, request, properties);
JsonObject jsonObject = parseResponseData(httpURLConnection);
String uhs = ((JsonObject) (jsonObject.get("DisplayClaims", JsonObject.class)).get("xui", JsonArray.class).get(0)).get("uhs", JsonString.class).getValue();
return new XboxLiveToken(jsonObject.get("Token", JsonString.class).getValue(), uhs);
} catch (IOException exception) {
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
}
}
/**
* Generate {@link XboxToken} from {@link XboxLiveToken}
*
* @param xboxLiveToken the xbox live token
* @return the xbox token
*/
public XboxToken generateXboxTokenPair(XboxLiveToken xboxLiveToken) {
try {
URL url = new URL("https://xsts.auth.xboxlive.com/xsts/authorize");
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
JsonObject request = new JsonObject();
request.add("RelyingParty", new JsonString("rp://api.minecraftservices.com/"));
request.add("TokenType", new JsonString("JWT"));
JsonObject properties = new JsonObject();
properties.add("SandboxId", new JsonString("RETAIL"));
JsonArray userTokens = new JsonArray();
userTokens.add(new JsonString(xboxLiveToken.getToken()));
properties.add("UserTokens", userTokens);
sendXboxRequest(httpURLConnection, request, properties);
if (httpURLConnection.getResponseCode() == 401) {
throw new AuthenticationException("No xbox account was found!");
}
JsonObject jsonObject = parseResponseData(httpURLConnection);
String uhs = ((JsonObject) (jsonObject.get("DisplayClaims", JsonObject.class)).get("xui", JsonArray.class).get(0)).get("uhs", JsonString.class).getValue();
return new XboxToken(jsonObject.get("Token", JsonString.class).getValue(), uhs);
} catch (IOException exception) {
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
}
}
/**
* Parse response data to {@link JsonObject}
*
* @param httpURLConnection the http url connection
* @return the json object
* @throws IOException the io exception
*/
public JsonObject parseResponseData(HttpURLConnection httpURLConnection) throws IOException {
BufferedReader bufferedReader;
if (httpURLConnection.getResponseCode() != 200) {
bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream()));
} else {
bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
}
String lines = bufferedReader.lines().collect(Collectors.joining());
JsonObject jsonObject = json.fromJsonString(lines, JsonObject.class);
if (jsonObject.has("error")) {
throw new AuthenticationException(jsonObject.get("error") + ": " + jsonObject.get("error_description"));
}
return jsonObject;
}
/**
* Encode url string.
*
* @param url the url
* @return the string
*/
private String encodeURL(String url) {
try {
return URLEncoder.encode(url, "UTF-8");
} catch (UnsupportedEncodingException exception) {
throw new UnsupportedOperationException(exception);
}
}
/**
* Encode url string.
*
* @param map the map
* @return the string
*/
private String encodeURL(Map<String, String> map) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : map.entrySet()) {
if (sb.length() > 0) {
sb.append("&");
}
sb.append(String.format("%s=%s",
encodeURL(entry.getKey().toString()),
encodeURL(entry.getValue().toString())
));
}
return sb.toString();
}
}

View File

@ -0,0 +1,48 @@
package me.ratsiel.auth.model.microsoft;
import me.ratsiel.auth.abstracts.AuthenticationToken;
/**
* The class Microsoft token stores token and refreshToken
*/
public class MicrosoftToken extends AuthenticationToken {
protected String token;
protected String refreshToken;
/**
* Instantiates a new Microsoft token.
*/
public MicrosoftToken() {
}
/**
* Instantiates a new Microsoft token.
*
* @param token the token
* @param refreshToken the refresh token
*/
public MicrosoftToken(String token, String refreshToken) {
this.token = token;
this.refreshToken = refreshToken;
}
/**
* Gets token.
*
* @return the token
*/
public String getToken() {
return token;
}
/**
* Gets refresh token.
*
* @return the refresh token
*/
public String getRefreshToken() {
return refreshToken;
}
}

View File

@ -0,0 +1,49 @@
package me.ratsiel.auth.model.microsoft;
import me.ratsiel.auth.abstracts.AuthenticationToken;
/**
* The class Xbox live token stores token and uhs
*/
public class XboxLiveToken extends AuthenticationToken {
protected String token;
protected String uhs;
/**
* Instantiates a new Xbox live token.
*/
public XboxLiveToken() {
}
/**
* Instantiates a new Xbox live token.
*
* @param token the token
* @param uhs the uhs
*/
public XboxLiveToken(String token, String uhs) {
this.token = token;
this.uhs = uhs;
}
/**
* Gets token.
*
* @return the token
*/
public String getToken() {
return token;
}
/**
* Gets uhs.
*
* @return the uhs
*/
public String getUhs() {
return uhs;
}
}

View File

@ -0,0 +1,24 @@
package me.ratsiel.auth.model.microsoft;
/**
* The class xbox token has the same functions as {@link XboxLiveToken}
*/
public class XboxToken extends XboxLiveToken {
/**
* Instantiates a new Xbox token.
*/
public XboxToken() {
}
/**
* Instantiates a new Xbox token.
*
* @param token the token
* @param uhs the uhs
*/
public XboxToken(String token, String uhs) {
super(token, uhs);
}
}

View File

@ -0,0 +1,188 @@
package me.ratsiel.auth.model.mojang;
import me.ratsiel.auth.abstracts.Authenticator;
import me.ratsiel.auth.abstracts.exception.AuthenticationException;
import me.ratsiel.auth.model.microsoft.MicrosoftAuthenticator;
import me.ratsiel.auth.model.microsoft.XboxToken;
import me.ratsiel.auth.model.mojang.profile.MinecraftCape;
import me.ratsiel.auth.model.mojang.profile.MinecraftProfile;
import me.ratsiel.auth.model.mojang.profile.MinecraftSkin;
import me.ratsiel.json.Json;
import me.ratsiel.json.model.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* The class Minecraft authenticator is used to log in with normal minecraft details or with microsoft
*/
public class MinecraftAuthenticator extends Authenticator<MinecraftToken> {
/**
* The Microsoft authenticator is used for {@link #loginWithXbox(String, String)}
*/
protected final MicrosoftAuthenticator microsoftAuthenticator = new MicrosoftAuthenticator();
@Override
public MinecraftToken login(String email, String password) {
try {
URL url = new URL("https://authserver.mojang.com/authenticate");
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
JsonObject request = new JsonObject();
JsonObject agent = new JsonObject();
agent.add(new JsonString("name", "Minecraft"));
agent.add(new JsonNumber("version", "1"));
request.add("agent", agent);
request.add(new JsonString("username", email));
request.add(new JsonString("password", password));
request.add(new JsonBoolean("requestUser", false));
String requestBody = request.toString();
httpURLConnection.setFixedLengthStreamingMode(requestBody.length());
httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setRequestProperty("Host", "authserver.mojang.com");
httpURLConnection.connect();
try (OutputStream outputStream = httpURLConnection.getOutputStream()) {
outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII));
}
JsonObject jsonObject = parseResponseData(httpURLConnection);
return new MinecraftToken(jsonObject.get("accessToken", JsonString.class).getValue(), ((JsonObject)jsonObject.get("selectedProfile")).get("name", JsonString.class).getValue());
} catch (IOException exception) {
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
}
}
/**
* Login with microsoft email and microsoft password
*
* @param email the email
* @param password the password
* @return the minecraft token
*/
public MinecraftToken loginWithXbox(String email, String password) {
XboxToken xboxToken = microsoftAuthenticator.login(email, password);
try {
URL url = new URL("https://api.minecraftservices.com/authentication/login_with_xbox");
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
JsonObject request = new JsonObject();
request.add("identityToken", new JsonString("XBL3.0 x=" + xboxToken.getUhs() + ";" + xboxToken.getToken()));
String requestBody = request.toString();
httpURLConnection.setFixedLengthStreamingMode(requestBody.length());
httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setRequestProperty("Host", "api.minecraftservices.com");
httpURLConnection.connect();
try (OutputStream outputStream = httpURLConnection.getOutputStream()) {
outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII));
}
JsonObject jsonObject = microsoftAuthenticator.parseResponseData(httpURLConnection);
return new MinecraftToken(jsonObject.get("access_token", JsonString.class).getValue(), jsonObject.get("username", JsonString.class).getValue());
} catch (IOException exception) {
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
}
}
/**
* Check ownership from {@link MinecraftToken} and generate {@link MinecraftProfile}
*
* @param minecraftToken the minecraft token
* @return the minecraft profile
*/
public MinecraftProfile checkOwnership(MinecraftToken minecraftToken) {
try {
URL url = new URL("https://api.minecraftservices.com/minecraft/profile");
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setRequestProperty("Authorization", "Bearer " + minecraftToken.getAccessToken());
httpURLConnection.setRequestProperty("Host", "api.minecraftservices.com");
httpURLConnection.connect();
JsonObject jsonObject = parseResponseData(httpURLConnection);
UUID uuid = generateUUID(jsonObject.get("id", JsonString.class).getValue());
String name = jsonObject.get("name", JsonString.class).getValue();
List<MinecraftSkin> minecraftSkins = json.fromJson(jsonObject.get("skins", JsonArray.class), List.class, MinecraftSkin.class);
List<MinecraftCape> minecraftCapes = json.fromJson(jsonObject.get("capes", JsonArray.class), List.class, MinecraftCape.class);
return new MinecraftProfile(uuid, name, minecraftSkins, minecraftCapes);
} catch (IOException exception) {
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
}
}
/**
* Parse response data to {@link JsonObject}
*
* @param httpURLConnection the http url connection
* @return the json object
* @throws IOException the io exception
*/
public JsonObject parseResponseData(HttpURLConnection httpURLConnection) throws IOException {
BufferedReader bufferedReader;
if (httpURLConnection.getResponseCode() != 200) {
bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream()));
} else {
bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
}
String lines = bufferedReader.lines().collect(Collectors.joining());
JsonObject jsonObject = json.fromJsonString(lines, JsonObject.class);
if (jsonObject.has("error")) {
throw new AuthenticationException(String.format("Could not find profile!. Error: '%s'", jsonObject.get("errorMessage", JsonString.class).getValue()));
}
return jsonObject;
}
/**
* Generate uuid from trimmedUUID
*
* @param trimmedUUID the trimmed uuid
* @return the uuid
* @throws IllegalArgumentException the illegal argument exception
*/
public UUID generateUUID(String trimmedUUID) throws IllegalArgumentException {
if (trimmedUUID == null) throw new IllegalArgumentException();
StringBuilder builder = new StringBuilder(trimmedUUID.trim());
try {
builder.insert(20, "-");
builder.insert(16, "-");
builder.insert(12, "-");
builder.insert(8, "-");
return UUID.fromString(builder.toString());
} catch (StringIndexOutOfBoundsException e) {
return null;
}
}
}

View File

@ -0,0 +1,53 @@
package me.ratsiel.auth.model.mojang;
/**
* The class Minecraft token stores minecraft accessToken and username
*/
public class MinecraftToken {
private String accessToken;
private String username;
/**
* Instantiates a new Minecraft token.
*/
public MinecraftToken() {
}
/**
* Instantiates a new Minecraft token.
*
* @param accessToken the access token
* @param username the username
*/
public MinecraftToken(String accessToken, String username) {
this.accessToken = accessToken;
this.username = username;
}
/**
* Gets access token.
*
* @return the access token
*/
public String getAccessToken() {
return accessToken;
}
/**
* Gets username.
*
* @return the username
*/
public String getUsername() {
return username;
}
@Override
public String toString() {
return "MinecraftToken{" +
"accessToken='" + accessToken + '\'' +
", username='" + username + '\'' +
'}';
}
}

View File

@ -0,0 +1,31 @@
package me.ratsiel.auth.model.mojang.profile;
import me.ratsiel.auth.abstracts.TextureVariable;
/**
* The class Minecraft cape stores cape data from {@link me.ratsiel.auth.model.mojang.profile.MinecraftProfile}
*/
public class MinecraftCape extends TextureVariable {
/**
* Instantiates a new Minecraft cape.
*/
public MinecraftCape() {
}
/**
* Instantiates a new Minecraft cape.
*
* @param id the id
* @param state the state
* @param url the url
* @param alias the alias
*/
public MinecraftCape(String id, String state, String url, String alias) {
super(id, state, url, alias);
}
}

View File

@ -0,0 +1,82 @@
package me.ratsiel.auth.model.mojang.profile;
import java.util.List;
import java.util.UUID;
/**
* The class Minecraft profile stores uuid, username, skins and capes
*/
public class MinecraftProfile {
private UUID uuid;
private String username;
private List<MinecraftSkin> skins;
private List<MinecraftCape> capes;
/**
* Instantiates a new Minecraft profile.
*/
public MinecraftProfile() {
}
/**
* Instantiates a new Minecraft profile.
*
* @param uuid the uuid
* @param username the username
* @param skins the skins
* @param capes the capes
*/
public MinecraftProfile(UUID uuid, String username, List<MinecraftSkin> skins, List<MinecraftCape> capes) {
this.uuid = uuid;
this.username = username;
this.skins = skins;
this.capes = capes;
}
/**
* Gets uuid.
*
* @return the uuid
*/
public UUID getUuid() {
return uuid;
}
/**
* Gets username.
*
* @return the username
*/
public String getUsername() {
return username;
}
/**
* Gets skins.
*
* @return the skins
*/
public List<MinecraftSkin> getSkins() {
return skins;
}
/**
* Gets capes.
*
* @return the capes
*/
public List<MinecraftCape> getCapes() {
return capes;
}
@Override
public String toString() {
return "MinecraftProfile{" +
"uuid=" + uuid +
", username='" + username + '\'' +
", skins=" + skins +
", capes=" + capes +
'}';
}
}

View File

@ -0,0 +1,61 @@
package me.ratsiel.auth.model.mojang.profile;
import me.ratsiel.auth.abstracts.TextureVariable;
/**
* The class Minecraft skin stores cape data from {@link me.ratsiel.auth.model.mojang.profile.MinecraftProfile}
*/
public class MinecraftSkin extends TextureVariable {
private String variant;
/**
* Instantiates a new Minecraft skin.
*/
public MinecraftSkin() {
}
/**
* Instantiates a new Minecraft skin.
*
* @param variant the variant
*/
public MinecraftSkin(String variant) {
this.variant = variant;
}
/**
* Instantiates a new Minecraft skin.
*
* @param id the id
* @param state the state
* @param url the url
* @param alias the alias
* @param variant the variant
*/
public MinecraftSkin(String id, String state, String url, String alias, String variant) {
super(id, state, url, alias);
this.variant = variant;
}
/**
* Gets variant.
*
* @return the variant
*/
public String getVariant() {
return variant;
}
@Override
public String toString() {
return "MinecraftSkin{" +
"id='" + getId() + '\'' +
", state='" + getState() + '\'' +
", url='" + getUrl() + '\'' +
", alias='" + getAlias() + '\'' +
"variant='" + variant + '\'' +
'}';
}
}

View File

@ -0,0 +1,183 @@
package me.ratsiel.json;
import me.ratsiel.json.abstracts.JsonHandler;
import me.ratsiel.json.abstracts.JsonValue;
import me.ratsiel.json.model.JsonString;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
/**
* The type Json.
*/
public class Json {
private final JsonGenerator jsonGenerator = new JsonGenerator();
private final JsonParser jsonParser = new JsonParser();
public Json() {
registerHandler(UUID.class, new JsonHandler<UUID>() {
@Override
public UUID serialize(JsonValue jsonValue) {
JsonString jsonString = (JsonString) jsonValue;
return UUID.fromString(jsonString.getValue());
}
@Override
public JsonValue deserialize(UUID value) {
return new JsonString(value.toString());
}
});
}
/**
* Parse {@link String} to {@link JsonValue}.
*
* @param json the json used to parse
* @return the json value is the raw return type
*/
public JsonValue fromJsonString(String json) {
return jsonParser.parse(json);
}
/**
* Parse {@link String} to {@link JsonValue} and cast it to {@link Class<T>}
*
* @param <T> the type parameter determines the type of {@link JsonValue}
* @param json the input stream is used to parse
* @param clazz the clazz is used to cast {@link T}
* @return the value {@link T}
*/
public <T extends JsonValue> T fromJsonString(String json, Class<T> clazz) {
return jsonParser.parse(json, clazz);
}
/**
* Parse {@link File} to {@link JsonValue} and cast it to {@link Class<T>}
*
* @param <T> the type parameter determines the type of {@link JsonValue}
* @param file the file is used to parse
* @param clazz the clazz is used to cast {@link T}
* @return the value {@link T}
* @throws FileNotFoundException the file not found exception
*/
public <T extends JsonValue> T fromFile(File file, Class<T> clazz) throws FileNotFoundException {
return clazz.cast(jsonParser.parse(file));
}
/**
* Parse {@link File} to {@link JsonValue}.
*
* @param file the file used to parse
* @return the json value raw return type
* @throws FileNotFoundException the file not found exception
*/
public JsonValue fromFile(File file) throws FileNotFoundException {
return jsonParser.parse(new FileInputStream(file));
}
/**
* Parse {@link InputStream} to {@link JsonValue} and cast it to {@link Class<T>}
*
* @param <T> the type parameter determines the type of {@link JsonValue}
* @param inputStream the input stream is used to parse
* @param clazz the clazz is used to cast {@link T}
* @return the value {@link T}
*/
public <T extends JsonValue> T parse(InputStream inputStream, Class<T> clazz) {
return jsonParser.parse(inputStream, clazz);
}
/**
* Parse json value with {@link InputStream}
*
* @param inputStream the input stream is used to parse
* @return the json value is the raw return type
*/
public JsonValue parse(InputStream inputStream) {
return jsonParser.parse(inputStream);
}
/**
* To json value.
* Parse object of type {@link T} to {@link JsonValue}
*
* @param <T> the type parameter used to determine value
* @param value the value used to parse
* @return the json value returns raw type of {@link JsonValue}
*/
public <T> JsonValue toJson(T value) {
return jsonGenerator.toJson(value);
}
/**
* From json to list.
* Convert {@link JsonValue} to {@link T} and cast with {@link Class<K>}
*
* @param <T> the type parameter determines object type
* @param <K> the type parameter is the class that is used t ocast
* @param jsonValue the json value is used to convert
* @param listClazz the list clazz is used to cast {@link T}
* @param clazz the clazz is used to determine object in {@link List}
* @return T is a list with cast {@link Class<T>}
*/
public <T extends List<K>, K> T fromJson(JsonValue jsonValue, Class<T> listClazz, Class<K> clazz) {
return jsonGenerator.fromJson(jsonValue, listClazz, clazz);
}
/**
* From json with cast.
* Convert {@link JsonValue} to {@link T}
*
* @param <T> the type parameter determines type of return object
* @param jsonValue the json value is used to convert to {@link T}
* @param clazz the clazz is used to cast {@link T}
* @return {@link T} cast with {@link Class<T>}
*/
public <T> T fromJsonCast(JsonValue jsonValue, Class<T> clazz) {
return jsonGenerator.fromJsonCast(jsonValue, clazz);
}
/**
* From json.
* Convert {@link JsonValue} to raw object
*
* @param <T> the type parameter determines type of return object
* @param jsonValue the json value is used to convert to {@link Object}
* @param clazz the clazz is used create object
* @return the object
*/
public <T> Object fromJson(JsonValue jsonValue, Class<T> clazz) {
return jsonGenerator.fromJson(jsonValue, clazz);
}
/**
* Register handler.
* Register a {@link JsonHandler<?>} by {@link Class<?>}
*
* @param clazz the clazz used to put {@link Class<?>} and {@link JsonHandler<?>} in {@link #jsonGenerator}
* @param jsonHandler the json handler is used to insert
*/
public void registerHandler(Class<?> clazz, JsonHandler<?> jsonHandler) {
jsonGenerator.registerHandler(clazz, jsonHandler);
}
/**
* Unregister handler.
* Unregister a {@link JsonHandler} by {@link Class<?>}
*
* @param clazz the clazz used to remove {@link JsonHandler} from {@link #jsonGenerator}
*/
public void unregisterHandler(Class<?> clazz) {
jsonGenerator.unregisterHandler(clazz);
}
}

View File

@ -0,0 +1,312 @@
package me.ratsiel.json;
import me.ratsiel.json.abstracts.JsonHandler;
import me.ratsiel.json.abstracts.JsonValue;
import me.ratsiel.json.model.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The class Json generator is used to parse json to a class or object to json.
*/
public class JsonGenerator {
/**
* The Handlers is {@link Map} with key {@link Class<?>} and {@link JsonHandler<?>}
*/
protected final HashMap<Class<?>, JsonHandler<?>> handlers = new HashMap<>();
/**
* To json value.
* Parse object of type {@link T} to {@link JsonValue}
*
* @param <T> the type parameter used to determine value
* @param value the value used to parse
* @return the json value returns raw type of {@link JsonValue}
*/
public <T> JsonValue toJson(T value) {
JsonValue jsonValue;
if (value == null) {
jsonValue = new JsonNull();
return jsonValue;
}
JsonHandler jsonHandler = getHandler(value.getClass());
if (jsonHandler != null) {
return jsonHandler.deserialize(value);
}
Class<?> clazz = value.getClass();
if (String.class.isAssignableFrom(clazz)) {
jsonValue = new JsonString();
((JsonString) jsonValue).setValue((String) value);
return jsonValue;
} else if (Enum.class.isAssignableFrom(clazz)) {
jsonValue = new JsonString();
((JsonString) jsonValue).setValue(((Enum) value).name());
return jsonValue;
} else if (Number.class.isAssignableFrom(clazz)) {
jsonValue = new JsonNumber();
((JsonNumber) jsonValue).setValue(value.toString());
return jsonValue;
} else if (Boolean.class.isAssignableFrom(clazz)) {
jsonValue = new JsonBoolean();
((JsonBoolean) jsonValue).setValue((Boolean) value);
return jsonValue;
} else if (List.class.isAssignableFrom(clazz)) {
JsonArray jsonArray = new JsonArray();
List<?> list = (List<?>) value;
for (Object listValue : list) {
jsonArray.add(toJson(listValue));
}
return jsonArray;
} else if (Map.class.isAssignableFrom(clazz)) {
JsonObject jsonObject = new JsonObject();
Map<?, ?> map = (Map<?, ?>) value;
for (Map.Entry<?, ?> entry : map.entrySet()) {
Object key = entry.getKey();
Object mapValue = entry.getValue();
if (key == null) {
jsonObject.add("null", toJson(mapValue));
continue;
}
Class<?> keyClazz = key.getClass();
if (String.class.isAssignableFrom(keyClazz)
|| Number.class.isAssignableFrom(keyClazz)
|| Boolean.class.isAssignableFrom(keyClazz)) {
jsonObject.add(String.valueOf(key), toJson(mapValue));
} else if (Enum.class.isAssignableFrom(keyClazz)) {
jsonObject.add(((Enum) key).name(), toJson(mapValue));
}
}
return jsonObject;
} else {
JsonObject jsonObject = new JsonObject();
if (hasSuperclass(clazz)) {
for (Field declaredField : clazz.getSuperclass().getDeclaredFields()) {
populateFields(value, jsonObject, declaredField);
}
}
for (Field declaredField : clazz.getDeclaredFields()) {
populateFields(value, jsonObject, declaredField);
}
jsonValue = jsonObject;
}
return jsonValue;
}
private <T> void populateFields(T value, JsonObject jsonObject, Field declaredField) {
if(declaredField.getModifiers() == Modifier.STATIC) return;
declaredField.setAccessible(true);
try {
JsonValue transformedValue = toJson(declaredField.get(value));
transformedValue.setKey(declaredField.getName());
jsonObject.add(transformedValue);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* From json to list.
* Convert {@link JsonValue} to {@link T} and cast with {@link Class<K>}
*
* @param <T> the type parameter determines object type
* @param <K> the type parameter is the class that is used t ocast
* @param jsonValue the json value is used to convert
* @param listClazz the list clazz is used to cast {@link T}
* @param clazz the clazz is used to determine object in {@link List}
* @return T is a list with cast {@link Class<T>}
*/
public <T extends List<K>, K> T fromJson(JsonValue jsonValue, Class<T> listClazz, Class<K> clazz) {
return listClazz.cast(fromJson(null, jsonValue, clazz));
}
/**
* From json with cast.
* Convert {@link JsonValue} to {@link T}
*
* @param <T> the type parameter determines type of return object
* @param jsonValue the json value is used to convert to {@link T}
* @param clazz the clazz is used to cast {@link T}
* @return {@link T} cast with {@link Class<T>}
*/
public <T> T fromJsonCast(JsonValue jsonValue, Class<T> clazz) {
return clazz.cast(fromJson(null, jsonValue, clazz));
}
/**
* From json.
* Convert {@link JsonValue} to raw object
*
* @param <T> the type parameter determines type of return object
* @param jsonValue the json value is used to convert to {@link Object}
* @param clazz the clazz is used create object
* @return the object
*/
public <T> Object fromJson(JsonValue jsonValue, Class<T> clazz) {
return fromJson(null, jsonValue, clazz);
}
/**
* From json.
* Convert {@link JsonValue} to raw object
*
* @param <T> the type parameter determines type of return object
* @param key the key is used to get a value out of {@link JsonObject}
* @param jsonValue the json value is used to convert to {@link Object}
* @param clazz the clazz is used create object
* @return the object
*/
public <T> Object fromJson(String key, JsonValue jsonValue, Class<T> clazz) {
JsonHandler jsonHandler = getHandler(clazz);
if (jsonValue instanceof JsonString) {
if (jsonHandler != null) {
return jsonHandler.serialize(jsonValue);
}
return clazz.cast(((JsonString) jsonValue).getValue());
} else if (jsonValue instanceof JsonNumber) {
if (jsonHandler != null) {
return jsonHandler.serialize(jsonValue);
}
return ((JsonNumber) jsonValue).getNumber(clazz);
} else if (jsonValue instanceof JsonBoolean) {
if (jsonHandler != null) {
return jsonHandler.serialize(jsonValue);
}
return clazz.cast(((JsonBoolean) jsonValue).isValue());
} else if (jsonValue instanceof JsonNull) {
if (jsonHandler != null) {
return jsonHandler.serialize(jsonValue);
}
return null;
} else if (jsonValue instanceof JsonObject) {
if (key != null) {
return fromJson(((JsonObject) jsonValue).get(key), clazz);
} else {
try {
T object = clazz.newInstance();
if (jsonHandler != null) {
return jsonHandler.serialize(jsonValue);
}
Class<?> objectClazz = object.getClass();
if (hasSuperclass(objectClazz)) {
for (Field declaredField : objectClazz.getSuperclass().getDeclaredFields()) {
declaredField.setAccessible(true);
declaredField.set(object, fromJson(declaredField.getName(), jsonValue, declaredField.getType()));
}
}
for (Field declaredField : objectClazz.getDeclaredFields()) {
declaredField.setAccessible(true);
declaredField.set(object, fromJson(declaredField.getName(), jsonValue, declaredField.getType()));
}
return object;
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
} else if (jsonValue instanceof JsonArray) {
List list = new ArrayList();
((JsonArray) jsonValue).loop((integer, listValue) -> {
list.add(fromJson(listValue, clazz));
});
return list;
}
return null;
}
/**
* Has superclass boolean.
* Checks if given class has a superclass
*
* @param <T> the type parameter determines type of class used in class
* @param clazz the clazz is used to check
* @return the boolean true or false
*/
public <T> boolean hasSuperclass(Class<T> clazz) {
return clazz.getSuperclass() != null;
}
/**
* Register handler.
* Register a {@link JsonHandler<?>} by {@link Class<?>}
*
* @param clazz the clazz used to put {@link Class<?>} and {@link JsonHandler<?>} in {@link #handlers}
* @param jsonHandler the json handler is used to insert
*/
public void registerHandler(Class<?> clazz, JsonHandler<?> jsonHandler) {
if (!isRegistered(clazz)) {
handlers.put(clazz, jsonHandler);
}
}
/**
* Unregister handler.
* Unregister a {@link JsonHandler} by {@link Class<?>}
*
* @param clazz the clazz used to remove {@link JsonHandler} from {@link #handlers}
*/
public void unregisterHandler(Class<?> clazz) {
if (isRegistered(clazz)) {
handlers.remove(clazz);
}
}
/**
* Gets handler from {@link #handlers}.
*
* @param clazz the clazz used to get {@link JsonHandler<?>} from {@link #handlers}
* @return the handler null or {@link JsonHandler<?>}
*/
public JsonHandler<?> getHandler(Class<?> clazz) {
if (!isRegistered(clazz)) return null;
return handlers.get(clazz);
}
/**
* Is registered boolean.
* Check if {@link JsonHandler<?>} is registered in {@link #handlers}
*
* @param clazz the clazz used to get {@link JsonHandler<?>}
* @return the boolean true or false
*/
public boolean isRegistered(Class<?> clazz) {
return handlers.containsKey(clazz);
}
}

View File

@ -0,0 +1,531 @@
package me.ratsiel.json;
import me.ratsiel.json.abstracts.JsonValue;
import me.ratsiel.json.model.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
* The class Json parser is used to parse a {@link String} or a {@link File} to {@link JsonValue}
*/
public class JsonParser {
private char[] jsonBuffer;
private int jsonBufferPosition = 0;
/**
* Parse {@link InputStream} to {@link JsonValue} and cast it to {@link Class<T>}
*
* @param <T> the type parameter determines the type of {@link JsonValue}
* @param inputStream the input stream is used to parse
* @param clazz the clazz is used to cast {@link T}
* @return the value {@link T}
*/
public <T extends JsonValue> T parse(InputStream inputStream, Class<T> clazz) {
return clazz.cast(parse(inputStream));
}
/**
* Parse json value with {@link InputStream}
*
* @param inputStream the input stream is used to parse
* @return the json value is the raw return type
*/
public JsonValue parse(InputStream inputStream) {
try {
prepareParser(inputStream);
} catch (IOException exception) {
exception.printStackTrace();
}
skipWhiteSpace();
switch (peekChar()) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case 'E':
case 'e':
case '+':
case '-': {
return parseJsonNumber();
}
case 'f':
case 't': {
return parseJsonBoolean();
}
case 'n': {
return parseJsonNull();
}
case '"': {
return parseJsonString();
}
case '{': {
JsonObject jsonObject = parseJsonObject();
jsonBuffer = null;
jsonBufferPosition = 0;
return jsonObject;
}
case '[': {
JsonArray jsonArray = parseJsonArray();
jsonBuffer = null;
jsonBufferPosition = 0;
return jsonArray;
}
default: {
throw new RuntimeException("Could not parse file to Json!");
}
}
}
/**
* Parse {@link String} to {@link JsonValue} and cast it to {@link Class<T>}
*
* @param <T> the type parameter determines the type of {@link JsonValue}
* @param json the input stream is used to parse
* @param clazz the clazz is used to cast {@link T}
* @return the value {@link T}
*/
public <T extends JsonValue> T parse(String json, Class<T> clazz) {
return clazz.cast(parse(json));
}
/**
* Parse {@link String} to {@link JsonValue}.
*
* @param json the json used to parse
* @return the json value is the raw return type
*/
public JsonValue parse(String json) {
return parse(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)));
}
/**
* Parse {@link File} to {@link JsonValue} and cast it to {@link Class<T>}
*
* @param <T> the type parameter determines the type of {@link JsonValue}
* @param file the file is used to parse
* @param clazz the clazz is used to cast {@link T}
* @return the value {@link T}
* @throws FileNotFoundException the file not found exception
*/
public <T extends JsonValue> T parse(File file, Class<T> clazz) throws FileNotFoundException {
return clazz.cast(parse(file));
}
/**
* Parse {@link File} to {@link JsonValue}.
*
* @param file the file used to parse
* @return the json value raw return type
* @throws FileNotFoundException the file not found exception
*/
public JsonValue parse(File file) throws FileNotFoundException {
return parse(new FileInputStream(file));
}
/**
* Prepare parser to parse given input to {@link JsonValue}.
*
* @param inputStream the input stream is used to parse
* @throws IOException the io exception
*/
public void prepareParser(InputStream inputStream) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
jsonBuffer = stringBuilder.toString().toCharArray();
bufferedReader.close();
}
/**
* Parse char from {@link #jsonBuffer} and increase {@link #jsonBufferPosition}
*
* @return the char
*/
public char parseChar() {
try {
return jsonBuffer[jsonBufferPosition++];
} catch (IndexOutOfBoundsException exception) {
return (char) -1;
}
}
/**
* Peek char with {@link #parseChar()} and revoke {@link #jsonBufferPosition}
*
* @return the char
*/
public char peekChar() {
char currentChar = parseChar();
jsonBufferPosition--;
return currentChar;
}
/**
* Skip white space.
*/
public void skipWhiteSpace() {
while (isWhiteSpace()) {
parseChar();
}
}
/**
* Parse json object json object.
* Iterates through chars and construct json object.
*
* @return the json object
*/
public JsonObject parseJsonObject() {
JsonObject jsonObject = new JsonObject();
skipWhiteSpace();
// Skip '{'
parseChar();
char currentChar = peekChar();
while (currentChar != '}') {
skipWhiteSpace();
// Check the next char and handle it!
switch (peekChar()) {
case '"': {
String key = parseJsonString().getValue();
skipWhiteSpace();
// Skip ':'
currentChar = parseChar();
skipWhiteSpace();
switch (peekChar()) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case 'E':
case 'e':
case '+':
case '-': {
JsonNumber jsonNumber = parseJsonNumber();
jsonNumber.setKey(key);
jsonObject.add(jsonNumber);
break;
}
case 'f':
case 't': {
JsonBoolean jsonBoolean = parseJsonBoolean();
jsonBoolean.setKey(key);
jsonObject.add(jsonBoolean);
break;
}
case 'n': {
JsonNull jsonNull = parseJsonNull();
jsonNull.setKey(key);
jsonObject.add(jsonNull);
break;
}
case '"': {
JsonString jsonString = parseJsonString();
jsonString.setKey(key);
jsonObject.add(jsonString);
break;
}
case '{': {
JsonObject object = parseJsonObject();
object.setKey(key);
jsonObject.add(object);
break;
}
case '[': {
JsonArray jsonArray = parseJsonArray();
jsonArray.setKey(key);
jsonObject.add(jsonArray);
break;
}
}
break;
}
case '}':
case ',': {
currentChar = parseChar();
break;
}
default: {
throw new RuntimeException(String.format("Could not parse JsonObject stuck at Index: %s as Char: %s", jsonBufferPosition, jsonBuffer[jsonBufferPosition]));
}
}
}
return jsonObject;
}
/**
* Parse json array json array.
* Iterates through chars and construct json array.
*
* @return the json array
*/
public JsonArray parseJsonArray() {
JsonArray jsonArray = new JsonArray();
skipWhiteSpace();
// Skip '['
parseChar();
char currentChar = peekChar();
while (currentChar != ']') {
skipWhiteSpace();
// Check the next char and handle it!
switch (peekChar()) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case 'E':
case 'e':
case '+':
case '-': {
jsonArray.add(parseJsonNumber());
break;
}
case '"': {
jsonArray.add(parseJsonString());
break;
}
case 'f':
case 't': {
jsonArray.add(parseJsonBoolean());
break;
}
case 'n': {
jsonArray.add(parseJsonNull());
break;
}
case '{': {
jsonArray.add(parseJsonObject());
break;
}
case '[': {
jsonArray.add(parseJsonArray());
break;
}
case ']':
case ',': {
currentChar = parseChar();
break;
}
default: {
throw new RuntimeException(String.format("Could not parse JsonArray stuck at Index: %s as Char: %s", jsonBufferPosition, jsonBuffer[jsonBufferPosition]));
}
}
}
return jsonArray;
}
/**
* Parse json string.
* Iterates through chars and construct json string.
*
* @return the json string
*/
public JsonString parseJsonString() {
JsonString jsonString = new JsonString();
StringBuilder stringBuilder = new StringBuilder();
skipWhiteSpace();
// Take the first '"'
parseChar();
char currentChar = parseChar();
while (currentChar != '"') {
// Check if in a string is an escape char
if (currentChar == '\\') {
stringBuilder.append(currentChar);
currentChar = parseChar();
}
stringBuilder.append(currentChar);
currentChar = parseChar();
}
skipWhiteSpace();
jsonString.setValue(stringBuilder.toString());
return jsonString;
}
/**
* Parse json null.
* Iterates through chars and check if json null is given.
*
* @return the json null
*/
public JsonNull parseJsonNull() {
char currentChar = parseChar();
if (currentChar == 'n' && isNextChar('u', 0) && isNextChar('l', 1) && isNextChar('l', 2)) {
for (int i = 0; i < 3; i++) {
jsonBufferPosition++;
}
return new JsonNull();
}
return null;
}
/**
* Parse json boolean.
* Iterates through chars and check if json boolean is given.
*
* @return the json boolean
*/
public JsonBoolean parseJsonBoolean() {
char currentChar = parseChar();
JsonBoolean jsonBoolean = null;
if (currentChar == 't' && isNextChar('r', 0) && isNextChar('u', 1) && isNextChar('e', 2)) {
for (int i = 0; i < 3; i++) {
jsonBufferPosition++;
}
jsonBoolean = new JsonBoolean();
jsonBoolean.setValue(true);
} else if (currentChar == 'f' && isNextChar('a', 0) && isNextChar('l', 1) && isNextChar('s', 2) && isNextChar('e', 3)) {
for (int i = 0; i < 4; i++) {
jsonBufferPosition++;
}
jsonBoolean = new JsonBoolean();
jsonBoolean.setValue(false);
}
return jsonBoolean;
}
/**
* Parse json number.
* Iterates through chars and check if json number is given.
*
* @return the json number
*/
public JsonNumber parseJsonNumber() {
StringBuilder stringBuilder = new StringBuilder();
char currentChar = parseChar();
while (isNumber(currentChar)) {
stringBuilder.append(currentChar);
currentChar = parseChar();
}
jsonBufferPosition--;
JsonNumber jsonNumber = new JsonNumber();
jsonNumber.setValue(stringBuilder.toString());
return jsonNumber;
}
/**
* Is white space boolean.
* Check if current char in {@link #jsonBuffer} is a whitespace
*
* @return the boolean true or false
*/
public boolean isWhiteSpace() {
char currentChar = jsonBuffer[jsonBufferPosition];
return currentChar == ' ' || currentChar == '\t' || currentChar == '\r' || currentChar == '\n';
}
/**
* Is next char boolean.
* Check if next char is given char by position
*
* @param currentChar the current char is the char that is going to be checked
* @param position the position used to get char at position from {@link #jsonBuffer}
* @return the boolean true or false
*/
public boolean isNextChar(char currentChar, int position) {
for (int i = 0; i < position; i++) {
parseChar();
}
char nextChar = peekChar();
for (int i = 0; i < position; i++) {
jsonBufferPosition--;
}
return nextChar == currentChar;
}
/**
* Is number boolean.
* Check if current char is a number
* @param currentChar the current char is used to check
* @return the boolean true or false
*/
public boolean isNumber(char currentChar) {
char[] numberElements = new char[]{
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'.',
'E',
'e',
'+',
'-'
};
for (char listChar : numberElements) {
if (listChar == currentChar) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,26 @@
package me.ratsiel.json.abstracts;
/**
* The abstract class {@link JsonHandler} with generic type {@link T} is used to serialize and deserialize an object
*
* @param <T> the type parameter type of object which is going to be serialized or deserialized.
*/
public abstract class JsonHandler<T> {
/**
* Serialize {@link JsonValue} to object of type {@link T}
*
* @param jsonValue the json value can be a value like something {@link me.ratsiel.json.model.JsonObject} or {@link me.ratsiel.json.model.JsonArray}
* @return the t
*/
public abstract T serialize(JsonValue jsonValue);
/**
* Deserialize {@link T} to {@link JsonValue}
*
* @param value the value is an object of {@link T}
* @return the json value is the deserialized value of {@link T}
*/
public abstract JsonValue deserialize(T value);
}

View File

@ -0,0 +1,80 @@
package me.ratsiel.json.abstracts;
/**
* The class {@link JsonValue} is an upper class for Json values like {@link me.ratsiel.json.model.JsonObject}
*/
public abstract class JsonValue {
private int intend = 0;
private String key;
/**
* Instantiates a new Json value.
*/
public JsonValue() {
}
/**
* Instantiates a new Json value.
*
* @param key the key is used to find a document in {@link me.ratsiel.json.model.JsonObject}
*/
public JsonValue(String key) {
this.key = key;
}
/**
* Create space string.
* Used to generate the spaces when a object of type {@link JsonValue} is used with {@link #toString()}
*
* @return the string
*/
protected String createSpace() {
StringBuilder spaceBuilder = new StringBuilder();
for (int i = 0; i < intend; i++) {
spaceBuilder.append(" ");
}
return spaceBuilder.toString();
}
@Override
public abstract String toString();
/**
* Gets key.
*
* @return key the key is used to find a document in {@link me.ratsiel.json.model.JsonObject}
*/
public String getKey() {
return key;
}
/**
* Sets key.
*
* @param key the key is used to find a document in {@link me.ratsiel.json.model.JsonObject}
*/
public void setKey(String key) {
this.key = key;
}
/**
* Gets intend.
*
* @return the intend used to calculate free space in method {@link #createSpace()}
*/
public int getIntend() {
return intend;
}
/**
* Sets intend.
*
* @param intend the intend used to calculate ree space in method {@link #createSpace()}
*/
public void setIntend(int intend) {
this.intend = intend;
}
}

View File

@ -0,0 +1,70 @@
package me.ratsiel.json.interfaces;
import me.ratsiel.json.abstracts.JsonValue;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* The interface Listable.
* Used to implement functions like {@link #loop(Consumer)} or {@link #get(int)}
*
* @param <T> the type parameter determines generic type of value that can be get or added from a list
*/
public interface IListable<T> {
/**
* Size int.
*
* @return the int determines the size of given list
*/
int size();
/**
* Add value to something.
*
* @param value the value is going to be add to a list or something else
*/
void add(T value);
/**
* Add value to something where a index is needed.
*
* @param index the index is the position identifier of the object
* @param value the value is going to be add to a list or something else
*/
void add(int index, T value);
/**
* Get a value of type {@link T} by its index and cast it with {@link Class<T>}.
*
* @param index the index is the position of the object
* @param clazz the clazz is the type of object
* @return object of type {@link T}
*/
T get(int index, Class<T> clazz);
/**
* Get a value of type {@link T} by its index.
*
* @param index the index is the position of the object
* @return object of type {@link T}
*/
T get(int index);
/**
* Loop is used to iterate through a {@link java.util.List} or an {@link java.util.Iterator}
*
* @param consumer the consumer accepts values from {@link java.util.List}
*/
void loop(Consumer<JsonValue> consumer);
/**
* Loop is used to iterate through a {@link java.util.List} or an {@link java.util.Iterator}
*
* @param consumer the consumer the consumer accepts values and indexes from {@link java.util.List}
*/
void loop(BiConsumer<Integer, JsonValue> consumer);
}

View File

@ -0,0 +1,147 @@
package me.ratsiel.json.model;
import me.ratsiel.json.abstracts.JsonValue;
import me.ratsiel.json.interfaces.IListable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* The class Json array is used to store objects of type {@link JsonValue} in {@link #values}
*/
public class JsonArray extends JsonValue implements IListable<JsonValue> {
/**
* The Values is a list which is used by the {@link IListable}
*/
protected final List<JsonValue> values = new ArrayList<>();
/**
* Instantiates a new Json array.
*/
public JsonArray() {
}
/**
* Instantiates a new Json array.
*
* @param key the key is the identifier of {@link JsonValue}
*/
public JsonArray(String key) {
super(key);
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
String space = createSpace();
stringBuilder.append(space);
if (getKey() != null && !getKey().isEmpty()) {
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
}
stringBuilder.append("[");
loop((integer, jsonValue) -> {
jsonValue.setIntend(getIntend() + 2);
stringBuilder.append("\n");
if(!(integer == size() - 1)) {
stringBuilder.append(jsonValue).append(",");
} else {
stringBuilder.append(jsonValue);
}
});
stringBuilder.append("\n").append(space).append("]");
return stringBuilder.toString();
}
@Override
public int size() {
return values.size();
}
@Override
public void add(JsonValue value) {
values.add(value);
}
@Override
public void add(int index, JsonValue value) {
values.set(index, value);
}
public void addString(String value) {
JsonString jsonString = new JsonString(value);
this.add(jsonString);
}
public void addBoolean(boolean value) {
JsonBoolean jsonBoolean = new JsonBoolean(value);
this.add(jsonBoolean);
}
public void addByte(byte value) {
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
this.add(jsonNumber);
}
public void addInteger(int value) {
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
this.add(jsonNumber);
}
public void addShort(short value) {
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
this.add(jsonNumber);
}
public void addDouble(double value) {
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
this.add(jsonNumber);
}
public void addFloat(float value) {
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
this.add(jsonNumber);
}
public void addLong(long value) {
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
this.add(jsonNumber);
}
@Override
public JsonValue get(int index, Class<JsonValue> clazz) {
return clazz.cast(get(index));
}
@Override
public JsonValue get(int index) {
return values.get(index);
}
@Override
public void loop(Consumer<JsonValue> consumer) {
for (JsonValue value : values) {
consumer.accept(value);
}
}
@Override
public void loop(BiConsumer<Integer, JsonValue> consumer) {
for (int index = 0; index < values.size(); index++) {
JsonValue jsonValue = values.get(index);
consumer.accept(index, jsonValue);
}
}
}

View File

@ -0,0 +1,77 @@
package me.ratsiel.json.model;
import me.ratsiel.json.abstracts.JsonValue;
/**
* The class Json boolean stores a boolean.
*/
public class JsonBoolean extends JsonValue {
/**
* The Value is the given boolean
*/
public boolean value;
/**
* Instantiates a new Json boolean.
*/
public JsonBoolean() {
}
/**
* Instantiates a new Json boolean.
*
* @param value the value is the given boolean that is set to {@link #value}
*/
public JsonBoolean(boolean value) {
this.value = value;
}
/**
* Instantiates a new Json boolean.
*
* @param key the key is the identifier of {@link JsonValue}
* @param value the value is the given boolean that is set to {@link #value}
*/
public JsonBoolean(String key, boolean value) {
super(key);
this.value = value;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
String space = createSpace();
stringBuilder.append(space);
if (getKey() != null && !getKey().isEmpty()) {
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
}
stringBuilder.append(isValue());
return stringBuilder.toString();
}
/**
* Is value boolean.
*
* @return the boolean value is the stored at {@link #value}
*/
public boolean isValue() {
return value;
}
/**
* Sets value.
*
* @param value the value is the value {@link #value}
*/
public void setValue(boolean value) {
this.value = value;
}
}

View File

@ -0,0 +1,53 @@
package me.ratsiel.json.model;
import me.ratsiel.json.abstracts.JsonValue;
/**
* The class Json null store a null value.
*/
public class JsonNull extends JsonValue {
/**
* The Value is a final value because null is null!
*/
protected final String value = "null";
/**
* Instantiates a new Json null.
*/
public JsonNull() {
}
/**
* Instantiates a new Json null.
*
* @param key the key is the identifier of {@link JsonValue}
*/
public JsonNull(String key) {
super(key);
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
String space = createSpace();
stringBuilder.append(space);
if (getKey() != null && !getKey().isEmpty()) {
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
}
stringBuilder.append("null");
return stringBuilder.toString();
}
/**
* Gets value.
*
* @return the value is the stored at {@link #value}
*/
public String getValue() {
return value;
}
}

View File

@ -0,0 +1,275 @@
package me.ratsiel.json.model;
import me.ratsiel.json.abstracts.JsonValue;
import java.math.BigDecimal;
/**
* The class Json number stores a string that can be cast to a number.
*/
public class JsonNumber extends JsonValue {
/**
* The Value is a string that can be cast to a number.
*/
protected String value;
/**
* Instantiates a new Json number.
*/
public JsonNumber() {
}
/**
* Instantiates a new Json number.
*
* @param key the key is the identifier of {@link JsonValue}
* @param value the value is the given string that is set to {@link #value}
*/
public JsonNumber(String key, String value) {
super(key);
this.value = value;
}
/**
* Instantiates a new Json number.
*
* @param value the value
*/
public JsonNumber(String value) {
this.value = value;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
String space = createSpace();
stringBuilder.append(space);
if (getKey() != null && !getKey().isEmpty()) {
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
}
stringBuilder.append(getValue());
return stringBuilder.toString();
}
/**
* Gets value.
*
* @return the value the value is the given string that is set to {@link #value}
*/
public String getValue() {
return value;
}
/**
* Sets value.
*
* @param value the value is set to {@link #value}
*/
public void setValue(String value) {
this.value = value;
}
/**
* Byte value byte.
* Convert {@link #value} to {@link Byte}
*
* @return the byte converted value
*/
public byte byteValue() {
return getBigDecimal().byteValue();
}
/**
* Int value int.
* Convert {@link #value} to {@link Integer}
*
* @return the int converted value
*/
public int intValue() {
return getBigDecimal().intValue();
}
/**
* Short value short.
* Convert {@link #value} to {@link Short}
*
* @return the short converted value
*/
public short shortValue() {
return getBigDecimal().shortValue();
}
/**
* Double value double.
* Convert {@link #value} to {@link Double}
*
* @return the double converted value
*/
public double doubleValue() {
return getBigDecimal().doubleValue();
}
/**
* Float value float.
* Convert {@link #value} to {@link Float}
*
* @return the float converted value
*/
public float floatValue() {
return getBigDecimal().floatValue();
}
/**
* Long value long.
* Convert {@link #value} to {@link Long}
*
* @return the long converted value
*/
public long longValue() {
return getBigDecimal().longValue();
}
/**
* Gets number determined by given class {@link Class<T>}
*
* @param <T> the type parameter determines the given number
* @param clazz the clazz used to use correct number.
* @return the number object of type {@link Number}
*/
public <T> Object getNumber(Class<T> clazz) {
if (clazz.equals(Byte.class) || clazz.equals(byte.class)) {
return byteValue();
} else if (clazz.equals(Integer.class) || clazz.equals(int.class)) {
return intValue();
} else if (clazz.equals(Short.class) || clazz.equals(short.class)) {
return shortValue();
} else if (clazz.equals(Double.class) || clazz.equals(double.class)) {
return doubleValue();
} else if (clazz.equals(Float.class) || clazz.equals(float.class)) {
return floatValue();
} else if (clazz.equals(Long.class) || clazz.equals(long.class)) {
return longValue();
}
return null;
}
/**
* Gets big decimal.
*
* @return the big decimal created by {@link #value}
*/
public BigDecimal getBigDecimal() {
return new BigDecimal(getValue());
}
/**
* Is numeric boolean.
* Check if given string is a number
*
* @param value the value is used to check
* @return the boolean true or false
*/
public boolean isNumeric(String value) {
if (value == null) {
return false;
}
boolean isNumber = value.matches("[+-]?(\\d+([.]\\d*)?([eE][+-]?\\d+)?|[.]\\d+([eE][+-]?\\d+)?)");
if (isNumber) {
String testValue;
if (isInteger(value)) {
int integerValue = intValue();
testValue = String.valueOf(integerValue);
} else if (isDouble(value)) {
double doubleValue = doubleValue();
if (doubleValue > Double.MAX_VALUE || doubleValue < Double.MIN_EXPONENT) {
return false;
}
testValue = String.valueOf(Math.round(doubleValue));
} else if (isFloat(value)) {
float floatValue = floatValue();
if (floatValue > Float.MAX_VALUE || floatValue < Float.MIN_EXPONENT) {
return false;
}
testValue = String.valueOf(Math.round(floatValue));
} else {
testValue = value;
}
try {
Long.parseLong(testValue);
} catch (Exception exception) {
return false;
}
}
return isNumber;
}
/**
* Is float boolean.
* Check if given string is a float
*
* @param value the value is used to check
* @return the boolean true or false
*/
public boolean isFloat(String value) {
try {
Float.parseFloat(value);
return true;
} catch (Exception exception) {
return false;
}
}
/**
* Is integer boolean.
* Check if given string is a integer
*
* @param value the value is used to check
* @return the boolean true or false
*/
public boolean isInteger(String value) {
try {
Integer.parseInt(value);
return true;
} catch (Exception exception) {
return false;
}
}
/**
* Is double boolean.
* Check if given string is a double
*
* @param value the value is used to check
* @return the boolean true or false
*/
public boolean isDouble(String value) {
try {
Double.parseDouble(value);
return true;
} catch (Exception exception) {
return false;
}
}
}

View File

@ -0,0 +1,215 @@
package me.ratsiel.json.model;
import me.ratsiel.json.abstracts.JsonValue;
import me.ratsiel.json.interfaces.IListable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* The class Json object is used to store objects of type {@link JsonValue} in {@link #values}
*/
public class JsonObject extends JsonValue implements IListable<JsonValue> {
/**
* The Values is a list which is used by the {@link IListable}
*/
protected final List<JsonValue> values = new ArrayList<>();
/**
* Instantiates a new Json object.
*/
public JsonObject() {
}
/**
* Instantiates a new Json object.
*
* @param key the key is the identifier of {@link JsonValue}
*/
public JsonObject(String key) {
super(key);
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
String space = createSpace();
stringBuilder.append(space);
if (getKey() != null && !getKey().isEmpty()) {
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
}
stringBuilder.append("{");
loop((integer, jsonValue) -> {
jsonValue.setIntend(getIntend() + 2);
stringBuilder.append("\n");
if(!(integer == size() - 1)) {
stringBuilder.append(jsonValue).append(",");
} else {
stringBuilder.append(jsonValue);
}
});
stringBuilder.append("\n").append(space).append("}");
return stringBuilder.toString();
}
/**
* Get json value by key.
*
* @param key the key is the identifier of {@link JsonValue}
* @return the json value is null or the Json value that is found in {@link #values}
*/
public JsonValue get(String key) {
if(!has(key)) return null;
return values.stream().filter(jsonValue -> jsonValue.getKey().equalsIgnoreCase(key)).findFirst().get();
}
/**
* Get {@link T} by key and cast it to {@link Class<T>}
*
* @param <T> the type parameter is used to determine what type of object is needed
* @param key the key is the identifier of {@link JsonValue}
* @param clazz the clazz is used to cast the {@link T}
* @return the {@link T} object
*/
public <T extends JsonValue> T get(String key, Class<T> clazz) {
return clazz.cast(get(key));
}
/**
* Has is used to find a {@link JsonValue} by its key in {@link #values}
*
* @param key the key is the identifier of {@link JsonValue}
* @return the boolean true or false
*/
public boolean has(String key) {
return values.stream().anyMatch(jsonValue -> jsonValue.getKey() != null && jsonValue.getKey().equalsIgnoreCase(key));
}
/**
* Gets index.
* Used to get the index of an key if it is found in {@link #values}
* @param key the key is the identifier of {@link JsonValue}
* @return the index by key
*/
public int getIndex(String key) {
if(!has(key)) return -1;
for (int index = 0; index < values.size(); index++) {
JsonValue jsonValue = values.get(index);
if(jsonValue.getKey().equalsIgnoreCase(key)) {
return index;
}
}
return -1;
}
@Override
public int size() {
return values.size();
}
/**
* Add an object to {@link #values} by its key.
*
* @param key the key is the identifier of {@link JsonValue}
* @param jsonValue the json value is the {@link JsonValue} that is going to be added to {@link #values}
*/
public void add(String key, JsonValue jsonValue) {
jsonValue.setKey(key);
add(jsonValue);
}
@Override
public void add(JsonValue value) {
if(has(value.getKey())) {
int index = getIndex(value.getKey());
add(index, value);
} else {
values.add(value);
}
}
@Override
public void add(int index, JsonValue value) {
values.set(index, value);
}
public void addString(String key, String value) {
JsonString jsonString = new JsonString(key, value);
this.add(jsonString);
}
public void addBoolean(String key, boolean value) {
JsonBoolean jsonBoolean = new JsonBoolean(key, value);
this.add(jsonBoolean);
}
public void addByte(String key, byte value) {
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
this.add(jsonNumber);
}
public void addInteger(String key, int value) {
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
this.add(jsonNumber);
}
public void addShort(String key, short value) {
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
this.add(jsonNumber);
}
public void addDouble(String key, double value) {
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
this.add(jsonNumber);
}
public void addFloat(String key, float value) {
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
this.add(jsonNumber);
}
public void addLong(String key, long value) {
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
this.add(jsonNumber);
}
@Override
public JsonValue get(int index, Class<JsonValue> clazz) {
return clazz.cast(get(index));
}
@Override
public JsonValue get(int index) {
return values.get(index);
}
@Override
public void loop(Consumer<JsonValue> consumer) {
for (JsonValue value : values) {
consumer.accept(value);
}
}
@Override
public void loop(BiConsumer<Integer, JsonValue> consumer) {
for (int index = 0; index < values.size(); index++) {
JsonValue jsonValue = values.get(index);
consumer.accept(index, jsonValue);
}
}
}

View File

@ -0,0 +1,73 @@
package me.ratsiel.json.model;
import me.ratsiel.json.abstracts.JsonValue;
/**
* The class Json string is used to store a string.
*/
public class JsonString extends JsonValue {
private String value;
/**
* Instantiates a new Json string.
*/
public JsonString() {
}
/**
* Instantiates a new Json string.
*
* @param key the key is the identifier of {@link JsonValue}
* @param value the value is the given string that is set to {@link #value}
*/
public JsonString(String key, String value) {
super(key);
this.value = value;
}
/**
* Instantiates a new Json string.
*
* @param value the value is the given string that is set to {@link #value}
*/
public JsonString(String value) {
this.value = value;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
String space = createSpace();
stringBuilder.append(space);
if (getKey() != null && !getKey().isEmpty()) {
stringBuilder.append("\"").append(getKey()).append("\"")
.append(" : ").append("\"").append(getValue()).append("\"");
} else {
stringBuilder.append("\"").append(value).append("\"");
}
return stringBuilder.toString();
}
/**
* Gets value.
*
* @return the value is the stored at {@link #value}
*/
public String getValue() {
return value;
}
/**
* Sets value.
*
* @param value the value is set to {@link #value}
*/
public void setValue(String value) {
this.value = value;
}
}

View File

@ -1,5 +1,9 @@
package net.lax1dude.eaglercraft;
import me.ratsiel.auth.abstracts.exception.AuthenticationException;
import me.ratsiel.auth.model.mojang.MinecraftAuthenticator;
import me.ratsiel.auth.model.mojang.MinecraftToken;
import me.ratsiel.auth.model.mojang.profile.MinecraftProfile;
import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiScreen;
import net.minecraft.src.GuiTextField;
@ -10,6 +14,7 @@ public class GuiScreenEditProfile extends GuiScreen {
private GuiScreen parent;
private GuiTextField username;
private GuiTextField password;
private boolean dropDownOpen = false;
private String[] dropDownOptions;
@ -66,15 +71,16 @@ public class GuiScreenEditProfile extends GuiScreen {
this.dropDownOptions = EaglerProfile.concatArrays(EaglerProfile.skinNames.toArray(new String[0]), defaultOptions);
}
private GuiButton button0, button1, button2, button3;
private GuiButton button0, button1, button2, button3, button4;
public void initGui() {
super.initGui();
EaglerAdapter.enableRepeatEvents(true);
StringTranslate var1 = StringTranslate.getInstance();
this.screenTitle = var1.translateKey("profile.title");
this.username = new GuiTextField(this.fontRenderer, this.width / 2 - 20 + 1, this.height / 6 + 24 + 1, 138, 20);
this.username = new GuiTextField(this.fontRenderer, this.width / 2 - 20 + 1, this.height / 6 + 1, 138, 20);
this.username.setFocused(true);
this.password = new GuiTextField(this.fontRenderer, this.width / 2 - 20 + 1, this.height / 6 + 24 + 1, 138, 20);
this.username.setText(EaglerProfile.username);
selectedSlot = EaglerProfile.presetSkinId == -1 ? EaglerProfile.customSkinId : (EaglerProfile.presetSkinId + EaglerProfile.skinNames.size());
//this.buttonList.add(new GuiButton(0, this.width / 2 - 100, 140, "eeeee"));
@ -83,6 +89,8 @@ public class GuiScreenEditProfile extends GuiScreen {
this.buttonList.add(button2 = new GuiButton(3, this.width / 2 - 21 + 71, this.height / 6 + 110, 72, 20, var1.translateKey("profile.clearSkin")));
this.buttonList.add(button3 = new GuiButton(4, this.width / 2 - 21 + 71, this.height / 6 + 134, 72, 20, this.mc.gameSettings.useDefaultProtocol?"Switch to Eaglercraft":"Switch to Vanilla"));
this.buttonList.add(button4 = new GuiButton(5, this.width / 2 - 21, this.height / 6 + 134, 72, 20, this.mc.gameSettings.sessionId==null?"Microsoft Login":"Logout"));
//this.buttonList.add(new GuiButton(200, this.width / 2, this.height / 6 + 72, 150, 20, var1.translateKey("gui.done")));
}
@ -183,7 +191,7 @@ public class GuiScreenEditProfile extends GuiScreen {
protected void actionPerformed(GuiButton par1GuiButton) {
if(!dropDownOpen) {
if(par1GuiButton.id == 200) {
EaglerProfile.username = this.username.getText().length() == 0 ? "null" : this.username.getText();
if(mc.gameSettings.sessionId==null)EaglerProfile.username = this.username.getText().length() == 0 ? "null" : this.username.getText();
EaglerProfile.presetSkinId = selectedSlot - EaglerProfile.skinNames.size();
if(EaglerProfile.presetSkinId < 0) {
EaglerProfile.presetSkinId = -1;
@ -219,7 +227,23 @@ public class GuiScreenEditProfile extends GuiScreen {
}else if (par1GuiButton.id == 4) {
//toggle version mode
this.mc.gameSettings.useDefaultProtocol=!this.mc.gameSettings.useDefaultProtocol;
button3.displayString=this.mc.gameSettings.useDefaultProtocol?"Switch to Eaglercraft":"Switch to Vanilla";
this.button3.displayString=this.mc.gameSettings.useDefaultProtocol?"Switch to Eaglercraft":"Switch to Vanilla";
}else if (par1GuiButton.id == 5) {
//log in/out
if(this.mc.gameSettings.sessionId==null){
try {
MinecraftAuthenticator minecraftAuthenticator = new MinecraftAuthenticator();
MinecraftToken minecraftToken = minecraftAuthenticator.loginWithXbox(this.username.getText(), "");
MinecraftProfile minecraftProfile = minecraftAuthenticator.checkOwnership(minecraftToken);
this.button4.displayString="Logout";
EaglerProfile.username=minecraftToken.getUsername();
this.username.setText(EaglerProfile.username);
this.password.setText("");
mc.gameSettings.sessionId=minecraftToken.getAccessToken();
}catch(AuthenticationException e){}
}else{
this.mc.gameSettings.sessionId=null;
}
}
}
}
@ -270,14 +294,18 @@ public class GuiScreenEditProfile extends GuiScreen {
public void onGuiClosed() {
EaglerAdapter.enableRepeatEvents(false);
if(mc.gameSettings.sessionId==null){
EaglerProfile.username=EaglerProfile.username.replaceAll("@","");
}
}
//will be called for password typing as well lol, meh
protected void keyTyped(char par1, int par2) {
this.username.textboxKeyTyped(par1, par2);
String text = username.getText();
if(text.length() > 16) text = text.substring(0, 16);
text = text.replaceAll("[^A-Za-z0-9\\-_]", "_");
text = text.replaceAll("[^A-Za-z0-9\\-_@]", "_");
this.username.setText(text);
if(par2 == 200 && selectedSlot > 0) {

View File

@ -6,6 +6,7 @@ import net.minecraft.client.Minecraft;
public class GameSettings {
public static boolean useDefaultProtocol = false;
public static String sessionId = null;
private static final String[] RENDER_DISTANCES = new String[] { "options.renderDistance.far", "options.renderDistance.normal", "options.renderDistance.short", "options.renderDistance.tiny" };