All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bspfsystems.basicmojangapi.BasicMojangAPI Maven / Gradle / Ivy

Go to download

A simple Java library for translating between a player's username and their UUID.

There is a newer version: 2.0.1
Show newest version
/*
 * This file is part of the BasicMojangAPI Java library.
 *
 * Copyright 2021 BSPF Systems, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.bspfsystems.basicmojangapi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bspfsystems.simplejson.JSONArray;
import org.bspfsystems.simplejson.JSONObject;
import org.bspfsystems.simplejson.SimpleJSONArray;
import org.bspfsystems.simplejson.parser.JSONException;
import org.bspfsystems.simplejson.parser.JSONParser;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * Represents a utility class to interact with basic parts of the Mojang API
 * using Java.
 * 

* The implemented API features include: *

  • Usernames to UUIDs
  • *
  • * PLEASE NOTE: Since November 2020, Mojang stopped supporting the timestamp * parameter. If a timestamp is provided, it is effectively ignored, and the * current time is used instead. This means that a username that has been * used on multiple accounts will return only the current {@link UUID} (if * any) that is associated with the given username. Please remind Mojang to * fix this issue here: * WEB-3367 * * @param username The username of the account to retrieve. * @return The {@link Account} associated with the given username, including * the case-corrected username and the {@link UUID}, or {@code null} * if there is no current account associated with the username. * @throws IllegalArgumentException If the username is invalid or otherwise * causes a bad request to be handled. * @throws IOException If there was an error while parsing the data from the * API. * @see BasicMojangAPI#usernameToUniqueId(String, long) */ @Nullable public static Account usernameToUniqueId(@NotNull final String username) throws IllegalArgumentException, IOException { return BasicMojangAPI.usernameToUniqueId(username, System.currentTimeMillis()); } /** * Gets the {@link Account} data, containing the case-corrected username and * the associated {@link UUID}. This will use the given time as the optional * timestamp parameter. *

    * PLEASE NOTE: Since November 2020, Mojang stopped supporting the timestamp * parameter. If a timestamp is provided, it is effectively ignored, and the * current time is used instead. This means that a username that has been * used on multiple accounts will return only the current {@link UUID} (if * any) that is associated with the given username. Please remind Mojang to * fix this issue here: * WEB-3367 * * @param username The username of the account to retrieve. * @param timestamp The timestamp to use. The milliseconds portion of the * timestamp will be ignored, as the API uses the UNIX * timestamp without milliseconds. * @return The {@link Account} associated with the given username, including * the case-corrected username and the {@link UUID}, or {@code null} * if there is no current account associated with the username. * @throws IllegalArgumentException If the username is invalid or otherwise * causes a bad request to be handled. * @throws IOException If there was an error while parsing the data from the * API. */ @Nullable public static Account usernameToUniqueId(@NotNull final String username, final long timestamp) throws IllegalArgumentException, IOException { final URL url = new URL(BasicMojangAPI.BASE_URL + BasicMojangAPI.USERNAME_TO_UUID.replace("", username).replace("", String.valueOf(timestamp / 1000L))); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); final int responseCode = connection.getResponseCode(); if (responseCode == 204) { return null; } final JSONObject responseData; try { responseData = JSONParser.deserializeObject(BasicMojangAPI.readData(connection.getInputStream())); } catch (JSONException e) { throw new IOException("Unable to parse data from the Mojang API.", e); } if (responseData == null) { return null; } if (responseCode == 400) { throw new IllegalArgumentException(responseData.getString("errorMessage", "An invalid parameter was given.")); } return new SimpleAccount(responseData); } /** * Gets a {@link List} of {@link Account} data from the Mojang API, given a * {@link List} of usernames. The usernames in the respective * {@link Account}s will be case-corrected. *

    * The supplied {@link List} may contain duplicates (Mojang usernames are * unique from a case-insensitive aspect, so {@code "example"} and * {@code "EXAMPLE"} cannot both be used at the same time). How Mojang * handles duplicates in the submitted data may change at any time. *

    * Depending on how the Mojang API handles duplicates, there may or may not * be duplicate {@link Account}s in the returned {@link List}. *

    * The supplied {@link List} may not contain more than 10 entries, and none * of the entries may be {@code null}. Otherwise, an * {@link IllegalArgumentException} will be thrown. * * @param usernames The {@link List} of usernames to retrieve. * @return The {@link List} of {@link Account}s returned from the Mojang * API. * @throws IllegalArgumentException If a username is invalid or otherwise * causes a bad request to be handled, or * there are more than 10 usernames. * @throws IOException If there was an error while parsing the data from the * API. */ @NotNull public static List usernamesToUniqueIds(@NotNull final List usernames) throws IllegalArgumentException, IOException { if (usernames.size() > 10) { throw new IllegalArgumentException("You cannot request " + usernames.size() + " usernames (maximum 10)."); } final JSONArray postData = new SimpleJSONArray(); for (final String username : usernames) { if (username == null) { throw new IllegalArgumentException("You cannot request a null username."); } postData.addEntry(username); } final String postDataSerialized; try { postDataSerialized = JSONParser.serialize(postData); } catch (JSONException e) { throw new IOException("Unable to serialize the list of usernames.", e); } final byte[] postDataBytes = postDataSerialized.getBytes(StandardCharsets.UTF_8); final URL url = new URL(BasicMojangAPI.BASE_URL + BasicMojangAPI.USERNAMES_TO_UUIDS); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", BasicMojangAPI.POST_PROPERTY + "; utf-8"); connection.setRequestProperty("Accept", BasicMojangAPI.POST_PROPERTY); connection.setDoOutput(true); connection.getOutputStream().write(postDataBytes, 0, postDataBytes.length); final JSONArray responseData; try { responseData = JSONParser.deserializeArray(BasicMojangAPI.readData(connection.getInputStream())); } catch (JSONException e) { throw new IOException("Unable to parse data from the Mojang API."); } if (connection.getResponseCode() == 400) { throw new IllegalArgumentException("An invalid username was passed in as part of the request."); } final List accounts = new ArrayList(); if (responseData == null || responseData.size() == 0) { return accounts; } for (final Object dataItem : responseData) { if (dataItem instanceof JSONObject) { accounts.add(new SimpleAccount((JSONObject) dataItem)); } else { throw new IOException("Invalid account data returned."); } } return accounts; } /** * Gets the {@link AccountHistory} for the given {@link UUID} from the * Mojang API. The usernames in the {@link AccountHistory} will be * case-corrected. *

    * If there is no Mojang account for the given {@link UUID}, {@code null} * will be returned. * * @param uniqueId The {@link UUID} of the retrieved {@link AccountHistory}. * @return The retrieved {@link AccountHistory}, or {@code null} if no * Mojang account exist with the given {@link UUID}. * @throws IllegalArgumentException If the {@link UUID} is invalid or * otherwise causes an error to occur while * creating the {@link AccountHistory}. * @throws IOException If there was an error while parsing the data from the * API. */ @Nullable public static AccountHistory uniqueIdToNameHistory(@NotNull final UUID uniqueId) throws IllegalArgumentException, IOException { final URL url = new URL(BasicMojangAPI.BASE_URL + BasicMojangAPI.UUID_TO_NAME_HISTORY.replace("", uniqueId.toString())); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); final int responseCode = connection.getResponseCode(); if (responseCode == 204) { return null; } final JSONArray responseData; try { responseData = JSONParser.deserializeArray(BasicMojangAPI.readData(connection.getInputStream())); } catch (JSONException e) { throw new IOException("Unable to parse data from the Mojang API.", e); } if (responseData == null) { return null; } if (responseCode == 400) { throw new IllegalArgumentException("An invalid UUID was passed in as part of the request."); } return new SimpleAccountHistory(uniqueId, responseData); } /** * Reads the data in from the given {@link InputStream} and returns the data * as a {@link String}. * * @param input The {@link InputStream} to read the data from. * @return A {@link String} representing the data. * @throws IOException If an I/O error occurs while reading in the data. */ @NotNull private static String readData(@NotNull final InputStream input) throws IOException { final BufferedReader reader = new BufferedReader(new InputStreamReader(input)); final StringBuilder builder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { builder.append(line); } return builder.toString(); } /** * Translates a 32-character {@link UUID} from the Mojang API into a * {@link UUID} that will represent the 36-character version (with the "-" * characters in the {@link UUID}). * * @param shortId The 32-character version of the {@link UUID} as a * {@link String}. * @return The {@link UUID} translated from the given {@link String}. * @throws IllegalArgumentException See {@link UUID#fromString(String)}. */ @NotNull static UUID translateUniqueId(@NotNull final String shortId) throws IllegalArgumentException { final StringBuilder builder = new StringBuilder(); builder.append(shortId, 0, 8); builder.append("-"); builder.append(shortId, 8, 12); builder.append("-"); builder.append(shortId, 12, 16); builder.append("-"); builder.append(shortId, 16, 20); builder.append("-"); builder.append(shortId, 20, 32); return UUID.fromString(builder.toString()); } }





  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy