Skip to content

Instantly share code, notes, and snippets.

@aikar
Created October 19, 2015 02:44
Show Gist options
  • Save aikar/9d2827799e3772b8ab62 to your computer and use it in GitHub Desktop.
Save aikar/9d2827799e3772b8ab62 to your computer and use it in GitHub Desktop.
Empire Minecraft Hologram System
/*
* Copyright (c) 2015. Starlis LLC / dba Empire Minecraft
*
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval
*
*/
package com.empireminecraft.systems.holograms;
import com.empireminecraft.config.meta.PersistentMetaKey;
import com.empireminecraft.entityai.EntityAIApi;
import com.empireminecraft.metaapi.MetaApi;
import com.empireminecraft.util.ItemUtil;
import com.empireminecraft.util.Util;
import lombok.Data;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import static org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.FORCE;
@Data
public class Hologram {
private static final double DIST_BETWEEN_LINES = 0.225;
public final String id;
Location loc;
List<String> lines = new ArrayList<>();
final ItemStack book;
public Hologram(Location loc) {
id = UUID.randomUUID().toString();
this.loc = loc;
lines.add("");
this.book = makeBook();
}
public Hologram(Entity entity) {
id = getId(entity);
loc = Util.stringToLocation((String) MetaApi.getEntityMeta(entity, PersistentMetaKey.HOLOGRAM_LOC), entity.getWorld());
final MetaApi.MetaList<String> pages = MetaApi.getEntityMeta(entity, PersistentMetaKey.HOLOGRAM_PAGES);
lines.addAll(pages);
this.book = makeBook();
}
public Hologram(ItemStack book) {
if (book == null || book.getType() != Material.BOOK_AND_QUILL) {
throw new IllegalStateException("Not a Hologram");
}
id = ItemUtil.getMeta(book, PersistentMetaKey.HOLOGRAM_ID);
if (id == null) {
throw new IllegalStateException("Invalid ID");
}
loc = Util.stringToLocation(ItemUtil.getMeta(book, PersistentMetaKey.HOLOGRAM_LOC));
if (loc == null) {
throw new IllegalStateException("Invalid Location");
}
lines = ((BookMeta) book.getItemMeta()).getPages();
ItemUtil.setMeta(book, PersistentMetaKey.HOLOGRAM_ID, id);
this.book = book;
}
public static boolean isHologram(ItemStack item) {
return item != null && item.getType() == Material.BOOK_AND_QUILL
&& ItemUtil.getMeta(item, PersistentMetaKey.HOLOGRAM_ID) != null;
}
public static boolean isHologram(Entity entity) {
return entity != null && getId(entity) != null;
}
public ItemStack makeBook() {
ItemStack book = new ItemStack(Material.BOOK_AND_QUILL);
final ItemUtil.LoreBuilder lore = ItemUtil.buildLore(book)
.setName("&5Hologram Editor")
.add(Util.blockLocationToString(loc))
.empty();
for (int i = 0; i < lines.size() && i < 2; i++) {
lore.add(lines.get(i));
}
lore.setMeta(PersistentMetaKey.HOLOGRAM_ID, id)
.setMeta(PersistentMetaKey.HOLOGRAM_LOC, Util.fullLocationToString(loc))
.makeSoulbound()
.save();
// Set a page or it breaks on rename
BookMeta meta = (BookMeta) book.getItemMeta();
meta.setPages(lines);
book.setItemMeta(meta);
return book;
}
public static void setId(Entity entity, String id) {
MetaApi.setEntityMeta(entity, PersistentMetaKey.HOLOGRAM_ID, id);
}
public static String getId(Entity entity) {
return MetaApi.getEntityMeta(entity, PersistentMetaKey.HOLOGRAM_ID);
}
private static Entity addLine(Location loc, final String line, final String id) {
return loc.getWorld().spawnEntity(loc, EntityType.ARMOR_STAND, FORCE, input -> {
ArmorStand entity = (ArmorStand) input;
entity.setVisible(false);
entity.setGravity(false);
entity.setSmall(true);
entity.setCustomName(Util.color(line));
entity.setCustomNameVisible(true);
entity.setMarker(true);
EntityAIApi.setEntitySize(entity, 0, 0);
EntityAIApi.setDisabledSlots(entity, 2039583);
EntityAIApi.setDisabledEntity(entity, true);
setId(input, id);
return false;
});
}
public void update(BookMeta meta) {
lines = meta.getPages();
refresh();
}
public void refresh() {
removeEntities();
final String locStr = Util.fullLocationToString(loc);
Location first = loc.clone().add(0, ((lines.size() / 2) * DIST_BETWEEN_LINES) - 0.75, 0);
boolean stored = false;
for (String line : lines) {
final Entity entity = addLine(first.clone(), line, id);
if (!stored) {
final MetaApi.MetaList<String> pages = new MetaApi.MetaList<>();
pages.addAll(lines);
MetaApi.setEntityMeta(entity, PersistentMetaKey.HOLOGRAM_PAGES, pages);
MetaApi.setEntityMeta(entity, PersistentMetaKey.HOLOGRAM_LOC, locStr);
stored = true;
}
first.subtract(0, DIST_BETWEEN_LINES, 0);
}
}
public void removeEntities() {
final Collection<Entity> nearby = loc.getWorld().getNearbyEntities(loc, 3, 256, 3);
for (Entity entity : nearby) {
if (isHologram(entity)) {
if (getId(entity).equals(id)) {
deinitialize(entity);
entity.remove();
}
}
}
}
public static void deinitialize(Entity entity) {
// Leave this in to clean up old horse holograms incase any are missed.
EntityAIApi.setDisabledEntity(entity, false);
final Entity vehicle = entity.getVehicle();
if (vehicle != null) {
EntityAIApi.setDisabledEntity(vehicle, false);
vehicle.eject();
vehicle.remove();
}
}
}
/*
* Copyright (c) 2015. Starlis LLC / dba Empire Minecraft
*
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval
*
*/
package com.empireminecraft.systems.holograms;
import com.empireminecraft.commands.features.HologramCommand;
import com.empireminecraft.config.meta.PersistentMetaKey;
import com.empireminecraft.customevents.EntityEvents;
import com.empireminecraft.metaapi.MetaApi;
import com.empireminecraft.util.BukkitUtil;
import com.empireminecraft.util.UserUtil;
import com.empireminecraft.util.Util;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerEditBookEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.inventory.meta.ItemMeta;
public class HologramManager {
public static void initialize() {
new HologramCommand();
new BukkitUtil.Listener() {
@EventHandler
public void onEntitySpawn(EntityEvents.EntitySpawnEvent event) {
final Entity entity = event.getEntity();
if (Hologram.isHologram(entity)) {
if (MetaApi.getEntityMeta(entity, PersistentMetaKey.HOLOGRAM_PAGES) != null) {
// Rebuild it with latest code.
final Hologram hologram = new Hologram(entity);
final Chunk chunk = entity.getLocation().getChunk();
BukkitUtil.runTaskNextTick(() -> {
if (chunk.isLoaded()) {
hologram.refresh();
}
});
}
}
}
@EventHandler
public void onBookChange(PlayerEditBookEvent event) {
final Player player = event.getPlayer();
if (!UserUtil.isSrStaff(player)) {
return;
}
final ItemStack item = player.getInventory().getItem(event.getSlot());
if (Hologram.isHologram(item)) {
final BookMeta newBookMeta = event.getNewBookMeta();
if (newBookMeta.getPageCount() == 0) {
newBookMeta.setPages("");
}
final Hologram hologram = getHologram(item);
if (hologram != null) {
hologram.update(newBookMeta);
Util.log(player.getName() + " updated hologram at " + Util.blockLocationToString(hologram.loc) + " to " + Util.join(
hologram.lines.toArray(new String[hologram.lines.size()]), ","));
final ItemMeta itemMeta = hologram.makeBook().getItemMeta();
itemMeta.setDisplayName(newBookMeta.getDisplayName());
event.setNewBookMeta((BookMeta) itemMeta);
}
}
}
};
}
public static Hologram getHologram(ItemStack item) {
if (!Hologram.isHologram(item)) {
return null;
}
return new Hologram(item);
}
public static void createHologram(Player player, Location loc) {
Hologram holo = new Hologram(loc);
UserUtil.givePlayerItem(player, holo.getBook());
Util.sendMsg(player, "&aEdit the book you received to manage this hologram.");
}
public static void getEditBooks(Player player) {
Location loc = player.getLocation();
for (ArmorStand armorStand : loc.getWorld().getNearbyEntitiesByType(ArmorStand.class, loc, 3, 5, 3)) {
if (Hologram.isHologram(armorStand)) {
try {
if (MetaApi.getEntityMeta(armorStand, PersistentMetaKey.HOLOGRAM_PAGES) != null) {
final Hologram hologram = new Hologram(armorStand);
UserUtil.givePlayerItem(player, hologram.getBook());
}
} catch (IllegalStateException ignored) {
Util.sendMsg(player, "&cFound a weird hologram");
Util.printException(ignored);
}
}
}
}
public static void deleteHologram(Player player) {
final ItemStack itemInHand = player.getItemInHand();
if (Hologram.isHologram(itemInHand)) {
try {
new Hologram(itemInHand).removeEntities();
} catch (IllegalStateException ignored) {
Util.printException(ignored);
Util.sendMsg(player, "&cHologram book is broken.");
}
} else {
Util.sendMsg(player, "&cMust be holding a hologram book");
}
}
public static void moveHologram(Player player, Location loc) {
final Hologram hologram = getHologram(player.getItemInHand());
if (hologram == null) {
Util.sendMsg(player, "&cMust be holding a hologram book");
return;
}
hologram.removeEntities();
hologram.setLoc(loc);
hologram.refresh();
player.setItemInHand(hologram.makeBook());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment