more cleanup

This commit is contained in:
Lee 2024-04-08 05:22:54 +01:00
parent 205ae144c0
commit 3f7f1864a6
16 changed files with 218 additions and 154 deletions

@ -1,9 +1,9 @@
package cc.fascinated.controller; package cc.fascinated.controller;
import cc.fascinated.player.PlayerService; import cc.fascinated.service.player.PlayerService;
import cc.fascinated.player.impl.Player; import cc.fascinated.service.player.impl.Player;
import cc.fascinated.player.impl.Skin; import cc.fascinated.service.player.impl.Skin;
import cc.fascinated.player.impl.SkinPart; import cc.fascinated.service.player.impl.SkinPart;
import lombok.NonNull; import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.CacheControl; import org.springframework.http.CacheControl;

@ -1,42 +0,0 @@
package cc.fascinated.mojang.types;
import lombok.Getter;
import lombok.ToString;
import java.util.ArrayList;
import java.util.List;
@Getter @ToString
public class MojangSessionServerProfile {
/**
* The UUID of the player.
*/
private String id;
/**
* The name of the player.
*/
private String name;
/**
* The properties for the player.
*/
private final List<MojangSessionServerProfileProperties> properties = new ArrayList<>();
public MojangSessionServerProfile() {}
/**
* Get the texture property for the player.
*
* @return the texture property
*/
public MojangSessionServerProfileProperties getTextureProperty() {
for (MojangSessionServerProfileProperties property : properties) {
if (property.getName().equals("textures")) {
return property;
}
}
return null;
}
}

@ -1,12 +0,0 @@
package cc.fascinated.mojang.types;
import lombok.Getter;
import lombok.ToString;
@Getter @ToString
public class MojangSessionServerProfileProperties {
private String name;
private String value;
public MojangSessionServerProfileProperties() {}
}

@ -1,65 +0,0 @@
package cc.fascinated.player.impl;
import cc.fascinated.Main;
import cc.fascinated.config.Config;
import cc.fascinated.mojang.types.MojangSessionServerProfile;
import cc.fascinated.mojang.types.MojangSessionServerProfileProperties;
import cc.fascinated.util.UUIDUtils;
import com.google.gson.JsonObject;
import lombok.Getter;
import java.util.UUID;
@Getter
public class Player {
/**
* The UUID of the player
*/
private final UUID uuid;
/**
* The name of the player
*/
private final String name;
/**
* The skin of the player
* <p>
* This will be null if the player does not have a skin.
* </p>
*/
private Skin skin;
/**
* The cape of the player
* <p>
* This will be null if the player does not have a cape.
* </p>
*/
private Cape cape;
public Player(MojangSessionServerProfile profile) {
this.uuid = UUID.fromString(UUIDUtils.addUUIDDashes(profile.getId()));
this.name = profile.getName();
MojangSessionServerProfileProperties textureProperty = profile.getTextureProperty();
if (textureProperty == null) {
return;
}
// Decode the texture property
String decoded = new String(java.util.Base64.getDecoder().decode(textureProperty.getValue()));
// Parse the decoded JSON
JsonObject json = Main.getGSON().fromJson(decoded, JsonObject.class);
JsonObject texturesJson = json.getAsJsonObject("textures");
JsonObject skinJson = texturesJson.getAsJsonObject("SKIN");
JsonObject capeJson = texturesJson.getAsJsonObject("CAPE");
JsonObject metadataJson = skinJson.get("metadata").getAsJsonObject();
this.skin = new Skin(this.uuid.toString(), skinJson.get("url").getAsString(),
Skin.SkinType.valueOf(metadataJson.get("model").getAsString().toUpperCase()));
this.cape = new Cape(capeJson.get("url").getAsString());
}
}

@ -1,7 +1,7 @@
package cc.fascinated.mojang; package cc.fascinated.service.mojang;
import cc.fascinated.mojang.types.MojangApiProfile; import cc.fascinated.service.mojang.types.MojangProfile;
import cc.fascinated.mojang.types.MojangSessionServerProfile; import cc.fascinated.service.mojang.types.MojangUsernameToUuid;
import cc.fascinated.util.WebRequest; import cc.fascinated.util.WebRequest;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -17,22 +17,24 @@ public class MojangAPIService {
private String mojangApiUrl; private String mojangApiUrl;
/** /**
* Gets the Session Server profile of the player with the given UUID. * Gets the Session Server profile of the
* player with the given UUID.
* *
* @param id the uuid or name of the player * @param id the uuid or name of the player
* @return the profile * @return the profile
*/ */
public MojangSessionServerProfile getSessionServerProfile(String id) { public MojangProfile getProfile(String id) {
return WebRequest.get(mojangSessionServerUrl + "/session/minecraft/profile/" + id, MojangSessionServerProfile.class); return WebRequest.get(mojangSessionServerUrl + "/session/minecraft/profile/" + id, MojangProfile.class);
} }
/** /**
* Gets the Mojang API profile of the player with the given UUID. * Gets the UUID of the player using
* the name of the player.
* *
* @param id the name of the player * @param id the name of the player
* @return the profile * @return the profile
*/ */
public MojangApiProfile getApiProfile(String id) { public MojangUsernameToUuid getUuidFromUsername(String id) {
return WebRequest.get(mojangApiUrl + "/users/profiles/minecraft/" + id, MojangApiProfile.class); return WebRequest.get(mojangApiUrl + "/users/profiles/minecraft/" + id, MojangUsernameToUuid.class);
} }
} }

@ -0,0 +1,101 @@
package cc.fascinated.service.mojang.types;
import cc.fascinated.Main;
import cc.fascinated.service.player.impl.Cape;
import cc.fascinated.service.player.impl.Skin;
import cc.fascinated.util.Tuple;
import com.google.gson.JsonObject;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Getter @NoArgsConstructor
public class MojangProfile {
/**
* The UUID of the player.
*/
private String id;
/**
* The name of the player.
*/
private String name;
/**
* The properties of the player.
*/
private final List<ProfileProperty> properties = new ArrayList<>();
/**
* Get the skin and cape of the player.
*
* @return the skin and cape of the player
*/
public Tuple<Skin, Cape> getSkinAndCape() {
ProfileProperty textureProperty = getTextureProperty();
if (textureProperty == null) {
return null;
}
// Decode the texture property
String decoded = new String(java.util.Base64.getDecoder().decode(textureProperty.getValue()));
// Parse the decoded JSON
JsonObject json = Main.getGSON().fromJson(decoded, JsonObject.class);
JsonObject texturesJson = json.getAsJsonObject("textures");
JsonObject skinJson = texturesJson.getAsJsonObject("SKIN");
JsonObject capeJson = texturesJson.getAsJsonObject("CAPE");
JsonObject metadataJson = skinJson.get("metadata").getAsJsonObject();
Skin skin = new Skin(id, skinJson.get("url").getAsString(),
Skin.SkinType.valueOf(metadataJson.get("model").getAsString().toUpperCase()));
Cape cape = new Cape(capeJson.get("url").getAsString());
return new Tuple<>(skin, cape);
}
/**
* Get the texture property of the player.
*
* @return the texture property
*/
public ProfileProperty getTextureProperty() {
for (ProfileProperty property : properties) {
if (property.getName().equals("textures")) {
return property;
}
}
return null;
}
@Getter @AllArgsConstructor
public static class ProfileProperty {
/**
* The name of the property.
*/
private String name;
/**
* The base64 value of the property.
*/
private String value;
/**
* The signature of the property.
*/
private String signature;
/**
* Check if the property is signed.
*
* @return true if the property is signed, false otherwise
*/
public boolean isSigned() {
return signature != null;
}
}
}

@ -1,15 +1,20 @@
package cc.fascinated.mojang.types; package cc.fascinated.service.mojang.types;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.NoArgsConstructor;
@Getter @ToString @Getter @NoArgsConstructor
public class MojangApiProfile { public class MojangUsernameToUuid {
/**
* The UUID of the player.
*/
private String id; private String id;
private String name;
public MojangApiProfile() {} /**
* The name of the player.
*/
private String name;
/** /**
* Check if the profile is valid. * Check if the profile is valid.

@ -1,9 +1,9 @@
package cc.fascinated.player; package cc.fascinated.service.player;
import cc.fascinated.mojang.MojangAPIService; import cc.fascinated.service.mojang.MojangAPIService;
import cc.fascinated.mojang.types.MojangApiProfile; import cc.fascinated.service.mojang.types.MojangProfile;
import cc.fascinated.mojang.types.MojangSessionServerProfile; import cc.fascinated.service.mojang.types.MojangUsernameToUuid;
import cc.fascinated.player.impl.Player; import cc.fascinated.service.player.impl.Player;
import cc.fascinated.util.UUIDUtils; import cc.fascinated.util.UUIDUtils;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import net.jodah.expiringmap.ExpirationPolicy; import net.jodah.expiringmap.ExpirationPolicy;
@ -47,25 +47,28 @@ public class PlayerService {
*/ */
public Player getPlayer(String id) { public Player getPlayer(String id) {
UUID uuid = null; UUID uuid = null;
if (id.length() == 32 || id.length() == 36) { if (id.length() == 32 || id.length() == 36) { // Check if the id is a UUID
try { try {
uuid = UUID.fromString(id.length() == 32 ? UUIDUtils.addUUIDDashes(id) : id); uuid = UUID.fromString(id.length() == 32 ? UUIDUtils.addUUIDDashes(id) : id);
} catch (Exception ignored) {} } catch (Exception ignored) {}
} else { } else { // Check if the id is a name
uuid = playerNameToUUIDCache.get(id.toUpperCase()); uuid = playerNameToUUIDCache.get(id.toUpperCase());
} }
// Check if the player is cached
if (uuid != null && players.containsKey(uuid)) { if (uuid != null && players.containsKey(uuid)) {
return players.get(uuid); return players.get(uuid);
} }
MojangSessionServerProfile profile = uuid == null ? null : mojangAPIService.getSessionServerProfile(uuid.toString()); MojangProfile profile = uuid == null ? null : mojangAPIService.getProfile(uuid.toString());
if (profile == null) { if (profile == null) { // The player cannot be found using their UUID
MojangApiProfile apiProfile = mojangAPIService.getApiProfile(id); MojangUsernameToUuid apiProfile = mojangAPIService.getUuidFromUsername(id); // Get the UUID of the player using their name
if (apiProfile == null || !apiProfile.isValid()) { if (apiProfile == null || !apiProfile.isValid()) {
return null; return null;
} }
profile = mojangAPIService.getSessionServerProfile(apiProfile.getId().length() == 32 ? UUIDUtils.addUUIDDashes(apiProfile.getId()) : apiProfile.getId()); // Get the profile of the player using their UUID
profile = mojangAPIService.getProfile(apiProfile.getId().length() == 32 ?
UUIDUtils.addUUIDDashes(apiProfile.getId()) : apiProfile.getId());
} }
if (profile == null) { // The player cannot be found using their name or UUID if (profile == null) { // The player cannot be found using their name or UUID
log.info("Player with id {} could not be found", id); log.info("Player with id {} could not be found", id);

@ -1,4 +1,4 @@
package cc.fascinated.player.impl; package cc.fascinated.service.player.impl;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;

@ -0,0 +1,50 @@
package cc.fascinated.service.player.impl;
import cc.fascinated.service.mojang.types.MojangProfile;
import cc.fascinated.util.Tuple;
import cc.fascinated.util.UUIDUtils;
import lombok.Getter;
import java.util.UUID;
@Getter
public class Player {
/**
* The UUID of the player
*/
private final UUID uuid;
/**
* The name of the player
*/
private final String name;
/**
* The skin of the player
* <p>
* This will be null if the player does not have a skin.
* </p>
*/
private Skin skin;
/**
* The cape of the player
* <p>
* This will be null if the player does not have a cape.
* </p>
*/
private Cape cape;
public Player(MojangProfile profile) {
this.uuid = UUID.fromString(UUIDUtils.addUUIDDashes(profile.getId()));
this.name = profile.getName();
// Get the skin and cape
Tuple<Skin, Cape> skinAndCape = profile.getSkinAndCape();
if (skinAndCape != null) {
this.skin = skinAndCape.getLeft();
this.cape = skinAndCape.getRight();
}
}
}

@ -1,4 +1,4 @@
package cc.fascinated.player.impl; package cc.fascinated.service.player.impl;
import cc.fascinated.Main; import cc.fascinated.Main;
import cc.fascinated.config.Config; import cc.fascinated.config.Config;

@ -1,4 +1,4 @@
package cc.fascinated.player.impl; package cc.fascinated.service.player.impl;
import lombok.Getter; import lombok.Getter;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;

@ -0,0 +1,18 @@
package cc.fascinated.util;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter @AllArgsConstructor
public class Tuple<L, R> {
/**
* The left value of the tuple.
*/
private final L left;
/**
* The right value of the tuple.
*/
private final R right;
}

@ -1,5 +1,8 @@
package cc.fascinated.util; package cc.fascinated.util;
import lombok.experimental.UtilityClass;
@UtilityClass
public class UUIDUtils { public class UUIDUtils {
/** /**

@ -1,10 +1,12 @@
package cc.fascinated.util; package cc.fascinated.util;
import lombok.experimental.UtilityClass;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClient; import org.springframework.web.client.RestClient;
@UtilityClass
public class WebRequest { public class WebRequest {
/** /**

@ -19,8 +19,7 @@
<p>Wrapper for the Minecraft APIs to make them easier to use.</p> <p>Wrapper for the Minecraft APIs to make them easier to use.</p>
<div class="flex flex-col mt-3"> <div class="flex flex-col mt-3">
<p>Player Data: <a class="text-blue-600" th:href="${url}" th:text="${url}">???</a></p> <p>Player Data: <a class="text-blue-600" th:href="${player_example_url}" th:text="${player_example_url}">???</a></p>
<p>Avatar Url: <a class="text-blue-600" th:href="${avatar_url}" th:text="${avatar_url}">???</a></p>
</div> </div>
</body> </body>
</html> </html>