Add new plugin classes

This commit is contained in:
filoghost 2014-12-20 15:37:50 +01:00
parent 19b2839174
commit 686a69385a
149 changed files with 14453 additions and 0 deletions

View File

@ -0,0 +1,260 @@
package com.gmail.filoghost.holographicdisplays;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import com.gmail.filoghost.holographicdisplays.SimpleUpdater.ResponseHandler;
import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerTracker;
import com.gmail.filoghost.holographicdisplays.bridge.protocollib.ProtocolLibHook;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramsCommandHandler;
import com.gmail.filoghost.holographicdisplays.disk.Configuration;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.disk.UnicodeSymbols;
import com.gmail.filoghost.holographicdisplays.exception.HologramNotFoundException;
import com.gmail.filoghost.holographicdisplays.exception.InvalidFormatException;
import com.gmail.filoghost.holographicdisplays.exception.WorldNotFoundException;
import com.gmail.filoghost.holographicdisplays.listener.MainListener;
import com.gmail.filoghost.holographicdisplays.metrics.MetricsLite;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.placeholder.AnimationsRegister;
import com.gmail.filoghost.holographicdisplays.placeholder.PlaceholdersManager;
import com.gmail.filoghost.holographicdisplays.task.BungeeCleanupTask;
import com.gmail.filoghost.holographicdisplays.task.WorldPlayerCounterTask;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
public class HolographicDisplays extends JavaPlugin {
// The main instance of the plugin.
private static HolographicDisplays instance;
// The manager for net.minecraft.server access.
private static NMSManager nmsManager;
// Since 1.8 we use armor stands instead of wither skulls.
private static boolean is1_8;
// True if ProtocolLib is installed and successfully loaded.
private static boolean useProtocolLib;
// The new version found by the updater, null if there is no new version.
private static String newVersion;
@Override
public void onEnable() {
// Blocks plugin reloaders and the /reload command.
if (instance != null) {
getLogger().warning("Please do not use /reload or plugin reloaders. Do \"/holograms reload\" instead.");
return;
}
instance = this;
// Load placeholders.yml.
UnicodeSymbols.load(this);
// Load the configuration.
Configuration.load(this);
if (Configuration.updateNotification) {
new SimpleUpdater(this, 75097).checkForUpdates(new ResponseHandler() {
@Override
public void onUpdateFound(final String newVersion) {
HolographicDisplays.newVersion = newVersion;
getLogger().info("Found a new version available: " + newVersion);
getLogger().info("Download it on Bukkit Dev:");
getLogger().info("dev.bukkit.org/bukkit-plugins/holographic-displays");
}
});
}
String version = VersionUtils.getBukkitVersion();
if (version == null) {
// Caused by MCPC+ / Cauldron renaming packages, extract the version from Bukkit.getVersion().
version = VersionUtils.getMinecraftVersion();
if ("1.6.4".equals(version)) {
version = "v1_6_R3";
} else if ("1.7.2".equals(version)) {
version = "v1_7_R1";
} else if ("1.7.5".equals(version)) {
version = "v1_7_R2";
} else if ("1.7.8".equals(version)) {
version = "v1_7_R3";
} else if ("1.7.10".equals(version)) {
version = "v1_7_R4";
} else if ("1.8".equals(version)) {
version = "v1_8_R1";
} else {
// Cannot definitely get the version. This will cause the plugin to disable itself.
version = null;
}
}
// It's simple, we don't need reflection.
if ("v1_6_R3".equals(version)) {
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_6_R3.NmsManagerImpl();
} else if ("v1_7_R1".equals(version)) {
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_7_R1.NmsManagerImpl();
} else if ("v1_7_R2".equals(version)) {
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_7_R2.NmsManagerImpl();
} else if ("v1_7_R3".equals(version)) {
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_7_R3.NmsManagerImpl();
} else if ("v1_7_R4".equals(version)) {
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_7_R4.NmsManagerImpl();
} else if ("v1_8_R1".equals(version)) {
is1_8 = true;
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_8_R1.NmsManagerImpl();
} else {
printWarnAndDisable(
"******************************************************",
" This version of HolographicDisplays can",
" only work on these server versions:",
" 1.6.4, from 1.7 to 1.8.1.",
" The plugin will be disabled.",
"******************************************************"
);
return;
}
try {
if (VersionUtils.isMCPCOrCauldron()) {
getLogger().info("Trying to enable Cauldron/MCPC+ support...");
}
nmsManager.registerCustomEntities();
if (VersionUtils.isMCPCOrCauldron()) {
getLogger().info("Successfully added support for Cauldron/MCPC+!");
}
} catch (Exception e) {
e.printStackTrace();
printWarnAndDisable(
"******************************************************",
" HolographicDisplays was unable to register",
" custom entities, the plugin will be disabled.",
" Are you using the correct Bukkit version?",
"******************************************************"
);
return;
}
// ProtocolLib check.
try {
if (Bukkit.getPluginManager().isPluginEnabled("ProtocolLib")) {
useProtocolLib = ProtocolLibHook.load(nmsManager, this, is1_8);
}
} catch (Exception ex) {
ex.printStackTrace();
getLogger().warning("Failed to load ProtocolLib support. Is it updated?");
}
// Load animation files and the placeholder manager.
PlaceholdersManager.load(this);
try {
AnimationsRegister.loadAnimations(this);
} catch (Exception ex) {
ex.printStackTrace();
getLogger().warning("Failed to load animation files!");
}
// Initalize other static classes.
HologramDatabase.loadYamlFile(this);
BungeeServerTracker.startTask(Configuration.bungeeRefreshSeconds);
// Start repeating tasks.
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new BungeeCleanupTask(), 5 * 60 * 20, 5 * 60 * 20);
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new WorldPlayerCounterTask(), 0L, 3 * 20);
Set<String> savedHologramsNames = HologramDatabase.getHolograms();
if (savedHologramsNames != null && savedHologramsNames.size() > 0) {
for (String singleHologramName : savedHologramsNames) {
try {
NamedHologram singleHologram = HologramDatabase.loadHologram(singleHologramName);
NamedHologramManager.addHologram(singleHologram);
} catch (HologramNotFoundException e) {
getLogger().warning("Hologram '" + singleHologramName + "' not found, skipping it.");
} catch (InvalidFormatException e) {
getLogger().warning("Hologram '" + singleHologramName + "' has an invalid location format.");
} catch (WorldNotFoundException e) {
getLogger().warning("Hologram '" + singleHologramName + "' was in the world '" + e.getMessage() + "' but it wasn't loaded.");
} catch (Exception e) {
e.printStackTrace();
getLogger().warning("Unhandled exception while loading the hologram '" + singleHologramName + "'. Please contact the developer.");
}
}
}
getCommand("holograms").setExecutor(new HologramsCommandHandler());
Bukkit.getPluginManager().registerEvents(new MainListener(nmsManager), this);
try {
MetricsLite metrics = new MetricsLite(this);
metrics.start();
} catch (Exception ignore) { }
// The entities are loaded when the server is ready.
new BukkitRunnable() {
@Override
public void run() {
for (NamedHologram hologram : NamedHologramManager.getHolograms()) {
hologram.refreshAll();
}
}
}.runTaskLater(this, 10L);
}
@Override
public void onDisable() {
for (NamedHologram hologram : NamedHologramManager.getHolograms()) {
hologram.despawnEntities();
}
}
public static NMSManager getNMSManager() {
return nmsManager;
}
public static boolean is1_8() {
return is1_8;
}
private static void printWarnAndDisable(String... messages) {
StringBuffer buffer = new StringBuffer("\n ");
for (String message : messages) {
buffer.append('\n');
buffer.append(message);
}
buffer.append('\n');
System.out.println(buffer.toString());
try {
Thread.sleep(5000);
} catch (InterruptedException ex) { }
instance.setEnabled(false);
}
public static HolographicDisplays getInstance() {
return instance;
}
public static String getNewVersion() {
return newVersion;
}
public static boolean useProtocolLib() {
return useProtocolLib;
}
}

View File

@ -0,0 +1,173 @@
package com.gmail.filoghost.holographicdisplays;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
/**
* A very simple and lightweight updater, without download features.
* @autor filoghost
*/
public final class SimpleUpdater {
public interface ResponseHandler {
/**
* Called when the updater finds a new version.
* @param newVersion - the new version
*/
public void onUpdateFound(final String newVersion);
}
private Plugin plugin;
private int projectId;
public SimpleUpdater(Plugin plugin, int projectId) {
if (plugin == null) {
throw new NullPointerException("Plugin cannot be null");
}
this.plugin = plugin;
this.projectId = projectId;
}
/**
* This method creates a new async thread to check for updates.
* @param responseHandler the response handler
*/
public void checkForUpdates(final ResponseHandler responseHandler) {
Thread updaterThread = new Thread(new Runnable() {
@Override
public void run() {
try {
JSONArray filesArray = (JSONArray) readJson("https://api.curseforge.com/servermods/files?projectIds=" + projectId);
if (filesArray.size() == 0) {
// The array cannot be empty, there must be at least one file. The project ID is not valid.
plugin.getLogger().warning("The author of this plugin has misconfigured the Updater system.");
plugin.getLogger().warning("The project ID (" + projectId + ") provided for updating is invalid.");
plugin.getLogger().warning("Please notify the author of this error.");
return;
}
String updateName = (String) ((JSONObject) filesArray.get(filesArray.size() - 1)).get("name");
final String newVersion = extractVersion(updateName);
if (newVersion == null) {
throw new NumberFormatException();
}
if (isNewerVersion(newVersion)) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
responseHandler.onUpdateFound(newVersion);
}
});
}
} catch (IOException e) {
plugin.getLogger().warning("Could not contact BukkitDev to check for updates.");
} catch (NumberFormatException e) {
plugin.getLogger().warning("The author of this plugin has misconfigured the Updater system.");
plugin.getLogger().warning("File versions should follow the format 'PluginName vVERSION'");
plugin.getLogger().warning("Please notify the author of this error.");
} catch (Exception e) {
e.printStackTrace();
plugin.getLogger().warning("Unable to check for updates: unhandled exception.");
}
}
});
updaterThread.start();
}
private Object readJson(String url) throws MalformedURLException, IOException {
URLConnection conn = new URL(url).openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(8000);
conn.addRequestProperty("User-Agent", "Updater (by filoghost)");
conn.setDoOutput(true);
return JSONValue.parse(new BufferedReader(new InputStreamReader(conn.getInputStream())));
}
/**
* Compare the version found with the plugin's version, from an array of integer separated by full stops.
* Examples:
* v1.2 > v1.12
* v2.1 = v2.01
* @param remoteVersion the remote version of the plugin
* @return true if the remove version is newer
*/
private boolean isNewerVersion(String remoteVersion) {
String pluginVersion = plugin.getDescription().getVersion();
if (pluginVersion == null || !pluginVersion.matches("v?[0-9\\.]+")) {
// Do not throw exceptions, just consider it as v0.
pluginVersion = "0";
}
if (!remoteVersion.matches("v?[0-9\\.]+")) {
// Should always be checked before by this class.
throw new IllegalArgumentException("fetched version's format is incorrect");
}
// Remove all the "v" from the versions, replace multiple full stops with a single full stop, and split them.
String[] pluginVersionSplit = pluginVersion.replace("v", "").replaceAll("[\\.]{2,}", ".").split("\\.");
String[] remoteVersionSplit = remoteVersion.replace("v", "").replaceAll("[\\.]{2,}", ".").split("\\.");
int longest = Math.max(pluginVersionSplit.length, remoteVersionSplit.length);
int[] pluginVersionArray = new int[longest];
int[] remoteVersionArray = new int[longest];
for (int i = 0; i < pluginVersionSplit.length; i++) {
pluginVersionArray[i] = Integer.parseInt(pluginVersionSplit[i]);
}
for (int i = 0; i < remoteVersionSplit.length; i++) {
remoteVersionArray[i] = Integer.parseInt(remoteVersionSplit[i]);
}
for (int i = 0; i < longest; i++) {
int diff = remoteVersionArray[i] - pluginVersionArray[i];
if (diff > 0) {
return true;
} else if (diff < 0) {
return false;
}
// Continue the loop until diff = 0.
}
return false;
}
private String extractVersion(String input) {
Matcher matcher = Pattern.compile("v[0-9\\.]+").matcher(input);
String result = null;
if (matcher.find()) {
result = matcher.group();
}
return result;
}
}

View File

@ -0,0 +1,85 @@
package com.gmail.filoghost.holographicdisplays.bridge.bungeecord;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.messaging.PluginMessageListener;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.disk.Configuration;
public class BungeeChannel implements PluginMessageListener {
private static BungeeChannel instance;
public static BungeeChannel getInstance() {
if (instance == null) {
instance = new BungeeChannel(HolographicDisplays.getInstance());
}
return instance;
}
public BungeeChannel(Plugin plugin) {
Bukkit.getMessenger().registerOutgoingPluginChannel(plugin, "BungeeCord");
Bukkit.getMessenger().registerIncomingPluginChannel(plugin, "BungeeCord", instance);
Bukkit.getMessenger().registerOutgoingPluginChannel(plugin, "RedisBungee");
Bukkit.getMessenger().registerIncomingPluginChannel(plugin, "RedisBungee", instance);
}
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
if (!channel.equals("BungeeCord") && !channel.equals("RedisBungee")) {
return;
}
DataInputStream in = new DataInputStream(new ByteArrayInputStream(message));
try {
String subChannel = in.readUTF();
if (subChannel.equals("PlayerCount")) {
String server = in.readUTF();
if (in.available() > 0) {
int online = in.readInt();
BungeeServerTracker.handlePing(server, online);
}
}
} catch (EOFException e) {
// Do nothing.
} catch (IOException e) {
// This should never happen.
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public void askPlayerCount(String server) {
ByteArrayOutputStream b = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(b);
try {
out.writeUTF("PlayerCount");
out.writeUTF(server);
} catch (IOException e) {
// It should not happen.
e.printStackTrace();
HolographicDisplays.getInstance().getLogger().warning("I/O Exception while asking for player count on server '" + server + "'.");
}
// OR, if you don't need to send it to a specific player
Player[] players = Bukkit.getOnlinePlayers();
if (players.length > 0) {
players[0].sendPluginMessage(HolographicDisplays.getInstance(), Configuration.useRedisBungee ? "RedisBungee" : "BungeeCord", b.toByteArray());
}
}
}

View File

@ -0,0 +1,29 @@
package com.gmail.filoghost.holographicdisplays.bridge.bungeecord;
public class BungeeServerInfo {
private int onlinePlayers;
private long lastRequest;
protected BungeeServerInfo(int onlinePlayers, long lastRequest) {
this.onlinePlayers = onlinePlayers;
this.lastRequest = lastRequest;
}
public int getOnlinePlayers() {
return onlinePlayers;
}
public void setOnlinePlayers(int onlinePlayers) {
this.onlinePlayers = onlinePlayers;
}
public long getLastRequest() {
return lastRequest;
}
public void setLastRequest(long lastRequest) {
this.lastRequest = lastRequest;
}
}

View File

@ -0,0 +1,72 @@
package com.gmail.filoghost.holographicdisplays.bridge.bungeecord;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
public class BungeeServerTracker {
private static Map<String, BungeeServerInfo> trackedServers = new HashMap<String, BungeeServerInfo>();
private static int taskID = -1;
public static void resetTrackedServers() {
trackedServers.clear();
}
public static void track(String server) {
if (!trackedServers.containsKey(server)) {
BungeeServerInfo info = new BungeeServerInfo(0, System.currentTimeMillis());
trackedServers.put(server, info);
BungeeChannel.getInstance().askPlayerCount(server);
}
}
public static void untrack(String server) {
trackedServers.remove(server);
}
// Handle a successful ping.
protected static void handlePing(String server, int online) {
BungeeServerInfo info = trackedServers.get(server);
if (info == null) {
info = new BungeeServerInfo(online, System.currentTimeMillis());
trackedServers.put(server, info);
} else {
info.setOnlinePlayers(online);
}
}
public static int getPlayersOnline(String server) {
BungeeServerInfo info = trackedServers.get(server);
if (info != null) {
info.setLastRequest(System.currentTimeMillis());
return info.getOnlinePlayers();
} else {
// It was not tracked, add it.
track(server);
return 0;
}
}
public static Map<String, BungeeServerInfo> getTrackedServers() {
return trackedServers;
}
public static void startTask(int refreshSeconds) {
if (taskID != -1) {
Bukkit.getScheduler().cancelTask(taskID);
}
taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(HolographicDisplays.getInstance(), new Runnable() {
public void run() {
for (String server : trackedServers.keySet()) {
BungeeChannel.getInstance().askPlayerCount(server);
}
}
}, 0, refreshSeconds * 20);
}
}

View File

@ -0,0 +1,82 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
import java.lang.reflect.InvocationTargetException;
import org.bukkit.entity.Player;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.base.Objects;
public abstract class AbstractPacket {
// The packet we will be modifying
protected PacketContainer handle;
/**
* Constructs a new strongly typed wrapper for the given packet.
* @param handle - handle to the raw packet data.
* @param type - the packet type.
*/
protected AbstractPacket(PacketContainer handle, PacketType type) {
// Make sure we're given a valid packet
if (handle == null)
throw new IllegalArgumentException("Packet handle cannot be NULL.");
if (!Objects.equal(handle.getType(), type))
throw new IllegalArgumentException(
handle.getHandle() + " is not a packet of type " + type);
this.handle = handle;
}
/**
* Retrieve a handle to the raw packet data.
* @return Raw packet data.
*/
public PacketContainer getHandle() {
return handle;
}
/**
* Send the current packet to the given receiver.
* @param receiver - the receiver.
* @throws RuntimeException If the packet cannot be sent.
*/
public void sendPacket(Player receiver) {
try {
ProtocolLibrary.getProtocolManager().sendServerPacket(receiver, getHandle());
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot send packet.", e);
}
}
/**
* Simulate receiving the current packet from the given sender.
* @param sender - the sender.
* @throws RuntimeException If the packet cannot be received.
*/
public void recievePacket(Player sender) {
try {
ProtocolLibrary.getProtocolManager().recieveClientPacket(sender, getHandle());
} catch (Exception e) {
throw new RuntimeException("Cannot recieve packet.", e);
}
}
}

View File

@ -0,0 +1,305 @@
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.bridge.protocollib.WrapperPlayServerSpawnEntity.ObjectTypes;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.object.CraftHologram;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTextLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchableLine;
import com.gmail.filoghost.holographicdisplays.util.Utils;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
public class ProtocolLibHook {
private static boolean hasProtocolLib;
private static NMSManager nmsManager;
private static int customNameWatcherIndex;
public static boolean load(NMSManager nmsManager, Plugin plugin, boolean is1_8) {
ProtocolLibHook.nmsManager = nmsManager;
if (Bukkit.getPluginManager().isPluginEnabled("ProtocolLib")) {
hasProtocolLib = true;
plugin.getLogger().info("Found ProtocolLib, adding support for player relative variables.");
if (is1_8) {
customNameWatcherIndex = 2;
} else {
customNameWatcherIndex = 10;
}
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.SPAWN_ENTITY_LIVING, PacketType.Play.Server.SPAWN_ENTITY, PacketType.Play.Server.ENTITY_METADATA) {
@Override
public void onPacketSending(PacketEvent event) {
PacketContainer packet = event.getPacket();
// Spawn entity packet
if (packet.getType() == PacketType.Play.Server.SPAWN_ENTITY_LIVING) {
WrapperPlayServerSpawnEntityLiving spawnEntityPacket = new WrapperPlayServerSpawnEntityLiving(packet);
Entity entity = spawnEntityPacket.getEntity(event);
if (entity == null || !isHologramType(entity.getType())) {
return;
}
CraftHologram hologram = getHologram(entity);
if (hologram == null) {
return;
}
Player player = event.getPlayer();
if (!hologram.getVisibilityManager().isVisibleTo(player)) {
event.setCancelled(true);
return;
}
WrappedDataWatcher dataWatcher = spawnEntityPacket.getMetadata();
String customName = dataWatcher.getString(customNameWatcherIndex);
if (customName.contains("{player}") || customName.contains("{displayname}")) {
WrappedDataWatcher dataWatcherClone = dataWatcher.deepClone();
dataWatcherClone.setObject(customNameWatcherIndex, customName.replace("{player}", player.getName()).replace("{displayname}", player.getDisplayName()));
spawnEntityPacket.setMetadata(dataWatcherClone);
event.setPacket(spawnEntityPacket.getHandle());
}
} else if (packet.getType() == PacketType.Play.Server.SPAWN_ENTITY) {
WrapperPlayServerSpawnEntity spawnEntityPacket = new WrapperPlayServerSpawnEntity(packet);
int objectId = spawnEntityPacket.getType();
if (objectId != ObjectTypes.ITEM_STACK && objectId != ObjectTypes.WITHER_SKULL && objectId != ObjectTypes.ARMOR_STAND) {
return;
}
Entity entity = spawnEntityPacket.getEntity(event);
if (entity == null) {
return;
}
CraftHologram hologram = getHologram(entity);
if (hologram == null) {
return;
}
Player player = event.getPlayer();
if (!hologram.getVisibilityManager().isVisibleTo(player)) {
event.setCancelled(true);
return;
}
} else if (packet.getType() == PacketType.Play.Server.ENTITY_METADATA) {
WrapperPlayServerEntityMetadata entityMetadataPacket = new WrapperPlayServerEntityMetadata(packet);
Entity entity = entityMetadataPacket.getEntity(event);
if (entity == null) {
return;
}
if (entity.getType() != EntityType.HORSE && !VersionUtils.isArmorstand(entity.getType())) {
// Enough, only horses and armorstands are used with custom names.
return;
}
CraftHologram hologram = getHologram(entity);
if (hologram == null) {
return;
}
Player player = event.getPlayer();
if (!hologram.getVisibilityManager().isVisibleTo(player)) {
event.setCancelled(true);
return;
}
List<WrappedWatchableObject> dataWatcherValues = entityMetadataPacket.getEntityMetadata();
for (int i = 0; i < dataWatcherValues.size(); i++) {
if (dataWatcherValues.get(i).getIndex() == customNameWatcherIndex) {
Object customNameObject = dataWatcherValues.get(i).deepClone().getValue();
if (customNameObject instanceof String == false) {
return;
}
String customName = (String) customNameObject;
if (customName.contains("{player}") || customName.contains("{displayname}")) {
entityMetadataPacket = new WrapperPlayServerEntityMetadata(packet.deepClone());
List<WrappedWatchableObject> clonedList = entityMetadataPacket.getEntityMetadata();
WrappedWatchableObject clonedElement = clonedList.get(i);
clonedElement.setValue(customName.replace("{player}", player.getName()).replace("{displayname}", player.getDisplayName()));
entityMetadataPacket.setEntityMetadata(clonedList);
event.setPacket(entityMetadataPacket.getHandle());
return;
}
}
}
}
}
});
return true;
}
return false;
}
public static void sendDestroyEntitiesPacket(Player player, CraftHologram hologram) {
if (!hasProtocolLib) {
return;
}
List<Integer> ids = Utils.newList();
for (CraftHologramLine line : hologram.getLinesUnsafe()) {
if (line.isSpawned()) {
for (int id : line.getEntitiesIDs()) {
ids.add(id);
}
}
}
if (!ids.isEmpty()) {
WrapperPlayServerEntityDestroy packet = new WrapperPlayServerEntityDestroy();
packet.setEntities(ids);
packet.sendPacket(player);
}
}
public static void sendCreateEntitiesPacket(Player player, CraftHologram hologram) {
if (!hasProtocolLib) {
return;
}
for (CraftHologramLine line : hologram.getLinesUnsafe()) {
if (line.isSpawned()) {
if (line instanceof CraftTextLine) {
CraftTextLine textLine = (CraftTextLine) line;
if (textLine.isSpawned()) {
AbstractPacket nameablePacket = new WrapperPlayServerSpawnEntityLiving(textLine.getNmsNameble().getBukkitEntityNMS());
nameablePacket.sendPacket(player);
if (textLine.getNmsSkullVehicle() != null) {
AbstractPacket vehiclePacket = new WrapperPlayServerSpawnEntity(textLine.getNmsSkullVehicle().getBukkitEntityNMS(), ObjectTypes.WITHER_SKULL, 0);
vehiclePacket.sendPacket(player);
WrapperPlayServerAttachEntity attachPacket = new WrapperPlayServerAttachEntity();
attachPacket.setVehicleId(textLine.getNmsSkullVehicle().getIdNMS());
attachPacket.setEntityId(textLine.getNmsNameble().getIdNMS());
attachPacket.sendPacket(player);
}
}
} else if (line instanceof CraftItemLine) {
CraftItemLine itemLine = (CraftItemLine) line;
if (itemLine.isSpawned()) {
AbstractPacket itemPacket = new WrapperPlayServerSpawnEntity(itemLine.getNmsItem().getBukkitEntityNMS(), ObjectTypes.ITEM_STACK, 1);
itemPacket.sendPacket(player);
AbstractPacket vehiclePacket;
if (HolographicDisplays.is1_8()) {
// In 1.8 we have armor stands, that are living entities.
vehiclePacket = new WrapperPlayServerSpawnEntityLiving(itemLine.getNmsVehicle().getBukkitEntityNMS());
} else {
vehiclePacket = new WrapperPlayServerSpawnEntity(itemLine.getNmsVehicle().getBukkitEntityNMS(), ObjectTypes.WITHER_SKULL, 0);
}
vehiclePacket.sendPacket(player);
WrapperPlayServerAttachEntity attachPacket = new WrapperPlayServerAttachEntity();
attachPacket.setVehicleId(itemLine.getNmsVehicle().getIdNMS());
attachPacket.setEntityId(itemLine.getNmsItem().getIdNMS());
attachPacket.sendPacket(player);
WrapperPlayServerEntityMetadata itemDataPacket = new WrapperPlayServerEntityMetadata();
List<WrappedWatchableObject> metadata = Utils.newList();
metadata.add(new WrappedWatchableObject(10, itemLine.getItemStack()));
metadata.add(new WrappedWatchableObject(1, (short) 300));
metadata.add(new WrappedWatchableObject(0, (byte) 0));
itemDataPacket.setEntityMetadata(metadata);
itemDataPacket.setEntityId(itemLine.getNmsItem().getIdNMS());
itemDataPacket.sendPacket(player);
}
}
// Unsafe cast, however both CraftTextLine and CraftItemLine are touchable.
CraftTouchableLine touchableLine = (CraftTouchableLine) line;
if (touchableLine.isSpawned() && touchableLine.getTouchSlime() != null) {
CraftTouchSlimeLine touchSlime = touchableLine.getTouchSlime();
if (touchSlime.isSpawned()) {
AbstractPacket vehiclePacket;
if (HolographicDisplays.is1_8()) {
// Armor stand vehicle
vehiclePacket = new WrapperPlayServerSpawnEntityLiving(touchSlime.getNmsVehicle().getBukkitEntityNMS());
} else {
// Wither skull vehicle
vehiclePacket = new WrapperPlayServerSpawnEntity(touchSlime.getNmsVehicle().getBukkitEntityNMS(), ObjectTypes.WITHER_SKULL, 0);
}
vehiclePacket.sendPacket(player);
AbstractPacket slimePacket = new WrapperPlayServerSpawnEntityLiving(touchSlime.getNmsSlime().getBukkitEntityNMS());
slimePacket.sendPacket(player);
WrapperPlayServerAttachEntity attachPacket = new WrapperPlayServerAttachEntity();
attachPacket.setVehicleId(touchSlime.getNmsVehicle().getIdNMS());
attachPacket.setEntityId(touchSlime.getNmsSlime().getIdNMS());
attachPacket.sendPacket(player);
}
}
}
}
}
private static boolean isHologramType(EntityType type) {
return type == EntityType.HORSE || type == EntityType.WITHER_SKULL || type == EntityType.DROPPED_ITEM || type == EntityType.SLIME || VersionUtils.isArmorstand(type); // To maintain backwards compatibility
}
private static CraftHologram getHologram(Entity bukkitEntity) {
NMSEntityBase entity = nmsManager.getNMSEntityBase(bukkitEntity);
if (entity != null) {
return entity.getHologramLine().getParent();
}
return null;
}
}

View File

@ -0,0 +1,122 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
public class WrapperPlayServerAttachEntity extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.ATTACH_ENTITY;
public WrapperPlayServerAttachEntity() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerAttachEntity(PacketContainer packet) {
super(packet, TYPE);
}
/**
* Retrieve whether or not the entity is leached onto the vehicle.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean getLeached() {
return handle.getIntegers().read(0) != 0;
}
/**
* Set whether or not the entity is leached onto the vehicle.
* @param value - TRUE if it is leached, FALSE otherwise.
*/
public void setLeached(boolean value) {
handle.getIntegers().write(0, value ? 1 : 0);
}
/**
* Retrieve the player entity ID being attached.
* @return The current Entity ID
*/
public int getEntityId() {
return handle.getIntegers().read(1);
}
/**
* Set the player entity ID being attached.
* @param value - new value.
*/
public void setEntityId(int value) {
handle.getIntegers().write(1, value);
}
/**
* Retrieve the entity being attached.
* @param world - the current world of the entity.
* @return The entity.
*/
public Entity getEntity(World world) {
return handle.getEntityModifier(world).read(1);
}
/**
* Retrieve the entity being attached.
* @param event - the packet event.
* @return The entity.
*/
public Entity getEntity(PacketEvent event) {
return getEntity(event.getPlayer().getWorld());
}
/**
* Retrieve the vehicle entity ID attached to (-1 for unattaching).
* @return The current Vehicle ID
*/
public int getVehicleId() {
return handle.getIntegers().read(2);
}
/**
* Set the vehicle entity ID attached to (-1 for unattaching).
* @param value - new value.
*/
public void setVehicleId(int value) {
handle.getIntegers().write(2, value);
}
/**
* Retrieve the vehicle entity attached to (NULL for unattaching).
* @param world - the current world of the entity.
* @return The vehicle.
*/
public Entity getVehicle(World world) {
return handle.getEntityModifier(world).read(2);
}
/**
* Retrieve the vehicle entity attached to (NULL for unattaching).
* @param event - the packet event.
* @return The vehicle.
*/
public Entity getVehicle(PacketEvent event) {
return getVehicle(event.getPlayer().getWorld());
}
}

View File

@ -0,0 +1,61 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
import java.util.List;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.primitives.Ints;
public class WrapperPlayServerEntityDestroy extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.ENTITY_DESTROY;
public WrapperPlayServerEntityDestroy() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerEntityDestroy(PacketContainer packet) {
super(packet, TYPE);
}
/**
* Retrieve the IDs of the entities that will be destroyed.
* @return The current entities.
*/
public List<Integer> getEntities() {
return Ints.asList(handle.getIntegerArrays().read(0));
}
/**
* Set the entities that will be destroyed.
* @param value - new value.
*/
public void setEntities(int[] entities) {
handle.getIntegerArrays().write(0, entities);
}
/**
* Set the entities that will be destroyed.
* @param value - new value.
*/
public void setEntities(List<Integer> entities) {
setEntities(Ints.toArray(entities));
}
}

View File

@ -0,0 +1,94 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
import java.util.List;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
public class WrapperPlayServerEntityMetadata extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.ENTITY_METADATA;
public WrapperPlayServerEntityMetadata() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerEntityMetadata(PacketContainer packet) {
super(packet, TYPE);
}
/**
* Retrieve unique entity ID to update.
* @return The current Entity ID
*/
public int getEntityId() {
return handle.getIntegers().read(0);
}
/**
* Set unique entity ID to update.
* @param value - new value.
*/
public void setEntityId(int value) {
handle.getIntegers().write(0, value);
}
/**
* Retrieve the entity.
* @param world - the current world of the entity.
* @return The entity.
*/
public Entity getEntity(World world) {
return handle.getEntityModifier(world).read(0);
}
/**
* Retrieve the entity.
* @param event - the packet event.
* @return The entity.
*/
public Entity getEntity(PacketEvent event) {
return getEntity(event.getPlayer().getWorld());
}
/**
* Retrieve a list of all the watchable objects.
* <p>
* This can be converted to a data watcher using {@link WrappedDataWatcher#WrappedDataWatcher(List) WrappedDataWatcher(List)}
* @return The current metadata
*/
public List<WrappedWatchableObject> getEntityMetadata() {
return handle.getWatchableCollectionModifier().read(0);
}
/**
* Set the list of the watchable objects (meta data).
* @param value - new value.
*/
public void setEntityMetadata(List<WrappedWatchableObject> value) {
handle.getWatchableCollectionModifier().write(0, value);
}
}

View File

@ -0,0 +1,334 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.PacketConstructor;
import com.comphenix.protocol.reflect.IntEnum;
public class WrapperPlayServerSpawnEntity extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.SPAWN_ENTITY;
private static PacketConstructor entityConstructor;
/**
* Represents the different object types.
*
* @author Kristian
*/
public static class ObjectTypes extends IntEnum {
public static final int BOAT = 1;
public static final int ITEM_STACK = 2;
public static final int MINECART = 10;
public static final int MINECART_STORAGE = 11;
public static final int MINECART_POWERED = 12;
public static final int ACTIVATED_TNT = 50;
public static final int ENDER_CRYSTAL = 51;
public static final int ARROW_PROJECTILE = 60;
public static final int SNOWBALL_PROJECTILE = 61;
public static final int EGG_PROJECTILE = 62;
public static final int FIRE_BALL_GHAST = 63;
public static final int FIRE_BALL_BLAZE = 64;
public static final int THROWN_ENDERPEARL = 65;
public static final int WITHER_SKULL = 66;
public static final int FALLING_BLOCK = 70;
public static final int ITEM_FRAME = 71;
public static final int EYE_OF_ENDER = 72;
public static final int THROWN_POTION = 73;
public static final int FALLING_DRAGON_EGG = 74;
public static final int THROWN_EXP_BOTTLE = 75;
public static final int FIREWORK = 76;
public static final int ARMOR_STAND = 78;
public static final int FISHING_FLOAT = 90;
/**
* The singleton instance. Can also be retrieved from the parent class.
*/
private static ObjectTypes INSTANCE = new ObjectTypes();
/**
* Retrieve an instance of the object types enum.
* @return Object type enum.
*/
public static ObjectTypes getInstance() {
return INSTANCE;
}
}
public WrapperPlayServerSpawnEntity() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerSpawnEntity(PacketContainer packet) {
super(packet, TYPE);
}
public WrapperPlayServerSpawnEntity(Entity entity, int type, int objectData) {
super(fromEntity(entity, type, objectData), TYPE);
}
// Useful constructor
private static PacketContainer fromEntity(Entity entity, int type, int objectData) {
if (entityConstructor == null)
entityConstructor = ProtocolLibrary.getProtocolManager().createPacketConstructor(TYPE, entity, type, objectData);
return entityConstructor.createPacket(entity, type, objectData);
}
/**
* Retrieve entity ID of the Object.
* @return The current EID
*/
public int getEntityID() {
return handle.getIntegers().read(0);
}
/**
* Retrieve the entity that will be spawned.
* @param world - the current world of the entity.
* @return The spawned entity.
*/
public Entity getEntity(World world) {
return handle.getEntityModifier(world).read(0);
}
/**
* Retrieve the entity that will be spawned.
* @param event - the packet event.
* @return The spawned entity.
*/
public Entity getEntity(PacketEvent event) {
return getEntity(event.getPlayer().getWorld());
}
/**
* Set entity ID of the Object.
* @param value - new value.
*/
public void setEntityID(int value) {
handle.getIntegers().write(0, value);
}
/**
* Retrieve the type of object. See {@link ObjectTypes}
* @return The current Type
*/
public int getType() {
return handle.getIntegers().read(9);
}
/**
* Set the type of object. See {@link ObjectTypes}.
* @param value - new value.
*/
public void setType(int value) {
handle.getIntegers().write(9, value);
}
/**
* Retrieve the x position of the object.
* <p>
* Note that the coordinate is rounded off to the nearest 1/32 of a meter.
* @return The current X
*/
public double getX() {
return handle.getIntegers().read(1) / 32.0D;
}
/**
* Set the x position of the object.
* @param value - new value.
*/
public void setX(double value) {
handle.getIntegers().write(1, (int) Math.floor(value * 32.0D));
}
/**
* Retrieve the y position of the object.
* <p>
* Note that the coordinate is rounded off to the nearest 1/32 of a meter.
* @return The current y
*/
public double getY() {
return handle.getIntegers().read(2) / 32.0D;
}
/**
* Set the y position of the object.
* @param value - new value.
*/
public void setY(double value) {
handle.getIntegers().write(2, (int) Math.floor(value * 32.0D));
}
/**
* Retrieve the z position of the object.
* <p>
* Note that the coordinate is rounded off to the nearest 1/32 of a meter.
* @return The current z
*/
public double getZ() {
return handle.getIntegers().read(3) / 32.0D;
}
/**
* Set the z position of the object.
* @param value - new value.
*/
public void setZ(double value) {
handle.getIntegers().write(3, (int) Math.floor(value * 32.0D));
}
/**
* Retrieve the optional speed x.
* <p>
* This is ignored if {@link #getObjectData()} is zero.
* @return The optional speed x.
*/
public double getOptionalSpeedX() {
return handle.getIntegers().read(4) / 8000.0D;
}
/**
* Set the optional speed x.
* @param value - new value.
*/
public void setOptionalSpeedX(double value) {
handle.getIntegers().write(4, (int) (value * 8000.0D));
}
/**
* Retrieve the optional speed y.
* <p>
* This is ignored if {@link #getObjectData()} is zero.
* @return The optional speed y.
*/
public double getOptionalSpeedY() {
return handle.getIntegers().read(5) / 8000.0D;
}
/**
* Set the optional speed y.
* @param value - new value.
*/
public void setOptionalSpeedY(double value) {
handle.getIntegers().write(5, (int) (value * 8000.0D));
}
/**
* Retrieve the optional speed z.
* <p>
* This is ignored if {@link #getObjectData()} is zero.
* @return The optional speed z.
*/
public double getOptionalSpeedZ() {
return handle.getIntegers().read(6) / 8000.0D;
}
/**
* Set the optional speed z.
* @param value - new value.
*/
public void setOptionalSpeedZ(double value) {
handle.getIntegers().write(6, (int) (value * 8000.0D));
}
/**
* Retrieve the yaw.
* @return The current Yaw
*/
public float getYaw() {
return (handle.getIntegers().read(7) * 360.F) / 256.0F;
}
/**
* Set the yaw of the object spawned.
* @param value - new yaw.
*/
public void setYaw(float value) {
handle.getIntegers().write(7, (int) (value * 256.0F / 360.0F));
}
/**
* Retrieve the pitch.
* @return The current pitch.
*/
public float getPitch() {
return (handle.getIntegers().read(8) * 360.F) / 256.0F;
}
/**
* Set the pitch.
* @param value - new pitch.
*/
public void setPitch(float value) {
handle.getIntegers().write(8, (int) (value * 256.0F / 360.0F));
}
/**
* Retrieve object data.
* <p>
* The content depends on the object type:
* <table border="1" cellpadding="4">
* <tr>
* <th>Object Type:</th>
* <th>Name:</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>ITEM_FRAME</td>
* <td>Orientation</td>
* <td>0-3: South, West, North, East</td>
* </tr>
* <tr>
* <td>FALLING_BLOCK</td>
* <td>Block Type</td>
* <td>BlockID | (Metadata << 0xC)</td>
* </tr>
* <tr>
* <td>Projectiles</td>
* <td>Entity ID</td>
* <td>The entity ID of the thrower</td>
* </tr>
* <tr>
* <td>Splash Potions</td>
* <td>Data Value</td>
* <td>Potion data value.</td>
* </tr>
* </table>
* @return The current object Data
*/
public int getObjectData() {
return handle.getIntegers().read(10);
}
/**
* Set object Data.
* <p>
* The content depends on the object type. See {@link #getObjectData()} for more information.
* @param value - new object data.
*/
public void setObjectData(int value) {
handle.getIntegers().write(10, value);
}
}

View File

@ -0,0 +1,275 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.PacketConstructor;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
public class WrapperPlayServerSpawnEntityLiving extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.SPAWN_ENTITY_LIVING;
private static PacketConstructor entityConstructor;
public WrapperPlayServerSpawnEntityLiving() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerSpawnEntityLiving(PacketContainer packet) {
super(packet, TYPE);
}
public WrapperPlayServerSpawnEntityLiving(Entity entity) {
super(fromEntity(entity), TYPE);
}
// Useful constructor
private static PacketContainer fromEntity(Entity entity) {
if (entityConstructor == null)
entityConstructor = ProtocolLibrary.getProtocolManager().createPacketConstructor(TYPE, entity);
return entityConstructor.createPacket(entity);
}
/**
* Retrieve entity ID.
* @return The current EID
*/
public int getEntityID() {
return handle.getIntegers().read(0);
}
/**
* Retrieve the entity that will be spawned.
* @param world - the current world of the entity.
* @return The spawned entity.
*/
public Entity getEntity(World world) {
return handle.getEntityModifier(world).read(0);
}
/**
* Retrieve the entity that will be spawned.
* @param event - the packet event.
* @return The spawned entity.
*/
public Entity getEntity(PacketEvent event) {
return getEntity(event.getPlayer().getWorld());
}
/**
* Set entity ID.
* @param value - new value.
*/
public void setEntityID(int value) {
handle.getIntegers().write(0, value);
}
/**
* Retrieve the type of mob.
* @return The current Type
*/
@SuppressWarnings("deprecation")
public EntityType getType() {
return EntityType.fromId(handle.getIntegers().read(1));
}
/**
* Set the type of mob.
* @param value - new value.
*/
@SuppressWarnings("deprecation")
public void setType(EntityType value) {
handle.getIntegers().write(1, (int) value.getTypeId());
}
/**
* Retrieve the x position of the object.
* <p>
* Note that the coordinate is rounded off to the nearest 1/32 of a meter.
* @return The current X
*/
public double getX() {
return handle.getIntegers().read(2) / 32.0D;
}
/**
* Set the x position of the object.
* @param value - new value.
*/
public void setX(double value) {
handle.getIntegers().write(2, (int) Math.floor(value * 32.0D));
}
/**
* Retrieve the y position of the object.
* <p>
* Note that the coordinate is rounded off to the nearest 1/32 of a meter.
* @return The current y
*/
public double getY() {
return handle.getIntegers().read(3) / 32.0D;
}
/**
* Set the y position of the object.
* @param value - new value.
*/
public void setY(double value) {
handle.getIntegers().write(3, (int) Math.floor(value * 32.0D));
}
/**
* Retrieve the z position of the object.
* <p>
* Note that the coordinate is rounded off to the nearest 1/32 of a meter.
* @return The current z
*/
public double getZ() {
return handle.getIntegers().read(4) / 32.0D;
}
/**
* Set the z position of the object.
* @param value - new value.
*/
public void setZ(double value) {
handle.getIntegers().write(4, (int) Math.floor(value * 32.0D));
}
/**
* Retrieve the yaw.
* @return The current Yaw
*/
public float getYaw() {
return (handle.getBytes().read(0) * 360.F) / 256.0F;
}
/**
* Set the yaw of the spawned mob.
* @param value - new yaw.
*/
public void setYaw(float value) {
handle.getBytes().write(0, (byte) (value * 256.0F / 360.0F));
}
/**
* Retrieve the pitch.
* @return The current pitch
*/
public float getHeadPitch() {
return (handle.getBytes().read(1) * 360.F) / 256.0F;
}
/**
* Set the pitch of the spawned mob.
* @param value - new pitch.
*/
public void setHeadPitch(float value) {
handle.getBytes().write(1, (byte) (value * 256.0F / 360.0F));
}
/**
* Retrieve the yaw of the mob's head.
* @return The current yaw.
*/
public float getHeadYaw() {
return (handle.getBytes().read(2) * 360.F) / 256.0F;
}
/**
* Set the yaw of the mob's head.
* @param value - new yaw.
*/
public void setHeadYaw(float value) {
handle.getBytes().write(2, (byte) (value * 256.0F / 360.0F));
}
/**
* Retrieve the velocity in the x axis.
* @return The current velocity X
*/
public double getVelocityX() {
return handle.getIntegers().read(5) / 8000.0D;
}
/**
* Set the velocity in the x axis.
* @param value - new value.
*/
public void setVelocityX(double value) {
handle.getIntegers().write(5, (int) (value * 8000.0D));
}
/**
* Retrieve the velocity in the y axis.
* @return The current velocity y
*/
public double getVelocityY() {
return handle.getIntegers().read(6) / 8000.0D;
}
/**
* Set the velocity in the y axis.
* @param value - new value.
*/
public void setVelocityY(double value) {
handle.getIntegers().write(6, (int) (value * 8000.0D));
}
/**
* Retrieve the velocity in the z axis.
* @return The current velocity z
*/
public double getVelocityZ() {
return handle.getIntegers().read(7) / 8000.0D;
}
/**
* Set the velocity in the z axis.
* @param value - new value.
*/
public void setVelocityZ(double value) {
handle.getIntegers().write(7, (int) (value * 8000.0D));
}
/**
* Retrieve the data watcher.
* <p>
* Content varies by mob, see Entities.
* @return The current Metadata
*/
public WrappedDataWatcher getMetadata() {
return handle.getDataWatcherModifier().read(0);
}
/**
* Set the data watcher.
* @param value - new value.
*/
public void setMetadata(WrappedDataWatcher value) {
handle.getDataWatcherModifier().write(0, value);
}
}

View File

@ -0,0 +1,19 @@
package com.gmail.filoghost.holographicdisplays.commands;
import org.bukkit.ChatColor;
public class Colors {
public static final String
PRIMARY = "" + ChatColor.AQUA,
PRIMARY_SHADOW = "" + ChatColor.DARK_AQUA,
SECONDARY = "" + ChatColor.WHITE,
SECONDARY_SHADOW = "" + ChatColor.GRAY,
BOLD = "" + ChatColor.BOLD,
ERROR = "" + ChatColor.RED;
}

View File

@ -0,0 +1,86 @@
package com.gmail.filoghost.holographicdisplays.commands;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.util.ItemUtils;
public class CommandValidator {
public static void notNull(Object obj, String string) throws CommandException {
if (obj == null) {
throw new CommandException(string);
}
}
public static void isTrue(boolean b, String string) throws CommandException {
if (!b) {
throw new CommandException(string);
}
}
public static int getInteger(String integer) throws CommandException {
try {
return Integer.parseInt(integer);
} catch (NumberFormatException ex) {
throw new CommandException("Invalid number: '" + integer + "'.");
}
}
public static boolean isInteger(String integer) {
try {
Integer.parseInt(integer);
return true;
} catch (NumberFormatException ex) {
return false;
}
}
public static Player getPlayerSender(CommandSender sender) throws CommandException {
if (sender instanceof Player) {
return (Player) sender;
} else {
throw new CommandException("You must be a player to use this command.");
}
}
public static boolean isPlayerSender(CommandSender sender) {
return sender instanceof Player;
}
@SuppressWarnings("deprecation")
public static ItemStack matchItemStack(String input) throws CommandException {
input = input.replace(" ", ""); // Remove the spaces
int dataValue = 0;
if (input.contains(":")) {
String[] split = input.split(":", 2);
dataValue = getInteger(split[1]);
input = split[0];
}
Material match = null;
if (isInteger(input)) {
int id = getInteger(input);
for (Material mat : Material.values()) {
if (mat.getId() == id) {
match = mat;
break;
}
}
} else {
match = ItemUtils.matchMaterial(input);
}
if (match == null || match == Material.AIR) {
throw new CommandException("Invalid material: " + input);
}
return new ItemStack(match, 1, (short) dataValue);
}
}

View File

@ -0,0 +1,23 @@
package com.gmail.filoghost.holographicdisplays.commands;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
public class Strings {
public static final String NO_SUCH_HOLOGRAM = ChatColor.RED + "A hologram with that name doesn't exist.";
public static final String BASE_PERM = "holograms.";
public static final String TIP_PREFIX = "" + ChatColor.YELLOW + ChatColor.BOLD + "TIP" + Colors.SECONDARY_SHADOW + " ";
public static String formatTitle(String input) {
return "" + Colors.PRIMARY_SHADOW + ChatColor.BOLD + "----- " + input + Colors.PRIMARY_SHADOW + ChatColor.BOLD + " -----";
}
public static void sendWarning(CommandSender recipient, String warning) {
recipient.sendMessage(ChatColor.RED + "( " + ChatColor.DARK_RED + ChatColor.BOLD + "!" + ChatColor.RED + " ) " + Colors.SECONDARY_SHADOW + warning);
}
}

View File

@ -0,0 +1,72 @@
package com.gmail.filoghost.holographicdisplays.commands.main;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
public abstract class HologramSubCommand {
private String name;
private String permission;
private String[] aliases;
public HologramSubCommand(String name) {
this(name, new String[0]);
}
public HologramSubCommand(String name, String... aliases) {
this.name = name;
this.aliases = aliases;
}
public String getName() {
return name;
}
public void setPermission(String permission) {
this.permission = permission;
}
public String getPermission() {
return permission;
}
public final boolean hasPermission(CommandSender sender) {
if (permission == null) return true;
return sender.hasPermission(permission);
}
public abstract String getPossibleArguments();
public abstract int getMinimumArguments();
public abstract void execute(CommandSender sender, String label, String[] args) throws CommandException;
public abstract List<String> getTutorial();
public abstract SubCommandType getType();
public enum SubCommandType {
GENERIC, EDIT_LINES, HIDDEN
}
public final boolean isValidTrigger(String name) {
if (this.name.equalsIgnoreCase(name)) {
return true;
}
if (aliases != null) {
for (String alias : aliases) {
if (alias.equalsIgnoreCase(name)) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,106 @@
package com.gmail.filoghost.holographicdisplays.commands.main;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.AddlineCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.AlignCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.CreateCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.DeleteCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.EditCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.FixCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.HelpCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.InsertlineCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.ListCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.MovehereCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.NearCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.ReadimageCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.ReadtextCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.ReloadCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.RemovelineCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.SetlineCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.subs.TeleportCommand;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class HologramsCommandHandler implements CommandExecutor {
private List<HologramSubCommand> subCommands;
public HologramsCommandHandler() {
subCommands = Utils.newList();
registerSubCommand(new AddlineCommand());
registerSubCommand(new CreateCommand());
registerSubCommand(new DeleteCommand());
registerSubCommand(new EditCommand(this));
registerSubCommand(new ListCommand());
registerSubCommand(new NearCommand());
registerSubCommand(new TeleportCommand());
registerSubCommand(new MovehereCommand());
registerSubCommand(new AlignCommand());
registerSubCommand(new FixCommand());
registerSubCommand(new ReloadCommand());
registerSubCommand(new RemovelineCommand());
registerSubCommand(new SetlineCommand());
registerSubCommand(new InsertlineCommand());
registerSubCommand(new ReadtextCommand());
registerSubCommand(new ReadimageCommand());
registerSubCommand(new HelpCommand(this));
}
public void registerSubCommand(HologramSubCommand subCommand) {
subCommands.add(subCommand);
}
public List<HologramSubCommand> getSubCommands() {
return new ArrayList<HologramSubCommand>(subCommands);
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (args.length == 0) {
sender.sendMessage(Colors.PRIMARY_SHADOW + "This server is running " + Colors.PRIMARY + "Holographic Displays " + Colors.PRIMARY_SHADOW + "v" + HolographicDisplays.getInstance().getDescription().getVersion() + " by " + Colors.PRIMARY + "filoghost");
if (sender.hasPermission(Strings.BASE_PERM + "help")) {
sender.sendMessage(Colors.PRIMARY_SHADOW + "Commands: " + Colors.PRIMARY + "/" + label + " help");
}
return true;
}
for (HologramSubCommand subCommand : subCommands) {
if (subCommand.isValidTrigger(args[0])) {
if (!subCommand.hasPermission(sender)) {
sender.sendMessage(Colors.ERROR + "You don't have permission.");
return true;
}
if (args.length - 1 >= subCommand.getMinimumArguments()) {
try {
subCommand.execute(sender, label, Arrays.copyOfRange(args, 1, args.length));
} catch (CommandException e) {
sender.sendMessage(Colors.ERROR + e.getMessage());
}
} else {
sender.sendMessage(Colors.ERROR + "Usage: /" + label + " " + subCommand.getName() + " " + subCommand.getPossibleArguments());
}
return true;
}
}
sender.sendMessage(Colors.ERROR + "Unknown sub-command. Type \"/" + label + " help\" for a list of commands.");
return true;
}
}

View File

@ -0,0 +1,58 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class AddlineCommand extends HologramSubCommand {
public AddlineCommand() {
super("addline");
setPermission(Strings.BASE_PERM + "addline");
}
@Override
public String getPossibleArguments() {
return "<hologramName> <text>";
}
@Override
public int getMinimumArguments() {
return 2;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
hologram.getLinesUnsafe().add(HologramDatabase.readLineFromString(Utils.join(args, " ", 1, args.length), hologram));
hologram.refreshAll();
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
sender.sendMessage(Colors.PRIMARY + "Line added!");
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Adds a line to an existing hologram.");
}
@Override
public SubCommandType getType() {
return SubCommandType.EDIT_LINES;
}
}

View File

@ -0,0 +1,79 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
public class AlignCommand extends HologramSubCommand {
public AlignCommand() {
super("align");
setPermission(Strings.BASE_PERM + "align");
}
@Override
public String getPossibleArguments() {
return "<X|Y|Z|XZ> <hologram> <referenceHologram>";
}
@Override
public int getMinimumArguments() {
return 3;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
NamedHologram hologram = NamedHologramManager.getHologram(args[1].toLowerCase());
NamedHologram referenceHologram = NamedHologramManager.getHologram(args[2].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM + " (hologram to align)");
CommandValidator.notNull(referenceHologram, Strings.NO_SUCH_HOLOGRAM + " (reference hologram)");
CommandValidator.isTrue(hologram != referenceHologram, "The hologram must not be the same!");
Location loc = hologram.getLocation();
if (args[0].equalsIgnoreCase("x")) {
loc.setX(referenceHologram.getX());
} else if (args[0].equalsIgnoreCase("y")) {
loc.setY(referenceHologram.getY());
} else if (args[0].equalsIgnoreCase("z")) {
loc.setZ(referenceHologram.getZ());
} else if (args[0].equalsIgnoreCase("xz")) {
loc.setX(referenceHologram.getX());
loc.setZ(referenceHologram.getZ());
} else {
throw new CommandException("You must specify either X, Y, Z or XZ, " + args[0] + " is not a valid axis.");
}
hologram.teleport(loc.getWorld(), loc.getX(), loc.getY(), loc.getZ());
hologram.despawnEntities();
hologram.refreshAll();
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
sender.sendMessage(Colors.PRIMARY + "Hologram \"" + hologram.getName() + "\" aligned to the hologram \"" + referenceHologram.getName() + "\" on the " + args[0].toUpperCase() + " axis.");
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Aligns the first hologram to the second, in the specified axis.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,113 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.exception.InvalidCharactersException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class CreateCommand extends HologramSubCommand {
private static final String VALID_HOLOGRAM_NAME_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
public CreateCommand() {
super("create");
setPermission(Strings.BASE_PERM + "create");
}
@Override
public String getPossibleArguments() {
return "<hologramName> [text]";
}
@Override
public int getMinimumArguments() {
return 1;
}
@SuppressWarnings("deprecation")
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
Player player = CommandValidator.getPlayerSender(sender);
String name = args[0];
if (!name.matches("[a-zA-Z_\\-]+")) {
throw new CommandException("The name must contain only alphanumeric chars, underscores and hyphens.");
}
name = name.toLowerCase();
CommandValidator.isTrue(!NamedHologramManager.isExistingHologram(name), "A hologram with that name already exists.");
Location spawnLoc = player.getLocation();
boolean moveUp = player.isOnGround();
if (moveUp) {
spawnLoc.add(0.0, 1.2, 0.0);
}
NamedHologram hologram = new NamedHologram(spawnLoc, name);
NamedHologramManager.addHologram(hologram);
if (args.length > 1) {
String text = Utils.join(args, " ", 1, args.length);
CommandValidator.isTrue(!text.equalsIgnoreCase("{empty}"), "The first line should not be empty.");
hologram.getLinesUnsafe().add(HologramDatabase.readLineFromString(text, hologram));
player.sendMessage(Colors.SECONDARY_SHADOW + "(Change the lines with /" + label + " edit " + hologram.getName() + ")");
} else {
hologram.appendTextLine("Default hologram. Change it with " + Colors.PRIMARY + "/" + label + " edit " + hologram.getName());
}
hologram.refreshAll();
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
Location look = player.getLocation();
look.setPitch(90);
player.teleport(look, TeleportCause.PLUGIN);
player.sendMessage(Colors.PRIMARY + "You created a hologram named '" + hologram.getName() + "'.");
if (moveUp) {
player.sendMessage(Colors.SECONDARY_SHADOW + "(You were on the ground, the hologram was automatically moved up. If you use /" + label + " movehere " + hologram.getName() + ", the hologram will be moved to your feet)");
}
}
public static String validateName(String name) throws InvalidCharactersException {
for (char c : name.toCharArray()) {
if (VALID_HOLOGRAM_NAME_CHARS.indexOf(c) < 0) {
throw new InvalidCharactersException(Character.toString(c));
}
}
return name;
}
@Override
public List<String> getTutorial() {
return Arrays.asList(
"Creates a new hologram with the given name, that must",
"be alphanumeric. The name will be used as reference to",
"that hologram for editing commands.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,59 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
public class DeleteCommand extends HologramSubCommand {
public DeleteCommand() {
super("delete", "remove");
setPermission(Strings.BASE_PERM + "delete");
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
hologram.delete();
NamedHologramManager.removeHologram(hologram);
HologramDatabase.deleteHologram(hologram.getName());
HologramDatabase.trySaveToDisk();
sender.sendMessage(Colors.PRIMARY + "You deleted the hologram '" + hologram.getName() + "'.");
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Deletes a hologram. Cannot be undone.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,90 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import net.minecraft.util.com.google.common.base.Joiner;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramsCommandHandler;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class EditCommand extends HologramSubCommand {
private HologramsCommandHandler mainCommandHandler;
public EditCommand(HologramsCommandHandler mainCommandHandler) {
super("edit");
setPermission(Strings.BASE_PERM + "edit");
this.mainCommandHandler = mainCommandHandler;
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
String name = args[0].toLowerCase();
NamedHologram hologram = NamedHologramManager.getHologram(name);
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
sender.sendMessage("");
sender.sendMessage(Strings.formatTitle("How to edit the hologram '" + name + "'"));
for (HologramSubCommand subCommand : mainCommandHandler.getSubCommands()) {
if (subCommand.getType() == SubCommandType.EDIT_LINES) {
String usage = "/" + label + " " + subCommand.getName() + (subCommand.getPossibleArguments().length() > 0 ? " " + subCommand.getPossibleArguments().replace("<hologramName>", hologram.getName()).replace("<hologram>", hologram.getName()) : "");
if (CommandValidator.isPlayerSender(sender)) {
List<String> help = Utils.newList();
help.add(Colors.PRIMARY + usage);
for (String tutLine : subCommand.getTutorial()) {
help.add(Colors.SECONDARY_SHADOW + tutLine);
}
HolographicDisplays.getNMSManager().newFancyMessage(usage)
.color(ChatColor.AQUA)
.suggest(usage)
.tooltip(Joiner.on('\n').join(help))
.send((Player) sender);
} else {
sender.sendMessage(Colors.PRIMARY + usage);
}
}
}
if (CommandValidator.isPlayerSender(sender) && HolographicDisplays.getNMSManager().hasChatHoverFeature()) {
HelpCommand.sendHoverTip(sender);
}
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Shows the commands to manipulate an existing hologram.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,72 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
public class FixCommand extends HologramSubCommand {
public FixCommand() {
super("fix");
setPermission(Strings.BASE_PERM + "fix");
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
if (args.length <= 1) {
sender.sendMessage(Colors.PRIMARY + "This command will put a glowstone 16 blocks above the hologram to fix the lightning.");
sender.sendMessage(Colors.PRIMARY + "If you're sure, type " + Colors.SECONDARY + "/" + label + " fix " + args[0].toLowerCase() + " confirm");
return;
}
if (args[1].equalsIgnoreCase("confirm")) {
Block block = hologram.getWorld().getBlockAt((int) hologram.getX(), (int) hologram.getY() + 16, (int) hologram.getZ());
String oldType = block.getType().toString().replace("_", " ").toLowerCase();
block.setType(Material.GLOWSTONE);
sender.sendMessage(Colors.PRIMARY + "Changed the block 16 block above the hologram (" + oldType + ") to glowstone!");
} else {
throw new CommandException(args[1] + " is not a valid confirmation! Use \"confirm\".");
}
}
@Override
public List<String> getTutorial() {
return Arrays.asList("This command will fix the lightning of a hologram,",
"placing a glowstone block 16 blocks above it.",
"That's the only way to fix it (Only for 1.7 and lower).");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,98 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.List;
import net.minecraft.util.com.google.common.base.Joiner;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramsCommandHandler;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class HelpCommand extends HologramSubCommand {
private HologramsCommandHandler mainCommandHandler;
public HelpCommand(HologramsCommandHandler mainCommandHandler) {
super("help");
setPermission(Strings.BASE_PERM + "help");
this.mainCommandHandler = mainCommandHandler;
}
@Override
public String getPossibleArguments() {
return "";
}
@Override
public int getMinimumArguments() {
return 0;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
sender.sendMessage("");
sender.sendMessage(Strings.formatTitle("Holographic Displays Commands"));
for (HologramSubCommand subCommand : mainCommandHandler.getSubCommands()) {
if (subCommand.getType() == SubCommandType.GENERIC) {
String usage = "/" + label + " " + subCommand.getName() + (subCommand.getPossibleArguments().length() > 0 ? " " + subCommand.getPossibleArguments() : "");
if (CommandValidator.isPlayerSender(sender)) {
List<String> help = Utils.newList();
help.add(Colors.PRIMARY + usage);
for (String tutLine : subCommand.getTutorial()) {
help.add(Colors.SECONDARY_SHADOW + tutLine);
}
HolographicDisplays.getNMSManager().newFancyMessage(usage)
.color(ChatColor.AQUA)
.suggest(usage)
.tooltip(Joiner.on('\n').join(help))
.send((Player) sender);
} else {
sender.sendMessage(Colors.PRIMARY + usage);
}
}
}
if (CommandValidator.isPlayerSender(sender) && HolographicDisplays.getNMSManager().hasChatHoverFeature()) {
sendHoverTip(sender);
}
}
public static void sendHoverTip(CommandSender sender) {
sender.sendMessage("");
HolographicDisplays.getNMSManager().newFancyMessage("TIP").style(ChatColor.BOLD).color(ChatColor.YELLOW)
.then(" Try to ").color(ChatColor.GRAY)
.then("hover").color(ChatColor.WHITE).style(ChatColor.ITALIC, ChatColor.UNDERLINE)
.tooltip(ChatColor.LIGHT_PURPLE + "Hover on the commands to get info about them.")
.then(" or ").color(ChatColor.GRAY)
.then("click").color(ChatColor.WHITE).style(ChatColor.ITALIC, ChatColor.UNDERLINE)
.tooltip(ChatColor.LIGHT_PURPLE + "Click on the commands to insert them in the chat.")
.then(" on the commands!").color(ChatColor.GRAY)
.send((Player) sender);
}
@Override
public List<String> getTutorial() {
return null;
}
@Override
public SubCommandType getType() {
return SubCommandType.HIDDEN;
}
}

View File

@ -0,0 +1,75 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class InsertlineCommand extends HologramSubCommand {
public InsertlineCommand() {
super("insertline");
setPermission(Strings.BASE_PERM + "insertline");
}
@Override
public String getPossibleArguments() {
return "<hologramName> <lineNumber> <text>";
}
@Override
public int getMinimumArguments() {
return 3;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
int insertAfter = CommandValidator.getInteger(args[1]);
int oldLinesAmount = hologram.size();
CommandValidator.isTrue(insertAfter >= 0 && insertAfter <= oldLinesAmount, "The number must be between 0 and " + hologram.size() + "(amount of lines of the hologram).");
hologram.getLinesUnsafe().add(insertAfter, HologramDatabase.readLineFromString(Utils.join(args, " ", 2, args.length), hologram));
hologram.refreshAll();
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
if (insertAfter == 0) {
sender.sendMessage(Colors.PRIMARY + "Line inserted before line n.1!");
} else if (insertAfter == oldLinesAmount) {
sender.sendMessage(Colors.PRIMARY + "Line appended at the end!");
sender.sendMessage(Strings.TIP_PREFIX + "Next time use /" + label + " addline to add a line at the end.");
} else {
sender.sendMessage(Colors.PRIMARY + "Line inserted between lines " + insertAfter + " and " + (insertAfter + 1) + "!");
}
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Inserts a line after the specified index.",
"If the index is 0, the line will be put before",
"the first line of the hologram.");
}
@Override
public SubCommandType getType() {
return SubCommandType.EDIT_LINES;
}
}

View File

@ -0,0 +1,81 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
public class ListCommand extends HologramSubCommand {
private static final int HOLOGRAMS_PER_PAGE = 10;
public ListCommand() {
super("list");
setPermission(Strings.BASE_PERM + "list");
}
@Override
public String getPossibleArguments() {
return "[page]";
}
@Override
public int getMinimumArguments() {
return 0;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
int page = args.length > 0 ? CommandValidator.getInteger(args[0]) : 1;
if (page < 1) {
throw new CommandException("Page number must be 1 or greater.");
}
int totalPages = NamedHologramManager.size() / HOLOGRAMS_PER_PAGE;
if (NamedHologramManager.size() % HOLOGRAMS_PER_PAGE != 0) {
totalPages++;
}
if (NamedHologramManager.size() == 0) {
throw new CommandException("There are no holograms yet. Create one with /" + label + " create.");
}
sender.sendMessage("");
sender.sendMessage(Strings.formatTitle("Holograms list " + Colors.SECONDARY + "(Page " + page + " of " + totalPages + ")"));
int fromIndex = (page - 1) * HOLOGRAMS_PER_PAGE;
int toIndex = fromIndex + HOLOGRAMS_PER_PAGE;
for (int i = fromIndex; i < toIndex; i++) {
if (i < NamedHologramManager.size()) {
NamedHologram hologram = NamedHologramManager.get(i);
sender.sendMessage(Colors.SECONDARY_SHADOW + "- " + Colors.SECONDARY + Colors.BOLD + hologram.getName() + " " + Colors.SECONDARY_SHADOW + "at x: " + (int) hologram.getX() + ", y: " + (int) hologram.getY() + ", z: " + (int) hologram.getZ() + " (lines: " + hologram.size() + ", world: \"" + hologram.getWorld().getName() + "\")");
}
}
if (page < totalPages) {
sender.sendMessage(Strings.TIP_PREFIX + "See the next page with /" + label + " list " + (page + 1));
}
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Lists all the existing holograms.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,67 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
public class MovehereCommand extends HologramSubCommand {
public MovehereCommand() {
super("movehere");
setPermission(Strings.BASE_PERM + "movehere");
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
Player player = CommandValidator.getPlayerSender(sender);
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
hologram.teleport(player.getWorld(), player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ());
hologram.despawnEntities();
hologram.refreshAll();
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
Location to = player.getLocation();
to.setPitch(90);
player.teleport(to, TeleportCause.PLUGIN);
player.sendMessage(Colors.PRIMARY + "You moved the hologram '" + hologram.getName() + "' near to you.");
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Moves a hologram to your location.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,70 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class NearCommand extends HologramSubCommand {
public NearCommand() {
super("near");
setPermission(Strings.BASE_PERM + "near");
}
@Override
public String getPossibleArguments() {
return "<radius>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
Player player = CommandValidator.getPlayerSender(sender);
int radius = CommandValidator.getInteger(args[0]);
CommandValidator.isTrue(radius > 0, "Radius must be at least 1.");
World world = player.getWorld();
int radiusSquared = radius * radius;
List<NamedHologram> nearHolograms = Utils.newList();
for (NamedHologram hologram : NamedHologramManager.getHolograms()) {
if (hologram.getLocation().getWorld().equals(world) && hologram.getLocation().distanceSquared(player.getLocation()) <= radiusSquared) {
nearHolograms.add(hologram);
}
}
CommandValidator.isTrue(!nearHolograms.isEmpty(), "There are no holograms in the given radius.");
player.sendMessage(Strings.formatTitle("Near holograms"));
for (NamedHologram nearHologram : nearHolograms) {
player.sendMessage(Colors.SECONDARY_SHADOW + "- " + Colors.SECONDARY + Colors.BOLD + nearHologram.getName() + " " + Colors.SECONDARY_SHADOW + "at x: " + (int) nearHologram.getX() + ", y: " + (int) nearHologram.getY() + ", z: " + (int) nearHologram.getZ() + " (lines: " + nearHologram.size() + ")");
}
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Get a list of near holograms.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,157 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import net.minecraft.util.com.google.common.collect.Lists;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.exception.TooWideException;
import com.gmail.filoghost.holographicdisplays.exception.UnreadableImageException;
import com.gmail.filoghost.holographicdisplays.image.ImageMessage;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.util.FileUtils;
public class ReadimageCommand extends HologramSubCommand {
public ReadimageCommand() {
super("readimage", "image");
setPermission(Strings.BASE_PERM + "readimage");
}
@Override
public String getPossibleArguments() {
return "<hologram> <imageWithExtension> <width>";
}
@Override
public int getMinimumArguments() {
return 3;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
boolean append = false;
List<String> newArgs = Lists.newArrayList();
for (int i = 0; i < args.length; i++) {
if (args[i].equalsIgnoreCase("-a") || args[i].equalsIgnoreCase("-append")) {
append = true;
} else {
newArgs.add(args[i]);
}
}
args = newArgs.toArray(new String[0]);
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
int width = CommandValidator.getInteger(args[2]);
CommandValidator.isTrue(width >= 2, "The width of the image must be 2 or greater.");
boolean isUrl = false;
try {
String fileName = args[1];
BufferedImage image = null;
if (fileName.startsWith("http://") || fileName.startsWith("https://")) {
isUrl = true;
image = FileUtils.readImage(new URL(fileName));
} else {
if (fileName.matches(".*[a-zA-Z0-9\\-]+\\.[a-zA-Z0-9\\-]{1,4}\\/.+")) {
Strings.sendWarning(sender, "The image path seems to be an URL. If so, please use http:// or https:// in the path.");
}
image = FileUtils.readImage(new File(HolographicDisplays.getInstance().getDataFolder(), fileName));
}
if (!append) {
hologram.clearLines();
}
ImageMessage imageMessage = new ImageMessage(image, width);
String[] newLines = imageMessage.getLines();
for (int i = 0; i < newLines.length; i++) {
hologram.appendTextLine(newLines[i]);
}
hologram.refreshAll();
if (newLines.length < 5) {
sender.sendMessage(Strings.TIP_PREFIX + "The image has a very low height. You can increase it by increasing the width, it will scale automatically.");
}
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
if (append) {
sender.sendMessage(Colors.PRIMARY + "The image was appended int the end of the hologram!");
} else {
sender.sendMessage(Colors.PRIMARY + "The image was drawn in the hologram!");
}
} catch (MalformedURLException e) {
throw new CommandException("The provided URL was not valid.");
} catch (FileNotFoundException e) {
throw new CommandException("The image '" + args[1] + "' doesn't exist in the plugin's folder.");
} catch (TooWideException e) {
throw new CommandException("The image is too large. Max width allowed is " + ImageMessage.MAX_WIDTH + " pixels.");
} catch (UnreadableImageException e) {
throw new CommandException("The plugin was unable to read the image. Be sure that the format is supported.");
} catch (IOException e) {
throw new CommandException("I/O exception while reading the image." + (isUrl ? "Is the URL valid?" : "Is it in use?"));
} catch (Exception e) {
e.printStackTrace();
throw new CommandException("Unhandled exception while reading the image! Please look the console.");
}
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Reads an image from a file. Tutorial:",
"1) Move the image in the plugin's folder",
"2) Do not use spaces in the name",
"3) Do /holograms read <hologram> <image> <width>",
"4) Choose <width> to automatically resize the image",
"5) (Optional) Use the flag '-a' if you only want to append",
" the image to the hologram without clearing the lines",
"",
"Example: you have an image named 'logo.png', you want to append",
"it to the lines of the hologram named 'test', with a width of",
"50 pixels. In this case you would execute the following command:",
ChatColor.YELLOW + "/holograms readimage test logo.png 50 -a",
"",
"The symbols used to create the image are taken from the config.yml.");
}
@Override
public SubCommandType getType() {
return SubCommandType.EDIT_LINES;
}
}

View File

@ -0,0 +1,104 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.disk.StringConverter;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.util.FileUtils;
public class ReadtextCommand extends HologramSubCommand {
public ReadtextCommand() {
super("readtext", "readlines");
setPermission(Strings.BASE_PERM + "readtext");
}
@Override
public String getPossibleArguments() {
return "<hologramName> <fileWithExtension>";
}
@Override
public int getMinimumArguments() {
return 2;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
try {
List<String> lines = FileUtils.readLines(new File(HolographicDisplays.getInstance().getDataFolder(), args[1]));
hologram.clearLines();
int linesAmount = lines.size();
if (linesAmount > 40) {
Strings.sendWarning(sender, "The file contained more than 40 lines, that have been limited.");
linesAmount = 40;
}
for (int i = 0; i < linesAmount; i++) {
hologram.appendTextLine(StringConverter.toReadableFormat(lines.get(i)));
}
hologram.refreshAll();
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
if (args[1].contains(".")) {
if (isImageExtension(args[1].substring(args[1].lastIndexOf('.') + 1))) {
Strings.sendWarning(sender, "The read file has an image's extension. If it is an image, you should use /" + label + " readimage.");
}
}
sender.sendMessage(Colors.PRIMARY + "The lines were pasted into the hologram!");
} catch (FileNotFoundException e) {
throw new CommandException("A file named '" + args[1] + "' doesn't exist in the plugin's folder.");
} catch (IOException e) {
throw new CommandException("I/O exception while reading the file. Is it in use?");
} catch (Exception e) {
e.printStackTrace();
throw new CommandException("Unhandled exception while reading the file! Please look the console.");
}
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Reads the lines from a text file. Tutorial:",
"1) Create a new text file in the plugin's folder",
"2) Do not use spaces in the name",
"3) Each line will be a line in the hologram",
"4) Do /holograms readlines <hologramName> <fileWithExtension>",
"",
"Example: you have a file named 'info.txt', and you want",
"to paste it in the hologram named 'test'. In this case you",
"would execute "+ ChatColor.YELLOW + "/holograms readlines test info.txt");
}
@Override
public SubCommandType getType() {
return SubCommandType.EDIT_LINES;
}
private boolean isImageExtension(String input) {
return Arrays.asList("jpg", "png", "jpeg", "gif").contains(input.toLowerCase());
}
}

View File

@ -0,0 +1,99 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerTracker;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.Configuration;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.disk.UnicodeSymbols;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.exception.HologramNotFoundException;
import com.gmail.filoghost.holographicdisplays.exception.InvalidFormatException;
import com.gmail.filoghost.holographicdisplays.exception.WorldNotFoundException;
import com.gmail.filoghost.holographicdisplays.object.CraftHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.placeholder.AnimationsRegister;
import com.gmail.filoghost.holographicdisplays.placeholder.PlaceholdersManager;
public class ReloadCommand extends HologramSubCommand {
public ReloadCommand() {
super("reload");
setPermission(Strings.BASE_PERM + "reload");
}
@Override
public String getPossibleArguments() {
return "";
}
@Override
public int getMinimumArguments() {
return 0;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
try {
long startMillis = System.currentTimeMillis();
Configuration.load(HolographicDisplays.getInstance());
BungeeServerTracker.startTask(Configuration.bungeeRefreshSeconds);
UnicodeSymbols.load(HolographicDisplays.getInstance());
HologramDatabase.loadYamlFile(HolographicDisplays.getInstance());
AnimationsRegister.loadAnimations(HolographicDisplays.getInstance());
PlaceholdersManager.untrackAll();
NamedHologramManager.clearAll();
Set<String> savedHolograms = HologramDatabase.getHolograms();
if (savedHolograms != null && savedHolograms.size() > 0) {
for (String singleSavedHologram : savedHolograms) {
try {
NamedHologram singleHologramEntity = HologramDatabase.loadHologram(singleSavedHologram);
NamedHologramManager.addHologram(singleHologramEntity);
} catch (HologramNotFoundException e) {
Strings.sendWarning(sender, "Hologram '" + singleSavedHologram + "' not found, skipping it.");
} catch (InvalidFormatException e) {
Strings.sendWarning(sender, "Hologram '" + singleSavedHologram + "' has an invalid location format.");
} catch (WorldNotFoundException e) {
Strings.sendWarning(sender, "Hologram '" + singleSavedHologram + "' was in the world '" + e.getMessage() + "' but it wasn't loaded.");
}
}
}
for (CraftHologram hologram : NamedHologramManager.getHolograms()) {
hologram.refreshAll();
}
long endMillis = System.currentTimeMillis();
sender.sendMessage(Colors.PRIMARY + "Configuration reloaded successfully in " + (endMillis - startMillis) + "ms!");
} catch (Exception ex) {
ex.printStackTrace();
throw new CommandException("Exception while reloading the configuration. Please look the console.");
}
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Reloads the holograms from the database.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,65 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
public class RemovelineCommand extends HologramSubCommand {
public RemovelineCommand() {
super("removeline");
setPermission(Strings.BASE_PERM + "removeline");
}
@Override
public String getPossibleArguments() {
return "<hologramName> <lineNumber>";
}
@Override
public int getMinimumArguments() {
return 2;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
int lineNumber = CommandValidator.getInteger(args[1]);
CommandValidator.isTrue(lineNumber >= 1 && lineNumber <= hologram.size(), "The line number must be between 1 and " + hologram.size() + ".");
int index = lineNumber - 1;
CommandValidator.isTrue(hologram.size() > 1, "The hologram should have at least 1 line. If you want to delete it, use /" + label + " delete.");
hologram.removeLine(index);
hologram.refreshAll();
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
sender.sendMessage(Colors.PRIMARY + "Line " + lineNumber + " removed!");
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Removes a line from a hologram.");
}
@Override
public SubCommandType getType() {
return SubCommandType.EDIT_LINES;
}
}

View File

@ -0,0 +1,66 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class SetlineCommand extends HologramSubCommand {
public SetlineCommand() {
super("setline");
setPermission(Strings.BASE_PERM + "setline");
}
@Override
public String getPossibleArguments() {
return "<hologramName> <lineNumber> <newText>";
}
@Override
public int getMinimumArguments() {
return 3;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
int lineNumber = CommandValidator.getInteger(args[1]);
CommandValidator.isTrue(lineNumber >= 1 && lineNumber <= hologram.size(), "The line number must be between 1 and " + hologram.size() + ".");
int index = lineNumber - 1;
hologram.getLinesUnsafe().get(index).despawn();
hologram.getLinesUnsafe().set(index, HologramDatabase.readLineFromString(Utils.join(args, " ", 2, args.length), hologram));
hologram.refreshAll();
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
sender.sendMessage(Colors.PRIMARY + "Line " + lineNumber + " changed!");
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Changes a line of a hologram.");
}
@Override
public SubCommandType getType() {
return SubCommandType.EDIT_LINES;
}
}

View File

@ -0,0 +1,60 @@
package com.gmail.filoghost.holographicdisplays.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.CommandValidator;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramSubCommand;
import com.gmail.filoghost.holographicdisplays.exception.CommandException;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
public class TeleportCommand extends HologramSubCommand {
public TeleportCommand() {
super("teleport", "tp");
setPermission(Strings.BASE_PERM + "teleport");
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
Player player = CommandValidator.getPlayerSender(sender);
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.NO_SUCH_HOLOGRAM);
Location loc = hologram.getLocation();
loc.setPitch(90);
player.teleport(loc, TeleportCause.PLUGIN);
player.sendMessage(Colors.PRIMARY + "You were teleported to the hologram named '" + hologram.getName() + "'.");
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Teleports you to the given hologram.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,32 @@
package com.gmail.filoghost.holographicdisplays.disk;
public enum ConfigNode {
SPACE_BETWEEN_LINES("space-between-lines", 0.02),
IMAGES_SYMBOL("images.symbol", "[x]"),
TRANSPARENCY_SPACE("images.transparency.space", " [|] "),
TRANSPARENCY_COLOR("images.transparency.color", "&7"),
UPDATE_NOTIFICATION("update-notification", true),
BUNGEE_REFRESH_SECONDS("bungee.refresh-seconds", 3),
BUNGEE_USE_REDIS_BUNGEE("bungee.use-RedisBungee", false),
TIME_FORMAT("time.format", "H:mm"),
TIME_ZONE("time.zone", "GMT+1"),
DEBUG("debug", false);
private final String path;
private final Object value;
private ConfigNode(String path, Object defaultValue) {
this.path = path;
value = defaultValue;
}
public String getPath() {
return path;
}
public Object getDefaultValue() {
return value;
}
}

View File

@ -0,0 +1,149 @@
package com.gmail.filoghost.holographicdisplays.disk;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone;
import org.bukkit.ChatColor;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import com.google.common.base.Joiner;
/**
* Just a bunch of static varibles to hold the settings.
* Useful for fast access.
*/
public class Configuration {
public static double spaceBetweenLines;
public static String imageSymbol;
public static String transparencySymbol;
public static boolean updateNotification;
public static ChatColor transparencyColor;
public static SimpleDateFormat timeFormat;
public static int bungeeRefreshSeconds;
public static String bungeeOnlineFormat;
public static String bungeeOfflineFormat;
public static boolean useRedisBungee;
public static boolean debug;
public static void load(Plugin plugin) {
File configFile = new File(plugin.getDataFolder(), "config.yml");
if (!configFile.exists()) {
plugin.getDataFolder().mkdirs();
plugin.saveResource("config.yml", true);
}
YamlConfiguration config = new YamlConfiguration();
try {
config.load(configFile);
} catch (InvalidConfigurationException e) {
e.printStackTrace();
plugin.getLogger().warning("The configuration is not a valid YAML file! Please check it with a tool like http://yaml-online-parser.appspot.com/");
return;
} catch (IOException e) {
e.printStackTrace();
plugin.getLogger().warning("I/O error while reading the configuration. Was the file in use?");
return;
} catch (Exception e) {
e.printStackTrace();
plugin.getLogger().warning("Unhandled exception while reading the configuration!");
return;
}
boolean needsSave = false;
for (ConfigNode node : ConfigNode.values()) {
if (!config.isSet(node.getPath())) {
needsSave = true;
config.set(node.getPath(), node.getDefaultValue());
}
}
// Check the old values.
List<String> nodesToRemove = Arrays.asList(
"vertical-spacing",
"time-format",
"bungee-refresh-seconds",
"using-RedisBungee",
"bungee-online-format",
"bungee-offline-format"
);
for (String oldNode : nodesToRemove) {
if (config.isSet(oldNode)) {
config.set(oldNode, null);
needsSave = true;
}
}
if (needsSave) {
config.options().header(Joiner.on('\n').join(
".",
". Read the tutorial at: http://dev.bukkit.org/bukkit-plugins/holographic-displays/",
".",
". Plugin created by filoghost.",
"."
));
config.options().copyHeader(true);
try {
config.save(configFile);
} catch (IOException e) {
e.printStackTrace();
plugin.getLogger().warning("I/O error while saving the configuration. Was the file in use?");
}
}
spaceBetweenLines = config.getDouble(ConfigNode.SPACE_BETWEEN_LINES.getPath());
updateNotification = config.getBoolean(ConfigNode.UPDATE_NOTIFICATION.getPath());
imageSymbol = StringConverter.toReadableFormat(config.getString(ConfigNode.IMAGES_SYMBOL.getPath()));
transparencySymbol = StringConverter.toReadableFormat(config.getString(ConfigNode.TRANSPARENCY_SPACE.getPath()));
bungeeRefreshSeconds = config.getInt(ConfigNode.BUNGEE_REFRESH_SECONDS.getPath());
useRedisBungee = config.getBoolean(ConfigNode.BUNGEE_USE_REDIS_BUNGEE.getPath());
debug = config.getBoolean(ConfigNode.DEBUG.getPath());
String tempColor = config.getString(ConfigNode.TRANSPARENCY_COLOR.getPath()).replace('&', ChatColor.COLOR_CHAR);
boolean foundColor = false;
for (ChatColor chatColor : ChatColor.values()) {
if (chatColor.toString().equals(tempColor)) {
Configuration.transparencyColor = chatColor;
foundColor = true;
}
}
if (!foundColor) {
Configuration.transparencyColor = ChatColor.GRAY;
plugin.getLogger().warning("You didn't set a valid chat color for transparency in the configuration, light gray (&7) will be used.");
}
try {
timeFormat = new SimpleDateFormat(config.getString(ConfigNode.TIME_FORMAT.getPath()));
timeFormat.setTimeZone(TimeZone.getTimeZone(config.getString(ConfigNode.TIME_ZONE.getPath())));
} catch (IllegalArgumentException ex) {
timeFormat = new SimpleDateFormat("H:mm");
plugin.getLogger().warning("Time format not valid in the configuration, using the default.");
}
if (bungeeRefreshSeconds < 1) {
plugin.getLogger().warning("The minimum interval for pinging BungeeCord's servers is 1 second. It has been automatically set.");
bungeeRefreshSeconds = 1;
}
if (bungeeRefreshSeconds > 60) {
plugin.getLogger().warning("The maximum interval for pinging BungeeCord's servers is 60 seconds. It has been automatically set.");
bungeeRefreshSeconds = 60;
}
}
}

View File

@ -0,0 +1,146 @@
package com.gmail.filoghost.holographicdisplays.disk;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.exception.HologramNotFoundException;
import com.gmail.filoghost.holographicdisplays.exception.InvalidFormatException;
import com.gmail.filoghost.holographicdisplays.exception.WorldNotFoundException;
import com.gmail.filoghost.holographicdisplays.object.CraftHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologram;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTextLine;
import com.gmail.filoghost.holographicdisplays.util.ItemUtils;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class HologramDatabase {
private static File file;
private static FileConfiguration config;
public static void loadYamlFile(Plugin plugin) {
file = new File(plugin.getDataFolder(), "database.yml");
if (!file.exists()) {
plugin.getDataFolder().mkdirs();
plugin.saveResource("database.yml", true);
}
config = YamlConfiguration.loadConfiguration(file);
}
public static NamedHologram loadHologram(String name) throws HologramNotFoundException, InvalidFormatException, WorldNotFoundException {
ConfigurationSection configSection = config.getConfigurationSection(name);
if (configSection == null) {
throw new HologramNotFoundException();
}
List<String> lines = configSection.getStringList("lines");
String locationString = configSection.getString("location");
if (lines == null || locationString == null || lines.size() == 0) {
throw new HologramNotFoundException();
}
Location loc = LocationSerializer.locationFromString(locationString);
NamedHologram hologram = new NamedHologram(loc, name);
for (int i = 0; i < lines.size(); i++) {
hologram.getLinesUnsafe().add(readLineFromString(lines.get(i), hologram));
}
return hologram;
}
public static CraftHologramLine readLineFromString(String rawText, CraftHologram hologram) {
if (rawText.toLowerCase().startsWith("icon:")) {
String iconMaterial = ItemUtils.stripSpacingChars(rawText.substring("icon:".length(), rawText.length()));
short dataValue = 0;
if (iconMaterial.contains(":")) {
try {
dataValue = (short) Integer.parseInt(iconMaterial.split(":")[1]);
} catch (NumberFormatException e) { }
iconMaterial = iconMaterial.split(":")[0];
}
Material mat = ItemUtils.matchMaterial(iconMaterial);
if (mat == null) {
mat = Material.BEDROCK;
}
return new CraftItemLine(hologram, new ItemStack(mat, 1, dataValue));
} else {
if (rawText.trim().equalsIgnoreCase("{empty}")) {
return new CraftTextLine(hologram, "");
} else {
return new CraftTextLine(hologram, StringConverter.toReadableFormat(rawText));
}
}
}
public static void deleteHologram(String name) {
config.set(name, null);
}
public static void saveHologram(NamedHologram hologram) {
ConfigurationSection configSection = config.isConfigurationSection(hologram.getName()) ? config.getConfigurationSection(hologram.getName()) : config.createSection(hologram.getName());
configSection.set("location", LocationSerializer.locationToString(hologram.getLocation()));
List<String> lines = Utils.newList();
for (CraftHologramLine line : hologram.getLinesUnsafe()) {
if (line instanceof CraftTextLine) {
lines.add(StringConverter.toSaveableFormat(((CraftTextLine) line).getText()));
} else if (line instanceof CraftItemLine) {
CraftItemLine itemLine = (CraftItemLine) line;
lines.add("ICON: " + itemLine.getItemStack().getType().toString().replace("_", " ").toLowerCase() + (itemLine.getItemStack().getDurability() != 0 ? String.valueOf(itemLine.getItemStack().getDurability()) : ""));
}
}
configSection.set("lines", lines);
}
public static Set<String> getHolograms() {
return config.getKeys(false);
}
public static boolean isExistingHologram(String name) {
return config.isConfigurationSection(name);
}
public static void saveToDisk() throws IOException {
if (config != null && file != null) {
config.save(file);
}
}
public static void trySaveToDisk() {
try {
saveToDisk();
} catch (IOException ex) {
ex.printStackTrace();
HolographicDisplays.getInstance().getLogger().severe("Unable to save database.yml to disk!");
}
}
}

View File

@ -0,0 +1,55 @@
package com.gmail.filoghost.holographicdisplays.disk;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import com.gmail.filoghost.holographicdisplays.exception.InvalidFormatException;
import com.gmail.filoghost.holographicdisplays.exception.WorldNotFoundException;
public class LocationSerializer {
private static DecimalFormat decimalFormat;
static {
// More precision is not needed at all.
decimalFormat = new DecimalFormat("0.0000");
DecimalFormatSymbols formatSymbols = decimalFormat.getDecimalFormatSymbols();
formatSymbols.setDecimalSeparator('.');
decimalFormat.setDecimalFormatSymbols(formatSymbols);
}
public static Location locationFromString(String input) throws WorldNotFoundException, InvalidFormatException {
if (input == null) {
throw new InvalidFormatException();
}
String[] parts = input.replace(" ", "").split(",");
if (parts.length != 4) {
throw new InvalidFormatException();
}
try {
double x = Double.parseDouble(parts[1]);
double y = Double.parseDouble(parts[2]);
double z = Double.parseDouble(parts[3]);
World world = Bukkit.getWorld(parts[0]);
if (world == null) {
throw new WorldNotFoundException(parts[0]);
}
return new Location(world, x, y, z);
} catch (NumberFormatException ex) {
throw new InvalidFormatException();
}
}
public static String locationToString(Location loc) {
return (loc.getWorld().getName() + ", " + decimalFormat.format(loc.getX()) + ", " + decimalFormat.format(loc.getY()) + ", " + decimalFormat.format(loc.getZ()));
}
}

View File

@ -0,0 +1,28 @@
package com.gmail.filoghost.holographicdisplays.disk;
import org.bukkit.ChatColor;
public class StringConverter {
public static String toReadableFormat(String input) {
if (input == null) {
return null;
}
input = UnicodeSymbols.placeholdersToSymbols(input);
input = ChatColor.translateAlternateColorCodes('&', input);
return input;
}
public static String toSaveableFormat(String input) {
if (input == null) {
return null;
}
input = UnicodeSymbols.symbolsToPlaceholders(input);
input = input.replace("§", "&");
return input;
}
}

View File

@ -0,0 +1,102 @@
package com.gmail.filoghost.holographicdisplays.disk;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang.StringEscapeUtils;
import org.bukkit.plugin.Plugin;
import com.gmail.filoghost.holographicdisplays.util.FileUtils;
public class UnicodeSymbols {
private static Map<String, String> placeholders = new HashMap<String, String>();
public static void load(Plugin plugin) {
placeholders.clear();
File file = new File(plugin.getDataFolder(), "symbols.yml");
if (!file.exists()) {
plugin.getDataFolder().mkdirs();
plugin.saveResource("symbols.yml", true);
}
List<String> lines;
try {
lines = FileUtils.readLines(file);
} catch (IOException e) {
e.printStackTrace();
plugin.getLogger().warning("I/O error while reading symbols.yml. Was the file in use?");
return;
} catch (Exception e) {
e.printStackTrace();
plugin.getLogger().warning("Unhandled exception while reading symbols.yml!");
return;
}
for (String line : lines) {
// Comment or empty line.
if (line.length() == 0 || line.startsWith("#")) {
continue;
}
if (!line.contains(":")) {
plugin.getLogger().warning("Unable to parse a line(" + line + ") from symbols.yml: it must contain ':' to separate the placeholder and the replacement.");
continue;
}
int indexOf = line.indexOf(':');
String placeholder = unquote(line.substring(0, indexOf).trim());
String replacement = StringEscapeUtils.unescapeJava(unquote(line.substring(indexOf + 1, line.length()).trim()));
if (placeholder.isEmpty() || replacement.isEmpty()) {
plugin.getLogger().warning("Unable to parse a line(" + line + ") from symbols.yml: the placeholder and the replacement must have both at least 1 character.");
continue;
}
if (placeholder.length() > 30) {
plugin.getLogger().warning("Unable to parse a line(" + line + ") from symbols.yml: the placeholder cannot be longer than 30 characters.");
continue;
}
placeholders.put(placeholder, replacement);
}
}
protected static String placeholdersToSymbols(String input) {
for (Entry<String, String> entry : placeholders.entrySet()) {
input = input.replace(entry.getKey(), entry.getValue());
}
return input;
}
protected static String symbolsToPlaceholders(String input) {
for (Entry<String, String> entry : placeholders.entrySet()) {
input = input.replace(entry.getValue(), entry.getKey());
}
return input;
}
private static String unquote(String input) {
if (input.length() < 2) {
// Cannot be quoted.
return input;
}
if (input.startsWith("'") && input.endsWith("'")) {
return input.substring(1, input.length() - 1);
} else if (input.startsWith("\"") && input.endsWith("\"")) {
return input.substring(1, input.length() - 1);
}
return input;
}
}

View File

@ -0,0 +1,10 @@
package com.gmail.filoghost.holographicdisplays.exception;
public class CommandException extends Exception {
private static final long serialVersionUID = 1L;
public CommandException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.gmail.filoghost.holographicdisplays.exception;
public class HologramNotFoundException extends Exception {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,10 @@
package com.gmail.filoghost.holographicdisplays.exception;
public class InvalidCharactersException extends Exception {
private static final long serialVersionUID = 1L;
public InvalidCharactersException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.gmail.filoghost.holographicdisplays.exception;
public class InvalidFormatException extends Exception {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,11 @@
package com.gmail.filoghost.holographicdisplays.exception;
public class InvalidMaterialException extends Exception {
private static final long serialVersionUID = 1L;
public InvalidMaterialException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.gmail.filoghost.holographicdisplays.exception;
public class SpawnFailedException extends Exception {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,17 @@
package com.gmail.filoghost.holographicdisplays.exception;
public class TooWideException extends Exception {
private static final long serialVersionUID = 1L;
private int width;
public TooWideException(int width) {
this.width = width;
}
public int getWidth() {
return width;
}
}

View File

@ -0,0 +1,7 @@
package com.gmail.filoghost.holographicdisplays.exception;
public class UnreadableImageException extends Exception {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,11 @@
package com.gmail.filoghost.holographicdisplays.exception;
public class WorldNotFoundException extends Exception {
private static final long serialVersionUID = 1L;
public WorldNotFoundException(String message) {
super(message);
}
}

View File

@ -0,0 +1,207 @@
package com.gmail.filoghost.holographicdisplays.image;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.Map;
import java.util.Map.Entry;
import org.bukkit.ChatColor;
import com.gmail.filoghost.holographicdisplays.disk.Configuration;
import com.gmail.filoghost.holographicdisplays.exception.TooWideException;
import com.gmail.filoghost.holographicdisplays.util.Utils;
/**
* Huge thanks to bobacadodl for this awesome library!
* Bukkit thread: https://forums.bukkit.org/threads/lib-imagemessage-v2-1-send-images-to-players-via-the-chat.204902
*/
public class ImageMessage {
public static final int MAX_WIDTH = 150;
private static final Map<ChatColor, Color> colorsMap = Utils.newMap();
private static final Map<ChatColor, Color> graysMap = Utils.newMap();
static {
colorsMap.put(ChatColor.DARK_BLUE, new Color(0, 0, 170));
colorsMap.put(ChatColor.DARK_GREEN, new Color(0, 170, 0));
colorsMap.put(ChatColor.DARK_AQUA, new Color(0, 170, 170));
colorsMap.put(ChatColor.DARK_RED, new Color(170, 0, 0));
colorsMap.put(ChatColor.DARK_PURPLE, new Color(170, 0, 170));
colorsMap.put(ChatColor.GOLD, new Color(255, 170, 0));
colorsMap.put(ChatColor.BLUE, new Color(85, 85, 255));
colorsMap.put(ChatColor.GREEN, new Color(85, 255, 85));
colorsMap.put(ChatColor.AQUA, new Color(85, 255, 255));
colorsMap.put(ChatColor.RED, new Color(255, 85, 85));
colorsMap.put(ChatColor.LIGHT_PURPLE, new Color(255, 85, 255));
colorsMap.put(ChatColor.YELLOW, new Color(255, 255, 85));
graysMap.put(ChatColor.BLACK, new Color(0, 0, 0));
graysMap.put(ChatColor.DARK_GRAY, new Color(85, 85, 85));
graysMap.put(ChatColor.GRAY, new Color(170, 170, 170));
graysMap.put(ChatColor.WHITE, new Color(255, 255, 255));
}
private String[] lines;
public ImageMessage(BufferedImage image, int width) throws TooWideException {
ChatColor[][] chatColors = toChatColorArray(image, width);
lines = toImgMessage(chatColors);
}
private ChatColor[][] toChatColorArray(BufferedImage image, int width) throws TooWideException {
double ratio = (double) image.getHeight() / image.getWidth();
int height = (int) (((double)width) * ratio);
if (height == 0) {
height = 1;
}
if (width > MAX_WIDTH) {
throw new TooWideException(width);
}
BufferedImage resized = resizeImage(image, width, height);
ChatColor[][] chatImg = new ChatColor[resized.getWidth()][resized.getHeight()];
for (int x = 0; x < resized.getWidth(); x++) {
for (int y = 0; y < resized.getHeight(); y++) {
int rgb = resized.getRGB(x, y);
chatImg[x][y] = getClosestChatColor(new Color(rgb, true));
}
}
return chatImg;
}
private String[] toImgMessage(ChatColor[][] colors) {
String[] lines = new String[colors[0].length];
ChatColor transparencyColor = Configuration.transparencyColor;
String transparencySymbol = Configuration.transparencySymbol;
String imageSymbol = Configuration.imageSymbol;
for (int y = 0; y < colors[0].length; y++) {
StringBuffer line = new StringBuffer();
ChatColor previous = ChatColor.RESET;
for (int x = 0; x < colors.length; x++) {
ChatColor currentColor = colors[x][y];
if (currentColor == null) {
// Use the trasparent char
if (previous != transparencyColor) {
// Change the previous chat color and append the newer
line.append(transparencyColor);
previous = transparencyColor;
}
line.append(transparencySymbol);
} else {
if (previous != currentColor) {
line.append(currentColor.toString());
previous = currentColor;
}
line.append(imageSymbol);
}
}
lines[y] = line.toString();
}
return lines;
}
private BufferedImage resizeImage(BufferedImage originalImage, int width, int height) {
return toBufferedImage(originalImage.getScaledInstance(width, height, Image.SCALE_DEFAULT));
}
private BufferedImage toBufferedImage(Image img) {
// Creates a buffered image with transparency.
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
// Draws the image on to the buffered image.
Graphics2D graphics = bimage.createGraphics();
graphics.drawImage(img, 0, 0, null);
graphics.dispose();
// Returns the buffered image.
return bimage;
}
private double getDistance(Color c1, Color c2) {
double rmean = (c1.getRed() + c2.getRed()) / 2.0;
double r = c1.getRed() - c2.getRed();
double g = c1.getGreen() - c2.getGreen();
int b = c1.getBlue() - c2.getBlue();
double weightR = 2 + rmean / 256.0;
double weightG = 4.0;
double weightB = 2 + (255 - rmean) / 256.0;
return weightR * r * r + weightG * g * g + weightB * b * b;
}
private boolean areIdentical(Color c1, Color c2) {
return Math.abs(c1.getRed() - c2.getRed()) <= 5 &&
Math.abs(c1.getGreen() - c2.getGreen()) <= 5 &&
Math.abs(c1.getBlue() - c2.getBlue()) <= 5;
}
private ChatColor getClosestChatColor(Color color) {
if (color.getAlpha() < 80) return null;
for (Entry<ChatColor, Color> entry : colorsMap.entrySet()) {
if (areIdentical(entry.getValue(), color)) {
return entry.getKey();
}
}
double bestGrayDistance = -1;
ChatColor bestGrayMatch = null;
for (Entry<ChatColor, Color> entry : graysMap.entrySet()) {
double distance = getDistance(color, entry.getValue());
if (distance < bestGrayDistance || bestGrayDistance == -1) {
bestGrayDistance = distance;
bestGrayMatch = entry.getKey();
}
}
if (bestGrayDistance < 17500) {
return bestGrayMatch;
}
double bestColorDistance = -1;
ChatColor bestColorMatch = null;
for (Entry<ChatColor, Color> entry : colorsMap.entrySet()) {
double distance = getDistance(color, entry.getValue());
if (distance < bestColorDistance || bestColorDistance == -1) {
bestColorDistance = distance;
bestColorMatch = entry.getKey();
}
}
// Minecraft has 15 colors
return bestColorMatch;
}
public String[] getLines() {
return lines;
}
}

View File

@ -0,0 +1,150 @@
package com.gmail.filoghost.holographicdisplays.listener;
import java.util.Map;
import java.util.logging.Level;
import org.bukkit.Chunk;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.plugin.Plugin;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.api.handler.PickupHandler;
import com.gmail.filoghost.holographicdisplays.commands.Colors;
import com.gmail.filoghost.holographicdisplays.commands.Strings;
import com.gmail.filoghost.holographicdisplays.disk.Configuration;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.object.CraftHologram;
import com.gmail.filoghost.holographicdisplays.object.NamedHologramManager;
import com.gmail.filoghost.holographicdisplays.object.PluginHologram;
import com.gmail.filoghost.holographicdisplays.object.PluginHologramManager;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class MainListener implements Listener {
private NMSManager nmsManager;
private Map<Player, Long> anticlickSpam = Utils.newMap();
public MainListener(NMSManager nmsManager) {
this.nmsManager = nmsManager;
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onChunkUnload(ChunkUnloadEvent event) {
for (Entity entity : event.getChunk().getEntities()) {
if (!entity.isDead()) {
NMSEntityBase entityBase = nmsManager.getNMSEntityBase(entity);
if (entityBase != null) {
entityBase.getHologramLine().getParent().despawnEntities();
}
}
}
}
@EventHandler (priority = EventPriority.MONITOR)
public void onChunkLoad(ChunkLoadEvent event) {
Chunk chunk = event.getChunk();
NamedHologramManager.onChunkLoad(chunk);
PluginHologramManager.onChunkLoad(chunk);
}
@EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onCreatureSpawn(CreatureSpawnEvent event) {
if (nmsManager.isNMSEntityBase(event.getEntity())) {
if (event.isCancelled()) {
event.setCancelled(false);
}
}
}
@EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onProjectileLaunch(ProjectileLaunchEvent event) {
if (nmsManager.isNMSEntityBase(event.getEntity())) {
if (event.isCancelled()) {
event.setCancelled(false);
}
}
}
@EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onItemSpawn(ItemSpawnEvent event) {
if (nmsManager.isNMSEntityBase(event.getEntity())) {
if (event.isCancelled()) {
event.setCancelled(false);
}
}
}
@EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSlimeInteract(PlayerInteractEntityEvent event) {
if (event.getRightClicked().getType() == EntityType.SLIME) {
NMSEntityBase entityBase = nmsManager.getNMSEntityBase(event.getRightClicked());
if (entityBase == null) return;
if (entityBase.getHologramLine() instanceof CraftTouchSlimeLine) {
CraftTouchSlimeLine touchSlime = (CraftTouchSlimeLine) entityBase.getHologramLine();
if (touchSlime.getTouchablePiece().getTouchHandler() != null && touchSlime.getParent().getVisibilityManager().isVisibleTo(event.getPlayer())) {
Long lastClick = anticlickSpam.get(event.getPlayer());
if (lastClick != null && System.currentTimeMillis() - lastClick.longValue() < 100) {
return;
}
anticlickSpam.put(event.getPlayer(), System.currentTimeMillis());
try {
touchSlime.getTouchablePiece().getTouchHandler().onTouch(event.getPlayer());
} catch (Exception ex) {
Plugin plugin = touchSlime.getParent() instanceof PluginHologram ? ((PluginHologram) touchSlime.getParent()).getOwner() : HolographicDisplays.getInstance();
HolographicDisplays.getInstance().getLogger().log(Level.WARNING, "The plugin " + plugin.getName() + " generated an exception when the player " + event.getPlayer().getName() + " touched a hologram.", ex);
}
}
}
}
}
public static void handleItemLinePickup(Player player, PickupHandler pickupHandler, CraftHologram hologram) {
try {
if (hologram.getVisibilityManager().isVisibleTo(player)) {
pickupHandler.onPickup(player);
}
} catch (Exception ex) {
Plugin plugin = hologram instanceof PluginHologram ? ((PluginHologram) hologram).getOwner() : HolographicDisplays.getInstance();
HolographicDisplays.getInstance().getLogger().log(Level.WARNING, "The plugin " + plugin.getName() + " generated an exception when the player " + player.getName() + " picked up an item from a hologram.", ex);
}
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
if (Configuration.updateNotification && HolographicDisplays.getNewVersion() != null) {
if (event.getPlayer().hasPermission(Strings.BASE_PERM + "update")) {
event.getPlayer().sendMessage(Colors.PRIMARY_SHADOW + "[HolographicDisplays] " + Colors.PRIMARY + "Found an update: " + HolographicDisplays.getNewVersion() + ". Download:");
event.getPlayer().sendMessage(Colors.PRIMARY_SHADOW + ">> " + Colors.PRIMARY + "http://dev.bukkit.org/bukkit-plugins/holographic-displays");
}
}
}
@EventHandler
public void onLeave(PlayerQuitEvent event) {
anticlickSpam.remove(event.getPlayer());
}
}

View File

@ -0,0 +1,514 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package com.gmail.filoghost.holographicdisplays.metrics;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
public class MetricsLite {
/**
* The current revision number
*/
private final static int REVISION = 7;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://report.mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/plugin/%s";
/**
* Interval of time to ping (in minutes)
*/
private final static int PING_INTERVAL = 15;
/**
* The plugin this metrics submits for
*/
private final Plugin plugin;
/**
* The plugin configuration file
*/
private final YamlConfiguration configuration;
/**
* The plugin configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
/**
* Lock for synchronization
*/
private final Object optOutLock = new Object();
/**
* Id of the scheduled task
*/
private volatile BukkitTask task = null;
public MetricsLite(Plugin plugin) throws IOException {
if (plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null");
}
this.plugin = plugin;
// load the config
configurationFile = getConfigFile();
configuration = YamlConfiguration.loadConfiguration(configurationFile);
// add some defaults
configuration.addDefault("opt-out", false);
configuration.addDefault("guid", UUID.randomUUID().toString());
configuration.addDefault("debug", false);
// Do we need to create the file?
if (configuration.get("guid", null) == null) {
configuration.options().header("http://mcstats.org").copyDefaults(true);
configuration.save(configurationFile);
}
// Load the guid then
guid = configuration.getString("guid");
debug = configuration.getBoolean("debug", false);
}
/**
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send
* the initial data to the metrics backend, and then after that it will post in increments of
* PING_INTERVAL * 1200 ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
synchronized (optOutLock) {
// Did we opt out?
if (isOptOut()) {
return false;
}
// Is metrics already running?
if (task != null) {
return true;
}
// Begin hitting the server with glorious data
task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
private boolean firstPost = true;
public void run() {
try {
// This has to be synchronized or it can collide with the disable method.
synchronized (optOutLock) {
// Disable Task, if it is running and the server owner decided to opt-out
if (isOptOut() && task != null) {
task.cancel();
task = null;
}
}
// We use the inverse of firstPost because if it is the first time we are posting,
// it is not a interval ping, so it evaluates to FALSE
// Each time thereafter it will evaluate to TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
}
}
}
}, 0, PING_INTERVAL * 1200);
return true;
}
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
synchronized (optOutLock) {
try {
// Reload the metrics file
configuration.load(getConfigFile());
} catch (IOException ex) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
} catch (InvalidConfigurationException ex) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
}
return configuration.getBoolean("opt-out", false);
}
}
/**
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.set("opt-out", false);
configuration.save(configurationFile);
}
// Enable Task, if it is not running
if (task == null) {
start();
}
}
}
/**
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
*
* @throws java.io.IOException
*/
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (!isOptOut()) {
configuration.set("opt-out", true);
configuration.save(configurationFile);
}
// Disable Task, if it is running
if (task != null) {
task.cancel();
task = null;
}
}
}
/**
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
// I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
// is to abuse the plugin object we already have
// plugin.getDataFolder() => base/plugins/PluginA/
// pluginsFolder => base/plugins/
// The base is not necessarily relative to the startup directory.
File pluginsFolder = plugin.getDataFolder().getParentFile();
// return => base/plugins/PluginMetrics/config.yml
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
}
/**
* Generic method that posts a plugin to the metrics website
*/
@SuppressWarnings("deprecation")
private void postPlugin(boolean isPing) throws IOException {
// Server software specific section
PluginDescriptionFile description = plugin.getDescription();
String pluginName = description.getName();
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
String pluginVersion = description.getVersion();
String serverVersion = Bukkit.getVersion();
int playersOnline = Bukkit.getServer().getOnlinePlayers().length;
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
StringBuilder json = new StringBuilder(1024);
json.append('{');
// The plugin's description file containg all of the plugin data such as name, version, author, etc
appendJSONPair(json, "guid", guid);
appendJSONPair(json, "plugin_version", pluginVersion);
appendJSONPair(json, "server_version", serverVersion);
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
appendJSONPair(json, "osname", osname);
appendJSONPair(json, "osarch", osarch);
appendJSONPair(json, "osversion", osversion);
appendJSONPair(json, "cores", Integer.toString(coreCount));
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
appendJSONPair(json, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
appendJSONPair(json, "ping", "1");
}
// close json
json.append('}');
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
byte[] uncompressed = json.toString().getBytes();
byte[] compressed = gzip(json.toString());
// Headers
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.setDoOutput(true);
if (debug) {
System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
}
// Write the data
OutputStream os = connection.getOutputStream();
os.write(compressed);
os.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = reader.readLine();
// close resources
os.close();
reader.close();
if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
if (response == null) {
response = "null";
} else if (response.startsWith("7")) {
response = response.substring(response.startsWith("7,") ? 2 : 1);
}
throw new IOException(response);
}
}
/**
* GZip compress a string of bytes
*
* @param input
* @return
*/
public static byte[] gzip(String input) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = null;
try {
gzos = new GZIPOutputStream(baos);
gzos.write(input.getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (gzos != null) try {
gzos.close();
} catch (IOException ignore) {
}
}
return baos.toByteArray();
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* Appends a json encoded key/value pair to the given string builder.
*
* @param json
* @param key
* @param value
* @throws UnsupportedEncodingException
*/
private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
boolean isValueNumeric = false;
try {
if (value.equals("0") || !value.endsWith("0")) {
Double.parseDouble(value);
isValueNumeric = true;
}
} catch (NumberFormatException e) {
isValueNumeric = false;
}
if (json.charAt(json.length() - 1) != '{') {
json.append(',');
}
json.append(escapeJSON(key));
json.append(':');
if (isValueNumeric) {
json.append(value);
} else {
json.append(escapeJSON(value));
}
}
/**
* Escape a string to create a valid JSON string
*
* @param text
* @return
*/
private static String escapeJSON(String text) {
StringBuilder builder = new StringBuilder();
builder.append('"');
for (int index = 0; index < text.length(); index++) {
char chr = text.charAt(index);
switch (chr) {
case '"':
case '\\':
builder.append('\\');
builder.append(chr);
break;
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
default:
if (chr < ' ') {
String t = "000" + Integer.toHexString(chr);
builder.append("\\u" + t.substring(t.length() - 4));
} else {
builder.append(chr);
}
break;
}
}
builder.append('"');
return builder.toString();
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String urlEncode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
}

View File

@ -0,0 +1,74 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces;
import java.io.IOException;
import org.bukkit.ChatColor;
import org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonWriter;
import org.bukkit.entity.Player;
public interface FancyMessage {
public FancyMessage color(final ChatColor color);
public FancyMessage style(final ChatColor... styles);
public FancyMessage file(final String path);
public FancyMessage link(final String url);
public FancyMessage suggest(final String command);
public FancyMessage command(final String command);
public FancyMessage tooltip(final String text);
public FancyMessage then(final Object obj);
public String toJSONString();
public void send(Player player);
static class MessagePart {
public ChatColor color = null;
public ChatColor[] styles = null;
public String clickActionName = null;
public String clickActionData = null;
public String hoverActionName = null;
public String hoverActionData = null;
public final String text;
public MessagePart(final String text) {
this.text = text;
}
public JsonWriter writeJson(final JsonWriter json) throws IOException {
json.beginObject().name("text").value(text);
if (color != null) {
json.name("color").value(color.name().toLowerCase());
}
if (styles != null) {
for (final ChatColor style : styles) {
json.name(style == ChatColor.UNDERLINE ? "underlined" : style.name().toLowerCase()).value(true);
}
}
if (clickActionName != null && clickActionData != null) {
json.name("clickEvent")
.beginObject()
.name("action").value(clickActionName)
.name("value").value(clickActionData)
.endObject();
}
if (hoverActionName != null && hoverActionData != null) {
json.name("hoverEvent")
.beginObject()
.name("action").value(hoverActionName)
.name("value").value(hoverActionData)
.endObject();
}
return json.endObject();
}
}
}

View File

@ -0,0 +1,38 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSArmorStand;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSHorse;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSSlime;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSWitherSkull;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
public interface NMSManager {
// A method to register all the custom entities of the plugin, it may fail.
public void registerCustomEntities() throws Exception;
public NMSArmorStand spawnNMSArmorStand(org.bukkit.World world, double x, double y, double z, CraftHologramLine parentPiece);
public NMSHorse spawnNMSHorse(org.bukkit.World world, double x, double y, double z, CraftHologramLine parentPiece);
public NMSWitherSkull spawnNMSWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z, CraftHologramLine parentPiece);
public NMSItem spawnNMSItem(org.bukkit.World bukkitWorld, double x, double y, double z, CraftItemLine parentPiece, ItemStack stack);
public NMSSlime spawnNMSSlime(org.bukkit.World bukkitWorld, double x, double y, double z, CraftTouchSlimeLine parentPiece);
public boolean isNMSEntityBase(org.bukkit.entity.Entity bukkitEntity);
public NMSEntityBase getNMSEntityBase(org.bukkit.entity.Entity bukkitEntity);
public FancyMessage newFancyMessage(String text);
public boolean hasChatHoverFeature();
}

View File

@ -0,0 +1,5 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces.entity;
public interface NMSArmorStand extends NMSNameable, NMSRideable {
}

View File

@ -0,0 +1,31 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces.entity;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
/**
* An interface to represent a custom NMS entity being part of a hologram.
*/
public interface NMSEntityBase {
// Returns the linked CraftHologramLine, all the entities are part of a piece. Should never be null.
public CraftHologramLine getHologramLine();
// Sets if the entity should tick or not.
public void setLockTick(boolean lock);
// Sets the location through NMS.
public void setLocationNMS(double x, double y, double z);
// Returns if the entity is dead through NMS.
public boolean isDeadNMS();
// Kills the entity through NMS.
public void killEntityNMS();
// The entity ID.
public int getIdNMS();
// Returns the bukkit entity.
public org.bukkit.entity.Entity getBukkitEntityNMS();
}

View File

@ -0,0 +1,5 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces.entity;
public interface NMSHorse extends NMSNameable {
}

View File

@ -0,0 +1,13 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces.entity;
import org.bukkit.inventory.ItemStack;
public interface NMSItem extends NMSEntityBase {
// Sets the bukkit ItemStack for this item.
public void setItemStackNMS(ItemStack stack);
// Sets if this item can be picked up by players.
public void allowPickup(boolean pickup);
}

View File

@ -0,0 +1,11 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces.entity;
public interface NMSNameable extends NMSEntityBase {
// Sets a custom name for this entity.
public void setCustomNameNMS(String name);
// Returns the custom name of this entity.
public String getCustomNameNMS();
}

View File

@ -0,0 +1,8 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces.entity;
public interface NMSRideable extends NMSEntityBase {
// Sets the passenger of this entity through NMS.
public void setPassengerNMS(NMSEntityBase passenger);
}

View File

@ -0,0 +1,5 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces.entity;
public interface NMSSlime extends NMSEntityBase {
}

View File

@ -0,0 +1,5 @@
package com.gmail.filoghost.holographicdisplays.nms.interfaces.entity;
public interface NMSWitherSkull extends NMSRideable {
}

View File

@ -0,0 +1,64 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_6_R3.CraftServer;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftHorse;
import org.bukkit.entity.AnimalTamer;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
public class CraftNMSHorse extends CraftHorse {
public CraftNMSHorse(CraftServer server, EntityNMSHorse entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Horse class
@Override public void setVariant(Variant variant) { }
@Override public void setColor(Color color) { }
@Override public void setStyle(Style style) { }
@Override public void setCarryingChest(boolean chest) { }
@Override public void setDomestication(int domestication) { }
@Override public void setJumpStrength(double jump) { }
// Methods form Ageable class
@Override public void setAge(int age) { }
@Override public void setAgeLock(boolean lock) { }
@Override public void setBreed(boolean breed) { }
@Override public void setAdult() { }
@Override public void setBaby() { }
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Tameable
@Override public void setTamed(boolean tame) { }
@Override public void setOwner(AnimalTamer owner) { }
}

View File

@ -0,0 +1,40 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_6_R3.CraftServer;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftItem;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public class CraftNMSItem extends CraftItem {
public CraftNMSItem(CraftServer server, EntityNMSItem entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Item
@Override public void setItemStack(ItemStack stack) { }
@Override public void setPickupDelay(int delay) { }
}

View File

@ -0,0 +1,47 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_6_R3.CraftServer;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftSlime;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
public class CraftNMSSlime extends CraftSlime {
public CraftNMSSlime(CraftServer server, EntityNMSSlime entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Slime
@Override public void setSize(int size) { }
}

View File

@ -0,0 +1,46 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_6_R3.CraftServer;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftWitherSkull;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.util.Vector;
public class CraftNMSWitherSkull extends CraftWitherSkull {
public CraftNMSWitherSkull(CraftServer server, EntityNMSWitherSkull entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Method from Fireball
@Override public void setDirection(Vector dir) { }
// Method from Projectile
@Override public void setBounce(boolean bounce) { }
// Methods from Explosive
@Override public void setYield(float yield) { }
@Override public void setIsIncendiary(boolean fire) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
}

View File

@ -0,0 +1,157 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import net.minecraft.server.v1_6_R3.EntityHorse;
import net.minecraft.server.v1_6_R3.NBTTagCompound;
import net.minecraft.server.v1_6_R3.World;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSHorse;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
public class EntityNMSHorse extends EntityHorse implements NMSHorse {
private boolean lockTick;
private CraftHologramLine parentPiece;
public EntityNMSHorse(World world, CraftHologramLine parentPiece) {
super(world);
super.ageLocked = true;
super.persistent = true;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
setAge(-1700000); // This is a magic value. No one will see the real horse.
this.parentPiece = parentPiece;
}
@Override
public void l_() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The horse dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.l_();
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public void makeSound(String sound, float volume, float pitch) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public void setCustomNameNMS(String name) {
if (name != null && name.length() > 64) {
name = name.substring(0, 64);
}
super.setCustomName(name);
super.setCustomNameVisible(name != null);
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSHorse(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public String getCustomNameNMS() {
return super.getCustomName();
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public int getIdNMS() {
return this.id;
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,183 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import net.minecraft.server.v1_6_R3.Block;
import net.minecraft.server.v1_6_R3.EntityHuman;
import net.minecraft.server.v1_6_R3.EntityItem;
import net.minecraft.server.v1_6_R3.EntityPlayer;
import net.minecraft.server.v1_6_R3.ItemStack;
import net.minecraft.server.v1_6_R3.NBTTagCompound;
import net.minecraft.server.v1_6_R3.NBTTagList;
import net.minecraft.server.v1_6_R3.NBTTagString;
import net.minecraft.server.v1_6_R3.World;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_6_R3.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.listener.MainListener;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.util.ItemUtils;
public class EntityNMSItem extends EntityItem implements NMSItem {
private boolean lockTick;
private CraftItemLine parentPiece;
public EntityNMSItem(World world, CraftItemLine piece) {
super(world);
super.pickupDelay = Integer.MAX_VALUE;
this.parentPiece = piece;
}
@Override
public void l_() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The item dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.l_();
}
}
@Override
public ItemStack getItemStack() {
// Dirty method to check if the icon is being picked up
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
if (stacktrace.length > 2 && stacktrace[2].getClassName().contains("EntityInsentient")) {
return null; // Try to pickup this, dear entity ignoring the pickupDelay!
}
return super.getItemStack();
}
// Method called when a player is near.
@Override
public void b_(EntityHuman human) {
if (parentPiece.getPickupHandler() != null && human instanceof EntityPlayer) {
MainListener.handleItemLinePickup((Player) human.getBukkitEntity(), parentPiece.getPickupHandler(), parentPiece.getParent());
// It is never added to the inventory.
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSItem(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public void setItemStackNMS(org.bukkit.inventory.ItemStack stack) {
ItemStack newItem = CraftItemStack.asNMSCopy(stack);
if (newItem == null) {
newItem = new ItemStack(Block.BEDROCK);
}
if (newItem.tag == null) {
newItem.tag = new NBTTagCompound();
}
NBTTagCompound display = newItem.tag.getCompound("display");
if (!newItem.tag.hasKey("display")) {
newItem.tag.set("display", display);
}
NBTTagList tagList = new NBTTagList();
tagList.add(new NBTTagString(ItemUtils.ANTISTACK_LORE)); // Antistack lore
display.set("Lore", tagList);
newItem.count = 0;
setItemStack(newItem);
}
@Override
public int getIdNMS() {
return this.id;
}
@Override
public CraftItemLine getHologramLine() {
return parentPiece;
}
@Override
public void allowPickup(boolean pickup) {
if (pickup) {
super.pickupDelay = 0;
} else {
super.pickupDelay = Integer.MAX_VALUE;
}
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,144 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import net.minecraft.server.v1_6_R3.EntitySlime;
import net.minecraft.server.v1_6_R3.NBTTagCompound;
import net.minecraft.server.v1_6_R3.World;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSSlime;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
public class EntityNMSSlime extends EntitySlime implements NMSSlime {
private boolean lockTick;
private CraftTouchSlimeLine parentPiece;
public EntityNMSSlime(World world, CraftTouchSlimeLine parentPiece) {
super(world);
super.persistent = true;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
setSize(1);
setInvisible(true);
this.parentPiece = parentPiece;
}
@Override
public void l_() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The slime dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.l_();
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public void makeSound(String sound, float volume, float pitch) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSSlime(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public int getIdNMS() {
return this.id;
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,177 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSWitherSkull;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.util.Utils;
import net.minecraft.server.v1_6_R3.Entity;
import net.minecraft.server.v1_6_R3.EntityWitherSkull;
import net.minecraft.server.v1_6_R3.NBTTagCompound;
import net.minecraft.server.v1_6_R3.Packet34EntityTeleport;
import net.minecraft.server.v1_6_R3.World;
import net.minecraft.server.v1_6_R3.EntityPlayer;
public class EntityNMSWitherSkull extends EntityWitherSkull implements NMSWitherSkull {
private boolean lockTick;
private CraftHologramLine parentPiece;
private int teleportedRecently;
public EntityNMSWitherSkull(World world, CraftHologramLine parentPiece) {
super(world);
super.motX = 0.0;
super.motY = 0.0;
super.motZ = 0.0;
super.dirX = 0.0;
super.dirY = 0.0;
super.dirZ = 0.0;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
this.parentPiece = parentPiece;
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void l_() {
// Fixed the position being modified by random move packets.
if (teleportedRecently != -1) {
if (teleportedRecently++ > 10) {
teleportedRecently = -1;
Packet34EntityTeleport teleportPacket = new Packet34EntityTeleport(this);
for (Object obj : this.world.players) {
if (obj instanceof EntityPlayer) {
EntityPlayer nmsPlayer = (EntityPlayer) obj;
double distanceSquared = Utils.square(nmsPlayer.locX - this.locX) + Utils.square(nmsPlayer.locZ - this.locZ);
if (distanceSquared < 8192 && nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(teleportPacket);
}
}
}
}
}
if (!lockTick) {
super.l_();
}
}
@Override
public void makeSound(String sound, float f1, float f2) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSWitherSkull(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
teleportedRecently = 0;
// Send a packet near to update the position.
Packet34EntityTeleport teleportPacket = new Packet34EntityTeleport(this);
for (Object obj : this.world.players) {
if (obj instanceof EntityPlayer) {
EntityPlayer nmsPlayer = (EntityPlayer) obj;
double distanceSquared = Utils.square(nmsPlayer.locX - this.locX) + Utils.square(nmsPlayer.locZ - this.locZ);
if (distanceSquared < 8192 && nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(teleportPacket);
}
}
}
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void setPassengerNMS(NMSEntityBase passenger) {
if (passenger instanceof Entity) {
((Entity) passenger).setPassengerOf(this);
}
}
@Override
public int getIdNMS() {
return this.id;
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,95 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.FancyMessage;
public class FancyMessageImpl implements FancyMessage {
private final List<MessagePart> messageParts;
public FancyMessageImpl(final String firstPartText) {
messageParts = new ArrayList<MessagePart>();
messageParts.add(new MessagePart(firstPartText));
}
@Override
public FancyMessageImpl color(final ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color");
}
latest().color = color;
return this;
}
@Override
public FancyMessageImpl style(final ChatColor... styles) {
for (final ChatColor style : styles) {
if (!style.isFormat()) {
throw new IllegalArgumentException(style.name() + " is not a style");
}
}
latest().styles = styles;
return this;
}
@Override
public FancyMessageImpl file(final String path) {
return this;
}
@Override
public FancyMessageImpl link(final String url) {
return this;
}
@Override
public FancyMessageImpl suggest(final String command) {
return this;
}
@Override
public FancyMessageImpl command(final String command) {
return this;
}
@Override
public FancyMessageImpl tooltip(final String text) {
return this;
}
@Override
public FancyMessageImpl then(final Object obj) {
messageParts.add(new MessagePart(obj.toString()));
return this;
}
@Override
public String toJSONString() {
StringBuilder sb = new StringBuilder();
for (MessagePart part : messageParts) {
if (part.color != null) {
sb.append(part.color.toString());
}
if (part.styles != null && part.styles.length > 0) {
for (ChatColor style : part.styles) {
sb.append(style.toString());
}
}
sb.append(part.text);
}
return sb.toString();
}
@Override
public void send(Player player) {
player.sendMessage(toJSONString());
}
private MessagePart latest() {
return messageParts.get(messageParts.size() - 1);
}
}

View File

@ -0,0 +1,127 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_6_R3;
import net.minecraft.server.v1_6_R3.Entity;
import net.minecraft.server.v1_6_R3.EntityTypes;
import net.minecraft.server.v1_6_R3.WorldServer;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_6_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftEntity;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.FancyMessage;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSArmorStand;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSHorse;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSWitherSkull;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
import com.gmail.filoghost.holographicdisplays.util.DebugHandler;
import com.gmail.filoghost.holographicdisplays.util.ReflectionUtils;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
public class NmsManagerImpl implements NMSManager {
@Override
public void registerCustomEntities() throws Exception {
registerCustomEntity(EntityNMSHorse.class, "EntityHorse", 100);
registerCustomEntity(EntityNMSWitherSkull.class, "WitherSkull", 19);
registerCustomEntity(EntityNMSItem.class, "Item", 1);
registerCustomEntity(EntityNMSSlime.class, "Slime", 55);
}
@SuppressWarnings("rawtypes")
public void registerCustomEntity(Class entityClass, String name, int id) throws Exception {
if (VersionUtils.isMCPCOrCauldron()) {
// MCPC+ / Cauldron entity registration.
Class<?> entityTypesClass = Class.forName("net.minecraft.server.v1_6_R3.EntityTypes");
ReflectionUtils.putInPrivateStaticMap(entityTypesClass, "field_75626_c", entityClass, name);
ReflectionUtils.putInPrivateStaticMap(entityTypesClass, "field_75624_e", entityClass, Integer.valueOf(id));
} else {
// Normal entity registration.
ReflectionUtils.putInPrivateStaticMap(EntityTypes.class, "c", entityClass, name);
ReflectionUtils.putInPrivateStaticMap(EntityTypes.class, "e", entityClass, Integer.valueOf(id));
}
}
@Override
public NMSHorse spawnNMSHorse(org.bukkit.World world, double x, double y, double z, CraftHologramLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
EntityNMSHorse invisibleHorse = new EntityNMSHorse(nmsWorld, parentPiece);
invisibleHorse.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(invisibleHorse, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return invisibleHorse;
}
@Override
public NMSWitherSkull spawnNMSWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z, CraftHologramLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSWitherSkull staticWitherSkull = new EntityNMSWitherSkull(nmsWorld, parentPiece);
staticWitherSkull.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(staticWitherSkull, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return staticWitherSkull;
}
@Override
public NMSItem spawnNMSItem(org.bukkit.World bukkitWorld, double x, double y, double z, CraftItemLine parentPiece, ItemStack stack) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSItem customItem = new EntityNMSItem(nmsWorld, parentPiece);
customItem.setLocationNMS(x, y, z);
customItem.setItemStackNMS(stack);
if (!nmsWorld.addEntity(customItem, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return customItem;
}
@Override
public EntityNMSSlime spawnNMSSlime(org.bukkit.World bukkitWorld, double x, double y, double z, CraftTouchSlimeLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSSlime touchSlime = new EntityNMSSlime(nmsWorld, parentPiece);
touchSlime.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(touchSlime, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return touchSlime;
}
@Override
public boolean isNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof NMSEntityBase;
}
@Override
public NMSEntityBase getNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) {
Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle();
if (nmsEntity instanceof NMSEntityBase) {
return ((NMSEntityBase) nmsEntity);
}
return null;
}
@Override
public FancyMessage newFancyMessage(String text) {
return new FancyMessageImpl(text);
}
@Override
public boolean hasChatHoverFeature() {
return false;
}
@Override
public NMSArmorStand spawnNMSArmorStand(World world, double x, double y, double z, CraftHologramLine parentPiece) {
throw new NotImplementedException("Method can only be used on 1.8 or higher");
}
}

View File

@ -0,0 +1,64 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R1.CraftServer;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftHorse;
import org.bukkit.entity.AnimalTamer;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
public class CraftNMSHorse extends CraftHorse {
public CraftNMSHorse(CraftServer server, EntityNMSHorse entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Horse class
@Override public void setVariant(Variant variant) { }
@Override public void setColor(Color color) { }
@Override public void setStyle(Style style) { }
@Override public void setCarryingChest(boolean chest) { }
@Override public void setDomestication(int domestication) { }
@Override public void setJumpStrength(double jump) { }
// Methods form Ageable class
@Override public void setAge(int age) { }
@Override public void setAgeLock(boolean lock) { }
@Override public void setBreed(boolean breed) { }
@Override public void setAdult() { }
@Override public void setBaby() { }
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Tameable
@Override public void setTamed(boolean tame) { }
@Override public void setOwner(AnimalTamer owner) { }
}

View File

@ -0,0 +1,40 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R1.CraftServer;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftItem;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public class CraftNMSItem extends CraftItem {
public CraftNMSItem(CraftServer server, EntityNMSItem entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Item
@Override public void setItemStack(ItemStack stack) { }
@Override public void setPickupDelay(int delay) { }
}

View File

@ -0,0 +1,47 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R1.CraftServer;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftSlime;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
public class CraftNMSSlime extends CraftSlime {
public CraftNMSSlime(CraftServer server, EntityNMSSlime entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Slime
@Override public void setSize(int size) { }
}

View File

@ -0,0 +1,46 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R1.CraftServer;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftWitherSkull;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.util.Vector;
public class CraftNMSWitherSkull extends CraftWitherSkull {
public CraftNMSWitherSkull(CraftServer server, EntityNMSWitherSkull entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Method from Fireball
@Override public void setDirection(Vector dir) { }
// Method from Projectile
@Override public void setBounce(boolean bounce) { }
// Methods from Explosive
@Override public void setYield(float yield) { }
@Override public void setIsIncendiary(boolean fire) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
}

View File

@ -0,0 +1,156 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import net.minecraft.server.v1_7_R1.EntityHorse;
import net.minecraft.server.v1_7_R1.NBTTagCompound;
import net.minecraft.server.v1_7_R1.World;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSHorse;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
public class EntityNMSHorse extends EntityHorse implements NMSHorse {
private boolean lockTick;
private CraftHologramLine parentPiece;
public EntityNMSHorse(World world, CraftHologramLine parentPiece) {
super(world);
super.ageLocked = true;
super.persistent = true;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
setAge(-1700000); // This is a magic value. No one will see the real horse.
this.parentPiece = parentPiece;
}
@Override
public void h() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The horse dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.h();
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public void makeSound(String sound, float volume, float pitch) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public void setCustomNameNMS(String name) {
if (name != null && name.length() > 300) {
name = name.substring(0, 300);
}
super.setCustomName(name);
super.setCustomNameVisible(name != null);
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSHorse(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public String getCustomNameNMS() {
return super.getCustomName();
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,183 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import net.minecraft.server.v1_7_R1.Blocks;
import net.minecraft.server.v1_7_R1.EntityHuman;
import net.minecraft.server.v1_7_R1.EntityItem;
import net.minecraft.server.v1_7_R1.EntityPlayer;
import net.minecraft.server.v1_7_R1.ItemStack;
import net.minecraft.server.v1_7_R1.NBTTagCompound;
import net.minecraft.server.v1_7_R1.NBTTagList;
import net.minecraft.server.v1_7_R1.NBTTagString;
import net.minecraft.server.v1_7_R1.World;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.listener.MainListener;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.util.ItemUtils;
public class EntityNMSItem extends EntityItem implements NMSItem {
private boolean lockTick;
private CraftItemLine parentPiece;
public EntityNMSItem(World world, CraftItemLine piece) {
super(world);
super.pickupDelay = Integer.MAX_VALUE;
this.parentPiece = piece;
}
@Override
public void h() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The item dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.h();
}
}
@Override
public ItemStack getItemStack() {
// Dirty method to check if the icon is being picked up
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
if (stacktrace.length > 2 && stacktrace[2].getClassName().contains("EntityInsentient")) {
return null; // Try to pickup this, dear entity ignoring the pickupDelay!
}
return super.getItemStack();
}
// Method called when a player is near.
@Override
public void b_(EntityHuman human) {
if (parentPiece.getPickupHandler() != null && human instanceof EntityPlayer) {
MainListener.handleItemLinePickup((Player) human.getBukkitEntity(), parentPiece.getPickupHandler(), parentPiece.getParent());
// It is never added to the inventory.
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSItem(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public void setItemStackNMS(org.bukkit.inventory.ItemStack stack) {
ItemStack newItem = CraftItemStack.asNMSCopy(stack);
if (newItem == null) {
newItem = new ItemStack(Blocks.BEDROCK);
}
if (newItem.tag == null) {
newItem.tag = new NBTTagCompound();
}
NBTTagCompound display = newItem.tag.getCompound("display");
if (!newItem.tag.hasKey("display")) {
newItem.tag.set("display", display);
}
NBTTagList tagList = new NBTTagList();
tagList.add(new NBTTagString(ItemUtils.ANTISTACK_LORE)); // Antistack lore
display.set("Lore", tagList);
newItem.count = 0;
setItemStack(newItem);
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftItemLine getHologramLine() {
return parentPiece;
}
@Override
public void allowPickup(boolean pickup) {
if (pickup) {
super.pickupDelay = 0;
} else {
super.pickupDelay = Integer.MAX_VALUE;
}
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,144 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import net.minecraft.server.v1_7_R1.EntitySlime;
import net.minecraft.server.v1_7_R1.NBTTagCompound;
import net.minecraft.server.v1_7_R1.World;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSSlime;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
public class EntityNMSSlime extends EntitySlime implements NMSSlime {
private boolean lockTick;
private CraftTouchSlimeLine parentPiece;
public EntityNMSSlime(World world, CraftTouchSlimeLine parentPiece) {
super(world);
super.persistent = true;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
setSize(1);
setInvisible(true);
this.parentPiece = parentPiece;
}
@Override
public void h() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The slime dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.h();
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public void makeSound(String sound, float volume, float pitch) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSSlime(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,166 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSWitherSkull;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.util.Utils;
import net.minecraft.server.v1_7_R1.Entity;
import net.minecraft.server.v1_7_R1.EntityWitherSkull;
import net.minecraft.server.v1_7_R1.NBTTagCompound;
import net.minecraft.server.v1_7_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_7_R1.World;
import net.minecraft.server.v1_7_R1.EntityPlayer;
public class EntityNMSWitherSkull extends EntityWitherSkull implements NMSWitherSkull {
private boolean lockTick;
private CraftHologramLine parentPiece;
public EntityNMSWitherSkull(World world, CraftHologramLine parentPiece) {
super(world);
super.motX = 0.0;
super.motY = 0.0;
super.motZ = 0.0;
super.dirX = 0.0;
super.dirY = 0.0;
super.dirZ = 0.0;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
this.parentPiece = parentPiece;
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public int getId() {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
if (elements.length > 2 && elements[2] != null && elements[2].getFileName().equals("EntityTrackerEntry.java") && elements[2].getLineNumber() > 134 && elements[2].getLineNumber() < 144) {
// Then this method is being called when creating a new packet, we return a fake ID!
return -1;
}
return super.getId();
}
@Override
public void h() {
if (!lockTick) {
super.h();
}
}
@Override
public void makeSound(String sound, float f1, float f2) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSWitherSkull(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
// Send a packet near to update the position.
PacketPlayOutEntityTeleport teleportPacket = new PacketPlayOutEntityTeleport(this);
for (Object obj : this.world.players) {
if (obj instanceof EntityPlayer) {
EntityPlayer nmsPlayer = (EntityPlayer) obj;
double distanceSquared = Utils.square(nmsPlayer.locX - this.locX) + Utils.square(nmsPlayer.locZ - this.locZ);
if (distanceSquared < 8192 && nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(teleportPacket);
}
}
}
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void setPassengerNMS(NMSEntityBase passenger) {
if (passenger instanceof Entity) {
((Entity) passenger).setPassengerOf(this);
}
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,125 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.server.v1_7_R1.ChatSerializer;
import net.minecraft.server.v1_7_R1.PacketPlayOutChat;
import org.bukkit.ChatColor;
import org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonWriter;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.FancyMessage;
public class FancyMessageImpl implements FancyMessage {
private List<MessagePart> messageParts;
public FancyMessageImpl(String firstPartText) {
messageParts = new ArrayList<MessagePart>();
messageParts.add(new MessagePart(firstPartText));
}
@Override
public FancyMessageImpl color(ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color");
}
latest().color = color;
return this;
}
@Override
public FancyMessageImpl style(ChatColor... styles) {
for (ChatColor style : styles) {
if (!style.isFormat()) {
throw new IllegalArgumentException(style.name() + " is not a style");
}
}
latest().styles = styles;
return this;
}
@Override
public FancyMessageImpl file(String path) {
onClick("open_file", path);
return this;
}
@Override
public FancyMessageImpl link(String url) {
onClick("open_url", url);
return this;
}
@Override
public FancyMessageImpl suggest(String command) {
onClick("suggest_command", command);
return this;
}
@Override
public FancyMessageImpl command(String command) {
onClick("run_command", command);
return this;
}
@Override
public FancyMessageImpl tooltip(String text) {
onHover("show_text", text);
return this;
}
@Override
public FancyMessageImpl then(Object obj) {
messageParts.add(new MessagePart(obj.toString()));
return this;
}
@Override
public String toJSONString() {
StringWriter stringWriter = new StringWriter();
JsonWriter json = new JsonWriter(stringWriter);
try {
if (messageParts.size() == 1) {
latest().writeJson(json);
} else {
json.beginObject().name("text").value("").name("extra").beginArray();
for (MessagePart part : messageParts) {
part.writeJson(json);
}
json.endArray().endObject();
}
} catch (IOException e) {
throw new RuntimeException("invalid message");
}
return stringWriter.toString();
}
@Override
public void send(Player player){
((CraftPlayer) player).getHandle().playerConnection.sendPacket(new PacketPlayOutChat(ChatSerializer.a(toJSONString())));
}
private MessagePart latest() {
return messageParts.get(messageParts.size() - 1);
}
private void onClick(String name, String data) {
MessagePart latest = latest();
latest.clickActionName = name;
latest.clickActionData = data;
}
private void onHover(String name, String data) {
MessagePart latest = latest();
latest.hoverActionName = name;
latest.hoverActionData = data;
}
}

View File

@ -0,0 +1,127 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R1;
import net.minecraft.server.v1_7_R1.Entity;
import net.minecraft.server.v1_7_R1.EntityTypes;
import net.minecraft.server.v1_7_R1.WorldServer;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_7_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.FancyMessage;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSArmorStand;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSHorse;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSWitherSkull;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
import com.gmail.filoghost.holographicdisplays.util.DebugHandler;
import com.gmail.filoghost.holographicdisplays.util.ReflectionUtils;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
public class NmsManagerImpl implements NMSManager {
@Override
public void registerCustomEntities() throws Exception {
registerCustomEntity(EntityNMSHorse.class, "EntityHorse", 100);
registerCustomEntity(EntityNMSWitherSkull.class, "WitherSkull", 19);
registerCustomEntity(EntityNMSItem.class, "Item", 1);
registerCustomEntity(EntityNMSSlime.class, "Slime", 55);
}
@SuppressWarnings("rawtypes")
public void registerCustomEntity(Class entityClass, String name, int id) throws Exception {
if (VersionUtils.isMCPCOrCauldron()) {
// MCPC+ / Cauldron entity registration.
Class<?> entityTypesClass = Class.forName("net.minecraft.server.v1_7_R1.EntityTypes");
ReflectionUtils.putInPrivateStaticMap(entityTypesClass, "field_75626_c", entityClass, name);
ReflectionUtils.putInPrivateStaticMap(entityTypesClass, "field_75624_e", entityClass, Integer.valueOf(id));
} else {
// Normal entity registration.
ReflectionUtils.putInPrivateStaticMap(EntityTypes.class, "d", entityClass, name);
ReflectionUtils.putInPrivateStaticMap(EntityTypes.class, "f", entityClass, Integer.valueOf(id));
}
}
@Override
public NMSHorse spawnNMSHorse(org.bukkit.World world, double x, double y, double z, CraftHologramLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
EntityNMSHorse invisibleHorse = new EntityNMSHorse(nmsWorld, parentPiece);
invisibleHorse.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(invisibleHorse, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return invisibleHorse;
}
@Override
public NMSWitherSkull spawnNMSWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z, CraftHologramLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSWitherSkull staticWitherSkull = new EntityNMSWitherSkull(nmsWorld, parentPiece);
staticWitherSkull.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(staticWitherSkull, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return staticWitherSkull;
}
@Override
public NMSItem spawnNMSItem(org.bukkit.World bukkitWorld, double x, double y, double z, CraftItemLine parentPiece, ItemStack stack) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSItem customItem = new EntityNMSItem(nmsWorld, parentPiece);
customItem.setLocationNMS(x, y, z);
customItem.setItemStackNMS(stack);
if (!nmsWorld.addEntity(customItem, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return customItem;
}
@Override
public EntityNMSSlime spawnNMSSlime(org.bukkit.World bukkitWorld, double x, double y, double z, CraftTouchSlimeLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSSlime touchSlime = new EntityNMSSlime(nmsWorld, parentPiece);
touchSlime.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(touchSlime, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return touchSlime;
}
@Override
public boolean isNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof NMSEntityBase;
}
@Override
public NMSEntityBase getNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) {
Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle();
if (nmsEntity instanceof NMSEntityBase) {
return ((NMSEntityBase) nmsEntity);
}
return null;
}
@Override
public FancyMessage newFancyMessage(String text) {
return new FancyMessageImpl(text);
}
@Override
public boolean hasChatHoverFeature() {
return true;
}
@Override
public NMSArmorStand spawnNMSArmorStand(World world, double x, double y, double z, CraftHologramLine parentPiece) {
throw new NotImplementedException("Method can only be used on 1.8 or higher");
}
}

View File

@ -0,0 +1,64 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R2.CraftServer;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftHorse;
import org.bukkit.entity.AnimalTamer;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
public class CraftNMSHorse extends CraftHorse {
public CraftNMSHorse(CraftServer server, EntityNMSHorse entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Horse class
@Override public void setVariant(Variant variant) { }
@Override public void setColor(Color color) { }
@Override public void setStyle(Style style) { }
@Override public void setCarryingChest(boolean chest) { }
@Override public void setDomestication(int domestication) { }
@Override public void setJumpStrength(double jump) { }
// Methods form Ageable class
@Override public void setAge(int age) { }
@Override public void setAgeLock(boolean lock) { }
@Override public void setBreed(boolean breed) { }
@Override public void setAdult() { }
@Override public void setBaby() { }
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Tameable
@Override public void setTamed(boolean tame) { }
@Override public void setOwner(AnimalTamer owner) { }
}

View File

@ -0,0 +1,40 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R2.CraftServer;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftItem;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public class CraftNMSItem extends CraftItem {
public CraftNMSItem(CraftServer server, EntityNMSItem entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Item
@Override public void setItemStack(ItemStack stack) { }
@Override public void setPickupDelay(int delay) { }
}

View File

@ -0,0 +1,47 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R2.CraftServer;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftSlime;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
public class CraftNMSSlime extends CraftSlime {
public CraftNMSSlime(CraftServer server, EntityNMSSlime entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Slime
@Override public void setSize(int size) { }
}

View File

@ -0,0 +1,46 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R2.CraftServer;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftWitherSkull;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.util.Vector;
public class CraftNMSWitherSkull extends CraftWitherSkull {
public CraftNMSWitherSkull(CraftServer server, EntityNMSWitherSkull entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Method from Fireball
@Override public void setDirection(Vector dir) { }
// Method from Projectile
@Override public void setBounce(boolean bounce) { }
// Methods from Explosive
@Override public void setYield(float yield) { }
@Override public void setIsIncendiary(boolean fire) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
}

View File

@ -0,0 +1,157 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import net.minecraft.server.v1_7_R2.EntityHorse;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.World;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSHorse;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
public class EntityNMSHorse extends EntityHorse implements NMSHorse {
private boolean lockTick;
private CraftHologramLine parentPiece;
public EntityNMSHorse(World world, CraftHologramLine parentPiece) {
super(world);
super.ageLocked = true;
super.persistent = true;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
setAge(-1700000); // This is a magic value. No one will see the real horse.
this.parentPiece = parentPiece;
}
@Override
public void h() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The horse dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.h();
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public void makeSound(String sound, float volume, float pitch) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public void setCustomNameNMS(String name) {
if (name != null && name.length() > 300) {
name = name.substring(0, 300);
}
super.setCustomName(name);
super.setCustomNameVisible(name != null);
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSHorse(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public String getCustomNameNMS() {
return super.getCustomName();
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,183 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import net.minecraft.server.v1_7_R2.Blocks;
import net.minecraft.server.v1_7_R2.EntityHuman;
import net.minecraft.server.v1_7_R2.EntityItem;
import net.minecraft.server.v1_7_R2.EntityPlayer;
import net.minecraft.server.v1_7_R2.ItemStack;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.NBTTagList;
import net.minecraft.server.v1_7_R2.NBTTagString;
import net.minecraft.server.v1_7_R2.World;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R2.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.listener.MainListener;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.util.ItemUtils;
public class EntityNMSItem extends EntityItem implements NMSItem {
private boolean lockTick;
private CraftItemLine parentPiece;
public EntityNMSItem(World world, CraftItemLine piece) {
super(world);
super.pickupDelay = Integer.MAX_VALUE;
this.parentPiece = piece;
}
@Override
public void h() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The item dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.h();
}
}
@Override
public ItemStack getItemStack() {
// Dirty method to check if the icon is being picked up
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
if (stacktrace.length > 2 && stacktrace[2].getClassName().contains("EntityInsentient")) {
return null; // Try to pickup this, dear entity ignoring the pickupDelay!
}
return super.getItemStack();
}
// Method called when a player is near.
@Override
public void b_(EntityHuman human) {
if (parentPiece.getPickupHandler() != null && human instanceof EntityPlayer) {
MainListener.handleItemLinePickup((Player) human.getBukkitEntity(), parentPiece.getPickupHandler(), parentPiece.getParent());
// It is never added to the inventory.
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSItem(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public void setItemStackNMS(org.bukkit.inventory.ItemStack stack) {
ItemStack newItem = CraftItemStack.asNMSCopy(stack);
if (newItem == null) {
newItem = new ItemStack(Blocks.BEDROCK);
}
if (newItem.tag == null) {
newItem.tag = new NBTTagCompound();
}
NBTTagCompound display = newItem.tag.getCompound("display");
if (!newItem.tag.hasKey("display")) {
newItem.tag.set("display", display);
}
NBTTagList tagList = new NBTTagList();
tagList.add(new NBTTagString(ItemUtils.ANTISTACK_LORE)); // Antistack lore
display.set("Lore", tagList);
newItem.count = 0;
setItemStack(newItem);
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftItemLine getHologramLine() {
return parentPiece;
}
@Override
public void allowPickup(boolean pickup) {
if (pickup) {
super.pickupDelay = 0;
} else {
super.pickupDelay = Integer.MAX_VALUE;
}
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,144 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import net.minecraft.server.v1_7_R2.EntitySlime;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.World;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSSlime;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
public class EntityNMSSlime extends EntitySlime implements NMSSlime {
private boolean lockTick;
private CraftTouchSlimeLine parentPiece;
public EntityNMSSlime(World world, CraftTouchSlimeLine parentPiece) {
super(world);
super.persistent = true;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
setSize(1);
setInvisible(true);
this.parentPiece = parentPiece;
}
@Override
public void h() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The slime dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.h();
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public void makeSound(String sound, float volume, float pitch) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSSlime(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,168 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import net.minecraft.server.v1_7_R2.Entity;
import net.minecraft.server.v1_7_R2.EntityPlayer;
import net.minecraft.server.v1_7_R2.EntityWitherSkull;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_7_R2.World;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSWitherSkull;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class EntityNMSWitherSkull extends EntityWitherSkull implements NMSWitherSkull {
private boolean lockTick;
private CraftHologramLine parentPiece;
public EntityNMSWitherSkull(World world, CraftHologramLine parentPiece) {
super(world);
super.motX = 0.0;
super.motY = 0.0;
super.motZ = 0.0;
super.dirX = 0.0;
super.dirY = 0.0;
super.dirZ = 0.0;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
this.parentPiece = parentPiece;
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public int getId() {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
if (elements.length > 2 && elements[2] != null && elements[2].getFileName().equals("EntityTrackerEntry.java") && elements[2].getLineNumber() > 134 && elements[2].getLineNumber() < 144) {
// Then this method is being called when creating a new packet, we return a fake ID!
return -1;
}
return super.getId();
}
@Override
public void h() {
if (!lockTick) {
super.h();
}
}
@Override
public void makeSound(String sound, float f1, float f2) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSWitherSkull(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
// Send a packet near to update the position.
PacketPlayOutEntityTeleport teleportPacket = new PacketPlayOutEntityTeleport(this);
for (Object obj : this.world.players) {
if (obj instanceof EntityPlayer) {
EntityPlayer nmsPlayer = (EntityPlayer) obj;
double distanceSquared = Utils.square(nmsPlayer.locX - this.locX) + Utils.square(nmsPlayer.locZ - this.locZ);
if (distanceSquared < 8192 && nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(teleportPacket);
}
}
}
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void setPassengerNMS(NMSEntityBase passenger) {
if (passenger instanceof Entity) {
((Entity) passenger).setPassengerOf(this);
}
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,125 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.server.v1_7_R2.ChatSerializer;
import net.minecraft.server.v1_7_R2.PacketPlayOutChat;
import org.bukkit.ChatColor;
import org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonWriter;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.FancyMessage;
public class FancyMessageImpl implements FancyMessage {
private List<MessagePart> messageParts;
public FancyMessageImpl(String firstPartText) {
messageParts = new ArrayList<MessagePart>();
messageParts.add(new MessagePart(firstPartText));
}
@Override
public FancyMessageImpl color(ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color");
}
latest().color = color;
return this;
}
@Override
public FancyMessageImpl style(ChatColor... styles) {
for (ChatColor style : styles) {
if (!style.isFormat()) {
throw new IllegalArgumentException(style.name() + " is not a style");
}
}
latest().styles = styles;
return this;
}
@Override
public FancyMessageImpl file(String path) {
onClick("open_file", path);
return this;
}
@Override
public FancyMessageImpl link(String url) {
onClick("open_url", url);
return this;
}
@Override
public FancyMessageImpl suggest(String command) {
onClick("suggest_command", command);
return this;
}
@Override
public FancyMessageImpl command(String command) {
onClick("run_command", command);
return this;
}
@Override
public FancyMessageImpl tooltip(String text) {
onHover("show_text", text);
return this;
}
@Override
public FancyMessageImpl then(Object obj) {
messageParts.add(new MessagePart(obj.toString()));
return this;
}
@Override
public String toJSONString() {
StringWriter stringWriter = new StringWriter();
JsonWriter json = new JsonWriter(stringWriter);
try {
if (messageParts.size() == 1) {
latest().writeJson(json);
} else {
json.beginObject().name("text").value("").name("extra").beginArray();
for (MessagePart part : messageParts) {
part.writeJson(json);
}
json.endArray().endObject();
}
} catch (IOException e) {
throw new RuntimeException("invalid message");
}
return stringWriter.toString();
}
@Override
public void send(Player player){
((CraftPlayer) player).getHandle().playerConnection.sendPacket(new PacketPlayOutChat(ChatSerializer.a(toJSONString())));
}
private MessagePart latest() {
return messageParts.get(messageParts.size() - 1);
}
private void onClick(String name, String data) {
MessagePart latest = latest();
latest.clickActionName = name;
latest.clickActionData = data;
}
private void onHover(String name, String data) {
MessagePart latest = latest();
latest.hoverActionName = name;
latest.hoverActionData = data;
}
}

View File

@ -0,0 +1,127 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R2;
import net.minecraft.server.v1_7_R2.Entity;
import net.minecraft.server.v1_7_R2.EntityTypes;
import net.minecraft.server.v1_7_R2.WorldServer;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_7_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.FancyMessage;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSArmorStand;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSHorse;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSWitherSkull;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
import com.gmail.filoghost.holographicdisplays.util.DebugHandler;
import com.gmail.filoghost.holographicdisplays.util.ReflectionUtils;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
public class NmsManagerImpl implements NMSManager {
@Override
public void registerCustomEntities() throws Exception {
registerCustomEntity(EntityNMSHorse.class, "EntityHorse", 100);
registerCustomEntity(EntityNMSWitherSkull.class, "WitherSkull", 19);
registerCustomEntity(EntityNMSItem.class, "Item", 1);
registerCustomEntity(EntityNMSSlime.class, "Slime", 55);
}
@SuppressWarnings("rawtypes")
public void registerCustomEntity(Class entityClass, String name, int id) throws Exception {
if (VersionUtils.isMCPCOrCauldron()) {
// MCPC+ / Cauldron entity registration.
Class<?> entityTypesClass = Class.forName("net.minecraft.server.v1_7_R2.EntityTypes");
ReflectionUtils.putInPrivateStaticMap(entityTypesClass, "field_75626_c", entityClass, name);
ReflectionUtils.putInPrivateStaticMap(entityTypesClass, "field_75624_e", entityClass, Integer.valueOf(id));
} else {
// Normal entity registration.
ReflectionUtils.putInPrivateStaticMap(EntityTypes.class, "d", entityClass, name);
ReflectionUtils.putInPrivateStaticMap(EntityTypes.class, "f", entityClass, Integer.valueOf(id));
}
}
@Override
public NMSHorse spawnNMSHorse(org.bukkit.World world, double x, double y, double z, CraftHologramLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
EntityNMSHorse invisibleHorse = new EntityNMSHorse(nmsWorld, parentPiece);
invisibleHorse.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(invisibleHorse, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return invisibleHorse;
}
@Override
public NMSWitherSkull spawnNMSWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z, CraftHologramLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSWitherSkull staticWitherSkull = new EntityNMSWitherSkull(nmsWorld, parentPiece);
staticWitherSkull.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(staticWitherSkull, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return staticWitherSkull;
}
@Override
public NMSItem spawnNMSItem(org.bukkit.World bukkitWorld, double x, double y, double z, CraftItemLine parentPiece, ItemStack stack) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSItem customItem = new EntityNMSItem(nmsWorld, parentPiece);
customItem.setLocationNMS(x, y, z);
customItem.setItemStackNMS(stack);
if (!nmsWorld.addEntity(customItem, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return customItem;
}
@Override
public EntityNMSSlime spawnNMSSlime(org.bukkit.World bukkitWorld, double x, double y, double z, CraftTouchSlimeLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSSlime touchSlime = new EntityNMSSlime(nmsWorld, parentPiece);
touchSlime.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(touchSlime, SpawnReason.CUSTOM)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return touchSlime;
}
@Override
public boolean isNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof NMSEntityBase;
}
@Override
public NMSEntityBase getNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) {
Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle();
if (nmsEntity instanceof NMSEntityBase) {
return ((NMSEntityBase) nmsEntity);
}
return null;
}
@Override
public FancyMessage newFancyMessage(String text) {
return new FancyMessageImpl(text);
}
@Override
public boolean hasChatHoverFeature() {
return true;
}
@Override
public NMSArmorStand spawnNMSArmorStand(World world, double x, double y, double z, CraftHologramLine parentPiece) {
throw new NotImplementedException("Method can only be used on 1.8 or higher");
}
}

View File

@ -0,0 +1,64 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R3;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R3.CraftServer;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftHorse;
import org.bukkit.entity.AnimalTamer;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
public class CraftNMSHorse extends CraftHorse {
public CraftNMSHorse(CraftServer server, EntityNMSHorse entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Horse class
@Override public void setVariant(Variant variant) { }
@Override public void setColor(Color color) { }
@Override public void setStyle(Style style) { }
@Override public void setCarryingChest(boolean chest) { }
@Override public void setDomestication(int domestication) { }
@Override public void setJumpStrength(double jump) { }
// Methods form Ageable class
@Override public void setAge(int age) { }
@Override public void setAgeLock(boolean lock) { }
@Override public void setBreed(boolean breed) { }
@Override public void setAdult() { }
@Override public void setBaby() { }
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Tameable
@Override public void setTamed(boolean tame) { }
@Override public void setOwner(AnimalTamer owner) { }
}

View File

@ -0,0 +1,40 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R3;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R3.CraftServer;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftItem;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public class CraftNMSItem extends CraftItem {
public CraftNMSItem(CraftServer server, EntityNMSItem entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Item
@Override public void setItemStack(ItemStack stack) { }
@Override public void setPickupDelay(int delay) { }
}

View File

@ -0,0 +1,47 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R3;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R3.CraftServer;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftSlime;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
public class CraftNMSSlime extends CraftSlime {
public CraftNMSSlime(CraftServer server, EntityNMSSlime entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
// Methods from Slime
@Override public void setSize(int size) { }
}

View File

@ -0,0 +1,46 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R3;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_7_R3.CraftServer;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftWitherSkull;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.util.Vector;
public class CraftNMSWitherSkull extends CraftWitherSkull {
public CraftNMSWitherSkull(CraftServer server, EntityNMSWitherSkull entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Method from Fireball
@Override public void setDirection(Vector dir) { }
// Method from Projectile
@Override public void setBounce(boolean bounce) { }
// Methods from Explosive
@Override public void setYield(float yield) { }
@Override public void setIsIncendiary(boolean fire) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
}

View File

@ -0,0 +1,156 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R3;
import net.minecraft.server.v1_7_R3.EntityHorse;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.World;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSHorse;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
public class EntityNMSHorse extends EntityHorse implements NMSHorse {
private boolean lockTick;
private CraftHologramLine parentPiece;
public EntityNMSHorse(World world, CraftHologramLine parentPiece) {
super(world);
super.ageLocked = true;
super.persistent = true;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
setAge(-1700000); // This is a magic value. No one will see the real horse.
this.parentPiece = parentPiece;
}
@Override
public void h() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The horse dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.h();
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public void makeSound(String sound, float volume, float pitch) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public void setCustomNameNMS(String name) {
if (name != null && name.length() > 300) {
name = name.substring(0, 300);
}
super.setCustomName(name);
super.setCustomNameVisible(name != null);
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSHorse(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public String getCustomNameNMS() {
return super.getCustomName();
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,183 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R3;
import net.minecraft.server.v1_7_R3.Blocks;
import net.minecraft.server.v1_7_R3.EntityHuman;
import net.minecraft.server.v1_7_R3.EntityItem;
import net.minecraft.server.v1_7_R3.EntityPlayer;
import net.minecraft.server.v1_7_R3.ItemStack;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.NBTTagList;
import net.minecraft.server.v1_7_R3.NBTTagString;
import net.minecraft.server.v1_7_R3.World;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R3.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.listener.MainListener;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.util.ItemUtils;
public class EntityNMSItem extends EntityItem implements NMSItem {
private boolean lockTick;
private CraftItemLine parentPiece;
public EntityNMSItem(World world, CraftItemLine piece) {
super(world);
super.pickupDelay = Integer.MAX_VALUE;
this.parentPiece = piece;
}
@Override
public void h() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The item dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.h();
}
}
@Override
public ItemStack getItemStack() {
// Dirty method to check if the icon is being picked up
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
if (stacktrace.length > 2 && stacktrace[2].getClassName().contains("EntityInsentient")) {
return null; // Try to pickup this, dear entity ignoring the pickupDelay!
}
return super.getItemStack();
}
// Method called when a player is near.
@Override
public void b_(EntityHuman human) {
if (parentPiece.getPickupHandler() != null && human instanceof EntityPlayer) {
MainListener.handleItemLinePickup((Player) human.getBukkitEntity(), parentPiece.getPickupHandler(), parentPiece.getParent());
// It is never added to the inventory.
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSItem(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public void setItemStackNMS(org.bukkit.inventory.ItemStack stack) {
ItemStack newItem = CraftItemStack.asNMSCopy(stack);
if (newItem == null) {
newItem = new ItemStack(Blocks.BEDROCK);
}
if (newItem.tag == null) {
newItem.tag = new NBTTagCompound();
}
NBTTagCompound display = newItem.tag.getCompound("display");
if (!newItem.tag.hasKey("display")) {
newItem.tag.set("display", display);
}
NBTTagList tagList = new NBTTagList();
tagList.add(new NBTTagString(ItemUtils.ANTISTACK_LORE)); // Antistack lore
display.set("Lore", tagList);
newItem.count = 0;
setItemStack(newItem);
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftItemLine getHologramLine() {
return parentPiece;
}
@Override
public void allowPickup(boolean pickup) {
if (pickup) {
super.pickupDelay = 0;
} else {
super.pickupDelay = Integer.MAX_VALUE;
}
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,143 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R3;
import net.minecraft.server.v1_7_R3.EntitySlime;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.World;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSSlime;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
public class EntityNMSSlime extends EntitySlime implements NMSSlime {
private boolean lockTick;
private CraftTouchSlimeLine parentPiece;
public EntityNMSSlime(World world, CraftTouchSlimeLine parentPiece) {
super(world);
super.persistent = true;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
setSize(1);
setInvisible(true);
this.parentPiece = parentPiece;
}
@Override
public void h() {
// Checks every 20 ticks.
if (ticksLived % 20 == 0) {
// The slime dies without a vehicle.
if (this.vehicle == null) {
die();
}
}
if (!lockTick) {
super.h();
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public void makeSound(String sound, float volume, float pitch) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSSlime(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,165 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_7_R3;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSWitherSkull;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.util.Utils;
import net.minecraft.server.v1_7_R3.Entity;
import net.minecraft.server.v1_7_R3.EntityWitherSkull;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_7_R3.World;
import net.minecraft.server.v1_7_R3.EntityPlayer;
public class EntityNMSWitherSkull extends EntityWitherSkull implements NMSWitherSkull {
private boolean lockTick;
private CraftHologramLine parentPiece;
public EntityNMSWitherSkull(World world, CraftHologramLine parentPiece) {
super(world);
super.motX = 0.0;
super.motY = 0.0;
super.motZ = 0.0;
super.dirX = 0.0;
super.dirY = 0.0;
super.dirZ = 0.0;
super.boundingBox.a = 0.0;
super.boundingBox.b = 0.0;
super.boundingBox.c = 0.0;
super.boundingBox.d = 0.0;
super.boundingBox.e = 0.0;
super.boundingBox.f = 0.0;
a(0.0F, 0.0F);
this.parentPiece = parentPiece;
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean isInvulnerable() {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public int getId() {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
if (elements.length > 2 && elements[2] != null && elements[2].getFileName().equals("EntityTrackerEntry.java") && elements[2].getLineNumber() > 134 && elements[2].getLineNumber() < 144) {
// Then this method is being called when creating a new packet, we return a fake ID!
return -1;
}
return super.getId();
}
@Override
public void h() {
if (!lockTick) {
super.h();
}
}
@Override
public void makeSound(String sound, float f1, float f2) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
setLockTick(false);
super.die();
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftNMSWitherSkull(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public void killEntityNMS() {
die();
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
// Send a packet near to update the position.
PacketPlayOutEntityTeleport teleportPacket = new PacketPlayOutEntityTeleport(this);
for (Object obj : this.world.players) {
if (obj instanceof EntityPlayer) {
EntityPlayer nmsPlayer = (EntityPlayer) obj;
double distanceSquared = Utils.square(nmsPlayer.locX - this.locX) + Utils.square(nmsPlayer.locZ - this.locZ);
if (distanceSquared < 8192 && nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(teleportPacket);
}
}
}
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void setPassengerNMS(NMSEntityBase passenger) {
if (passenger instanceof Entity) {
((Entity) passenger).setPassengerOf(this);
}
}
@Override
public int getIdNMS() {
return this.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

Some files were not shown because too many files have changed in this diff Show More