JackOUT

Untitled

Feb 4th, 2023
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.09 KB | None | 0 0
  1. package games.coob.laserturrets.util;
  2.  
  3. import lombok.AccessLevel;
  4. import lombok.NoArgsConstructor;
  5. import lombok.NonNull;
  6. import org.bukkit.Material;
  7. import org.bukkit.SkullType;
  8. import org.bukkit.block.Block;
  9. import org.bukkit.block.BlockFace;
  10. import org.bukkit.block.Skull;
  11. import org.bukkit.block.data.Rotatable;
  12. import org.bukkit.inventory.ItemStack;
  13. import org.bukkit.inventory.meta.SkullMeta;
  14. import org.mineacademy.fo.Common;
  15. import org.mineacademy.fo.MinecraftVersion;
  16. import org.mineacademy.fo.ReflectionUtil;
  17. import org.mineacademy.fo.Valid;
  18. import org.mineacademy.fo.remain.Remain;
  19.  
  20. import java.lang.reflect.Field;
  21. import java.lang.reflect.InvocationTargetException;
  22. import java.lang.reflect.Method;
  23. import java.net.URI;
  24. import java.net.URISyntaxException;
  25. import java.util.Base64;
  26. import java.util.UUID;
  27.  
  28. /**
  29.  * A library for the Bukkit API to create player skulls
  30.  * from names, base64 strings, and texture URLs.
  31.  * <p>
  32.  * Does not use any NMS code, and should work across all versions.
  33.  *
  34.  * @author Dean B on 12/28/2016.
  35.  */
  36. @NoArgsConstructor(access = AccessLevel.PRIVATE)
  37. public class SkullCreator {
  38.  
  39.     // some reflection stuff to be used when setting a skull's profile
  40.     private static Field blockProfileField;
  41.     private static Method metaSetProfileMethod;
  42.     private static Field metaProfileField;
  43.  
  44.     /**
  45.      * Creates a player skull, should work in both legacy and new Bukkit APIs.
  46.      *
  47.      * @return
  48.      */
  49.     public static ItemStack createSkull() {
  50.         try {
  51.             return new ItemStack(Material.valueOf("PLAYER_HEAD"));
  52.  
  53.         } catch (final IllegalArgumentException e) {
  54.             return new ItemStack(Material.valueOf("SKULL_ITEM"), 1, (byte) 3);
  55.         }
  56.     }
  57.  
  58.     /**
  59.      * Creates a player skull item with the skin based on a player's name.
  60.      *
  61.      * @param name The Player's name.
  62.      * @return The head of the Player.
  63.      */
  64.     public static ItemStack itemFromName(final String name) {
  65.         return itemWithName(createSkull(), name);
  66.     }
  67.  
  68.     /**
  69.      * Creates a player skull item with the skin based on a player's UUID.
  70.      *
  71.      * @param id The Player's UUID.
  72.      * @return The head of the Player.
  73.      */
  74.     public static ItemStack itemFromUuid(final UUID id) {
  75.         return itemWithUuid(createSkull(), id);
  76.     }
  77.  
  78.     /**
  79.      * Creates a player skull item with the skin at a Mojang URL.
  80.      *
  81.      * @param url The Mojang URL.
  82.      * @return The head of the Player.
  83.      */
  84.     public static ItemStack itemFromUrl(final String url) {
  85.         return itemWithUrl(createSkull(), url);
  86.     }
  87.  
  88.     /**
  89.      * Creates a player skull item with the skin based on a base64 string.
  90.      *
  91.      * @param base64 The Mojang URL.
  92.      * @return The head of the Player.
  93.      */
  94.     public static ItemStack itemFromBase64(final String base64) {
  95.         return itemWithBase64(createSkull(), base64);
  96.     }
  97.  
  98.     /**
  99.      * Modifies a skull to use the skin of the player with a given name.
  100.      *
  101.      * @param item The item to apply the name to. Must be a player skull.
  102.      * @param name The Player's name.
  103.      * @return The head of the Player.
  104.      */
  105.     public static ItemStack itemWithName(@NonNull final ItemStack item, @NonNull final String name) {
  106.         final SkullMeta meta = (SkullMeta) item.getItemMeta();
  107.  
  108.         meta.setOwner(name);
  109.         item.setItemMeta(meta);
  110.  
  111.         return item;
  112.     }
  113.  
  114.     /**
  115.      * Modifies a skull to use the skin of the player with a given UUID.
  116.      *
  117.      * @param item The item to apply the name to. Must be a player skull.
  118.      * @param id   The Player's UUID.
  119.      * @return The head of the Player.
  120.      */
  121.     public static ItemStack itemWithUuid(@NonNull final ItemStack item, @NonNull final UUID id) {
  122.         final SkullMeta meta = (SkullMeta) item.getItemMeta();
  123.  
  124.         try {
  125.             meta.setOwningPlayer(Remain.getOfflinePlayerByUUID(id));
  126.  
  127.         } catch (final Throwable t) {
  128.             meta.setOwner(Remain.getOfflinePlayerByUUID(id).getName());
  129.         }
  130.  
  131.         item.setItemMeta(meta);
  132.  
  133.         return item;
  134.     }
  135.  
  136.     /**
  137.      * Modifies a skull to use the skin at the given Mojang URL.
  138.      *
  139.      * @param item The item to apply the skin to. Must be a player skull.
  140.      * @param url  The URL of the Mojang skin.
  141.      * @return The head associated with the URL.
  142.      */
  143.     public static ItemStack itemWithUrl(@NonNull final ItemStack item, @NonNull final String url) {
  144.         return itemWithBase64(item, urlToBase64(url));
  145.     }
  146.  
  147.     /**
  148.      * Modifies a skull to use the skin based on the given base64 string.
  149.      *
  150.      * @param item   The ItemStack to put the base64 onto. Must be a player skull.
  151.      * @param base64 The base64 string containing the texture.
  152.      * @return The head with a custom texture.
  153.      */
  154.     public static ItemStack itemWithBase64(@NonNull final ItemStack item, @NonNull final String base64) {
  155.         if (!(item.getItemMeta() instanceof SkullMeta))
  156.             return null;
  157.  
  158.         final SkullMeta meta = (SkullMeta) item.getItemMeta();
  159.  
  160.         mutateItemMeta(meta, base64);
  161.  
  162.         item.setItemMeta(meta);
  163.  
  164.         return item;
  165.     }
  166.  
  167.     /**
  168.      * Modifies a skull meta to use the skin at the given Mojang URL.
  169.      *
  170.      * @param meta
  171.      * @param url  The URL of the Mojang skin.
  172.      * @return
  173.      */
  174.     public static SkullMeta metaWithUrl(@NonNull final SkullMeta meta, @NonNull final String url) {
  175.         final String base64 = urlToBase64(url);
  176.  
  177.         mutateItemMeta(meta, base64);
  178.  
  179.         return meta;
  180.     }
  181.  
  182.     /**
  183.      * Sets the block to a skull with the given UUID.
  184.      *
  185.      * @param block The block to set.
  186.      * @param id    The player to set it to.
  187.      */
  188.     public static void blockWithUuid(@NonNull final Block block, @NonNull final UUID id) {
  189.         setToSkull(block);
  190.  
  191.         final Skull state = (Skull) block.getState();
  192.         state.setRawData((byte) 0x1);
  193.  
  194.         try {
  195.             state.setOwningPlayer(Remain.getOfflinePlayerByUUID(id));
  196.  
  197.         } catch (final Throwable t) {
  198.             state.setOwner(Remain.getOfflinePlayerByUUID(id).getName());
  199.         }
  200.  
  201.         state.update(false, false);
  202.     }
  203.  
  204.     /**
  205.      * Sets the block to a skull with the skin found at the provided mojang URL.
  206.      *
  207.      * @param block The block to set.
  208.      * @param url   The mojang URL to set it to use.
  209.      */
  210.     public static void blockWithUrl(@NonNull final Block block, @NonNull final String url) {
  211.         blockWithBase64(block, urlToBase64(url));
  212.     }
  213.  
  214.     /**
  215.      * Sets the block to a skull with the skin for the base64 string.
  216.      *
  217.      * @param block  The block to set.
  218.      * @param base64 The base64 to set it to use.
  219.      */
  220.     public static void blockWithBase64(@NonNull final Block block, @NonNull final String base64) {
  221.         setToSkull(block);
  222.  
  223.         final Skull state = (Skull) block.getState();
  224.         mutateBlockState(state, base64);
  225.  
  226.         state.update(false, false);
  227.     }
  228.  
  229.     private static void setToSkull(final Block block) {
  230.  
  231.         try {
  232.             block.setType(Material.valueOf("PLAYER_HEAD"), false);
  233.  
  234.         } catch (final IllegalArgumentException e) {
  235.             block.setType(Material.valueOf("SKULL"), false);
  236.             final Skull state = (Skull) block.getState();
  237.             state.setSkullType(SkullType.PLAYER);
  238.             state.setRawData((byte) 0x1);
  239.             state.update(false, false);
  240.         }
  241.     }
  242.  
  243.     private static String urlToBase64(final String url) {
  244.         Valid.checkBoolean(url.startsWith("http://") || url.startsWith("https://"), "URL for skull must start with http:// or https://, given: " + url);
  245.  
  246.         final URI actualUrl;
  247.         try {
  248.             actualUrl = new URI(url);
  249.         } catch (final URISyntaxException e) {
  250.             throw new RuntimeException(e);
  251.         }
  252.         final String toEncode = "{\"textures\":{\"SKIN\":{\"url\":\"" + actualUrl.toString() + "\"}}}";
  253.         return Base64.getEncoder().encodeToString(toEncode.getBytes());
  254.     }
  255.  
  256.     private static Object makeProfile(final String b64) {
  257.         // random uuid based on the b64 string
  258.         final UUID id = new UUID(
  259.                 b64.substring(b64.length() - 20).hashCode(),
  260.                 b64.substring(b64.length() - 10).hashCode());
  261.  
  262.         try {
  263.             final Class<?> gameProfileClass = ReflectionUtil.lookupClass("com.mojang.authlib.GameProfile");
  264.  
  265.             final Object profile = ReflectionUtil.instantiate(gameProfileClass.getConstructor(UUID.class, String.class), id, "aaaaa");
  266.  
  267.             final Class<?> propertyClass = ReflectionUtil.lookupClass("com.mojang.authlib.properties.Property");
  268.             final Object property = ReflectionUtil.instantiate(propertyClass.getConstructor(String.class, String.class), "textures", b64);
  269.             final Object propertyMap = ReflectionUtil.invoke("getProperties", profile);
  270.  
  271.             ReflectionUtil.invoke("put", propertyMap, "textures", property);
  272.  
  273.             return profile;
  274.  
  275.         } catch (final ReflectiveOperationException ex) {
  276.             Common.throwError(ex);
  277.  
  278.             return null;
  279.         }
  280.     }
  281.  
  282.     /**
  283.      * Mutate the skull block
  284.      *
  285.      * @param block
  286.      * @param b64
  287.      */
  288.     public static void mutateBlockState(final Skull block, final String b64) {
  289.         try {
  290.             if (blockProfileField == null) {
  291.                 blockProfileField = block.getClass().getDeclaredField("profile");
  292.                 blockProfileField.setAccessible(true);
  293.             }
  294.             blockProfileField.set(block, makeProfile(b64));
  295.         } catch (NoSuchFieldException | IllegalAccessException e) {
  296.             e.printStackTrace();
  297.         }
  298.     }
  299.  
  300.     private static void mutateItemMeta(final SkullMeta meta, final String b64) {
  301.         try {
  302.             if (metaSetProfileMethod == null) {
  303.                 metaSetProfileMethod = meta.getClass().getDeclaredMethod("setProfile", ReflectionUtil.lookupClass("com.mojang.authlib.GameProfile"));
  304.                 metaSetProfileMethod.setAccessible(true);
  305.             }
  306.             metaSetProfileMethod.invoke(meta, makeProfile(b64));
  307.         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
  308.             // if in an older API where there is no setProfile method,
  309.             // we set the profile field directly.
  310.             try {
  311.                 if (metaProfileField == null) {
  312.                     metaProfileField = meta.getClass().getDeclaredField("profile");
  313.                     metaProfileField.setAccessible(true);
  314.                 }
  315.                 metaProfileField.set(meta, makeProfile(b64));
  316.  
  317.             } catch (NoSuchFieldException | IllegalAccessException ex2) {
  318.                 ex2.printStackTrace();
  319.             }
  320.         }
  321.     }
  322.  
  323.     /**
  324.      * Rotate the skull to a specific block face
  325.      *
  326.      * @param skull
  327.      * @param blockFace
  328.      */
  329.     public static void rotateSkull(final Skull skull, final BlockFace blockFace) {
  330.         if (MinecraftVersion.atLeast(MinecraftVersion.V.v1_13)) {
  331.             System.out.println("Blockdata");
  332.             final Rotatable skullRotation = (Rotatable) skull.getBlockData();
  333.  
  334.             skullRotation.setRotation(blockFace);
  335.             skull.setBlockData(skullRotation);
  336.             skull.update(true);
  337.         } else {
  338.             skull.setRotation(blockFace);
  339.         }
  340.     }
  341. }
Add Comment
Please, Sign In to add comment