From 002dae285ce945090a534f3dfbba99bc0fcd169a Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Fri, 8 Jan 2021 16:07:36 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20=D1=83=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2=D0=BA=D0=B8=20=D1=82=D0=B5=D0=BA=D1=81?= =?UTF-8?q?=D1=82=D1=83=D1=80=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=B3=D0=BE=D0=BB=D0=BE=D0=B2=D1=8B=20=D0=B8?= =?UTF-8?q?=D0=B3=D1=80=D0=BE=D0=BA=D0=B0=20(skull)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- src/main/java/ghast/BuildHelper.java | 111 +++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0804fb1..bc0e549 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ ext { ]], commons_text: 'org.apache.commons:commons-text:1.9', lombok: 'org.projectlombok:lombok:1.18.12', - reflection_object: 'ru.dmitriymx:reflection-object:1.0-BETA', + reflection_object: 'ru.dmitriymx:reflection-object:1.2', test: [ junit5: [ "org.junit.jupiter:junit-jupiter-api:$junitVersion", diff --git a/src/main/java/ghast/BuildHelper.java b/src/main/java/ghast/BuildHelper.java index f2b795c..70d97f4 100644 --- a/src/main/java/ghast/BuildHelper.java +++ b/src/main/java/ghast/BuildHelper.java @@ -3,26 +3,111 @@ package ghast; import lombok.experimental.UtilityClass; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.SkullType; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; import org.bukkit.block.Skull; +import ru.dmitriymx.reflection.ReflectionClass; +import ru.dmitriymx.reflection.ReflectionObject; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.UUID; @UtilityClass @SuppressWarnings("unused") public class BuildHelper { + private final Class CLASS_BLOCKPOSITION = getClassForName("net.minecraft.server.v1_12_R1.BlockPosition"); + private final Class CLASS_GAMEPROFILE = getClassForName("com.mojang.authlib.GameProfile"); + + /** + * Установка черепа. + *

+ * После установки, необходимо выполнить skull.update(true); + * + * @param location место установки. + * @param face куда будет повёрнут череп. + * @return Блок типа {@link Skull} + */ public Skull placeSkull(Location location, BlockFace face) { + Location fixedLocation = GhastTools.copyLocation(location); + fixedLocation.setZ(fixedLocation.getZ() - 1); + Block block = location.getWorld().getBlockAt(location); block.setType(Material.SKULL); + Skull skull = (Skull) block.getState(); skull.setRotation(face); + org.bukkit.material.Skull skullMaterial = (org.bukkit.material.Skull) skull.getData(); skullMaterial.setFacingDirection(BlockFace.SELF); return skull; } + /** + * Установка головы игрока. + *

+ * После установки, необходимо выполнить skull.update(true); + * + * @param location место установки. + * @param face куда будет повёрнута голова. + * @return Блок типа {@link Skull} + */ + public static Skull placePlayerHead(Location location, BlockFace face) { + Location fixedLocation = GhastTools.copyLocation(location); + fixedLocation.setZ(fixedLocation.getZ() - 1); + + Block block = fixedLocation.getWorld().getBlockAt(fixedLocation); + block.setType(Material.SKULL); + + Skull skull = (Skull) block.getState(); + skull.setSkullType(SkullType.PLAYER); + skull.setRotation(face); + + org.bukkit.material.Skull skullMaterial = (org.bukkit.material.Skull) skull.getData(); + skullMaterial.setFacingDirection(BlockFace.SELF); + return skull; + } + + /** + * Установка текстурированной головы игрока. + * + * @param location место установки. + * @param face куда будет повёрнута голова. + * @param skinUrl URL на текстуру + * @return Блок типа {@link Skull} + */ + public static Skull placePlayerHead(Location location, BlockFace face, String skinUrl) { + Skull playerHead = placePlayerHead(location, face); + playerHead.update(true); + setPlayerHeadSkin(playerHead, skinUrl); + + return playerHead; + } + + /** + * Установка текстуры для головы игрока. + * + * @param skull блок головы игрока + * @param skinUrl URL на текстуру + */ + public static void setPlayerHeadSkin(Skull skull, String skinUrl) { + //TODO заменить рефлексию на "фантомные" классы + ReflectionObject refobjBlockPosition = new ReflectionClass(CLASS_BLOCKPOSITION) + .constructor(double.class, double.class, double.class) + .newInstance(skull.getX(), skull.getY(), skull.getZ()); + + new ReflectionObject(skull.getWorld()) + .method("getHandle").invoke() + .method("getTileEntity", CLASS_BLOCKPOSITION) + .invoke(refobjBlockPosition.getOriginalObject()) + .method("setGameProfile", CLASS_GAMEPROFILE) + .invoke(getRefObjPlayerProfile(skinUrl).getOriginalObject()); + } + public Sign placeSignWall(Location location, BlockFace face) { Block block = location.getWorld().getBlockAt(location); block.setType(Material.WALL_SIGN); @@ -33,4 +118,30 @@ public class BuildHelper { return sign; } + + private ReflectionObject getRefObjPlayerProfile(String url){ + ReflectionObject refobjProperty = new ReflectionClass( + getClassForName("com.mojang.authlib.properties.Property")) + .constructor(String.class, String.class) + .newInstance("textures", Base64.getEncoder() + .encodeToString(("{textures:{SKIN:{url:\"" + url + "\"}}}").getBytes(StandardCharsets.UTF_8))); + + ReflectionObject refobjGameProfile = new ReflectionClass(CLASS_GAMEPROFILE) + .constructor(UUID.class, String.class) + .newInstance(UUID.randomUUID(), null); + refobjGameProfile + .method("getProperties").invoke() + .method("put", Object.class, Object.class) + .invoke("textures", refobjProperty.getOriginalObject()); + + return refobjGameProfile; + } + + private Class getClassForName(String className) { + try { + return Class.forName(className); + } catch (Exception e) { + throw new RuntimeException(e); + } + } }