mirror of
https://github.com/EpicEricEE/ShopChest.git
synced 2024-11-25 03:55:22 +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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import de.epiceric.shopchest.api.ShopChest;
|
import de.epiceric.shopchest.api.ShopChest;
|
||||||
import de.epiceric.shopchest.api.shop.Shop;
|
import de.epiceric.shopchest.api.shop.Shop;
|
||||||
import de.epiceric.shopchest.shop.ShopImpl;
|
import de.epiceric.shopchest.shop.ShopImpl;
|
||||||
import de.epiceric.shopchest.util.NmsUtil;
|
|
||||||
|
|
||||||
public class Hologram {
|
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 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) {
|
public Hologram(ShopChest plugin, Shop shop) {
|
||||||
this.shop = shop;
|
this.shop = shop;
|
||||||
|
this.item = HologramFactory.newHologramItem(getItemLocation(), shop.getProduct().getItemStack());
|
||||||
|
|
||||||
int topLine = shop.canPlayerBuy() && shop.canPlayerSell() ? 3 : 2;
|
int topLine = shop.canPlayerBuy() && shop.canPlayerSell() ? 3 : 2;
|
||||||
|
|
||||||
// TODO: Configurable
|
// 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()));
|
lines.add(HologramFactory.newHologramLine(getLineLocation(topLine),
|
||||||
if (shop.canPlayerBuy()) lines.add(newHologramLine(getLocation(topLine - 2), "§eBuy for " + plugin.formatEconomy(shop.getBuyPrice())));
|
shop.getVendor().map(OfflinePlayer::getName).orElse("§cAdmin Shop")));
|
||||||
if (shop.canPlayerSell()) lines.add(newHologramLine(getLocation(0), "§eSell for " + plugin.formatEconomy(shop.getSellPrice())));
|
|
||||||
|
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) {
|
private Location getCenterOfChest() {
|
||||||
double lineHeight = 0.25;
|
ShopImpl shop = (ShopImpl) this.shop;
|
||||||
Location loc = shop.getLocation().subtract(0, 0.75, 0);
|
Location location = shop.getLocation();
|
||||||
Location otherLoc = ((ShopImpl) shop).getOtherLocation().orElse(null);
|
Optional<Location> optional = shop.getOtherLocation();
|
||||||
|
|
||||||
if (otherLoc == null) {
|
if (optional.isPresent()) {
|
||||||
return loc.add(0.5, lineFromBottom * lineHeight, 0.5);
|
Location otherLoc = optional.get();
|
||||||
}
|
Vector diff = otherLoc.subtract(location).toVector();
|
||||||
|
|
||||||
if (loc.getX() == otherLoc.getX()) {
|
// Invert cross vector direction if diff has negative x or z
|
||||||
double zDiff = otherLoc.subtract(loc).getZ();
|
Vector cross = (diff.getX() < 0.1 || diff.getZ() < 0.1)
|
||||||
return loc.add(0.5, lineFromBottom * lineHeight, zDiff);
|
? diff.getCrossProduct(new Vector(0, -0.5, 0))
|
||||||
|
: diff.getCrossProduct(new Vector(0, 0.5, 0));
|
||||||
|
|
||||||
|
location.add(diff.add(cross));
|
||||||
} else {
|
} else {
|
||||||
double xDiff = otherLoc.subtract(loc).getX();
|
location.add(0.5, 0, 0.5);
|
||||||
return loc.add(xDiff, lineFromBottom * lineHeight, 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
|
* Hides the hologram from all players in the hologram's world and removes all lines
|
||||||
*/
|
*/
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
item.destroy();
|
||||||
lines.forEach(IHologramLine::destroy);
|
lines.forEach(IHologramLine::destroy);
|
||||||
lines.clear();
|
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
|
* @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
|
* @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;
|
package de.epiceric.shopchest.shop.hologram.v1_10_R1;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_10_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_10_R1.DataWatcherObject;
|
import net.minecraft.server.v1_10_R1.DataWatcherObject;
|
||||||
import net.minecraft.server.v1_10_R1.Entity;
|
import net.minecraft.server.v1_10_R1.Entity;
|
||||||
import net.minecraft.server.v1_10_R1.EntityArmorStand;
|
import net.minecraft.server.v1_10_R1.EntityArmorStand;
|
||||||
import net.minecraft.server.v1_10_R1.IChatBaseComponent;
|
import net.minecraft.server.v1_10_R1.IChatBaseComponent;
|
||||||
import net.minecraft.server.v1_10_R1.Packet;
|
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.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_10_R1.PacketPlayOutSpawnEntity;
|
import net.minecraft.server.v1_10_R1.PacketPlayOutSpawnEntity;
|
||||||
import net.minecraft.server.v1_10_R1.PlayerConnection;
|
|
||||||
|
|
||||||
public class HologramLine implements IHologramLine {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine {
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
PacketPlayOutEntityTeleport packet = createTeleportPacket();
|
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
|
||||||
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
|
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.register(customName, text);
|
dataWatcher.register(customName, text);
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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;
|
package de.epiceric.shopchest.shop.hologram.v1_11_R1;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_11_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_11_R1.DataWatcherObject;
|
import net.minecraft.server.v1_11_R1.DataWatcherObject;
|
||||||
import net.minecraft.server.v1_11_R1.Entity;
|
import net.minecraft.server.v1_11_R1.Entity;
|
||||||
import net.minecraft.server.v1_11_R1.EntityArmorStand;
|
import net.minecraft.server.v1_11_R1.EntityArmorStand;
|
||||||
import net.minecraft.server.v1_11_R1.IChatBaseComponent;
|
import net.minecraft.server.v1_11_R1.IChatBaseComponent;
|
||||||
import net.minecraft.server.v1_11_R1.Packet;
|
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.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_11_R1.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_11_R1.PacketPlayOutSpawnEntity;
|
import net.minecraft.server.v1_11_R1.PacketPlayOutSpawnEntity;
|
||||||
import net.minecraft.server.v1_11_R1.PlayerConnection;
|
|
||||||
|
|
||||||
public class HologramLine implements IHologramLine {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine {
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
PacketPlayOutEntityTeleport packet = createTeleportPacket();
|
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
|
||||||
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
|
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.register(customName, text);
|
dataWatcher.register(customName, text);
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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;
|
package de.epiceric.shopchest.shop.hologram.v1_12_R1;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_12_R1.DataWatcherObject;
|
import net.minecraft.server.v1_12_R1.DataWatcherObject;
|
||||||
import net.minecraft.server.v1_12_R1.Entity;
|
import net.minecraft.server.v1_12_R1.Entity;
|
||||||
import net.minecraft.server.v1_12_R1.EntityArmorStand;
|
import net.minecraft.server.v1_12_R1.EntityArmorStand;
|
||||||
import net.minecraft.server.v1_12_R1.IChatBaseComponent;
|
import net.minecraft.server.v1_12_R1.IChatBaseComponent;
|
||||||
import net.minecraft.server.v1_12_R1.Packet;
|
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.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_12_R1.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_12_R1.PacketPlayOutSpawnEntity;
|
import net.minecraft.server.v1_12_R1.PacketPlayOutSpawnEntity;
|
||||||
import net.minecraft.server.v1_12_R1.PlayerConnection;
|
|
||||||
|
|
||||||
public class HologramLine implements IHologramLine {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine {
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
PacketPlayOutEntityTeleport packet = createTeleportPacket();
|
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
|
||||||
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
|
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.register(customName, text);
|
dataWatcher.register(customName, text);
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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;
|
package de.epiceric.shopchest.shop.hologram.v1_13_R1;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_13_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_13_R1.DataWatcherObject;
|
import net.minecraft.server.v1_13_R1.DataWatcherObject;
|
||||||
import net.minecraft.server.v1_13_R1.Entity;
|
import net.minecraft.server.v1_13_R1.Entity;
|
||||||
import net.minecraft.server.v1_13_R1.EntityArmorStand;
|
import net.minecraft.server.v1_13_R1.EntityArmorStand;
|
||||||
import net.minecraft.server.v1_13_R1.IChatBaseComponent;
|
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.Packet;
|
||||||
import net.minecraft.server.v1_13_R1.PacketDataSerializer;
|
|
||||||
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityDestroy;
|
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_13_R1.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_13_R1.PacketPlayOutSpawnEntity;
|
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 {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -46,16 +40,16 @@ public class HologramLine implements IHologramLine {
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
PacketPlayOutEntityTeleport packet = createTeleportPacket();
|
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, false);
|
||||||
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
|
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -71,7 +65,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
|
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -85,7 +79,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -94,59 +88,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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;
|
package de.epiceric.shopchest.shop.hologram.v1_13_R2;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_13_R2.DataWatcherObject;
|
import net.minecraft.server.v1_13_R2.DataWatcherObject;
|
||||||
import net.minecraft.server.v1_13_R2.Entity;
|
import net.minecraft.server.v1_13_R2.Entity;
|
||||||
import net.minecraft.server.v1_13_R2.EntityArmorStand;
|
import net.minecraft.server.v1_13_R2.EntityArmorStand;
|
||||||
import net.minecraft.server.v1_13_R2.IChatBaseComponent;
|
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.Packet;
|
||||||
import net.minecraft.server.v1_13_R2.PacketDataSerializer;
|
|
||||||
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityDestroy;
|
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_13_R2.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_13_R2.PacketPlayOutSpawnEntity;
|
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 {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -46,16 +40,16 @@ public class HologramLine implements IHologramLine {
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
PacketPlayOutEntityTeleport packet = createTeleportPacket();
|
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
|
||||||
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
|
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -71,7 +65,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
|
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -85,7 +79,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -94,59 +88,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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;
|
package de.epiceric.shopchest.shop.hologram.v1_14_R1;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_14_R1.DataWatcherObject;
|
import net.minecraft.server.v1_14_R1.DataWatcherObject;
|
||||||
import net.minecraft.server.v1_14_R1.Entity;
|
import net.minecraft.server.v1_14_R1.Entity;
|
||||||
import net.minecraft.server.v1_14_R1.EntityArmorStand;
|
import net.minecraft.server.v1_14_R1.EntityArmorStand;
|
||||||
import net.minecraft.server.v1_14_R1.EntityTypes;
|
import net.minecraft.server.v1_14_R1.EntityTypes;
|
||||||
import net.minecraft.server.v1_14_R1.IChatBaseComponent;
|
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.Packet;
|
||||||
import net.minecraft.server.v1_14_R1.PacketDataSerializer;
|
|
||||||
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityDestroy;
|
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_14_R1.PacketPlayOutSpawnEntity;
|
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 {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -48,16 +41,16 @@ public class HologramLine implements IHologramLine {
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, EntityTypes.ARMOR_STAND, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, EntityTypes.ARMOR_STAND, spawnPacket, location);
|
||||||
|
|
||||||
PacketPlayOutEntityTeleport packet = createTeleportPacket();
|
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
|
||||||
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
|
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -73,7 +66,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
|
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -87,7 +80,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -96,59 +89,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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;
|
package de.epiceric.shopchest.shop.hologram.v1_15_R1;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_15_R1.DataWatcherObject;
|
import net.minecraft.server.v1_15_R1.DataWatcherObject;
|
||||||
import net.minecraft.server.v1_15_R1.Entity;
|
import net.minecraft.server.v1_15_R1.Entity;
|
||||||
import net.minecraft.server.v1_15_R1.EntityArmorStand;
|
import net.minecraft.server.v1_15_R1.EntityArmorStand;
|
||||||
import net.minecraft.server.v1_15_R1.EntityTypes;
|
import net.minecraft.server.v1_15_R1.EntityTypes;
|
||||||
import net.minecraft.server.v1_15_R1.IChatBaseComponent;
|
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.Packet;
|
||||||
import net.minecraft.server.v1_15_R1.PacketDataSerializer;
|
|
||||||
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityDestroy;
|
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_15_R1.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_15_R1.PacketPlayOutSpawnEntity;
|
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 {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -48,16 +41,16 @@ public class HologramLine implements IHologramLine {
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, EntityTypes.ARMOR_STAND, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, EntityTypes.ARMOR_STAND, spawnPacket, location);
|
||||||
|
|
||||||
PacketPlayOutEntityTeleport packet = createTeleportPacket();
|
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
|
||||||
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
|
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -73,7 +66,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
|
dataWatcher.register(customName, Optional.ofNullable(ChatSerializer.b(text)));
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -87,7 +80,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -96,59 +89,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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;
|
package de.epiceric.shopchest.shop.hologram.v1_8_R1;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_8_R1.MathHelper;
|
import net.minecraft.server.v1_8_R1.MathHelper;
|
||||||
import net.minecraft.server.v1_8_R1.Packet;
|
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.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_8_R1.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_8_R1.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_8_R1.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_8_R1.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_8_R1.PacketPlayOutSpawnEntity;
|
import net.minecraft.server.v1_8_R1.PacketPlayOutSpawnEntity;
|
||||||
import net.minecraft.server.v1_8_R1.PlayerConnection;
|
|
||||||
|
|
||||||
public class HologramLine implements IHologramLine {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -27,27 +21,27 @@ public class HologramLine implements IHologramLine {
|
|||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
public HologramLine(Location location, String text) {
|
public HologramLine(Location location, String text) {
|
||||||
this.id = 5;
|
this.id = HologramUtil.getFreeEntityId();
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
this.text = text == null ? "" : text;
|
this.text = text == null ? "" : text;
|
||||||
|
|
||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
int x = MathHelper.floor(location.getX() * 32d);
|
int x = MathHelper.floor(location.getX() * 32d);
|
||||||
int y = MathHelper.floor(location.getY() * 32d);
|
int y = MathHelper.floor(location.getY() * 32d);
|
||||||
int z = MathHelper.floor(location.getZ() * 32d);
|
int z = MathHelper.floor(location.getZ() * 32d);
|
||||||
|
|
||||||
Packet teleportPacket = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true);
|
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
|
@Override
|
||||||
@ -63,7 +57,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible
|
dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible
|
||||||
|
|
||||||
Packet metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -77,7 +71,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -86,26 +80,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataWatcher createDataWatcher() {
|
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;
|
package de.epiceric.shopchest.shop.hologram.v1_8_R2;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_8_R2.MathHelper;
|
import net.minecraft.server.v1_8_R2.MathHelper;
|
||||||
import net.minecraft.server.v1_8_R2.Packet;
|
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.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_8_R2.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_8_R2.PacketPlayOutSpawnEntity;
|
import net.minecraft.server.v1_8_R2.PacketPlayOutSpawnEntity;
|
||||||
import net.minecraft.server.v1_8_R2.PlayerConnection;
|
|
||||||
|
|
||||||
public class HologramLine implements IHologramLine {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -28,27 +21,27 @@ public class HologramLine implements IHologramLine {
|
|||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
public HologramLine(Location location, String text) {
|
public HologramLine(Location location, String text) {
|
||||||
this.id = 5;
|
this.id = HologramUtil.getFreeEntityId();
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
this.text = text == null ? "" : text;
|
this.text = text == null ? "" : text;
|
||||||
|
|
||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
int x = MathHelper.floor(location.getX() * 32d);
|
int x = MathHelper.floor(location.getX() * 32d);
|
||||||
int y = MathHelper.floor((location.getY() + 1.975) * 32d);
|
int y = MathHelper.floor((location.getY() + 1.975) * 32d);
|
||||||
int z = MathHelper.floor(location.getZ() * 32d);
|
int z = MathHelper.floor(location.getZ() * 32d);
|
||||||
|
|
||||||
Packet<?> teleportPacket = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true);
|
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
|
@Override
|
||||||
@ -64,7 +57,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible
|
dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -78,7 +71,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -87,32 +80,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataWatcher createDataWatcher() {
|
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;
|
package de.epiceric.shopchest.shop.hologram.v1_8_R3;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_8_R3.MathHelper;
|
import net.minecraft.server.v1_8_R3.MathHelper;
|
||||||
import net.minecraft.server.v1_8_R3.Packet;
|
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.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity;
|
import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity;
|
||||||
import net.minecraft.server.v1_8_R3.PlayerConnection;
|
|
||||||
|
|
||||||
public class HologramLine implements IHologramLine {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -35,20 +28,20 @@ public class HologramLine implements IHologramLine {
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
int x = MathHelper.floor(location.getX() * 32d);
|
int x = MathHelper.floor(location.getX() * 32d);
|
||||||
int y = MathHelper.floor((location.getY() + 1.975) * 32d);
|
int y = MathHelper.floor((location.getY() + 1.975) * 32d);
|
||||||
int z = MathHelper.floor(location.getZ() * 32d);
|
int z = MathHelper.floor(location.getZ() * 32d);
|
||||||
|
|
||||||
Packet<?> teleportPacket = new PacketPlayOutEntityTeleport(id, x, y, z, (byte) 0, (byte) 0, true);
|
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
|
@Override
|
||||||
@ -64,7 +57,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible
|
dataWatcher.a(3, (byte) (this.text.isEmpty() ? 0 : 1)); // name visible
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -78,7 +71,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -87,32 +80,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataWatcher createDataWatcher() {
|
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;
|
package de.epiceric.shopchest.shop.hologram.v1_9_R1;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_9_R1.DataWatcherObject;
|
import net.minecraft.server.v1_9_R1.DataWatcherObject;
|
||||||
import net.minecraft.server.v1_9_R1.Entity;
|
import net.minecraft.server.v1_9_R1.Entity;
|
||||||
import net.minecraft.server.v1_9_R1.EntityArmorStand;
|
import net.minecraft.server.v1_9_R1.EntityArmorStand;
|
||||||
import net.minecraft.server.v1_9_R1.IChatBaseComponent;
|
import net.minecraft.server.v1_9_R1.IChatBaseComponent;
|
||||||
import net.minecraft.server.v1_9_R1.Packet;
|
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.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_9_R1.PacketPlayOutSpawnEntity;
|
import net.minecraft.server.v1_9_R1.PacketPlayOutSpawnEntity;
|
||||||
import net.minecraft.server.v1_9_R1.PlayerConnection;
|
|
||||||
|
|
||||||
public class HologramLine implements IHologramLine {
|
public class HologramLine implements IHologramLine {
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine {
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
PacketPlayOutEntityTeleport packet = createTeleportPacket();
|
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
|
||||||
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
|
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
dataWatcher.register(customName, text);
|
dataWatcher.register(customName, text);
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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;
|
package de.epiceric.shopchest.shop.hologram.v1_9_R2;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.v1_9_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import de.epiceric.shopchest.shop.hologram.IHologramLine;
|
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.DataWatcher;
|
||||||
import net.minecraft.server.v1_9_R2.DataWatcherObject;
|
import net.minecraft.server.v1_9_R2.DataWatcherObject;
|
||||||
import net.minecraft.server.v1_9_R2.Entity;
|
import net.minecraft.server.v1_9_R2.Entity;
|
||||||
import net.minecraft.server.v1_9_R2.EntityArmorStand;
|
import net.minecraft.server.v1_9_R2.EntityArmorStand;
|
||||||
import net.minecraft.server.v1_9_R2.IChatBaseComponent;
|
import net.minecraft.server.v1_9_R2.IChatBaseComponent;
|
||||||
import net.minecraft.server.v1_9_R2.Packet;
|
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.PacketPlayOutEntityDestroy;
|
||||||
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityMetadata;
|
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityMetadata;
|
||||||
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityTeleport;
|
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityTeleport;
|
||||||
import net.minecraft.server.v1_9_R2.PacketPlayOutSpawnEntity;
|
import net.minecraft.server.v1_9_R2.PacketPlayOutSpawnEntity;
|
||||||
import net.minecraft.server.v1_9_R2.PlayerConnection;
|
|
||||||
|
|
||||||
public class HologramLine implements IHologramLine{
|
public class HologramLine implements IHologramLine{
|
||||||
private PacketPlayOutSpawnEntity spawnPacket;
|
private PacketPlayOutSpawnEntity spawnPacket;
|
||||||
@ -45,16 +39,16 @@ public class HologramLine implements IHologramLine{
|
|||||||
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
this.spawnPacket = new PacketPlayOutSpawnEntity();
|
||||||
this.dataWatcher = createDataWatcher();
|
this.dataWatcher = createDataWatcher();
|
||||||
|
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocation(Location location) {
|
public void setLocation(Location location) {
|
||||||
this.location = location.clone();
|
this.location = location.clone();
|
||||||
updatePacket();
|
HologramUtil.updateSpawnPacket(id, 78, spawnPacket, location);
|
||||||
|
|
||||||
PacketPlayOutEntityTeleport packet = createTeleportPacket();
|
PacketPlayOutEntityTeleport packet = HologramUtil.createTeleportPacket(id, location, true);
|
||||||
location.getWorld().getPlayers().forEach(player -> sendPackets(player, packet));
|
location.getWorld().getPlayers().forEach(player -> HologramUtil.sendPackets(player, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,7 +64,7 @@ public class HologramLine implements IHologramLine{
|
|||||||
dataWatcher.register(customName, text);
|
dataWatcher.register(customName, text);
|
||||||
|
|
||||||
Packet<?> metadataPacket = new PacketPlayOutEntityMetadata(id, dataWatcher, true);
|
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
|
@Override
|
||||||
@ -84,7 +78,7 @@ public class HologramLine implements IHologramLine{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
HologramUtil.sendPackets(player, spawnPacket, new PacketPlayOutEntityMetadata(id, dataWatcher, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -93,59 +87,7 @@ public class HologramLine implements IHologramLine{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPackets(player, new PacketPlayOutEntityDestroy(id));
|
HologramUtil.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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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