11package me .hsgamer .bettergui .modifier ;
22
3- import com .google .gson .Gson ;
4- import com .google .gson .JsonObject ;
5- import com .mojang .authlib .GameProfile ;
6- import com .mojang .authlib .properties .Property ;
3+ import io .github .projectunified .craftitem .spigot .skull .handler .SkullHandler ;
74import me .hsgamer .hscore .bukkit .item .modifier .ItemMetaModifier ;
8- import me .hsgamer .hscore .bukkit .utils .VersionUtils ;
95import me .hsgamer .hscore .common .StringReplacer ;
10- import me .hsgamer .hscore .common .Validate ;
11- import org .bukkit .Bukkit ;
12- import org .bukkit .Material ;
13- import org .bukkit .OfflinePlayer ;
14- import org .bukkit .inventory .ItemStack ;
156import org .bukkit .inventory .meta .ItemMeta ;
167import org .bukkit .inventory .meta .SkullMeta ;
17- import org .bukkit .profile .PlayerProfile ;
18- import org .bukkit .profile .PlayerTextures ;
198import org .jetbrains .annotations .NotNull ;
209import org .jetbrains .annotations .Nullable ;
2110
22- import java .lang .reflect .Field ;
23- import java .lang .reflect .Method ;
24- import java .net .URL ;
25- import java .nio .charset .StandardCharsets ;
26- import java .util .*;
27- import java .util .concurrent .ConcurrentHashMap ;
28- import java .util .regex .Pattern ;
11+ import java .util .UUID ;
2912
30- /**
31- * This is a legacy modifier that was removed from HSCore.
32- * I decide to keep it here for compatibility.
33- */
34- @ SuppressWarnings ("deprecation" )
3513public class SkullModifier implements ItemMetaModifier {
36- /**
37- * <a href="https://github.com/CryptoMorin/XSeries/blob/b633d00608435701f1045a566b98a81edd5f923c/src/main/java/com/cryptomorin/xseries/profiles/objects/ProfileInputType.java#L29C35-L29C50">...</a>
38- */
39- private static final Pattern MOJANG_SHA256_APPROX_PATTERN = Pattern .compile ("[0-9a-z]{55,70}" );
40- /**
41- * <a href="https://github.com/CryptoMorin/XSeries/blob/b11b176deca55da6d465e67a3d4be548c3ef06c6/src/main/java/com/cryptomorin/xseries/profiles/objects/ProfileInputType.java#L55C12-L55C57">...</a>
42- */
43- private static final Pattern BASE64_PATTERN = Pattern .compile ("[-A-Za-z0-9+/]{100,}={0,3}" );
44- private static final SkullMeta delegateSkullMeta ;
45- private static final SkullHandler skullHandler = getSkullHandler ();
46-
47- static {
48- ItemStack itemStack ;
49- if (VersionUtils .isAtLeast (13 )) {
50- itemStack = new ItemStack (Material .valueOf ("PLAYER_HEAD" ));
51- } else {
52- itemStack = new ItemStack (Material .valueOf ("SKULL_ITEM" ));
53- itemStack .setDurability ((short ) 3 );
54- }
55- delegateSkullMeta = (SkullMeta ) Objects .requireNonNull (itemStack .getItemMeta ());
56- }
14+ private static final SkullHandler skullHandler = SkullHandler .getInstance ();
5715
5816 private String skullString = "" ;
5917
60- private static SkullHandler getSkullHandler () {
61- try {
62- Class .forName ("org.bukkit.profile.PlayerProfile" );
63- return new NewSkullHandler ();
64- } catch (ClassNotFoundException e ) {
65- return new OldSkullHandler ();
66- }
67- }
68-
69- private static void setSkull (SkullMeta meta , String skull ) {
70- Optional <URL > url = Validate .getURL (skull );
71- if (url .isPresent ()) {
72- skullHandler .setSkullByURL (meta , url .get ());
73- return ;
74- }
75-
76- if (MOJANG_SHA256_APPROX_PATTERN .matcher (skull ).matches ()) {
77- skullHandler .setSkullByURL (meta , "https://textures.minecraft.net/texture/" + skull );
78- return ;
79- }
80-
81- if (BASE64_PATTERN .matcher (skull ).matches ()) {
82- skullHandler .setSkullByBase64 (meta , skull );
83- return ;
84- }
85-
86- Optional <UUID > uuid = Validate .getUUID (skull );
87- if (uuid .isPresent ()) {
88- skullHandler .setSkullByUUID (meta , uuid .get ());
89- return ;
90- }
91-
92- skullHandler .setSkullByName (meta , skull );
93- }
94-
95- private static SkullMeta getSkullMeta (String skull ) {
96- SkullMeta meta = delegateSkullMeta .clone ();
97- setSkull (meta , skull );
98- return meta ;
99- }
100-
10118 @ Override
10219 public @ NotNull ItemMeta modifyMeta (@ NotNull ItemMeta meta , @ Nullable UUID uuid , @ NotNull StringReplacer stringReplacer ) {
103- if (!( meta instanceof SkullMeta )) {
104- return meta ;
20+ if (meta instanceof SkullMeta && ! skullString . isEmpty ( )) {
21+ skullHandler . setSkull (( SkullMeta ) meta , stringReplacer . replaceOrOriginal ( skullString , uuid )) ;
10522 }
106- setSkull ((SkullMeta ) meta , stringReplacer .replaceOrOriginal (skullString , uuid ));
10723 return meta ;
10824 }
10925
@@ -125,177 +41,4 @@ public Object toObject() {
12541 public void loadFromObject (Object object ) {
12642 this .skullString = String .valueOf (object );
12743 }
128-
129- private interface SkullHandler {
130- @ SuppressWarnings ("deprecation" )
131- default void setSkullByName (SkullMeta meta , String name ) {
132- setSkullByPlayer (meta , Bukkit .getOfflinePlayer (name ));
133- }
134-
135- default void setSkullByUUID (SkullMeta meta , UUID uuid ) {
136- setSkullByPlayer (meta , Bukkit .getOfflinePlayer (uuid ));
137- }
138-
139- void setSkullByPlayer (SkullMeta meta , OfflinePlayer player );
140-
141- void setSkullByURL (SkullMeta meta , URL url );
142-
143- default void setSkullByURL (SkullMeta meta , String url ) {
144- try {
145- setSkullByURL (meta , new URL (url ));
146- } catch (Exception e ) {
147- throw new RuntimeException (e );
148- }
149- }
150-
151- void setSkullByBase64 (SkullMeta meta , String base64 );
152-
153- String getSkullValue (SkullMeta meta );
154- }
155-
156- private static class OldSkullHandler implements SkullHandler {
157- private final Map <String , GameProfile > cache = new ConcurrentHashMap <>();
158- private final Method getProfileMethod ;
159-
160- private OldSkullHandler () {
161- Method method = null ;
162- try {
163- //noinspection JavaReflectionMemberAccess
164- method = Property .class .getDeclaredMethod ("value" );
165- } catch (Exception e ) {
166- try {
167- //noinspection JavaReflectionMemberAccess
168- method = Property .class .getDeclaredMethod ("getValue" );
169- } catch (NoSuchMethodException ex ) {
170- // IGNORE
171- }
172- }
173- getProfileMethod = method ;
174- }
175-
176- @ SuppressWarnings ("deprecation" )
177- @ Override
178- public void setSkullByPlayer (SkullMeta meta , OfflinePlayer player ) {
179- if (VersionUtils .isAtLeast (12 )) {
180- meta .setOwningPlayer (player );
181- } else {
182- meta .setOwner (player .getName ());
183- }
184- }
185-
186- private void setSkullByGameProfile (SkullMeta meta , GameProfile profile ) {
187- try {
188- Method setProfile = meta .getClass ().getMethod ("setProfile" , GameProfile .class );
189- setProfile .setAccessible (true );
190- setProfile .invoke (meta , profile );
191- } catch (Exception e ) {
192- try {
193- Field profileField = meta .getClass ().getDeclaredField ("profile" );
194- profileField .setAccessible (true );
195- profileField .set (meta , profile );
196- } catch (Exception ignored ) {
197- // IGNORE
198- }
199- }
200- }
201-
202- @ Override
203- public void setSkullByURL (SkullMeta meta , URL url ) {
204- GameProfile profile = cache .computeIfAbsent (url .toString (), url1 -> {
205- GameProfile gameProfile = new GameProfile (UUID .randomUUID (), "" );
206- gameProfile .getProperties ().put ("textures" , new Property ("textures" , Base64 .getEncoder ().encodeToString (String .format ("{textures:{SKIN:{url:\" %s\" }}}" , url1 ).getBytes ())));
207- return gameProfile ;
208- });
209- setSkullByGameProfile (meta , profile );
210- }
211-
212- @ Override
213- public void setSkullByBase64 (SkullMeta meta , String base64 ) {
214- GameProfile gameProfile = cache .computeIfAbsent (base64 , b -> {
215- GameProfile profile = new GameProfile (UUID .randomUUID (), "" );
216- profile .getProperties ().put ("textures" , new Property ("textures" , b ));
217- return profile ;
218- });
219- setSkullByGameProfile (meta , gameProfile );
220- }
221-
222- @ Override
223- public String getSkullValue (SkullMeta meta ) {
224- GameProfile profile ;
225- try {
226- Field profileField = meta .getClass ().getDeclaredField ("profile" );
227- profileField .setAccessible (true );
228- profile = (GameProfile ) profileField .get (meta );
229- } catch (Exception e ) {
230- return "" ;
231- }
232-
233- Collection <Property > properties = profile .getProperties ().get ("textures" );
234- if (properties == null || properties .isEmpty ()) {
235- return "" ;
236- }
237-
238- for (Property property : properties ) {
239- String value ;
240- try {
241- value = (String ) getProfileMethod .invoke (property );
242- } catch (Exception e ) {
243- continue ;
244- }
245-
246- if (!value .isEmpty ()) {
247- return value ;
248- }
249- }
250- return "" ;
251- }
252- }
253-
254- private static class NewSkullHandler implements SkullHandler {
255- private final Map <String , PlayerProfile > profileMap = new ConcurrentHashMap <>();
256-
257- @ Override
258- public void setSkullByPlayer (SkullMeta meta , OfflinePlayer player ) {
259- meta .setOwningPlayer (player );
260- }
261-
262- @ Override
263- public void setSkullByURL (SkullMeta meta , URL url ) {
264- PlayerProfile profile = profileMap .computeIfAbsent (url .toString (), u -> {
265- PlayerProfile newProfile = Bukkit .createPlayerProfile (UUID .randomUUID (), "" );
266- PlayerTextures textures = newProfile .getTextures ();
267- textures .setSkin (url );
268- return newProfile ;
269- });
270- meta .setOwnerProfile (profile );
271- }
272-
273- @ Override
274- public void setSkullByBase64 (SkullMeta meta , String base64 ) {
275- try {
276- String decoded = new String (Base64 .getDecoder ().decode (base64 ), StandardCharsets .UTF_8 );
277- JsonObject json = new Gson ().fromJson (decoded , JsonObject .class );
278- String url = json .getAsJsonObject ("textures" ).getAsJsonObject ("SKIN" ).get ("url" ).getAsString ();
279- setSkullByURL (meta , url );
280- } catch (Exception e ) {
281- throw new RuntimeException (e );
282- }
283- }
284-
285- @ Override
286- public String getSkullValue (SkullMeta meta ) {
287- PlayerProfile profile = meta .getOwnerProfile ();
288- if (profile == null ) {
289- return "" ;
290- }
291-
292- PlayerTextures textures = profile .getTextures ();
293- URL url = textures .getSkin ();
294- if (url == null ) {
295- return "" ;
296- }
297-
298- return url .toString ();
299- }
300- }
30144}
0 commit comments