Skip to content

Instantly share code, notes, and snippets.

@MrPowerGamerBR
Last active November 18, 2016 00:02
Show Gist options
  • Select an option

  • Save MrPowerGamerBR/fab8698da506d9e6f338ce88346f04fb to your computer and use it in GitHub Desktop.

Select an option

Save MrPowerGamerBR/fab8698da506d9e6f338ce88346f04fb to your computer and use it in GitHub Desktop.
RetroHolograms - A quick and simple Hologram API for Spigot 1.7.10 Protocol Hack (supports 1.7 and 1.8)
package com.mrpowergamerbr.sparklycore.utils.hologram;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
import com.mrpowergamerbr.packetwrapper.AbstractPacket;
import com.mrpowergamerbr.packetwrapper.WrapperPlayServerAttachEntity;
import com.mrpowergamerbr.packetwrapper.WrapperPlayServerEntityDestroy;
import com.mrpowergamerbr.packetwrapper.WrapperPlayServerEntityMetadata;
import com.mrpowergamerbr.packetwrapper.WrapperPlayServerEntityTeleport;
import com.mrpowergamerbr.packetwrapper.WrapperPlayServerSpawnEntity;
import com.mrpowergamerbr.packetwrapper.WrapperPlayServerSpawnEntityLiving;
import lombok.*;
import me.mrpowergamerbr.sparklycore.utils.collections.WeakArrayList;
/**
* Class to spawn holograms in 1.7.10 Protocol Hack
* @author Leonardo
*
*/
public class Hologram {
int horseId = 0; // Also used as the Armor Stand ID
int witherSkullId = 0;
String line;
@Getter
Location location;
@Getter
@Setter
WeakArrayList<Player> viewers = new WeakArrayList<Player>();
@Getter
@Setter
ViewHandler vh;
public Hologram(Location location, String line) {
this.location = location;
this.line = line;
horseId = getId();
witherSkullId = getId();
}
public void setViewHandler(ViewHandler vh) {
this.vh = vh;
}
private static int getId() {
try {
Field field = Class.forName(
"net.minecraft.server." + Bukkit.getServer().getClass().getName().split("\\.")[3] + ".Entity")
.getDeclaredField("entityCount");
field.setAccessible(true);
int id = field.getInt(null);
field.set(null, id + 1);
return id;
} catch (Exception ex) {
ex.printStackTrace();
}
return -1;
}
public void setLine(String line) {
this.line = line;
for (WeakReference<Player> p : viewers.getItems()) {
if (p.get() != null) {
CraftPlayer craftPlayer = (CraftPlayer) p.get();
int protocol = craftPlayer.getHandle().playerConnection.networkManager.getVersion();
List<AbstractPacket> packets = null;
if (protocol >= 47) {
packets = generateMetadataPackets18(p.get());
} else {
packets = generateMetadataPackets17(p.get());
}
for (AbstractPacket packet : packets) {
packet.sendPacket(p.get());
}
}
}
}
public String getLineForPlayer(Player p) {
if (vh != null) {
return vh.onView(this, p, line);
}
return line;
}
private List<AbstractPacket> generateMetadataPackets17(Player p) {
WrapperPlayServerEntityMetadata metadata = new WrapperPlayServerEntityMetadata();
metadata.setEntityId(horseId);
WrappedWatchableObject wwo = new WrappedWatchableObject(10, getLineForPlayer(p));
metadata.setEntityMetadata(Arrays.asList(wwo));
return Arrays.asList(metadata);
}
private List<AbstractPacket> generateMetadataPackets18(Player p) {
WrapperPlayServerEntityMetadata metadata = new WrapperPlayServerEntityMetadata();
metadata.setEntityId(horseId);
WrappedWatchableObject wwo = new WrappedWatchableObject(2, getLineForPlayer(p));
metadata.setEntityMetadata(Arrays.asList(wwo));
return Arrays.asList(metadata);
}
public void addEveryoneAsViewer() {
for (Player p : Bukkit.getOnlinePlayers()) {
viewers.add(p);
}
}
public void addViewer(Player p) {
viewers.add(p);
spawnForPlayer(p);
}
public void removeViewer(Player p) {
viewers.remove(p);
despawnForPlayer(p);
}
public void spawnForAll() {
if (line == null) {
throw new RuntimeException("Line is null!");
}
for (WeakReference<Player> p : viewers.getItems()) {
if (p.get() != null) {
spawnForPlayer(p.get());
}
}
}
public void spawnForPlayer(Player p) {
if (!p.getLocation().getWorld().equals(location.getWorld())) {
return;
}
CraftPlayer craftPlayer = (CraftPlayer) p;
int protocol = craftPlayer.getHandle().playerConnection.networkManager.getVersion();
List<AbstractPacket> packets = null;
if (protocol >= 47) {
packets = generateSpawnPackets18(p);
} else {
packets = generateSpawnPackets17(p);
}
for (AbstractPacket packet : packets) {
packet.sendPacket(p);
}
}
private List<AbstractPacket> generateSpawnPackets17(Player p) {
// Create the wither skull packet first
WrapperPlayServerSpawnEntity skull = new WrapperPlayServerSpawnEntity();
skull.setEntityID(witherSkullId);
skull.setX(location.getX());
skull.setY(location.getY() + 56.28);
skull.setZ(location.getZ());
skull.setType(66); // Wither skull type
// Now the horse packet
WrapperPlayServerSpawnEntityLiving horse = new WrapperPlayServerSpawnEntityLiving();
horse.setEntityID(horseId);
horse.setType(EntityType.HORSE);
horse.setX(location.getX());
horse.setY(location.getY());
horse.setZ(location.getZ());
WrappedDataWatcher wdw = new WrappedDataWatcher(); // Create the data watcher
wdw.setObject(10, line); // And set the horse name to the hologram text
wdw.setObject(11, (byte) 1); // Always show nametag
wdw.setObject(12, -1700000);
horse.setMetadata(wdw);
// And, finally, the mount
WrapperPlayServerAttachEntity attach = new WrapperPlayServerAttachEntity();
attach.setVehicleId(witherSkullId);
attach.setEntityId(horseId);
List<AbstractPacket> packets = Arrays.asList(skull, horse, attach);
return packets;
}
private List<AbstractPacket> generateSpawnPackets18(Player p) {
// Because Armor Stand is a living entity...
WrapperPlayServerSpawnEntityLivingWorkaround armorStand = new WrapperPlayServerSpawnEntityLivingWorkaround();
armorStand.setEntityID(horseId);
armorStand.setX(location.getX());
armorStand.setY(location.getY() + 1.52);
armorStand.setZ(location.getZ());
armorStand.setType(30); // Armor Stand ID
WrappedDataWatcher wdw = new WrappedDataWatcher(); // Create the data watcher
wdw.setObject(0, (byte) 0x20); // Invisible
wdw.setObject(2, line); // And set the armor stand name to the hologram text
wdw.setObject(3, (byte) 1); // Always show nametag
wdw.setObject(10, (byte) 0x16); // Zero Bounding Box (Marker)
armorStand.setMetadata(wdw);
List<AbstractPacket> packets = Arrays.asList(armorStand);
return packets;
}
public void despawnForPlayer(Player p) {
WrapperPlayServerEntityDestroy remove = new WrapperPlayServerEntityDestroy();
remove.setEntities(new int[] { horseId }); // Do we need to add the witherSkullId too?
remove.sendPacket(p);
}
public void despawnForAll() {
WrapperPlayServerEntityDestroy remove = new WrapperPlayServerEntityDestroy();
remove.setEntities(new int[] { horseId }); // Do we need to add the witherSkullId too?
for (WeakReference<Player> p : viewers.getItems()) {
if (p.get() != null) {
remove.sendPacket(p.get());
}
}
}
public void teleport(Location l) {
for (WeakReference<Player> p : viewers.getItems()) {
if (p.get() != null) {
teleport(p.get(), l);
}
}
}
public void teleport(Player p, Location l) {
this.location = l;
CraftPlayer craftPlayer = (CraftPlayer) p;
int protocol = craftPlayer.getHandle().playerConnection.networkManager.getVersion();
WrapperPlayServerEntityTeleport teleport = new WrapperPlayServerEntityTeleport();
teleport.setEntityID(protocol >= 47 ? horseId : witherSkullId);
teleport.setX(l.getX());
teleport.setY(l.getY() + (protocol >= 47 ? 1.42 : 56.28));
teleport.setZ(l.getZ());
teleport.sendPacket(p);
}
public Hologram addLineBelow(String line) {
Hologram hologram = new Hologram(getLocation().clone().add(0, -0.285, 0), line);
return hologram;
}
public Hologram addLineAbove(String line) {
Hologram hologram = new Hologram(getLocation().clone().add(0, 0.285, 0), line);
return hologram;
}
}
class ViewHandler {
public String onView(Hologram hologram, Player player, String string) {
return string;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment