Last active
October 11, 2022 22:34
-
-
Save Jofkos/79af290e94acdc7d7d5b to your computer and use it in GitHub Desktop.
GameProfileBuilder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.lang.reflect.Type; | |
import java.net.HttpURLConnection; | |
import java.net.URL; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map.Entry; | |
import java.util.UUID; | |
import org.bukkit.craftbukkit.libs.com.google.gson.Gson; | |
import org.bukkit.craftbukkit.libs.com.google.gson.GsonBuilder; | |
import org.bukkit.craftbukkit.libs.com.google.gson.JsonDeserializationContext; | |
import org.bukkit.craftbukkit.libs.com.google.gson.JsonDeserializer; | |
import org.bukkit.craftbukkit.libs.com.google.gson.JsonElement; | |
import org.bukkit.craftbukkit.libs.com.google.gson.JsonObject; | |
import org.bukkit.craftbukkit.libs.com.google.gson.JsonParseException; | |
import org.bukkit.craftbukkit.libs.com.google.gson.JsonParser; | |
import org.bukkit.craftbukkit.libs.com.google.gson.JsonSerializationContext; | |
import org.bukkit.craftbukkit.libs.com.google.gson.JsonSerializer; | |
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; | |
import com.mojang.authlib.GameProfile; | |
import com.mojang.authlib.properties.Property; | |
import com.mojang.authlib.properties.PropertyMap; | |
import com.mojang.util.UUIDTypeAdapter; | |
public class GameProfileBuilder { | |
private static final String SERVICE_URL = "https://sessionserver.mojang.com/session/minecraft/profile/%s?unsigned=false"; | |
private static final String JSON_SKIN = "{\"timestamp\":%d,\"profileId\":\"%s\",\"profileName\":\"%s\",\"isPublic\":true,\"textures\":{\"SKIN\":{\"url\":\"%s\"}}}"; | |
private static final String JSON_CAPE = "{\"timestamp\":%d,\"profileId\":\"%s\",\"profileName\":\"%s\",\"isPublic\":true,\"textures\":{\"SKIN\":{\"url\":\"%s\"},\"CAPE\":{\"url\":\"%s\"}}}"; | |
private static Gson gson = new GsonBuilder().disableHtmlEscaping().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).registerTypeAdapter(GameProfile.class, new GameProfileSerializer()).registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()).create(); | |
private static HashMap<UUID, CachedProfile> cache = new HashMap<UUID, CachedProfile>(); | |
private static long cacheTime = -1; | |
/** | |
* Don't run in main thread! | |
* | |
* Fetches the GameProfile from the Mojang servers | |
* | |
* @param uuid The player uuid | |
* @return The GameProfile | |
* @throws IOException If something wents wrong while fetching | |
* @see GameProfile | |
*/ | |
public static GameProfile fetch(UUID uuid) throws IOException { | |
return fetch(uuid, false); | |
} | |
/** | |
* Don't run in main thread! | |
* | |
* Fetches the GameProfile from the Mojang servers | |
* @param uuid The player uuid | |
* @param forceNew If true the cache is ignored | |
* @return The GameProfile | |
* @throws IOException If something wents wrong while fetching | |
* @see GameProfile | |
*/ | |
public static GameProfile fetch(UUID uuid, boolean forceNew) throws IOException { | |
if (!forceNew && cache.containsKey(uuid) && cache.get(uuid).isValid()) { | |
return cache.get(uuid).profile; | |
} else { | |
HttpURLConnection connection = (HttpURLConnection) new URL(String.format(SERVICE_URL, UUIDTypeAdapter.fromUUID(uuid))).openConnection(); | |
connection.setReadTimeout(5000); | |
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { | |
String json = new BufferedReader(new InputStreamReader(connection.getInputStream())).readLine(); | |
GameProfile result = gson.fromJson(json, GameProfile.class); | |
cache.put(uuid, new CachedProfile(result)); | |
return result; | |
} else { | |
if (!forceNew && cache.containsKey(uuid)) { | |
return cache.get(uuid).profile; | |
} | |
JsonObject error = (JsonObject) new JsonParser().parse(new BufferedReader(new InputStreamReader(connection.getErrorStream())).readLine()); | |
throw new IOException(error.get("error").getAsString() + ": " + error.get("errorMessage").getAsString()); | |
} | |
} | |
} | |
/** | |
* Builds a GameProfile for the specified args | |
* | |
* @param uuid The uuid | |
* @param name The name | |
* @param skin The url from the skin image | |
* @return A GameProfile built from the arguments | |
* @see GameProfile | |
*/ | |
public static GameProfile getProfile(UUID uuid, String name, String skin) { | |
return getProfile(uuid, name, skin, null); | |
} | |
/** | |
* Builds a GameProfile for the specified args | |
* | |
* @param uuid The uuid | |
* @param name The name | |
* @param skinUrl Url from the skin image | |
* @param capeUrl Url from the cape image | |
* @return A GameProfile built from the arguments | |
* @see GameProfile | |
*/ | |
public static GameProfile getProfile(UUID uuid, String name, String skinUrl, String capeUrl) { | |
GameProfile profile = new GameProfile(uuid, name); | |
boolean cape = capeUrl != null && !capeUrl.isEmpty(); | |
List<Object> args = new ArrayList<Object>(); | |
args.add(System.currentTimeMillis()); | |
args.add(UUIDTypeAdapter.fromUUID(uuid)); | |
args.add(name); | |
args.add(skinUrl); | |
if (cape) args.add(capeUrl); | |
profile.getProperties().put("textures", new Property("textures", Base64Coder.encodeString(String.format(cape ? JSON_CAPE : JSON_SKIN, args.toArray(new Object[args.size()]))))); | |
return profile; | |
} | |
/** | |
* Sets the time as long as you want to keep the gameprofiles in cache (-1 = never remove it) | |
* @param time cache time (default = -1) | |
*/ | |
public static void setCacheTime(long time) { | |
cacheTime = time; | |
} | |
private static class GameProfileSerializer implements JsonSerializer<GameProfile>, JsonDeserializer<GameProfile> { | |
public GameProfile deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { | |
JsonObject object = (JsonObject) json; | |
UUID id = object.has("id") ? (UUID) context.deserialize(object.get("id"), UUID.class) : null; | |
String name = object.has("name") ? object.getAsJsonPrimitive("name").getAsString() : null; | |
GameProfile profile = new GameProfile(id, name); | |
if (object.has("properties")) { | |
for (Entry<String, Property> prop : ((PropertyMap) context.deserialize(object.get("properties"), PropertyMap.class)).entries()) { | |
profile.getProperties().put(prop.getKey(), prop.getValue()); | |
} | |
} | |
return profile; | |
} | |
public JsonElement serialize(GameProfile profile, Type type, JsonSerializationContext context) { | |
JsonObject result = new JsonObject(); | |
if (profile.getId() != null) | |
result.add("id", context.serialize(profile.getId())); | |
if (profile.getName() != null) | |
result.addProperty("name", profile.getName()); | |
if (!profile.getProperties().isEmpty()) | |
result.add("properties", context.serialize(profile.getProperties())); | |
return result; | |
} | |
} | |
private static class CachedProfile { | |
private long timestamp = System.currentTimeMillis(); | |
private GameProfile profile; | |
public CachedProfile(GameProfile profile) { | |
this.profile = profile; | |
} | |
public boolean isValid() { | |
return cacheTime < 0 ? true : (System.currentTimeMillis() - timestamp) < cacheTime; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hope you don't mind that I borrowed this for a project, good work though! (I did leave a code comment giving you credit with a link to this)