-
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: Recode SkullItemCreator to not use XSeries's XSkull class
XSkull is having a couple of issues and just throwing exceptions for a couple of people. No fix in sight etc. so let's get rid of it and have our own implementation.
- Loading branch information
Showing
30 changed files
with
561 additions
and
28 deletions.
There are no files selected for viewing
102 changes: 74 additions & 28 deletions
102
Core/src/main/java/com/craftaro/core/utils/SkullItemCreator.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,104 @@ | ||
package com.craftaro.core.utils; | ||
|
||
import com.craftaro.core.nms.Nms; | ||
import com.cryptomorin.xseries.profiles.builder.XSkull; | ||
import com.cryptomorin.xseries.profiles.objects.ProfileInputType; | ||
import com.cryptomorin.xseries.profiles.objects.Profileable; | ||
import org.bukkit.Bukkit; | ||
import com.craftaro.core.nms.entity.player.GameProfile; | ||
import com.cryptomorin.xseries.XMaterial; | ||
import org.bukkit.entity.Player; | ||
import org.bukkit.inventory.ItemStack; | ||
import org.bukkit.inventory.meta.SkullMeta; | ||
|
||
import java.lang.reflect.Field; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.util.Objects; | ||
import java.util.UUID; | ||
|
||
public final class SkullItemCreator { | ||
private static final String STEVE_TEXTURE = "ewogICJ0aW1lc3RhbXAiIDogMTYyMTcxNTMxMjI5MCwKICAicHJvZmlsZUlkIiA6ICJiNTM5NTkyMjMwY2I0MmE0OWY5YTRlYmYxNmRlOTYwYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJtYXJpYW5hZmFnIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzFhNGFmNzE4NDU1ZDRhYWI1MjhlN2E2MWY4NmZhMjVlNmEzNjlkMTc2OGRjYjEzZjdkZjMxOWE3MTNlYjgxMGIiCiAgICB9CiAgfQp9"; | ||
private static final String ALEX_TEXTURE = "rZvLQoZsgLYaoKqEuASopYAs7IAlZlsGkwagoM8ZX38cP9kalseZrWY5OHZVfoiftdQJ+lGOzkiFfyx6kNJDTZniLrnRa8sd3X6D65ZihT1sOm/RInCwxpS1K0zGCM2h9ErkWswfwaviIf7hJtrwk8/zL0bfzDk2IgX/IBvIZpVoYTfmQsVY9jgSwORrS9ObePGIfFgmThMoZnCYWQMVpS2+yTFA2wnw9hmisQK9UWBU+iBZv55bMmkMcyEuXw1w14DaEu+/M0UGD91LU4GmJLPA9T4GCuIV8GxOcraSVIajki1cMlOBQwIaibB2NE6KAwq1Zh6NnsNYucy6qFM+136lXfBchQ1Nx4FDRZQgt8VRqTMy/OQFpr2nTbWWbRU4gRFpKC3R0518DqUH0Qm612kPWniKku/QzUUBSe1PSVljBaZCyyRx0OB1a1/8MexboKRnPXuTDnmPa9UPfuH4VO0q+qYkjV2KUzP6e5vIP5aQ6USPrMie7MmAHFJzwAMIbLjgkTVx91GWtYqg/t7qBlvrdBRLIPPsy/DSOqa+2+4hABouVCPZrBMCMLzstPPQoqZAyiCqcKb2HqWSU0h9Bhx19yoIcbHCeI3zsQs8PqIBjUL4mO6VQT4lzHy0e3M61Xsdd8S1GtsakSetTvEtMdUwCEDfBA5PRRTLOVYTY+g="; | ||
|
||
public static ItemStack byPlayer(Player player) { | ||
if (Bukkit.getOnlineMode()) { | ||
return XSkull.createItem().profile(new Profileable.PlayerProfileable(player)).apply(); | ||
} | ||
|
||
String textureValue = Nms.getImplementations().getPlayer().getProfile(player).getTextureValue(); | ||
if (textureValue != null) { | ||
return byTextureValue(textureValue); | ||
} | ||
public static ItemStack byProfile(GameProfile profile) { | ||
ItemStack item = Objects.requireNonNull(XMaterial.PLAYER_HEAD.parseItem()); | ||
SkullMeta meta = (SkullMeta) Objects.requireNonNull(item.getItemMeta()); | ||
applyProfile(meta, profile); | ||
item.setItemMeta(meta); | ||
return item; | ||
} | ||
|
||
return createDefaultSkull(player.getUniqueId()); | ||
public static ItemStack byPlayer(Player player) { | ||
return byProfile(Nms.getImplementations().getPlayer().getProfile(player)); | ||
} | ||
|
||
public static ItemStack byUuid(UUID uuid) { | ||
return XSkull.createItem().profile(new Profileable.UUIDProfileable(uuid)).apply(); | ||
public static ItemStack byTextureValue(String textureValue) { | ||
return byProfile(Nms.getImplementations().getPlayer().createProfileByTextureValue(textureValue)); | ||
} | ||
|
||
public static ItemStack byUsername(String username) { | ||
return XSkull.createItem().profile(new Profileable.StringProfileable(username, ProfileInputType.USERNAME)).apply(); | ||
public static ItemStack byTextureUrl(String textureUrl) { | ||
return byProfile(Nms.getImplementations().getPlayer().createProfileByUrl(textureUrl)); | ||
} | ||
|
||
public static ItemStack byTextureValue(String textureValue) { | ||
return XSkull.createItem().profile(new Profileable.StringProfileable(textureValue, ProfileInputType.BASE64)).apply(); | ||
public static ItemStack byTextureUrlHash(String textureUrlHash) { | ||
return byTextureUrl("https://textures.minecraft.net/texture/" + textureUrlHash); | ||
} | ||
|
||
public static ItemStack byTextureUrl(String textureUrl) { | ||
return XSkull.createItem().profile(new Profileable.StringProfileable(textureUrl, ProfileInputType.TEXTURE_URL)).apply(); | ||
public static ItemStack createSteve() { | ||
return byTextureValue(STEVE_TEXTURE); | ||
} | ||
|
||
public static ItemStack byTextureHash(String textureHash) { | ||
return XSkull.createItem().profile(new Profileable.StringProfileable(textureHash, ProfileInputType.TEXTURE_HASH)).apply(); | ||
public static ItemStack createAlex() { | ||
return byTextureValue(ALEX_TEXTURE); | ||
} | ||
|
||
private static ItemStack createDefaultSkull(UUID uuid) { | ||
String textureValue = STEVE_TEXTURE; | ||
public static ItemStack createDefaultSkullForUuid(UUID uuid) { | ||
if ((uuid.hashCode() & 1) != 0) { | ||
textureValue = ALEX_TEXTURE; | ||
return byTextureValue(ALEX_TEXTURE); | ||
} | ||
return byTextureValue(STEVE_TEXTURE); | ||
} | ||
|
||
private static Method skullMetaSetProfile = null; | ||
private static Field skullMetaProfileField = null; | ||
private static boolean setProfileUsesResolvable = false; | ||
|
||
private static void applyProfile(SkullMeta skullMeta, GameProfile profile) { | ||
if (skullMetaSetProfile == null && profile.getMojangResolvableGameProfile() != null) { | ||
try { | ||
skullMetaSetProfile = skullMeta.getClass().getDeclaredMethod("setProfile", profile.getMojangResolvableGameProfile().getClass()); | ||
skullMetaSetProfile.setAccessible(true); | ||
setProfileUsesResolvable = true; | ||
} catch (ReflectiveOperationException ignored) { | ||
} | ||
} | ||
if (skullMetaSetProfile == null) { | ||
try { | ||
skullMetaSetProfile = skullMeta.getClass().getDeclaredMethod("setProfile", profile.getMojangGameProfile().getClass()); | ||
skullMetaSetProfile.setAccessible(true); | ||
} catch (ReflectiveOperationException ignored) { | ||
} | ||
} | ||
|
||
return XSkull.createItem().profile(new Profileable.StringProfileable(textureValue, ProfileInputType.BASE64)).apply(); | ||
if (skullMetaSetProfile != null) { | ||
try { | ||
skullMetaSetProfile.invoke(skullMeta, setProfileUsesResolvable ? profile.getMojangResolvableGameProfile() : profile.getMojangGameProfile()); | ||
} catch (IllegalAccessException | InvocationTargetException ex) { | ||
throw new RuntimeException(ex); | ||
} | ||
return; | ||
} | ||
|
||
if (skullMetaProfileField == null) { | ||
try { | ||
skullMetaProfileField = skullMeta.getClass().getDeclaredField("profile"); | ||
skullMetaProfileField.setAccessible(true); | ||
} catch (ReflectiveOperationException ex) { | ||
throw new RuntimeException("Unable to find compatible #setProfile method or profile field", ex); | ||
} | ||
} | ||
|
||
try { | ||
skullMetaProfileField.set(skullMeta, profile.getMojangGameProfile()); | ||
} catch (IllegalAccessException | IllegalArgumentException ex) { | ||
throw new RuntimeException("Encountered an error while setting the profile field", ex); | ||
} | ||
} | ||
} |
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
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
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
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
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
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
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
Oops, something went wrong.