Add hologram item

This commit is contained in:
Eric 2020-03-19 18:26:25 +01:00
parent ff9c1a4cb4
commit 263137acba
39 changed files with 2972 additions and 747 deletions

View File

@ -2,86 +2,87 @@ package de.epiceric.shopchest.shop.hologram;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import de.epiceric.shopchest.api.ShopChest;
import de.epiceric.shopchest.api.shop.Shop;
import de.epiceric.shopchest.shop.ShopImpl;
import de.epiceric.shopchest.util.NmsUtil;
public class Hologram {
/**
* Constructs a new hologram line
*
* @param location the line's location
* @param text the line's text
* @return the hologram line
*/
public static IHologramLine newHologramLine(Location location, String text) {
switch (NmsUtil.getServerVersion()) {
case "v1_8_R1": return new de.epiceric.shopchest.shop.hologram.v1_8_R1.HologramLine(location, text);
case "v1_8_R2": return new de.epiceric.shopchest.shop.hologram.v1_8_R2.HologramLine(location, text);
case "v1_8_R3": return new de.epiceric.shopchest.shop.hologram.v1_8_R3.HologramLine(location, text);
case "v1_9_R1": return new de.epiceric.shopchest.shop.hologram.v1_9_R1.HologramLine(location, text);
case "v1_9_R2": return new de.epiceric.shopchest.shop.hologram.v1_9_R2.HologramLine(location, text);
case "v1_10_R1": return new de.epiceric.shopchest.shop.hologram.v1_10_R1.HologramLine(location, text);
case "v1_11_R1": return new de.epiceric.shopchest.shop.hologram.v1_11_R1.HologramLine(location, text);
case "v1_12_R1": return new de.epiceric.shopchest.shop.hologram.v1_12_R1.HologramLine(location, text);
case "v1_13_R1": return new de.epiceric.shopchest.shop.hologram.v1_13_R1.HologramLine(location, text);
case "v1_13_R2": return new de.epiceric.shopchest.shop.hologram.v1_13_R2.HologramLine(location, text);
case "v1_14_R1": return new de.epiceric.shopchest.shop.hologram.v1_14_R1.HologramLine(location, text);
case "v1_15_R1": return new de.epiceric.shopchest.shop.hologram.v1_15_R1.HologramLine(location, text);
default: throw new IllegalStateException("Invalid server version: " + NmsUtil.getServerVersion());
}
}
private final Shop shop;
private List<IHologramLine> lines = new ArrayList<>();
private final List<IHologramLine> lines = new ArrayList<>();
private final IHologramItem item;
public Hologram(ShopChest plugin, Shop shop) {
this.shop = shop;
this.item = HologramFactory.newHologramItem(getItemLocation(), shop.getProduct().getItemStack());
int topLine = shop.canPlayerBuy() && shop.canPlayerSell() ? 3 : 2;
// TODO: Configurable
lines.add(newHologramLine(getLocation(topLine), shop.getVendor().map(OfflinePlayer::getName).orElse("§cAdmin Shop")));
lines.add(newHologramLine(getLocation(topLine - 1), shop.getProduct().getAmount() + " §7x §f" + shop.getProduct().getLocalizedName()));
if (shop.canPlayerBuy()) lines.add(newHologramLine(getLocation(topLine - 2), "§eBuy for " + plugin.formatEconomy(shop.getBuyPrice())));
if (shop.canPlayerSell()) lines.add(newHologramLine(getLocation(0), "§eSell for " + plugin.formatEconomy(shop.getSellPrice())));
lines.add(HologramFactory.newHologramLine(getLineLocation(topLine),
shop.getVendor().map(OfflinePlayer::getName).orElse("§cAdmin Shop")));
lines.add(HologramFactory.newHologramLine(getLineLocation(topLine - 1),
shop.getProduct().getAmount() + " §7x §f" + shop.getProduct().getLocalizedName()));
if (shop.canPlayerBuy()) lines.add(HologramFactory.newHologramLine(getLineLocation(topLine - 2),
"§eBuy for " + plugin.formatEconomy(shop.getBuyPrice())));
if (shop.canPlayerSell()) lines.add(HologramFactory.newHologramLine(getLineLocation(0),
"§eSell for " + plugin.formatEconomy(shop.getSellPrice())));
}
private Location getLocation(int lineFromBottom) {
double lineHeight = 0.25;
Location loc = shop.getLocation().subtract(0, 0.75, 0);
Location otherLoc = ((ShopImpl) shop).getOtherLocation().orElse(null);
private Location getCenterOfChest() {
ShopImpl shop = (ShopImpl) this.shop;
Location location = shop.getLocation();
Optional<Location> optional = shop.getOtherLocation();
if (otherLoc == null) {
return loc.add(0.5, lineFromBottom * lineHeight, 0.5);
}
if (loc.getX() == otherLoc.getX()) {
double zDiff = otherLoc.subtract(loc).getZ();
return loc.add(0.5, lineFromBottom * lineHeight, zDiff);
if (optional.isPresent()) {
Location otherLoc = optional.get();
Vector diff = otherLoc.subtract(location).toVector();
// Invert cross vector direction if diff has negative x or z
Vector cross = (diff.getX() < 0.1 || diff.getZ() < 0.1)
? diff.getCrossProduct(new Vector(0, -0.5, 0))
: diff.getCrossProduct(new Vector(0, 0.5, 0));
location.add(diff.add(cross));
} else {
double xDiff = otherLoc.subtract(loc).getX();
return loc.add(xDiff, lineFromBottom * lineHeight, 0.5);
location.add(0.5, 0, 0.5);
}
return location;
}
private Location getItemLocation() {
double itemLift = 0.9;
return getCenterOfChest().add(0, itemLift, 0);
}
private Location getLineLocation(int lineFromBottom) {
double lineHeight = 0.25;
double armorStandLift = -0.75;
return getCenterOfChest().add(0, lineFromBottom * lineHeight - armorStandLift, 0);
}
/**
* Hides the hologram from all players in the hologram's world and removes all lines
*/
public void destroy() {
item.destroy();
lines.forEach(IHologramLine::destroy);
lines.clear();
}
/**
* Displays the hologram to the given player
* Displays the hologram text to the given player
*
* @param player the player to show the hologram to
*/
@ -90,7 +91,7 @@ public class Hologram {
}
/**
* Hides the hologram from the given player
* Hides the hologram text from the given player
*
* @param player the player to hide the hologram from
*/

View File

@ -0,0 +1,47 @@
package de.epiceric.shopchest.shop.hologram;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.util.NmsUtil;
class HologramFactory {
private HologramFactory() {
}
static IHologramLine newHologramLine(Location location, String text) {
switch (NmsUtil.getServerVersion()) {
case "v1_8_R1": return new de.epiceric.shopchest.shop.hologram.v1_8_R1.HologramLine(location, text);
case "v1_8_R2": return new de.epiceric.shopchest.shop.hologram.v1_8_R2.HologramLine(location, text);
case "v1_8_R3": return new de.epiceric.shopchest.shop.hologram.v1_8_R3.HologramLine(location, text);
case "v1_9_R1": return new de.epiceric.shopchest.shop.hologram.v1_9_R1.HologramLine(location, text);
case "v1_9_R2": return new de.epiceric.shopchest.shop.hologram.v1_9_R2.HologramLine(location, text);
case "v1_10_R1": return new de.epiceric.shopchest.shop.hologram.v1_10_R1.HologramLine(location, text);
case "v1_11_R1": return new de.epiceric.shopchest.shop.hologram.v1_11_R1.HologramLine(location, text);
case "v1_12_R1": return new de.epiceric.shopchest.shop.hologram.v1_12_R1.HologramLine(location, text);
case "v1_13_R1": return new de.epiceric.shopchest.shop.hologram.v1_13_R1.HologramLine(location, text);
case "v1_13_R2": return new de.epiceric.shopchest.shop.hologram.v1_13_R2.HologramLine(location, text);
case "v1_14_R1": return new de.epiceric.shopchest.shop.hologram.v1_14_R1.HologramLine(location, text);
case "v1_15_R1": return new de.epiceric.shopchest.shop.hologram.v1_15_R1.HologramLine(location, text);
default: throw new IllegalStateException("Invalid server version: " + NmsUtil.getServerVersion());
}
}
static IHologramItem newHologramItem(Location location, ItemStack itemStack) {
switch (NmsUtil.getServerVersion()) {
case "v1_8_R1": return new de.epiceric.shopchest.shop.hologram.v1_8_R1.HologramItem(location, itemStack);
case "v1_8_R2": return new de.epiceric.shopchest.shop.hologram.v1_8_R2.HologramItem(location, itemStack);
case "v1_8_R3": return new de.epiceric.shopchest.shop.hologram.v1_8_R3.HologramItem(location, itemStack);
case "v1_9_R1": return new de.epiceric.shopchest.shop.hologram.v1_9_R1.HologramItem(location, itemStack);
case "v1_9_R2": return new de.epiceric.shopchest.shop.hologram.v1_9_R2.HologramItem(location, itemStack);
case "v1_10_R1": return new de.epiceric.shopchest.shop.hologram.v1_10_R1.HologramItem(location, itemStack);
case "v1_11_R1": return new de.epiceric.shopchest.shop.hologram.v1_11_R1.HologramItem(location, itemStack);
case "v1_12_R1": return new de.epiceric.shopchest.shop.hologram.v1_12_R1.HologramItem(location, itemStack);
case "v1_13_R1": return new de.epiceric.shopchest.shop.hologram.v1_13_R1.HologramItem(location, itemStack);
case "v1_13_R2": return new de.epiceric.shopchest.shop.hologram.v1_13_R2.HologramItem(location, itemStack);
case "v1_14_R1": return new de.epiceric.shopchest.shop.hologram.v1_14_R1.HologramItem(location, itemStack);
case "v1_15_R1": return new de.epiceric.shopchest.shop.hologram.v1_15_R1.HologramItem(location, itemStack);
default: throw new IllegalStateException("Invalid server version: " + NmsUtil.getServerVersion());
}
}
}

View File

@ -0,0 +1,61 @@
package de.epiceric.shopchest.shop.hologram;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public interface IHologramItem {
/**
* Sets the location of this item and sends the update to
* all players in the hologram's world
*
* @param location the location to set
*/
void setLocation(Location location);
/**
* Gets the current location
*
* @return the location
*/
Location getLocation();
/**
* Sets the item shown in the hologram
* <p>
* The amount of the item stack will always be set to 1.
*
* @param itemStack the item to set
*/
void setItemStack(ItemStack itemStack);
/**
* Gets the current item of the hologram
*
* @return the item
*/
ItemStack getItemStack();
/**
* Displays the item to the given player
*
* @param player the player to show the item to
*/
void showPlayer(Player player);
/**
* Hides the item from the given player
*
* @param player the player to hide the item from
*/
void hidePlayer(Player player);
/**
* Hides the item from all players in the hologram's world
*/
default void destroy() {
getLocation().getWorld().getPlayers().forEach(this::hidePlayer);
}
}

View File

@ -0,0 +1,130 @@
package de.epiceric.shopchest.shop.hologram.v1_10_R1;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import com.google.common.base.Optional;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_10_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_10_R1.DataWatcher;
import net.minecraft.server.v1_10_R1.DataWatcherObject;
import net.minecraft.server.v1_10_R1.Entity;
import net.minecraft.server.v1_10_R1.EntityItem;
import net.minecraft.server.v1_10_R1.Packet;
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_10_R1.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private DataWatcherObject<Optional<net.minecraft.server.v1_10_R1.ItemStack>> item;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
Packet<?> teleportPacket = HologramUtil.createTeleportPacket(id, location, false);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.register(item, Optional.of(getNmsItemStack())); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")
private DataWatcher createDataWatcher() {
try {
Field fAirTicks = Entity.class.getDeclaredField("az");
Field fNoGravity = Entity.class.getDeclaredField("aD");
Field fItem = EntityItem.class.getDeclaredField("c");
setAccessible(fAirTicks, fNoGravity, fItem);
item = (DataWatcherObject<Optional<net.minecraft.server.v1_10_R1.ItemStack>>) fItem.get(null);
DataWatcherObject<Integer> airTicks = (DataWatcherObject<Integer>) fAirTicks.get(null);
DataWatcherObject<Boolean> noGravity = (DataWatcherObject<Boolean>) fNoGravity.get(null);
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.register(airTicks, 300);
dataWatcher.register(noGravity, true);
dataWatcher.register(item, Optional.of(getNmsItemStack()));
return dataWatcher;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
private net.minecraft.server.v1_10_R1.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
private void setAccessible(AccessibleObject... args) {
Arrays.stream(args).forEach(arg -> arg.setAccessible(true));
}
}

View File

@ -1,30 +1,24 @@
package de.epiceric.shopchest.shop.hologram.v1_10_R1;
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_10_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_10_R1.DataWatcher;
import net.minecraft.server.v1_10_R1.DataWatcherObject;
import net.minecraft.server.v1_10_R1.Entity;
import net.minecraft.server.v1_10_R1.EntityArmorStand;
import net.minecraft.server.v1_10_R1.IChatBaseComponent;
import net.minecraft.server.v1_10_R1.Packet;
import net.minecraft.server.v1_10_R1.PacketDataSerializer;
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_10_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_10_R1.PlayerConnection;
public class HologramLine implements IHologramLine {
private PacketPlayOutSpawnEntity spawnPacket;
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine {
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
PacketPlayOutEntityTeleport packet = createTeleportPacket();
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
}
@Override
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.register(customName, text);
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(packet -> con.sendPacket(packet));
}
private PacketPlayOutEntityTeleport createTeleportPacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
private void updatePacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.a(UUID.randomUUID()); // uuid
s.writeByte(78); // type
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // 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 {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")

View File

@ -0,0 +1,114 @@
package de.epiceric.shopchest.shop.hologram.v1_10_R1;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_10_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_10_R1.Entity;
import net.minecraft.server.v1_10_R1.Packet;
import net.minecraft.server.v1_10_R1.PacketDataSerializer;
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_10_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_10_R1.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id + 1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType == 78 ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.a(UUID.randomUUID()); // uuid
serializer.writeByte(entityType); // entity type
serializer.writeDouble(location.getX()); // x
serializer.writeDouble(location.getY() + yLift); // y
serializer.writeDouble(location.getZ()); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
/**
* Creates a PacketPlayOutEntityTeleport
*
* @param id the entity ID
* @param location the new entity location
* @param lift whether the entity will be lifted by 1.975
* @return the packet
*/
public static PacketPlayOutEntityTeleport createTeleportPacket(int id, Location location, boolean lift) {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + (lift ? 1.975 : 0)); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
}

View File

@ -0,0 +1,128 @@
package de.epiceric.shopchest.shop.hologram.v1_11_R1;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_11_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_11_R1.DataWatcher;
import net.minecraft.server.v1_11_R1.DataWatcherObject;
import net.minecraft.server.v1_11_R1.Entity;
import net.minecraft.server.v1_11_R1.EntityItem;
import net.minecraft.server.v1_11_R1.Packet;
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_11_R1.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private DataWatcherObject<net.minecraft.server.v1_11_R1.ItemStack> item;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
Packet<?> teleportPacket = HologramUtil.createTeleportPacket(id, location, false);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.register(item, getNmsItemStack()); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")
private DataWatcher createDataWatcher() {
try {
Field fAirTicks = Entity.class.getDeclaredField("az");
Field fNoGravity = Entity.class.getDeclaredField("aD");
Field fItem = EntityItem.class.getDeclaredField("c");
setAccessible(fAirTicks, fNoGravity, fItem);
item = (DataWatcherObject<net.minecraft.server.v1_11_R1.ItemStack>) fItem.get(null);
DataWatcherObject<Integer> airTicks = (DataWatcherObject<Integer>) fAirTicks.get(null);
DataWatcherObject<Boolean> noGravity = (DataWatcherObject<Boolean>) fNoGravity.get(null);
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.register(airTicks, 300);
dataWatcher.register(noGravity, true);
dataWatcher.register(item, getNmsItemStack());
return dataWatcher;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
private net.minecraft.server.v1_11_R1.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
private void setAccessible(AccessibleObject... args) {
Arrays.stream(args).forEach(arg -> arg.setAccessible(true));
}
}

View File

@ -1,30 +1,24 @@
package de.epiceric.shopchest.shop.hologram.v1_11_R1;
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_11_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_11_R1.DataWatcher;
import net.minecraft.server.v1_11_R1.DataWatcherObject;
import net.minecraft.server.v1_11_R1.Entity;
import net.minecraft.server.v1_11_R1.EntityArmorStand;
import net.minecraft.server.v1_11_R1.IChatBaseComponent;
import net.minecraft.server.v1_11_R1.Packet;
import net.minecraft.server.v1_11_R1.PacketDataSerializer;
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_11_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_11_R1.PlayerConnection;
public class HologramLine implements IHologramLine {
private PacketPlayOutSpawnEntity spawnPacket;
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine {
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
PacketPlayOutEntityTeleport packet = createTeleportPacket();
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
}
@Override
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.register(customName, text);
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(packet -> con.sendPacket(packet));
}
private PacketPlayOutEntityTeleport createTeleportPacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
private void updatePacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.a(UUID.randomUUID()); // uuid
s.writeByte(78); // type
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // 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 {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")

View File

@ -0,0 +1,114 @@
package de.epiceric.shopchest.shop.hologram.v1_11_R1;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_11_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_11_R1.Entity;
import net.minecraft.server.v1_11_R1.Packet;
import net.minecraft.server.v1_11_R1.PacketDataSerializer;
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_11_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_11_R1.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id + 1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType == 78 ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.a(UUID.randomUUID()); // uuid
serializer.writeByte(entityType); // entity type
serializer.writeDouble(location.getX()); // x
serializer.writeDouble(location.getY() + yLift); // y
serializer.writeDouble(location.getZ()); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
/**
* Creates a PacketPlayOutEntityTeleport
*
* @param id the entity ID
* @param location the new entity location
* @param lift whether the entity will be lifted by 1.975
* @return the packet
*/
public static PacketPlayOutEntityTeleport createTeleportPacket(int id, Location location, boolean lift) {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + (lift ? 1.975 : 0)); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
}

View File

@ -0,0 +1,128 @@
package de.epiceric.shopchest.shop.hologram.v1_12_R1;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_12_R1.DataWatcher;
import net.minecraft.server.v1_12_R1.DataWatcherObject;
import net.minecraft.server.v1_12_R1.Entity;
import net.minecraft.server.v1_12_R1.EntityItem;
import net.minecraft.server.v1_12_R1.Packet;
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_12_R1.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private DataWatcherObject<net.minecraft.server.v1_12_R1.ItemStack> item;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
Packet<?> teleportPacket = HologramUtil.createTeleportPacket(id, location, false);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.register(item, getNmsItemStack()); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")
private DataWatcher createDataWatcher() {
try {
Field fAirTicks = Entity.class.getDeclaredField("aA");
Field fNoGravity = Entity.class.getDeclaredField("aE");
Field fItem = EntityItem.class.getDeclaredField("c");
setAccessible(fAirTicks, fNoGravity, fItem);
item = (DataWatcherObject<net.minecraft.server.v1_12_R1.ItemStack>) fItem.get(null);
DataWatcherObject<Integer> airTicks = (DataWatcherObject<Integer>) fAirTicks.get(null);
DataWatcherObject<Boolean> noGravity = (DataWatcherObject<Boolean>) fNoGravity.get(null);
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.register(airTicks, 300);
dataWatcher.register(noGravity, true);
dataWatcher.register(item, getNmsItemStack());
return dataWatcher;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
private net.minecraft.server.v1_12_R1.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
private void setAccessible(AccessibleObject... args) {
Arrays.stream(args).forEach(arg -> arg.setAccessible(true));
}
}

View File

@ -1,30 +1,24 @@
package de.epiceric.shopchest.shop.hologram.v1_12_R1;
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_12_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_12_R1.DataWatcher;
import net.minecraft.server.v1_12_R1.DataWatcherObject;
import net.minecraft.server.v1_12_R1.Entity;
import net.minecraft.server.v1_12_R1.EntityArmorStand;
import net.minecraft.server.v1_12_R1.IChatBaseComponent;
import net.minecraft.server.v1_12_R1.Packet;
import net.minecraft.server.v1_12_R1.PacketDataSerializer;
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_12_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_12_R1.PlayerConnection;
public class HologramLine implements IHologramLine {
private PacketPlayOutSpawnEntity spawnPacket;
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine {
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
PacketPlayOutEntityTeleport packet = createTeleportPacket();
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
}
@Override
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.register(customName, text);
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(packet -> con.sendPacket(packet));
}
private PacketPlayOutEntityTeleport createTeleportPacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
private void updatePacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.a(UUID.randomUUID()); // uuid
s.writeByte(78); // type
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // 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 {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")

View File

@ -0,0 +1,114 @@
package de.epiceric.shopchest.shop.hologram.v1_12_R1;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_12_R1.Entity;
import net.minecraft.server.v1_12_R1.Packet;
import net.minecraft.server.v1_12_R1.PacketDataSerializer;
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_12_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_12_R1.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id + 1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType == 78 ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.a(UUID.randomUUID()); // uuid
serializer.writeByte(entityType); // entity type
serializer.writeDouble(location.getX()); // x
serializer.writeDouble(location.getY() + yLift); // y
serializer.writeDouble(location.getZ()); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
/**
* Creates a PacketPlayOutEntityTeleport
*
* @param id the entity ID
* @param location the new entity location
* @param lift whether the entity will be lifted by 1.975
* @return the packet
*/
public static PacketPlayOutEntityTeleport createTeleportPacket(int id, Location location, boolean lift) {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + (lift ? 1.975 : 0)); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
}

View File

@ -0,0 +1,128 @@
package de.epiceric.shopchest.shop.hologram.v1_13_R1;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_13_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_13_R1.DataWatcher;
import net.minecraft.server.v1_13_R1.DataWatcherObject;
import net.minecraft.server.v1_13_R1.Entity;
import net.minecraft.server.v1_13_R1.EntityItem;
import net.minecraft.server.v1_13_R1.Packet;
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_13_R1.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private DataWatcherObject<net.minecraft.server.v1_13_R1.ItemStack> item;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
Packet<?> teleportPacket = HologramUtil.createTeleportPacket(id, location, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.register(item, getNmsItemStack()); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")
private DataWatcher createDataWatcher() {
try {
Field fAirTicks = Entity.class.getDeclaredField("aD");
Field fNoGravity = Entity.class.getDeclaredField("aH");
Field fItem = EntityItem.class.getDeclaredField("b");
setAccessible(fAirTicks, fNoGravity, fItem);
item = (DataWatcherObject<net.minecraft.server.v1_13_R1.ItemStack>) fItem.get(null);
DataWatcherObject<Integer> airTicks = (DataWatcherObject<Integer>) fAirTicks.get(null);
DataWatcherObject<Boolean> noGravity = (DataWatcherObject<Boolean>) fNoGravity.get(null);
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.register(airTicks, 300);
dataWatcher.register(noGravity, true);
dataWatcher.register(item, getNmsItemStack());
return dataWatcher;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
private net.minecraft.server.v1_13_R1.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
private void setAccessible(AccessibleObject... args) {
Arrays.stream(args).forEach(arg -> arg.setAccessible(true));
}
}

View File

@ -1,31 +1,25 @@
package de.epiceric.shopchest.shop.hologram.v1_13_R1;
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_13_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_13_R1.DataWatcher;
import net.minecraft.server.v1_13_R1.DataWatcherObject;
import net.minecraft.server.v1_13_R1.Entity;
import net.minecraft.server.v1_13_R1.EntityArmorStand;
import net.minecraft.server.v1_13_R1.IChatBaseComponent;
import net.minecraft.server.v1_13_R1.IChatBaseComponent.ChatSerializer;
import net.minecraft.server.v1_13_R1.Packet;
import net.minecraft.server.v1_13_R1.PacketDataSerializer;
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_13_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_13_R1.PlayerConnection;
import net.minecraft.server.v1_13_R1.IChatBaseComponent.ChatSerializer;
public class HologramLine implements IHologramLine {
private PacketPlayOutSpawnEntity spawnPacket;
@ -46,16 +40,16 @@ public class HologramLine implements IHologramLine {
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
PacketPlayOutEntityTeleport packet = createTeleportPacket();
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, false);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
}
@Override
@ -71,7 +65,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -85,7 +79,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -94,59 +88,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(packet -> con.sendPacket(packet));
}
private PacketPlayOutEntityTeleport createTeleportPacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
private void updatePacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.a(UUID.randomUUID()); // uuid
s.writeByte(78); // type
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // 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 {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")

View File

@ -0,0 +1,114 @@
package de.epiceric.shopchest.shop.hologram.v1_13_R1;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_13_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_13_R1.Entity;
import net.minecraft.server.v1_13_R1.Packet;
import net.minecraft.server.v1_13_R1.PacketDataSerializer;
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_13_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_13_R1.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id + 1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType == 78 ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.a(UUID.randomUUID()); // uuid
serializer.writeByte(entityType); // entity type
serializer.writeDouble(location.getX()); // x
serializer.writeDouble(location.getY() + yLift); // y
serializer.writeDouble(location.getZ()); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
/**
* Creates a PacketPlayOutEntityTeleport
*
* @param id the entity ID
* @param location the new entity location
* @param lift whether the entity will be lifted by 1.975
* @return the packet
*/
public static PacketPlayOutEntityTeleport createTeleportPacket(int id, Location location, boolean lift) {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + (lift ? 1.975 : 0)); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
}

View File

@ -0,0 +1,128 @@
package de.epiceric.shopchest.shop.hologram.v1_13_R2;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_13_R2.DataWatcher;
import net.minecraft.server.v1_13_R2.DataWatcherObject;
import net.minecraft.server.v1_13_R2.Entity;
import net.minecraft.server.v1_13_R2.EntityItem;
import net.minecraft.server.v1_13_R2.Packet;
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_13_R2.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private DataWatcherObject<net.minecraft.server.v1_13_R2.ItemStack> item;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
Packet<?> teleportPacket = HologramUtil.createTeleportPacket(id, location, false);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.register(item, getNmsItemStack()); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")
private DataWatcher createDataWatcher() {
try {
Field fAirTicks = Entity.class.getDeclaredField("aD");
Field fNoGravity = Entity.class.getDeclaredField("aH");
Field fItem = EntityItem.class.getDeclaredField("b");
setAccessible(fAirTicks, fNoGravity, fItem);
item = (DataWatcherObject<net.minecraft.server.v1_13_R2.ItemStack>) fItem.get(null);
DataWatcherObject<Integer> airTicks = (DataWatcherObject<Integer>) fAirTicks.get(null);
DataWatcherObject<Boolean> noGravity = (DataWatcherObject<Boolean>) fNoGravity.get(null);
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.register(airTicks, 300);
dataWatcher.register(noGravity, true);
dataWatcher.register(item, getNmsItemStack());
return dataWatcher;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
private net.minecraft.server.v1_13_R2.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
private void setAccessible(AccessibleObject... args) {
Arrays.stream(args).forEach(arg -> arg.setAccessible(true));
}
}

View File

@ -1,31 +1,25 @@
package de.epiceric.shopchest.shop.hologram.v1_13_R2;
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_13_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_13_R2.DataWatcher;
import net.minecraft.server.v1_13_R2.DataWatcherObject;
import net.minecraft.server.v1_13_R2.Entity;
import net.minecraft.server.v1_13_R2.EntityArmorStand;
import net.minecraft.server.v1_13_R2.IChatBaseComponent;
import net.minecraft.server.v1_13_R2.IChatBaseComponent.ChatSerializer;
import net.minecraft.server.v1_13_R2.Packet;
import net.minecraft.server.v1_13_R2.PacketDataSerializer;
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_13_R2.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_13_R2.PlayerConnection;
import net.minecraft.server.v1_13_R2.IChatBaseComponent.ChatSerializer;
public class HologramLine implements IHologramLine {
private PacketPlayOutSpawnEntity spawnPacket;
@ -46,16 +40,16 @@ public class HologramLine implements IHologramLine {
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
PacketPlayOutEntityTeleport packet = createTeleportPacket();
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
}
@Override
@ -71,7 +65,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -85,7 +79,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -94,59 +88,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(packet -> con.sendPacket(packet));
}
private PacketPlayOutEntityTeleport createTeleportPacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
private void updatePacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.a(UUID.randomUUID()); // uuid
s.writeByte(78); // type
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // 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 {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")

View File

@ -0,0 +1,114 @@
package de.epiceric.shopchest.shop.hologram.v1_13_R2;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_13_R2.Entity;
import net.minecraft.server.v1_13_R2.Packet;
import net.minecraft.server.v1_13_R2.PacketDataSerializer;
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_13_R2.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_13_R2.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id + 1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType == 78 ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.a(UUID.randomUUID()); // uuid
serializer.writeByte(entityType); // entity type
serializer.writeDouble(location.getX()); // x
serializer.writeDouble(location.getY() + yLift); // y
serializer.writeDouble(location.getZ()); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
/**
* Creates a PacketPlayOutEntityTeleport
*
* @param id the entity ID
* @param location the new entity location
* @param lift whether the entity will be lifted by 1.975
* @return the packet
*/
public static PacketPlayOutEntityTeleport createTeleportPacket(int id, Location location, boolean lift) {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + (lift ? 1.975 : 0)); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
}

View File

@ -0,0 +1,130 @@
package de.epiceric.shopchest.shop.hologram.v1_14_R1;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_14_R1.DataWatcher;
import net.minecraft.server.v1_14_R1.DataWatcherObject;
import net.minecraft.server.v1_14_R1.Entity;
import net.minecraft.server.v1_14_R1.EntityItem;
import net.minecraft.server.v1_14_R1.EntityTypes;
import net.minecraft.server.v1_14_R1.Packet;
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_14_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_14_R1.Vec3D;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private DataWatcherObject<net.minecraft.server.v1_14_R1.ItemStack> item;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, EntityTypes.ITEM, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, EntityTypes.ITEM, spawnPacket, location);
Packet<?> teleportPacket = HologramUtil.createTeleportPacket(id, location, false);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.register(item, getNmsItemStack()); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, new Vec3D(0, 0, 0));
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")
private DataWatcher createDataWatcher() {
try {
Field fAirTicks = Entity.class.getDeclaredField("AIR_TICKS");
Field fNoGravity = Entity.class.getDeclaredField("aC");
Field fItem = EntityItem.class.getDeclaredField("ITEM");
setAccessible(fAirTicks, fNoGravity, fItem);
item = (DataWatcherObject<net.minecraft.server.v1_14_R1.ItemStack>) fItem.get(null);
DataWatcherObject<Integer> airTicks = (DataWatcherObject<Integer>) fAirTicks.get(null);
DataWatcherObject<Boolean> noGravity = (DataWatcherObject<Boolean>) fNoGravity.get(null);
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.register(airTicks, 300);
dataWatcher.register(noGravity, true);
dataWatcher.register(item, getNmsItemStack());
return dataWatcher;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
private net.minecraft.server.v1_14_R1.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
private void setAccessible(AccessibleObject... args) {
Arrays.stream(args).forEach(arg -> arg.setAccessible(true));
}
}

View File

@ -1,33 +1,26 @@
package de.epiceric.shopchest.shop.hologram.v1_14_R1;
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_14_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_14_R1.DataWatcher;
import net.minecraft.server.v1_14_R1.DataWatcherObject;
import net.minecraft.server.v1_14_R1.Entity;
import net.minecraft.server.v1_14_R1.EntityArmorStand;
import net.minecraft.server.v1_14_R1.EntityTypes;
import net.minecraft.server.v1_14_R1.IChatBaseComponent;
import net.minecraft.server.v1_14_R1.IRegistry;
import net.minecraft.server.v1_14_R1.IChatBaseComponent.ChatSerializer;
import net.minecraft.server.v1_14_R1.Packet;
import net.minecraft.server.v1_14_R1.PacketDataSerializer;
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_14_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_14_R1.PlayerConnection;
import net.minecraft.server.v1_14_R1.IChatBaseComponent.ChatSerializer;
public class HologramLine implements IHologramLine {
private PacketPlayOutSpawnEntity spawnPacket;
@ -48,16 +41,16 @@ public class HologramLine implements IHologramLine {
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, EntityTypes.ARMOR_STAND, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, EntityTypes.ARMOR_STAND, spawnPacket, location);
PacketPlayOutEntityTeleport packet = createTeleportPacket();
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
}
@Override
@ -73,7 +66,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -87,7 +80,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -96,59 +89,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(packet -> con.sendPacket(packet));
}
private PacketPlayOutEntityTeleport createTeleportPacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
private 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 {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")

View File

@ -0,0 +1,116 @@
package de.epiceric.shopchest.shop.hologram.v1_14_R1;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_14_R1.Entity;
import net.minecraft.server.v1_14_R1.EntityTypes;
import net.minecraft.server.v1_14_R1.IRegistry;
import net.minecraft.server.v1_14_R1.Packet;
import net.minecraft.server.v1_14_R1.PacketDataSerializer;
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_14_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_14_R1.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
AtomicInteger count = (AtomicInteger) entityCountField.get(null);
return count.incrementAndGet();
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, EntityTypes<?> entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType.equals(EntityTypes.ARMOR_STAND) ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.a(UUID.randomUUID()); // uuid
serializer.d(IRegistry.ENTITY_TYPE.a(entityType)); // type
serializer.writeDouble(location.getX()); // x
serializer.writeDouble(location.getY() + yLift); // y
serializer.writeDouble(location.getZ()); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
/**
* Creates a PacketPlayOutEntityTeleport
*
* @param id the entity ID
* @param location the new entity location
* @param lift whether the entity will be lifted by 1.975
* @return the packet
*/
public static PacketPlayOutEntityTeleport createTeleportPacket(int id, Location location, boolean lift) {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + (lift ? 1.975 : 0)); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
}

View File

@ -0,0 +1,130 @@
package de.epiceric.shopchest.shop.hologram.v1_15_R1;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
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.EntityItem;
import net.minecraft.server.v1_15_R1.EntityTypes;
import net.minecraft.server.v1_15_R1.Packet;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_15_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_15_R1.Vec3D;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private DataWatcherObject<net.minecraft.server.v1_15_R1.ItemStack> item;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, EntityTypes.ITEM, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, EntityTypes.ITEM, spawnPacket, location);
Packet<?> teleportPacket = HologramUtil.createTeleportPacket(id, location, false);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.register(item, getNmsItemStack()); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, new Vec3D(0, 0, 0));
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")
private DataWatcher createDataWatcher() {
try {
Field fAirTicks = Entity.class.getDeclaredField("AIR_TICKS");
Field fNoGravity = Entity.class.getDeclaredField("aC");
Field fItem = EntityItem.class.getDeclaredField("ITEM");
setAccessible(fAirTicks, fNoGravity, fItem);
item = (DataWatcherObject<net.minecraft.server.v1_15_R1.ItemStack>) fItem.get(null);
DataWatcherObject<Integer> airTicks = (DataWatcherObject<Integer>) fAirTicks.get(null);
DataWatcherObject<Boolean> noGravity = (DataWatcherObject<Boolean>) fNoGravity.get(null);
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.register(airTicks, 300);
dataWatcher.register(noGravity, true);
dataWatcher.register(item, getNmsItemStack());
return dataWatcher;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
private net.minecraft.server.v1_15_R1.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
private void setAccessible(AccessibleObject... args) {
Arrays.stream(args).forEach(arg -> arg.setAccessible(true));
}
}

View File

@ -1,33 +1,26 @@
package de.epiceric.shopchest.shop.hologram.v1_15_R1;
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 de.epiceric.shopchest.shop.hologram.IHologramLine;
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.IChatBaseComponent.ChatSerializer;
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 spawnPacket;
@ -48,16 +41,16 @@ public class HologramLine implements IHologramLine {
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, EntityTypes.ARMOR_STAND, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, EntityTypes.ARMOR_STAND, spawnPacket, location);
PacketPlayOutEntityTeleport packet = createTeleportPacket();
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
}
@Override
@ -73,7 +66,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -87,7 +80,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -96,59 +89,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(packet -> con.sendPacket(packet));
}
private PacketPlayOutEntityTeleport createTeleportPacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
private 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 {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")

View File

@ -0,0 +1,116 @@
package de.epiceric.shopchest.shop.hologram.v1_15_R1;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
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.Entity;
import net.minecraft.server.v1_15_R1.EntityTypes;
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.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_15_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_15_R1.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
AtomicInteger count = (AtomicInteger) entityCountField.get(null);
return count.incrementAndGet();
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, EntityTypes<?> entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType.equals(EntityTypes.ARMOR_STAND) ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.a(UUID.randomUUID()); // uuid
serializer.d(IRegistry.ENTITY_TYPE.a(entityType)); // type
serializer.writeDouble(location.getX()); // x
serializer.writeDouble(location.getY() + yLift); // y
serializer.writeDouble(location.getZ()); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
/**
* Creates a PacketPlayOutEntityTeleport
*
* @param id the entity ID
* @param location the new entity location
* @param lift whether the entity will be lifted by 1.975
* @return the packet
*/
public static PacketPlayOutEntityTeleport createTeleportPacket(int id, Location location, boolean lift) {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + (lift ? 1.975 : 0)); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
}

View File

@ -0,0 +1,105 @@
package de.epiceric.shopchest.shop.hologram.v1_8_R1;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
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.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_8_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_8_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_8_R1.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_8_R1.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
int x = MathHelper.floor(location.getX() * 32d);
int y = MathHelper.floor(location.getY() * 32d);
int z = MathHelper.floor(location.getZ() * 32d);
Packet teleportPacket = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.a(10, getNmsItemStack()); // item stack
Packet metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private DataWatcher createDataWatcher() {
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.a(0, 0); // entity flags
dataWatcher.a(1, (short) 300); // air ticks
dataWatcher.a(2, ""); // custom name
dataWatcher.a(3, 0); // name visible
dataWatcher.a(10, getNmsItemStack()); // item stack
return dataWatcher;
}
private net.minecraft.server.v1_8_R1.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
}

View File

@ -1,22 +1,16 @@
package de.epiceric.shopchest.shop.hologram.v1_8_R1;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
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 spawnPacket;
@ -27,27 +21,27 @@ public class HologramLine implements IHologramLine {
private String text;
public HologramLine(Location location, String text) {
this.id = 5;
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.text = text == null ? "" : text;
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
int x = MathHelper.floor(location.getX() * 32d);
int y = MathHelper.floor(location.getY() * 32d);
int z = MathHelper.floor(location.getZ() * 32d);
Packet teleportPacket = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, teleportPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
@ -63,7 +57,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible
Packet metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -77,7 +71,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -86,26 +80,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
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.spawnPacket.a(serializer);
serializer.release();
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private DataWatcher createDataWatcher() {

View File

@ -0,0 +1,72 @@
package de.epiceric.shopchest.shop.hologram.v1_8_R1;
import java.lang.reflect.Field;
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.Entity;
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.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_8_R1.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id+1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.writeByte(entityType); // 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 (?)
spawnPacket.a(serializer);
serializer.release();
}
}

View File

@ -0,0 +1,102 @@
package de.epiceric.shopchest.shop.hologram.v1_8_R2;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R2.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_8_R2.DataWatcher;
import net.minecraft.server.v1_8_R2.MathHelper;
import net.minecraft.server.v1_8_R2.Packet;
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_8_R2.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
int x = MathHelper.floor(location.getX() * 32d);
int y = MathHelper.floor(location.getY() * 32d);
int z = MathHelper.floor(location.getZ() * 32d);
Packet<?> teleportPacket = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.a(10, getNmsItemStack()); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private DataWatcher createDataWatcher() {
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.a(1, (short) 300); // air ticks
dataWatcher.a(10, getNmsItemStack()); // item stack
return dataWatcher;
}
private net.minecraft.server.v1_8_R2.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
}

View File

@ -1,23 +1,16 @@
package de.epiceric.shopchest.shop.hologram.v1_8_R2;
import java.io.IOException;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_8_R2.DataWatcher;
import net.minecraft.server.v1_8_R2.MathHelper;
import net.minecraft.server.v1_8_R2.Packet;
import net.minecraft.server.v1_8_R2.PacketDataSerializer;
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_8_R2.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_8_R2.PlayerConnection;
public class HologramLine implements IHologramLine {
private PacketPlayOutSpawnEntity spawnPacket;
@ -28,27 +21,27 @@ public class HologramLine implements IHologramLine {
private String text;
public HologramLine(Location location, String text) {
this.id = 5;
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.text = text == null ? "" : text;
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
int x = MathHelper.floor(location.getX() * 32d);
int y = MathHelper.floor((location.getY() + 1.975) * 32d);
int z = MathHelper.floor(location.getZ() * 32d);
Packet<?> teleportPacket = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, teleportPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
@ -64,7 +57,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -78,7 +71,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -87,32 +80,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
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 s = new PacketDataSerializer(Unpooled.buffer());
s.b(id); // id
s.writeByte(78); // entity type
s.writeInt(MathHelper.floor(location.getX() * 32d)); // x
s.writeInt(MathHelper.floor((location.getY() + 1.975) * 32d)); // y
s.writeInt(MathHelper.floor(location.getZ() * 32d)); // z
s.writeByte(0); // pitch
s.writeByte(0); // yaw
s.writeInt(0); // has motion (?)
try {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private DataWatcher createDataWatcher() {

View File

@ -0,0 +1,81 @@
package de.epiceric.shopchest.shop.hologram.v1_8_R2;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_8_R2.Entity;
import net.minecraft.server.v1_8_R2.MathHelper;
import net.minecraft.server.v1_8_R2.Packet;
import net.minecraft.server.v1_8_R2.PacketDataSerializer;
import net.minecraft.server.v1_8_R2.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_8_R2.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id + 1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType == 78 ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.writeByte(entityType); // entity type
serializer.writeInt(MathHelper.floor(location.getX() * 32d)); // x
serializer.writeInt(MathHelper.floor((location.getY() + yLift) * 32d)); // y
serializer.writeInt(MathHelper.floor(location.getZ() * 32d)); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
}

View File

@ -0,0 +1,102 @@
package de.epiceric.shopchest.shop.hologram.v1_8_R3;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_8_R3.DataWatcher;
import net.minecraft.server.v1_8_R3.MathHelper;
import net.minecraft.server.v1_8_R3.Packet;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
int x = MathHelper.floor(location.getX() * 32d);
int y = MathHelper.floor(location.getY() * 32d);
int z = MathHelper.floor(location.getZ() * 32d);
Packet<?> teleportPacket = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.a(10, getNmsItemStack());
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private DataWatcher createDataWatcher() {
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.a(1, (short) 300); // air ticks
dataWatcher.a(10, getNmsItemStack()); // item stack
return dataWatcher;
}
private net.minecraft.server.v1_8_R3.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
}

View File

@ -1,23 +1,16 @@
package de.epiceric.shopchest.shop.hologram.v1_8_R3;
import java.io.IOException;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_8_R3.DataWatcher;
import net.minecraft.server.v1_8_R3.MathHelper;
import net.minecraft.server.v1_8_R3.Packet;
import net.minecraft.server.v1_8_R3.PacketDataSerializer;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_8_R3.PlayerConnection;
public class HologramLine implements IHologramLine {
private PacketPlayOutSpawnEntity spawnPacket;
@ -35,20 +28,20 @@ public class HologramLine implements IHologramLine {
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
int x = MathHelper.floor(location.getX() * 32d);
int y = MathHelper.floor((location.getY() + 1.975) * 32d);
int z = MathHelper.floor(location.getZ() * 32d);
Packet<?> teleportPacket = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, teleportPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
@ -64,7 +57,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -78,7 +71,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -87,32 +80,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
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 s = new PacketDataSerializer(Unpooled.buffer());
s.b(id); // id
s.writeByte(78); // entity type
s.writeInt(MathHelper.floor(location.getX() * 32d)); // x
s.writeInt(MathHelper.floor((location.getY() + 1.975) * 32d)); // y
s.writeInt(MathHelper.floor(location.getZ() * 32d)); // z
s.writeByte(0); // pitch
s.writeByte(0); // yaw
s.writeInt(0); // has motion (?)
try {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private DataWatcher createDataWatcher() {

View File

@ -0,0 +1,81 @@
package de.epiceric.shopchest.shop.hologram.v1_8_R3;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_8_R3.Entity;
import net.minecraft.server.v1_8_R3.MathHelper;
import net.minecraft.server.v1_8_R3.Packet;
import net.minecraft.server.v1_8_R3.PacketDataSerializer;
import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_8_R3.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id + 1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType == 78 ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.writeByte(entityType); // entity type
serializer.writeInt(MathHelper.floor(location.getX() * 32d)); // x
serializer.writeInt(MathHelper.floor((location.getY() + yLift) * 32d)); // y
serializer.writeInt(MathHelper.floor(location.getZ() * 32d)); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
}

View File

@ -0,0 +1,127 @@
package de.epiceric.shopchest.shop.hologram.v1_9_R1;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import com.google.common.base.Optional;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_9_R1.DataWatcher;
import net.minecraft.server.v1_9_R1.DataWatcherObject;
import net.minecraft.server.v1_9_R1.Entity;
import net.minecraft.server.v1_9_R1.EntityItem;
import net.minecraft.server.v1_9_R1.Packet;
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_9_R1.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private DataWatcherObject<Optional<net.minecraft.server.v1_9_R1.ItemStack>> item;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
Packet<?> teleportPacket = HologramUtil.createTeleportPacket(id, location, false);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.register(item, Optional.of(getNmsItemStack())); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")
private DataWatcher createDataWatcher() {
try {
Field fAirTicks = Entity.class.getDeclaredField("ay");
Field fItem = EntityItem.class.getDeclaredField("c");
setAccessible(fAirTicks, fItem);
item = (DataWatcherObject<Optional<net.minecraft.server.v1_9_R1.ItemStack>>) fItem.get(null);
DataWatcherObject<Integer> airTicks = (DataWatcherObject<Integer>) fAirTicks.get(null);
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.register(airTicks, 300);
dataWatcher.register(item, Optional.of(getNmsItemStack()));
return dataWatcher;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
private net.minecraft.server.v1_9_R1.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
private void setAccessible(AccessibleObject... args) {
Arrays.stream(args).forEach(arg -> arg.setAccessible(true));
}
}

View File

@ -1,30 +1,24 @@
package de.epiceric.shopchest.shop.hologram.v1_9_R1;
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_9_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_9_R1.DataWatcher;
import net.minecraft.server.v1_9_R1.DataWatcherObject;
import net.minecraft.server.v1_9_R1.Entity;
import net.minecraft.server.v1_9_R1.EntityArmorStand;
import net.minecraft.server.v1_9_R1.IChatBaseComponent;
import net.minecraft.server.v1_9_R1.Packet;
import net.minecraft.server.v1_9_R1.PacketDataSerializer;
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_9_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_9_R1.PlayerConnection;
public class HologramLine implements IHologramLine {
private PacketPlayOutSpawnEntity spawnPacket;
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine {
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
PacketPlayOutEntityTeleport packet = createTeleportPacket();
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
}
@Override
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine {
dataWatcher.register(customName, text);
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine {
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(packet -> con.sendPacket(packet));
}
private PacketPlayOutEntityTeleport createTeleportPacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
private void updatePacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.a(UUID.randomUUID()); // uuid
s.writeByte(78); // type
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // 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 {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")

View File

@ -0,0 +1,114 @@
package de.epiceric.shopchest.shop.hologram.v1_9_R1;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_9_R1.Entity;
import net.minecraft.server.v1_9_R1.Packet;
import net.minecraft.server.v1_9_R1.PacketDataSerializer;
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_9_R1.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_9_R1.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id + 1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType == 78 ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.a(UUID.randomUUID()); // uuid
serializer.writeByte(entityType); // entity type
serializer.writeDouble(location.getX()); // x
serializer.writeDouble(location.getY() + yLift); // y
serializer.writeDouble(location.getZ()); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
/**
* Creates a PacketPlayOutEntityTeleport
*
* @param id the entity ID
* @param location the new entity location
* @param lift whether the entity will be lifted by 1.975
* @return the packet
*/
public static PacketPlayOutEntityTeleport createTeleportPacket(int id, Location location, boolean lift) {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + (lift ? 1.975 : 0)); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
}

View File

@ -0,0 +1,127 @@
package de.epiceric.shopchest.shop.hologram.v1_9_R2;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import com.google.common.base.Optional;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R2.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.shop.hologram.IHologramItem;
import net.minecraft.server.v1_9_R2.DataWatcher;
import net.minecraft.server.v1_9_R2.DataWatcherObject;
import net.minecraft.server.v1_9_R2.Entity;
import net.minecraft.server.v1_9_R2.EntityItem;
import net.minecraft.server.v1_9_R2.Packet;
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityVelocity;
import net.minecraft.server.v1_9_R2.PacketPlayOutSpawnEntity;
public class HologramItem implements IHologramItem {
private PacketPlayOutSpawnEntity spawnPacket;
private DataWatcher dataWatcher;
private DataWatcherObject<Optional<net.minecraft.server.v1_9_R2.ItemStack>> item;
private int id;
private Location location;
private ItemStack itemStack;
public HologramItem(Location location, ItemStack itemStack) {
this.id = HologramUtil.getFreeEntityId();
this.location = location.clone();
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
HologramUtil.updateSpawnPacket(id, 2, spawnPacket, location);
Packet<?> teleportPacket = HologramUtil.createTeleportPacket(id, location, false);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, teleportPacket));
}
@Override
public Location getLocation() {
return this.location.clone();
}
@Override
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack.clone();
this.itemStack.setAmount(1);
dataWatcher.register(item, Optional.of(getNmsItemStack())); // item stack
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
public ItemStack getItemStack() {
return this.itemStack.clone();
}
@Override
public void showPlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
Packet<?> velocityPacket = new PacketPlayOutEntityVelocity(id, 0, 0, 0);
HologramUtil.sendPackets(player, spawnPacket, metadataPacket, velocityPacket);
}
@Override
public void hidePlayer(Player player) {
if (player == null || !player.isOnline()) {
return;
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")
private DataWatcher createDataWatcher() {
try {
Field fAirTicks = Entity.class.getDeclaredField("az");
Field fItem = EntityItem.class.getDeclaredField("c");
setAccessible(fAirTicks, fItem);
item = (DataWatcherObject<Optional<net.minecraft.server.v1_9_R2.ItemStack>>) fItem.get(null);
DataWatcherObject<Integer> airTicks = (DataWatcherObject<Integer>) fAirTicks.get(null);
DataWatcher dataWatcher = new DataWatcher(null);
dataWatcher.register(airTicks, 300);
dataWatcher.register(item, Optional.of(getNmsItemStack()));
return dataWatcher;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
private net.minecraft.server.v1_9_R2.ItemStack getNmsItemStack() {
return CraftItemStack.asNMSCopy(itemStack);
}
private void setAccessible(AccessibleObject... args) {
Arrays.stream(args).forEach(arg -> arg.setAccessible(true));
}
}

View File

@ -1,30 +1,24 @@
package de.epiceric.shopchest.shop.hologram.v1_9_R2;
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_9_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.shop.hologram.IHologramLine;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_9_R2.DataWatcher;
import net.minecraft.server.v1_9_R2.DataWatcherObject;
import net.minecraft.server.v1_9_R2.Entity;
import net.minecraft.server.v1_9_R2.EntityArmorStand;
import net.minecraft.server.v1_9_R2.IChatBaseComponent;
import net.minecraft.server.v1_9_R2.Packet;
import net.minecraft.server.v1_9_R2.PacketDataSerializer;
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_9_R2.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_9_R2.PlayerConnection;
public class HologramLine implements IHologramLine{
private PacketPlayOutSpawnEntity spawnPacket;
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine{
this.spawnPacket = new PacketPlayOutSpawnEntity();
this.dataWatcher = createDataWatcher();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
}
@Override
public void setLocation(Location location) {
this.location = location.clone();
updatePacket();
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
PacketPlayOutEntityTeleport packet = createTeleportPacket();
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
}
@Override
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine{
dataWatcher.register(customName, text);
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
location.getWorld().getPlayers().forEach(player -> sendPackets(player, metadataPacket));
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, metadataPacket));
}
@Override
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine{
return;
}
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
}
@Override
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine{
return;
}
sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
private void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(packet -> con.sendPacket(packet));
}
private PacketPlayOutEntityTeleport createTeleportPacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
private void updatePacket() {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.a(UUID.randomUUID()); // uuid
s.writeByte(78); // type
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + 1.975); // 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 {
spawnPacket.a(s);
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
HologramUtil.sendPackets(player, new PacketPlayOutEntityDestroy(id));
}
@SuppressWarnings("unchecked")

View File

@ -0,0 +1,114 @@
package de.epiceric.shopchest.shop.hologram.v1_9_R2;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_9_R2.Entity;
import net.minecraft.server.v1_9_R2.Packet;
import net.minecraft.server.v1_9_R2.PacketDataSerializer;
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_9_R2.PacketPlayOutSpawnEntity;
import net.minecraft.server.v1_9_R2.PlayerConnection;
public class HologramUtil {
private HologramUtil() {
}
/**
* Gets an unused entity ID to be used for hologram lines and items
*
* @return an unused entity ID or -1 if an error occurred
*/
public static int getFreeEntityId() {
try {
Field entityCountField = Entity.class.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id + 1);
return id;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Sends the given packets to the given player
*
* @param player the player to send the packets to
* @param packets the packets to send
*/
public static void sendPackets(Player player, Packet<?>... packets) {
PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;
Arrays.stream(packets).forEach(con::sendPacket);
}
/**
* Updates the PacketPlayOutSpawnEntity data to include the correct location
*
* @param id the entity ID
* @param entityType the entity type
* @param spawnPacket the packet
* @param location the entity's location
*/
public static void updateSpawnPacket(int id, int entityType, PacketPlayOutSpawnEntity spawnPacket, Location location) {
double yLift = entityType == 78 ? 1.975 : 0;
PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer());
serializer.b(id); // id
serializer.a(UUID.randomUUID()); // uuid
serializer.writeByte(entityType); // entity type
serializer.writeDouble(location.getX()); // x
serializer.writeDouble(location.getY() + yLift); // y
serializer.writeDouble(location.getZ()); // z
serializer.writeByte(0); // pitch
serializer.writeByte(0); // yaw
serializer.writeInt(0); // has motion (?)
try {
spawnPacket.a(serializer);
} catch (IOException e) {
e.printStackTrace();
} finally {
serializer.release();
}
}
/**
* Creates a PacketPlayOutEntityTeleport
*
* @param id the entity ID
* @param location the new entity location
* @param lift whether the entity will be lifted by 1.975
* @return the packet
*/
public static PacketPlayOutEntityTeleport createTeleportPacket(int id, Location location, boolean lift) {
PacketDataSerializer s = new PacketDataSerializer(Unpooled.buffer());
s.d(id); // id
s.writeDouble(location.getX()); // x
s.writeDouble(location.getY() + (lift ? 1.975 : 0)); // y
s.writeDouble(location.getZ()); // z
s.writeByte(0); // yaw
s.writeByte(0); // pitch
s.writeBoolean(true); // on ground
try {
PacketPlayOutEntityTeleport packet = new PacketPlayOutEntityTeleport();
packet.a(s);
return packet;
} catch (IOException e) {
e.printStackTrace();
} finally {
s.release();
}
return null;
}
}