From 5e479d65c2174214567638aa9fb6d50ea6be48b7 Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 15 Dec 2019 14:27:51 +0100 Subject: [PATCH] Use Abstraction (part 1) --- nms/interfaces/pom.xml | 18 ++ .../shop/hologram/IHologramLine.java | 18 ++ nms/pom.xml | 35 ++++ nms/v15r1/pom.xml | 34 ++++ .../shopchest/shop/hologram/HologramLine.java | 162 ++++++++++++++++++ nms/v8r1/pom.xml | 34 ++++ .../shopchest/shop/hologram/HologramLine.java | 114 ++++++++++++ pom.xml | 1 + 8 files changed, 416 insertions(+) create mode 100644 nms/interfaces/pom.xml create mode 100644 nms/interfaces/src/main/java/de/epiceric/shopchest/shop/hologram/IHologramLine.java create mode 100644 nms/pom.xml create mode 100644 nms/v15r1/pom.xml create mode 100644 nms/v15r1/src/main/java/de/epiceric/shopchest/shop/hologram/HologramLine.java create mode 100644 nms/v8r1/pom.xml create mode 100644 nms/v8r1/src/main/java/de/epiceric/shopchest/shop/hologram/HologramLine.java diff --git a/nms/interfaces/pom.xml b/nms/interfaces/pom.xml new file mode 100644 index 0000000..4e974bd --- /dev/null +++ b/nms/interfaces/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + de.epiceric.shopchest + shopchest-nms-interfaces + 1.13-SNAPSHOT + + ShopChest NMS Interfaces + + + de.epiceric.shopchest + shopchest-nms + 1.13-SNAPSHOT + + diff --git a/nms/interfaces/src/main/java/de/epiceric/shopchest/shop/hologram/IHologramLine.java b/nms/interfaces/src/main/java/de/epiceric/shopchest/shop/hologram/IHologramLine.java new file mode 100644 index 0000000..766f47c --- /dev/null +++ b/nms/interfaces/src/main/java/de/epiceric/shopchest/shop/hologram/IHologramLine.java @@ -0,0 +1,18 @@ +package de.epiceric.shopchest.shop.hologram; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public interface IHologramLine { + + void setLocation(Location location); + + void setText(String text); + + void showPlayer(Player player); + + void hidePlayer(Player player); + + void destroy(); + +} \ No newline at end of file diff --git a/nms/pom.xml b/nms/pom.xml new file mode 100644 index 0000000..2ff285b --- /dev/null +++ b/nms/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + de.epiceric.shopchest + shopchest-nms + 1.13-SNAPSHOT + pom + + + interfaces + v8r1 + + v15r1 + + + ShopChest NMS + + + de.epiceric.shopchest + shopchest-parent + 1.13-SNAPSHOT + + diff --git a/nms/v15r1/pom.xml b/nms/v15r1/pom.xml new file mode 100644 index 0000000..5bc207d --- /dev/null +++ b/nms/v15r1/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + de.epiceric.shopchest + shopchest-nms-v15r1 + 1.13-SNAPSHOT + + ShopChest NMS v1.15-R1 + + + de.epiceric.shopchest + shopchest-nms + 1.13-SNAPSHOT + + + + + de.epiceric.shopchest + shopchest-nms-interfaces + 1.13-SNAPSHOT + provided + + + + org.bukkit + craftbukkit + 1.15-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v15r1/src/main/java/de/epiceric/shopchest/shop/hologram/HologramLine.java b/nms/v15r1/src/main/java/de/epiceric/shopchest/shop/hologram/HologramLine.java new file mode 100644 index 0000000..702d07e --- /dev/null +++ b/nms/v15r1/src/main/java/de/epiceric/shopchest/shop/hologram/HologramLine.java @@ -0,0 +1,162 @@ +package de.epiceric.shopchest.shop.hologram; + +import java.io.IOException; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Optional; +import java.util.UUID; + +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import io.netty.buffer.Unpooled; +import net.minecraft.server.v1_15_R1.DataWatcher; +import net.minecraft.server.v1_15_R1.DataWatcherObject; +import net.minecraft.server.v1_15_R1.Entity; +import net.minecraft.server.v1_15_R1.EntityArmorStand; +import net.minecraft.server.v1_15_R1.EntityTypes; +import net.minecraft.server.v1_15_R1.IChatBaseComponent; +import net.minecraft.server.v1_15_R1.IRegistry; +import net.minecraft.server.v1_15_R1.Packet; +import net.minecraft.server.v1_15_R1.PacketDataSerializer; +import net.minecraft.server.v1_15_R1.PacketPlayOutEntityDestroy; +import net.minecraft.server.v1_15_R1.PacketPlayOutEntityMetadata; +import net.minecraft.server.v1_15_R1.PacketPlayOutEntityTeleport; +import net.minecraft.server.v1_15_R1.PacketPlayOutSpawnEntity; +import net.minecraft.server.v1_15_R1.PlayerConnection; +import net.minecraft.server.v1_15_R1.IChatBaseComponent.ChatSerializer; + +public class HologramLine implements IHologramLine { + private PacketPlayOutSpawnEntity packet; + private DataWatcher dataWatcher; + + private DataWatcherObject nameVisible; + private DataWatcherObject> customName; + + private int id; + private Location location; + private String text; + + public HologramLine(Location location, String text) { + this.id = 5; + this.location = location.clone(); + this.text = text; + + this.packet = new PacketPlayOutSpawnEntity(); + this.dataWatcher = createDataWatcher(); + + updatePacket(); + } + + @Override + public void setLocation(Location location) { + this.location = location.clone(); + updatePacket(); + + PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport(); + location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet)); + } + + @Override + public void setText(String text) { + this.text = text; + + dataWatcher.register(nameVisible, !text.isEmpty()); + dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text))); + + location.getWorld().getPlayers() + .forEach(player -> sendPackets(player, new PacketPlayOutEntityMetadata(id, dataWatcher, true))); + } + + @Override + public void showPlayer(Player player) { + if (player == null || !player.isOnline()) { + return; + } + + sendPackets(player, packet, new PacketPlayOutEntityMetadata(id, dataWatcher, true)); + } + + @Override + public void hidePlayer(Player player) { + if (player == null || !player.isOnline()) { + return; + } + + sendPackets(player, new PacketPlayOutEntityDestroy(id)); + } + + @Override + public void destroy() { + location.getWorld().getPlayers().forEach(player -> hidePlayer(player)); + } + + private void sendPackets(Player player, Packet... packets) { + PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection; + Arrays.stream(packets).forEach(packet -> con.sendPacket(packet)); + } + + public void updatePacket() { + PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer()); + s.d(id); // id + s.a(UUID.randomUUID()); // uuid + s.d(IRegistry.ENTITY_TYPE.a(EntityTypes.ARMOR_STAND)); // type + s.writeDouble(location.getX()); // x + s.writeDouble(location.getY()); // y + s.writeDouble(location.getZ()); // z + s.writeByte(0); // pitch + s.writeByte(0); // yaw + s.writeInt(0); // ? + s.writeShort(0); // mot x + s.writeShort(0); // mot y + s.writeShort(0); // mot z + + try { + packet.a(s); + } catch (IOException e) { + e.printStackTrace(); + } finally { + s.release(); + } + } + + @SuppressWarnings("unchecked") + public DataWatcher createDataWatcher() { + try { + Field fEntityFlags = Entity.class.getDeclaredField("T"); + Field fAirTicks = Entity.class.getDeclaredField("AIR_TICKS"); + Field fNameVisible = Entity.class.getDeclaredField("aA"); + Field fCustomName = Entity.class.getDeclaredField("az"); + Field fNoGravity = Entity.class.getDeclaredField("aC"); + + setAccessible(fEntityFlags, fAirTicks, fNameVisible, fCustomName, fNoGravity); + + nameVisible = (DataWatcherObject) fNameVisible.get(null); + customName = (DataWatcherObject>) fCustomName.get(null); + DataWatcherObject entityFlags = (DataWatcherObject) fEntityFlags.get(null); + DataWatcherObject airTicks = (DataWatcherObject) fAirTicks.get(null); + DataWatcherObject noGravity = (DataWatcherObject) fNoGravity.get(null); + DataWatcherObject armorStandFlags = EntityArmorStand.b; + + DataWatcher dataWatcher = new DataWatcher(null); + dataWatcher.register(entityFlags, (byte) 0b100000); + dataWatcher.register(airTicks, 300); + dataWatcher.register(nameVisible, !text.isEmpty()); + dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text))); + dataWatcher.register(noGravity, true); + dataWatcher.register(armorStandFlags, (byte) 0b10000); + + return dataWatcher; + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + + return null; + } + + void setAccessible(AccessibleObject... args) { + Arrays.stream(args).forEach(arg -> arg.setAccessible(true)); + } +} \ No newline at end of file diff --git a/nms/v8r1/pom.xml b/nms/v8r1/pom.xml new file mode 100644 index 0000000..746fb12 --- /dev/null +++ b/nms/v8r1/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + de.epiceric.shopchest + shopchest-nms-v8r1 + 1.13-SNAPSHOT + + ShopChest NMS v1.8-R1 + + + de.epiceric.shopchest + shopchest-nms + 1.13-SNAPSHOT + + + + + de.epiceric.shopchest + shopchest-nms-interfaces + 1.13-SNAPSHOT + provided + + + + org.bukkit + craftbukkit + 1.8-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v8r1/src/main/java/de/epiceric/shopchest/shop/hologram/HologramLine.java b/nms/v8r1/src/main/java/de/epiceric/shopchest/shop/hologram/HologramLine.java new file mode 100644 index 0000000..eeeea0d --- /dev/null +++ b/nms/v8r1/src/main/java/de/epiceric/shopchest/shop/hologram/HologramLine.java @@ -0,0 +1,114 @@ +package de.epiceric.shopchest.shop.hologram; + +import java.util.Arrays; + +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import io.netty.buffer.Unpooled; +import net.minecraft.server.v1_8_R1.DataWatcher; +import net.minecraft.server.v1_8_R1.MathHelper; +import net.minecraft.server.v1_8_R1.Packet; +import net.minecraft.server.v1_8_R1.PacketDataSerializer; +import net.minecraft.server.v1_8_R1.PacketPlayOutEntityDestroy; +import net.minecraft.server.v1_8_R1.PacketPlayOutEntityMetadata; +import net.minecraft.server.v1_8_R1.PacketPlayOutEntityTeleport; +import net.minecraft.server.v1_8_R1.PacketPlayOutSpawnEntity; +import net.minecraft.server.v1_8_R1.PlayerConnection; + +public class HologramLine implements IHologramLine { + private PacketPlayOutSpawnEntity packet; + private DataWatcher dataWatcher; + + private int id; + private Location location; + private String text; + + public HologramLine(Location location, String text) { + this.id = 5; + this.location = location.clone(); + this.text = text == null ? "" : text; + + this.packet = new PacketPlayOutSpawnEntity(); + this.dataWatcher = createDataWatcher(); + + updatePacket(); + } + + @Override + public void setLocation(Location location) { + this.location = location.clone(); + updatePacket(); + + int x = MathHelper.floor(location.getX() * 32d); + int y = MathHelper.floor(location.getY() * 32d); + int z = MathHelper.floor(location.getZ() * 32d); + + Packet packet = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true); + location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet)); + } + + @Override + public void setText(String text) { + this.text = text == null ? "" : text; + + dataWatcher.a(2, this.text); // custom name + dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible + + location.getWorld().getPlayers() + .forEach(player -> sendPackets(player, new PacketPlayOutEntityMetadata(id, dataWatcher, true))); + } + + @Override + public void showPlayer(Player player) { + if (player == null || !player.isOnline()) { + return; + } + + sendPackets(player, packet, new PacketPlayOutEntityMetadata(id, dataWatcher, true)); + } + + @Override + public void hidePlayer(Player player) { + if (player == null || !player.isOnline()) { + return; + } + + sendPackets(player, new PacketPlayOutEntityDestroy(id)); + } + + @Override + public void destroy() { + location.getWorld().getPlayers().forEach(player -> hidePlayer(player)); + } + + private void sendPackets(Player player, Packet... packets) { + PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection; + Arrays.stream(packets).forEach(packet -> con.sendPacket(packet)); + } + + private void updatePacket() { + PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer()); + serializer.b(id); // id + serializer.writeByte(78); // entity type + serializer.writeInt(MathHelper.floor(location.getX() * 32d)); // x + serializer.writeInt(MathHelper.floor(location.getY() * 32d)); // y + serializer.writeInt(MathHelper.floor(location.getZ() * 32d)); // z + serializer.writeByte(0); // pitch + serializer.writeByte(0); // yaw + serializer.writeInt(0); // has motion (?) + this.packet.a(serializer); + serializer.release(); + } + + private DataWatcher createDataWatcher() { + DataWatcher dataWatcher = new DataWatcher(null); + dataWatcher.a(0, 0b100000); // entity flags + dataWatcher.a(1, (short) 300); // air ticks + dataWatcher.a(2, text); // custom name + dataWatcher.a(3, (byte) (text.isEmpty() ? 0 : 1)); // name visible + dataWatcher.a(10, (byte) 0b1100); // armor stand flags + return dataWatcher; + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index eb7f0d1..c21de3d 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ api implementation new-implementation + nms