mirror of
https://github.com/EpicEricEE/ShopChest.git
synced 2024-11-28 21:45:47 +01:00
Add hologram item
This commit is contained in:
parent
ff9c1a4cb4
commit
263137acba
@ -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
|
||||
*/
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user