Skip to content

Commit

Permalink
Added the ability to fetch heads directly from minecraft-heads.com wi…
Browse files Browse the repository at this point in the history
…thout needing the texture value
  • Loading branch information
OmerBenGera committed Jun 23, 2023
1 parent fda6b28 commit 42919af
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 2 deletions.
Expand Up @@ -77,7 +77,7 @@ public ItemBuilder asSkullOf(SuperiorPlayer superiorPlayer) {

public ItemBuilder asSkullOf(String textureValue) {
if (itemStack.getType() == Materials.PLAYER_HEAD.toBukkitType())
this.textureValue = textureValue;
this.textureValue = ItemSkulls.parseTexture(textureValue);
return this;
}

Expand Down
Expand Up @@ -2,7 +2,9 @@

import com.bgsoftware.common.config.CommentedConfiguration;
import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;
import com.bgsoftware.superiorskyblock.core.LazyReference;
import com.bgsoftware.superiorskyblock.core.ServerVersion;
import com.bgsoftware.superiorskyblock.core.itemstack.heads.MinecraftHeadsClient;
import com.bgsoftware.superiorskyblock.core.logging.Log;
import com.bgsoftware.superiorskyblock.core.serialization.Serializers;
import com.bgsoftware.superiorskyblock.tag.CompoundTag;
Expand All @@ -21,6 +23,12 @@ public class ItemSkulls {

private static final String NULL_PLAYER_TEXTURE = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmFkYzA0OGE3Y2U3OGY3ZGFkNzJhMDdkYTI3ZDg1YzA5MTY4ODFlNTUyMmVlZWQxZTNkYWYyMTdhMzhjMWEifX19";
private static final Map<String, String> entitySkullTextures = new HashMap<>();
private static final LazyReference<MinecraftHeadsClient> minecraftHeadsClient = new LazyReference<MinecraftHeadsClient>() {
@Override
protected MinecraftHeadsClient create() {
return new MinecraftHeadsClient();
}
};

private ItemSkulls() {

Expand All @@ -44,7 +52,7 @@ public static void readTextures(SuperiorSkyblockPlugin plugin) {
}

for (String entityType : cfg.getConfigurationSection("").getKeys(false))
entitySkullTextures.put(entityType, cfg.getString(entityType));
entitySkullTextures.put(entityType, parseTexture(cfg.getString(entityType)));
}

public static ItemStack getPlayerHead(ItemStack itemStack, String texture) {
Expand Down Expand Up @@ -88,4 +96,10 @@ public static String getTexture(String entityType) {
return entitySkullTextures.getOrDefault(entityType, "");
}

public static String parseTexture(String texture) {
return MinecraftHeadsClient.getMinecraftHeadsTextureId(texture)
.map(textureId -> minecraftHeadsClient.get().getTexture(textureId))
.orElse(texture);
}

}
@@ -0,0 +1,74 @@
package com.bgsoftware.superiorskyblock.core.itemstack.heads;

import com.bgsoftware.superiorskyblock.core.DynamicArray;
import com.bgsoftware.superiorskyblock.core.logging.Log;

import javax.annotation.Nullable;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MinecraftHeadsClient {

private static final Pattern MINECRAFT_HEADS_PATTERN = Pattern.compile("minecraft-heads:(\\d+)");
private static final int EXPECTED_HEADS_SIZE = 50_000;
private static final String MINECRAFT_HEADS_DATABASE_URL = "https://minecraft-heads.com/csv/2020-01-31-IUgRbJoHRbVhjKnOlkmH/Custom-Head-DB.csv";

public static Optional<Integer> getMinecraftHeadsTextureId(String texture) {
Matcher matcher = MINECRAFT_HEADS_PATTERN.matcher(texture);
return matcher.matches() ? Optional.of(Integer.parseInt(matcher.group(1))) : Optional.empty();
}

private final List<String> cachedHeads;

public MinecraftHeadsClient() {
this.cachedHeads = fetchHeadsDatabase();
}

@Nullable
public String getTexture(int id) {
int index = id - 1;
return index < cachedHeads.size() ? cachedHeads.get(index) : null;
}

private static List<String> fetchHeadsDatabase() {
DynamicArray<String> heads = new DynamicArray<>(EXPECTED_HEADS_SIZE);
boolean addedAnyHead = false;

try {
URLConnection connection = new URL(MINECRAFT_HEADS_DATABASE_URL).openConnection();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
String texture;
while ((texture = reader.readLine()) != null) {
String[] textureSegments = texture.split(";");
if (textureSegments.length >= 4) {
int id;
try {
id = Integer.parseInt(textureSegments[1]);
} catch (NumberFormatException ignored) {
continue;
}
String textureValue = textureSegments[3];
String textureUrl = "{\"textures\":{\"SKIN\":{\"url\":\"http://textures.minecraft.net/texture/" + textureValue + "\"}}}";
heads.set(id - 1, Base64.getEncoder().encodeToString(textureUrl.getBytes(StandardCharsets.UTF_8)));
addedAnyHead = true;
}
}
}
} catch (Exception error) {
Log.error(error, "Failed to obtain heads from minecraft-heads:");
}

return addedAnyHead ? heads.toList() : Collections.emptyList();
}

}

0 comments on commit 42919af

Please sign in to comment.