From c0f02d20d5a1d1c46894ff0ef164097bbc78e7a5 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Fri, 8 Jan 2021 16:06:48 +0300 Subject: [PATCH 1/3] =?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=D0=BA=D0=BE=D0=BF?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20Location?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ghast/GhastTools.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/ghast/GhastTools.java b/src/main/java/ghast/GhastTools.java index 9ce291e..df67957 100644 --- a/src/main/java/ghast/GhastTools.java +++ b/src/main/java/ghast/GhastTools.java @@ -2,6 +2,7 @@ package ghast; import ghast.assets.AssetsManager; import lombok.experimental.UtilityClass; +import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; @@ -54,4 +55,8 @@ public class GhastTools { public YamlConfiguration loadConfig() { return loadConfig(true); } + + public Location copyLocation(Location location) { + return new Location(location.getWorld(), location.getX(), location.getY(), location.getZ()); + } } From 002dae285ce945090a534f3dfbba99bc0fcd169a Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Fri, 8 Jan 2021 16:07:36 +0300 Subject: [PATCH 2/3] =?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); + } + } } From 16ae1743c76a0d99df9c513d3911f59016962be2 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Fri, 8 Jan 2021 17:05:34 +0300 Subject: [PATCH 3/3] update README.MD --- README.MD | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 4972c77..75b357d 100644 --- a/README.MD +++ b/README.MD @@ -62,6 +62,15 @@ YamlConfiguration config = GhastTools.loadConfig(false); Если передать параметр `false`, то при отсутствии файла `config.yml` в папке плагина, будет загруден исключительно встроенный файл настроек. +### copyLocation + +Копирования объекта `Location` + +```java +Location location = ...; +Location copyLoc = GhastTools.copyLocation(location); +``` + ## AssetsManager Методы по работе с файлами плагина (_"ассетами"_). @@ -110,11 +119,45 @@ _По-умолчанию равен `StandardCharsets.UTF_8`_ ### placeSkull +Установка черепа. + ```java Location location = ...; -Skull skull = BuildHelper.placeSkull(location, BlockFace.NORTH) +Skull skull = BuildHelper.placeSkull(location, BlockFace.NORTH); +skull.update(true); // иначе изменения на карте не применятся и череп будет висеть в воздухе ``` +### placePlayerHead + +Установка головы игрока. + +```java +Location location = ...; +Skull playerHead = BuildHelper.placePlayerHead(location, BlockFace.NORTH); +playerHead.update(true); // иначе изменения на карте не применятся и голова будет висеть в воздухе +``` + +Если третьим параметром передать URL текстуры, то голова будет текстурирована. + +```java +Location location = ...; +BuildHelper.placePlayerHead(location, BlockFace.NORTH, "http://..."); +``` + +### setPlayerHeadSkin + +Установка текстуры для головы игрока. + +```java +Location location = ...; +Skull playerHead = BuildHelper.placePlayerHead(location, BlockFace.NORTH); +playerHead.update(true); // иначе изменения на карте не применятся и голова будет висеть в воздухе +setPlayerHeadSkin(playerHead); +``` + +Порядок выполнения методов в приведённом выше примере **важен**. Если `playerHead.update(true)` вызвать после +установки текстуры, она собъётся на стандартную. + ### placeSignWall ```java