Skip to content

Commit de8bd93

Browse files
committed
add PaperSkullHandler
1 parent 9ac2e83 commit de8bd93

File tree

4 files changed

+137
-8
lines changed

4 files changed

+137
-8
lines changed

spigot/skull/pom.xml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@
1717
<id>minecraft-repo</id>
1818
<url>https://libraries.minecraft.net/</url>
1919
</repository>
20+
<repository>
21+
<id>papermc</id>
22+
<url>https://repo.papermc.io/repository/maven-public/</url>
23+
</repository>
2024
</repositories>
2125

2226
<dependencies>
2327
<dependency>
24-
<groupId>org.spigotmc</groupId>
25-
<artifactId>spigot-api</artifactId>
26-
<version>1.18.2-R0.1-20220607.160742-53</version>
28+
<groupId>io.papermc.paper</groupId>
29+
<artifactId>paper-api</artifactId>
30+
<version>1.18.2-R0.1-20220920.010157-167</version>
2731
<scope>provided</scope>
2832
</dependency>
2933
<dependency>

spigot/skull/src/main/java/io/github/projectunified/craftitem/spigot/skull/NewSkullHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
* </ul>
3131
*/
3232
class NewSkullHandler implements SkullHandler {
33+
private final Gson gson = new Gson();
3334
private final Map<String, PlayerProfile> profileMap = new ConcurrentHashMap<>();
3435

3536
/**
@@ -78,7 +79,7 @@ public void setSkullByURL(SkullMeta meta, URL url) {
7879
public void setSkullByBase64(SkullMeta meta, String base64) {
7980
try {
8081
String decoded = new String(Base64.getDecoder().decode(base64), StandardCharsets.UTF_8);
81-
JsonObject json = new Gson().fromJson(decoded, JsonObject.class);
82+
JsonObject json = gson.fromJson(decoded, JsonObject.class);
8283
String url = json.getAsJsonObject("textures").getAsJsonObject("SKIN").get("url").getAsString();
8384
setSkullByURL(meta, url);
8485
} catch (Exception e) {
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package io.github.projectunified.craftitem.spigot.skull;
2+
3+
import com.destroystokyo.paper.profile.PlayerProfile;
4+
import com.destroystokyo.paper.profile.ProfileProperty;
5+
import org.bukkit.Bukkit;
6+
import org.bukkit.OfflinePlayer;
7+
import org.bukkit.inventory.meta.SkullMeta;
8+
9+
import java.net.URL;
10+
import java.util.Base64;
11+
import java.util.Map;
12+
import java.util.UUID;
13+
import java.util.concurrent.ConcurrentHashMap;
14+
15+
/**
16+
* Skull handler for Paper servers using the Paper-specific PlayerProfile API.
17+
*
18+
* <p>Uses Paper's faster PlayerProfile implementation compared to Bukkit's standard API.
19+
* Caches PlayerProfile instances to avoid recreation for repeated textures.
20+
*
21+
* <p><strong>Implementation Details:</strong>
22+
* <ul>
23+
* <li>Uses Bukkit.createProfile() to create profiles (Paper-optimized)</li>
24+
* <li>Uses ProfileProperty for direct property assignment</li>
25+
* <li>Caches profiles for performance optimization</li>
26+
* </ul>
27+
*/
28+
public class PaperSkullHandler implements SkullHandler {
29+
private final Map<String, PlayerProfile> profileMap = new ConcurrentHashMap<>();
30+
31+
/**
32+
* Sets a PlayerProfile on the SkullMeta.
33+
*
34+
* @param meta the SkullMeta to modify
35+
* @param profile the PlayerProfile with texture data
36+
*/
37+
private void setSkull(SkullMeta meta, PlayerProfile profile) {
38+
meta.setPlayerProfile(profile);
39+
}
40+
41+
/**
42+
* Sets skull texture using an OfflinePlayer.
43+
* Results are cached to avoid recreating profiles for the same player.
44+
*
45+
* @param meta the SkullMeta to modify
46+
* @param player the OfflinePlayer
47+
*/
48+
@Override
49+
public void setSkullByPlayer(SkullMeta meta, OfflinePlayer player) {
50+
PlayerProfile profile = profileMap.computeIfAbsent(player.getUniqueId().toString(), s -> Bukkit.createProfile(player.getUniqueId()));
51+
setSkull(meta, profile);
52+
}
53+
54+
/**
55+
* Sets skull texture from a URL using the PlayerProfile API.
56+
* Results are cached to avoid recreating profiles for the same URL.
57+
*
58+
* @param meta the SkullMeta to modify
59+
* @param url the texture URL
60+
*/
61+
@Override
62+
public void setSkullByURL(SkullMeta meta, URL url) {
63+
PlayerProfile profile = profileMap.computeIfAbsent(url.toString(), url1 -> {
64+
PlayerProfile playerProfile = Bukkit.createProfile(UUID.randomUUID());
65+
playerProfile.setProperty(new ProfileProperty("textures",
66+
Base64.getEncoder().encodeToString(
67+
String.format("{\"textures\":{\"SKIN\":{\"url\":\"%s\"}}}", url1).getBytes()
68+
)
69+
));
70+
return playerProfile;
71+
});
72+
setSkull(meta, profile);
73+
}
74+
75+
/**
76+
* Sets skull texture from Base64-encoded texture data.
77+
* Results are cached to avoid recreating profiles for the same Base64 string.
78+
*
79+
* @param meta the SkullMeta to modify
80+
* @param base64 the Base64-encoded texture data
81+
*/
82+
@Override
83+
public void setSkullByBase64(SkullMeta meta, String base64) {
84+
PlayerProfile profile = profileMap.computeIfAbsent(base64, b -> {
85+
PlayerProfile playerProfile = Bukkit.createProfile(UUID.randomUUID());
86+
playerProfile.setProperty(new ProfileProperty("textures", base64));
87+
return playerProfile;
88+
});
89+
setSkull(meta, profile);
90+
}
91+
92+
/**
93+
* Extracts the skull texture value (Base64 data) from SkullMeta.
94+
* Searches for the textures property in the PlayerProfile.
95+
*
96+
* @param meta the SkullMeta to query
97+
* @return the Base64 texture value, or empty string if not found
98+
*/
99+
@Override
100+
public String getSkullValue(SkullMeta meta) {
101+
PlayerProfile profile = meta.getPlayerProfile();
102+
if (profile == null) {
103+
return "";
104+
}
105+
106+
ProfileProperty texturesProperty = null;
107+
for (ProfileProperty property : profile.getProperties()) {
108+
if (property.getName().equalsIgnoreCase("textures")) {
109+
texturesProperty = property;
110+
break;
111+
}
112+
}
113+
if (texturesProperty == null) {
114+
return "";
115+
}
116+
117+
return texturesProperty.getValue();
118+
}
119+
}

spigot/skull/src/main/java/io/github/projectunified/craftitem/spigot/skull/SkullModifier.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,15 @@ public SkullModifier(String skullString) {
4646

4747
private static SkullHandler getSkullHandler() {
4848
try {
49-
Class.forName("org.bukkit.profile.PlayerProfile");
50-
return new NewSkullHandler();
51-
} catch (ClassNotFoundException e) {
52-
return new OldSkullHandler();
49+
Class.forName("com.destroystokyo.paper.profile.PlayerProfile");
50+
return new PaperSkullHandler();
51+
} catch (Exception e1) {
52+
try {
53+
Class.forName("org.bukkit.profile.PlayerProfile");
54+
return new NewSkullHandler();
55+
} catch (Exception e2) {
56+
return new OldSkullHandler();
57+
}
5358
}
5459
}
5560

0 commit comments

Comments
 (0)