Testing EGit

This commit is contained in:
filoghost 2014-06-09 15:47:10 +02:00
commit 915f1afbf9
160 changed files with 19192 additions and 0 deletions

View File

@ -0,0 +1,9 @@
Speed: 20
This is an example.
This line will change every 2 seconds...
because it's an animation.
You just have to put "{animation: example.txt}" in a hologram...
to see this animated text.
Each unit of speed will result in a 0.1 seconds delay...
for example 20 * 0.1 = 2 seconds, like in this example.
The fastest animation has speed 1, every 0.1 seconds.

View File

@ -0,0 +1,14 @@
#.
#. Read the tutorial at: http://dev.bukkit.org/bukkit-plugins/holographic-displays/
#.
#. Plugin created by filoghost.
#.
vertical-spacing: 0.25
images:
symbol: '[x]'
transparency:
space: ' [|] '
color: '&7'
bungee-refresh-seconds: 3
time-format: 'H:mm'
update-notification: true

View File

@ -0,0 +1,3 @@
#.
#. Please do NOT edit this file manually.
#.

View File

@ -0,0 +1,14 @@
#
# This is the configuration file for static placeholders.
# Dynamic placeholders are {online}, {max_players}, ...
# Static placeholders are symbols.
#
# List of unicode symbols: http://www.fileformat.info/info/unicode/index.htm
#
[x]: \u2588
[/]: \u258C
[.]: \u2591
[..]: \u2592
[...]: \u2593
[p]: \u2022
[|]: \u23B9

View File

@ -0,0 +1,15 @@
name: HolographicDisplays
main: com.gmail.filoghost.holograms.HolographicDisplays
version: 1.8.3
softdepend: [Multiverse-Core, MultiWorld, My Worlds, My_Worlds, ProtocolLib]
commands:
holograms:
description: Main command for HolographicDisplays.
usage: /<command> (Startup error)
aliases: [hd, holo, hologram]
icon:
description: Command to create unpickable floating items.
usage: /<command> (Startup error)
aliases: [icons, floatingitem, floatingitems]

View File

@ -0,0 +1,22 @@
package com.gmail.filoghost.holograms;
import java.text.SimpleDateFormat;
import org.bukkit.ChatColor;
public class Configuration {
public static double verticalLineSpacing;
public static String imageSymbol;
public static String transparencySymbol;
public static boolean updateNotification;
public static ChatColor transparencyColor;
public static int bungeeRefreshSeconds;
public static String bungeeOnlineFormat;
public static String bungeeOfflineFormat;
public static SimpleDateFormat timeFormat;
// Used for the updater.
public static String newVersion;
}

View File

@ -0,0 +1,344 @@
package com.gmail.filoghost.holograms;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Set;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import com.gmail.filoghost.holograms.SimpleUpdater.FailCause;
import com.gmail.filoghost.holograms.bungee.ServerInfoTimer;
import com.gmail.filoghost.holograms.commands.main.HologramsCommandHandler;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.HologramNotFoundException;
import com.gmail.filoghost.holograms.exception.InvalidLocationException;
import com.gmail.filoghost.holograms.exception.WorldNotFoundException;
import com.gmail.filoghost.holograms.listener.MainListener;
import com.gmail.filoghost.holograms.metrics.MetricsLite;
import com.gmail.filoghost.holograms.nms.interfaces.NmsManager;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.placeholders.AnimationManager;
import com.gmail.filoghost.holograms.placeholders.PlaceholderManager;
import com.gmail.filoghost.holograms.placeholders.StaticPlaceholders;
import com.gmail.filoghost.holograms.protocol.ProtocolLibHook;
import com.gmail.filoghost.holograms.utils.BungeeCleanupTask;
import com.gmail.filoghost.holograms.utils.StringUtils;
import com.gmail.filoghost.holograms.utils.VersionUtils;
import com.gmail.filoghost.holograms.utils.ConfigNode;
import com.gmail.filoghost.holograms.SimpleUpdater.ResponseHandler;
public class HolographicDisplays extends JavaPlugin {
private static Logger logger;
private static HolographicDisplays instance;
public static NmsManager nmsManager;
private HologramsCommandHandler mainCommandHandler;
private static PlaceholderManager placeholderManager;
public void onEnable() {
instance = this;
logger = getLogger();
try {
File oldItemDb = new File(getDataFolder(), "database-items.yml");
if (oldItemDb.exists()) {
oldItemDb.delete();
logger.info("Deleted old database-items.yml file.");
}
} catch (Exception e) {
}
// Load placeholders.yml.
try {
StaticPlaceholders.load();
} catch (Exception e) {
e.printStackTrace();
getLogger().severe("Unable to read placeholders.yml! Is the file in use?");
}
// Load the configuration.
loadConfiguration();
if (Configuration.updateNotification) {
new SimpleUpdater(this, 75097, this.getFile()).checkForUpdates(new ResponseHandler() {
@Override
public void onUpdateFound(final String newVersion) {
Bukkit.getScheduler().scheduleSyncDelayedTask(instance, new Runnable() {
@Override
public void run() {
Configuration.newVersion = newVersion;
logger.info("Found a new version available: " + newVersion);
logger.info("Download it on Bukkit Dev:");
logger.info("dev.bukkit.org/bukkit-plugins/holographic-displays");
}
});
}
@Override
public void onFail(FailCause result) {
// Handle BAD_VERSION and INVALID_PROJECT_ID only.
if (result == FailCause.BAD_VERSION) {
getLogger().warning("The author of this plugin has misconfigured the Updater system.");
getLogger().warning("File versions should follow the format 'PluginName vVERSION'");
getLogger().warning("Please notify the author of this error.");
} else if (result == FailCause.INVALID_PROJECT_ID) {
getLogger().warning("The author of this plugin has misconfigured the Updater system.");
getLogger().warning("The project ID (" + 75097 + ") provided for updating is invalid.");
getLogger().warning("Please notify the author of this error.");
} else if (result == FailCause.BUKKIT_OFFLINE) {
getLogger().warning("Could not contact BukkitDev to check for updates.");
}
}
});
}
String version = VersionUtils.getBukkitVersion();
if (version == null) {
// Caused by MCPC+ / Cauldron renaming packages, get 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 {
// Cannot definitely get the version. This will cause HD to disable itself.
version = null;
}
}
// It's simple, we don't need reflection.
if ("v1_6_R3".equals(version)) {
nmsManager = new com.gmail.filoghost.holograms.nms.v1_6_R3.NmsManagerImpl();
} else if ("v1_7_R1".equals(version)) {
nmsManager = new com.gmail.filoghost.holograms.nms.v1_7_R1.NmsManagerImpl();
} else if ("v1_7_R2".equals(version)) {
nmsManager = new com.gmail.filoghost.holograms.nms.v1_7_R2.NmsManagerImpl();
} else if ("v1_7_R3".equals(version)) {
nmsManager = new com.gmail.filoghost.holograms.nms.v1_7_R3.NmsManagerImpl();
} else {
printWarnAndDisable(
"******************************************************",
" This version of HolographicDisplays can",
" only work on these server versions:",
" 1.6.4, from 1.7.2 to 1.7.9.",
" The plugin will be disabled.",
"******************************************************"
);
return;
}
try {
if (VersionUtils.isMCPC()) {
getLogger().info("Trying to enable MCPC+ support...");
} else if (VersionUtils.isCauldron()) {
getLogger().info("Trying to enable Cauldron support...");
}
nmsManager.registerCustomEntities();
if (VersionUtils.isMCPC()) {
getLogger().info("Successfully added support for MCPC+!");
} else if (VersionUtils.isCauldron()) {
getLogger().info("Successfully added support for Cauldron!");
}
} 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")) {
ProtocolLibHook.initialize();
}
} catch (Exception ex) {
ex.printStackTrace();
logger.warning("Failed to load ProtocolLib support. Is it updated?");
}
// Load animation files
try {
AnimationManager.loadAnimations();
} catch (Exception ex) {
ex.printStackTrace();
logger.warning("Failed to load animation files!");
}
// Instantiate a PlaceholderManager
placeholderManager = new PlaceholderManager();
// Initalize other static classes.
HologramDatabase.initialize();
ServerInfoTimer.setRefreshSeconds(Configuration.bungeeRefreshSeconds);
ServerInfoTimer.startTask();
BungeeCleanupTask.start();
Set<String> savedHolograms = HologramDatabase.getHolograms();
if (savedHolograms != null && savedHolograms.size() > 0) {
for (String singleSavedHologram : savedHolograms) {
try {
CraftHologram singleHologramEntity = HologramDatabase.loadHologram(singleSavedHologram);
HologramManager.addHologram(singleHologramEntity);
} catch (HologramNotFoundException e) {
logger.warning("Hologram '" + singleSavedHologram + "' not found, skipping it.");
} catch (InvalidLocationException e) {
logger.warning("Hologram '" + singleSavedHologram + "' has an invalid location format.");
} catch (WorldNotFoundException e) {
logger.warning("Hologram '" + singleSavedHologram + "' was in the world '" + e.getMessage() + "' but it wasn't loaded.");
} catch (Exception e) {
e.printStackTrace();
logger.warning("Unhandled exception while loading '" + singleSavedHologram + "'. Please contact the developer.");
}
}
}
getCommand("holograms").setExecutor(mainCommandHandler = 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() {
public void run() {
for (CraftHologram hologram : HologramManager.getHolograms()) {
if (!hologram.update()) {
logger.warning("Unable to spawn entities for the hologram '" + hologram.getName() + "'.");
}
}
}
}.runTaskLater(this, 10L);
}
public void loadConfiguration() {
saveDefaultConfig();
boolean needsSave = false;
for (ConfigNode node : ConfigNode.values()) {
if (!getConfig().isSet(node.getPath())) {
getConfig().set(node.getPath(), node.getDefault());
needsSave = true;
}
}
if (needsSave) {
getConfig().options().header(".\n"
+ ". Read the tutorial at: http://dev.bukkit.org/bukkit-plugins/holographic-displays/\n"
+ ".\n"
+ ". Plugin created by filoghost.\n"
+ ".");
getConfig().options().copyHeader(true);
saveConfig();
}
Configuration.updateNotification = ConfigNode.UPDATE_NOTIFICATION.getBoolean(getConfig());
Configuration.verticalLineSpacing = ConfigNode.VERTICAL_SPACING.getDouble(getConfig());
Configuration.imageSymbol = StringUtils.toReadableFormat(ConfigNode.IMAGES_SYMBOL.getString(getConfig()));
Configuration.transparencySymbol = StringUtils.toReadableFormat(ConfigNode.TRANSPARENCY_SPACE.getString(getConfig()));
Configuration.bungeeRefreshSeconds = ConfigNode.BUNGEE_REFRESH_SECONDS.getInt(getConfig());
Configuration.bungeeOnlineFormat = StringUtils.toReadableFormat(ConfigNode.BUNGEE_ONLINE_FORMAT.getString(getConfig()));
Configuration.bungeeOfflineFormat = StringUtils.toReadableFormat(ConfigNode.BUNGEE_OFFLINE_FORMAT.getString(getConfig()));
try {
Configuration.timeFormat = new SimpleDateFormat(StringUtils.toReadableFormat(ConfigNode.TIME_FORMAT.getString(getConfig())));
} catch (IllegalArgumentException ex) {
Configuration.timeFormat = new SimpleDateFormat("H:mm");
logger.warning("Time format not valid, using the default.");
}
if (Configuration.bungeeRefreshSeconds < 1) {
logger.warning("The minimum interval for pinging BungeeCord's servers is 1 second. It has been automatically set.");
Configuration.bungeeRefreshSeconds = 1;
}
if (Configuration.bungeeRefreshSeconds > 30) {
logger.warning("The maximum interval for pinging BungeeCord's servers is 30 seconds. It has been automatically set.");
Configuration.bungeeRefreshSeconds = 30;
}
String tempColor = ConfigNode.TRANSPARENCY_COLOR.getString(getConfig()).replace("&", "§");
boolean foundColor = false;
for (ChatColor chatColor : ChatColor.values()) {
if (chatColor.toString().equals(tempColor)) {
Configuration.transparencyColor = chatColor;
foundColor = true;
}
}
if (!foundColor) {
Configuration.transparencyColor = ChatColor.GRAY;
logger.warning("You didn't set a valid chat color for the transparency, light gray will be used.");
}
}
public void onDisable() {
for (CraftHologram hologram : HologramManager.getHolograms()) {
hologram.hide();
}
}
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 HologramsCommandHandler getMainCommandHandler() {
return mainCommandHandler;
}
public static PlaceholderManager getPlaceholderManager() {
return placeholderManager;
}
public static void logInfo(String message) {
logger.info(message);
}
public static void logWarning(String message) {
logger.warning(message);
}
public static void logSevere(String message) {
logger.severe(message);
}
}

View File

@ -0,0 +1,252 @@
package com.gmail.filoghost.holograms;
import java.io.BufferedReader;
import java.io.File;
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;
public final class SimpleUpdater {
private Plugin plugin;
@SuppressWarnings("unused")
private File pluginFile;
private int projectId;
public SimpleUpdater(Plugin plugin, int projectId, File pluginFile) {
notNull(plugin, "Plugin cannot be null");
notNull(pluginFile, "Plugin file cannot be null");
this.plugin = plugin;
this.pluginFile = pluginFile;
this.projectId = projectId;
}
/**
* Checks for updated with the default response handler.
* You have just to provide the link to the bukkit dev's page of the plugin.
*
* @param bukkitDevPageLink The link to the bukkit dev's page of the plugin.
*/
public void checkForUpdates(final String bukkitDevPageLink) {
checkForUpdates(new ResponseHandler() {
@Override
public void onUpdateFound(final String newVersion) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
plugin.getLogger().info("Found a new version available: " + newVersion);
plugin.getLogger().info("Download it on Bukkit Dev:");
plugin.getLogger().info(bukkitDevPageLink);
}
});
}
@Override
public void onFail(FailCause result) {
// Handle BAD_VERSION and INVALID_PROJECT_ID only.
if (result == FailCause.BAD_VERSION) {
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.");
} else if (result == FailCause.INVALID_PROJECT_ID) {
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.");
} else if (result == FailCause.BUKKIT_OFFLINE) {
plugin.getLogger().warning("Could not contact BukkitDev to check for updates.");
}
}
});
}
/**
* This method creates a new async thread to check for updates.
*/
public void checkForUpdates(ResponseHandler responseHandler) {
Thread updaterThread = new Thread(new UpdaterRunnable(responseHandler));
updaterThread.start();
}
private class UpdaterRunnable implements Runnable {
ResponseHandler responseHandler;
private UpdaterRunnable(ResponseHandler responseHandler) {
this.responseHandler = responseHandler;
}
@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.
responseHandler.onFail(FailCause.INVALID_PROJECT_ID);
return;
}
String updateName = (String) ((JSONObject) filesArray.get(filesArray.size() - 1)).get("name");
//String downloadUrl = (String) ((JSONObject) filesArray.get(filesArray.size() - 1)).get("downloadUrl");
//String releaseType = (String) ((JSONObject) filesArray.get(filesArray.size() - 1)).get("releaseType");
String newVersion = extractVersion(updateName);
if (newVersion == null) {
responseHandler.onFail(FailCause.BAD_VERSION);
return;
}
if (isNewerVersion(newVersion)) {
responseHandler.onUpdateFound(newVersion);
} else {
responseHandler.onFail(FailCause.NO_UPDATES);
}
} catch (MalformedURLException e) {
responseHandler.onFail(FailCause.INVALID_PROJECT_ID);
} catch (IOException e) {
responseHandler.onFail(FailCause.BUKKIT_OFFLINE);
} catch (NumberFormatException e) {
responseHandler.onFail(FailCause.BAD_VERSION);
} catch (Exception e) {
e.printStackTrace();
plugin.getLogger().warning("Unable to check for updates: unhandled exception.");
}
}
}
public static interface ResponseHandler {
/**
* Called if the updater finds an update on Bukkit.
* @param newVersion the newer version of the plugin.
*/
public void onUpdateFound(String newVersion);
public void onFail(FailCause result);
}
public static enum FailCause {
/**
* The plugin is already updated to the latest version.
*/
NO_UPDATES,
/**
* Remote version format is not correct. Should be in the format "v{VERSION}".
*/
BAD_VERSION,
/**
* Bukkit is offline or the connection is very slow.
*/
BUKKIT_OFFLINE,
/**
* The provided project ID is not valid.
*/
INVALID_PROJECT_ID
}
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
*/
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
}
return false;
}
private String extractVersion(String input) {
Matcher matcher = Pattern.compile("v[0-9\\.]+").matcher(input);
String result = null;
while (matcher.find()) {
result = matcher.group();
}
return result;
}
private void notNull(Object o, String msg) {
if (o == null) {
throw new IllegalArgumentException(msg);
}
}
}

View File

@ -0,0 +1,124 @@
package com.gmail.filoghost.holograms.api;
import org.bukkit.Location;
import org.bukkit.World;
public interface Hologram {
/**
* Updates the hologram. This must be used after changing the lines.
* @return false if the spawn was blocked.
*/
public boolean update();
/**
* Hides the hologram.
*/
public void hide();
/**
* Appends a line at the end.
* @param text - the text to append.
*/
public void addLine(String text);
/**
* Removes a line at the given index (0 = first line)
* @param the index of the line to remove.
*/
public void removeLine(int index);
/**
* Changes a line at the given index (0 = first line).
* @param index - the index of the line to change.
* @param text - the new text of the line.
*/
public void setLine(int index, String text);
/**
* Adds a line before the given index (0 = insert before the first line).
* @param index - the text will be inserted before this index.
* @param text - the text to insert.
*/
public void insertLine(int index, String text);
/**
* @return a copy of the lines.
*/
public String[] getLines();
/**
* @return the amount of lines.
*/
public int getLinesLength();
/**
* Removes all the lines from the hologram.
*/
public void clearLines();
/**
* @return the location of the hologram.
*/
public Location getLocation();
/**
* @return the X coordinate of the hologram.
*/
public double getX();
/**
* @return the Y coordinate of the hologram.
*/
public double getY();
/**
* @return the Z coordinate of the hologram.
*/
public double getZ();
/**
* @return the world of the hologram.
*/
public World getWorld();
/**
* Change the location of the hologram. You have to call update() after this method.
* Please note that this method will create new entities every time, so use it wisely.
* @param location - the new location of the hologram.
*/
public void setLocation(Location location);
/**
* Sets the touch handler of the hologram: whenever a player right clicks it, the onTouch()
* method of the TouchHandler is called. If null, the previous touch handler will be removed.
* @param handler - the new TouchHandler.
*/
public void setTouchHandler(TouchHandler handler);
/**
* @return the current touch handler, null if hasTouchHandler() is false.
*/
public TouchHandler getTouchHandler();
/**
* @return true if the hologram has a touch handler.
*/
public boolean hasTouchHandler();
/**
* @return the timestamp of when the hologram was created, in milliseconds.
*/
public long getCreationTimestamp();
/**
* Deletes this hologram, removing it from the lists.
*/
public void delete();
/**
* @return true if this hologram was deleted. Calling update() on a deleted hologram will throw an exception.
*/
public boolean isDeleted();
}

View File

@ -0,0 +1,120 @@
package com.gmail.filoghost.holograms.api;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.gmail.filoghost.holograms.nms.interfaces.NmsManager;
import com.gmail.filoghost.holograms.object.APIHologramManager;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.utils.GenericUtils;
import com.gmail.filoghost.holograms.utils.Validator;
import com.gmail.filoghost.holograms.utils.VisibilityManager;
import static com.gmail.filoghost.holograms.HolographicDisplays.nmsManager;
public class HolographicDisplaysAPI {
/**
* Creates a hologram at given location.
* @param plugin - the plugin that creates it.
* @param source - the location where it will appear.
* @param lines - the lines of the new hologram.
* @return the new hologram created.
*/
public static Hologram createHologram(Plugin plugin, Location source, String... lines) {
Validator.notNull(plugin, "plugin cannot be null");
Validator.notNull(source, "source cannot be null");
Validator.notNull(source.getWorld(), "source's world cannot be null");
CraftHologram hologram = new CraftHologram("{API-Hologram}", source);
APIHologramManager.addHologram(plugin, hologram);
if (lines != null && lines.length > 0) {
for (String line : lines) {
hologram.addLine(line);
}
}
hologram.update();
return hologram;
}
/**
* Creates a hologram at given location that only a player can see. If the provided player is null, no one will be able to see it.
* IMPORTANT NOTE: Requires ProtocolLib.
* @param plugin - the plugin that creates it.
* @param source - the location where it will appear.
* @param whoCanSee - the player who can see it.
* @param lines - the lines of the new hologram.
* @return the new hologram created.
*/
public static Hologram createIndividualHologram(Plugin plugin, Location source, Player whoCanSee, String... lines) {
return createIndividualHologram(plugin, source, GenericUtils.createList(whoCanSee), lines);
}
/**
* Creates a hologram at given location that only a list of players can see. If the provided list is null, no one will be able to see it.
* IMPORTANT NOTE: Requires ProtocolLib.
* @param plugin - the plugin that creates it.
* @param source - the location where it will appear.
* @param whoCanSee - a list of players who can see it.
* @param lines - the lines of the new hologram.
* @return the new hologram created.
*/
public static Hologram createIndividualHologram(Plugin plugin, Location source, List<Player> whoCanSee, String... lines) {
Validator.notNull(plugin, "plugin cannot be null");
Validator.notNull(source, "source cannot be null");
Validator.notNull(source.getWorld(), "source's world cannot be null");
CraftHologram hologram = new CraftHologram("{API-Hologram}", source);
VisibilityManager visibilityManager = new VisibilityManager();
hologram.setVisibilityManager(visibilityManager);
if (whoCanSee != null) {
for (Player player : whoCanSee) {
hologram.getVisibilityManager().showTo(player);
}
}
APIHologramManager.addHologram(plugin, hologram);
if (lines != null && lines.length > 0) {
for (String line : lines) {
hologram.addLine(line);
}
}
hologram.update();
return hologram;
}
/**
* @return a copy of all the holograms created with the API by a plugin.
*/
public static Hologram[] getHolograms(Plugin plugin) {
Validator.notNull(plugin, "plugin cannot be null");
return APIHologramManager.getHolograms(plugin);
}
/**
* @return if the entity is part of a hologram.
*/
public static boolean isHologramEntity(Entity bukkitEntity) {
Validator.notNull(bukkitEntity, "entity cannot be null");
return nmsManager.isHologramComponent(bukkitEntity);
}
/**
* @deprecated for advanced use only. May change in the future.
*/
@Deprecated
public static NmsManager getNmsManager() {
return nmsManager;
}
}

View File

@ -0,0 +1,17 @@
package com.gmail.filoghost.holograms.api;
import org.bukkit.entity.Player;
/**
* Interface to handle touch holograms.
*/
public interface TouchHandler {
/**
* Called when a player interacts with the hologram.
* @param hologram - the involved hologram
* @param player - the player who interacts
*/
public void onTouch(Hologram hologram, Player player);
}

View File

@ -0,0 +1,86 @@
package com.gmail.filoghost.holograms.bungee;
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.messaging.PluginMessageListener;
import com.gmail.filoghost.holograms.HolographicDisplays;
public class BungeeChannel implements PluginMessageListener {
private static BungeeChannel instance;
private BungeeChannel() { }
private static void initialize() {
instance = new BungeeChannel();
Bukkit.getMessenger().registerOutgoingPluginChannel(HolographicDisplays.getInstance(), "BungeeCord");
Bukkit.getMessenger().registerIncomingPluginChannel(HolographicDisplays.getInstance(), "BungeeCord", instance);
}
public static BungeeChannel instance() {
if (instance == null) {
initialize();
}
return instance;
}
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
if (!channel.equals("BungeeCord")) {
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();
ServerInfoTimer.handlePing(server, online);
} else {
// If there are no bytes available it means that the server is offline.
ServerInfoTimer.handleOffline(server);
}
}
} catch (EOFException e) {
//TODO
System.out.println("Not online!");
} catch (IOException e) {
// This should never happen.
e.printStackTrace();
}
}
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.
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(), "BungeeCord", b.toByteArray());
}
}
}

View File

@ -0,0 +1,47 @@
package com.gmail.filoghost.holograms.bungee;
public class ServerInfo {
private int onlinePlayers;
private boolean isOnline;
private long lastPing;
private long lastRequest;
public ServerInfo(int onlinePlayers, boolean isOnline, long lastPing) {
this.onlinePlayers = onlinePlayers;
this.isOnline = isOnline;
this.lastPing = lastPing;
}
public int getOnlinePlayers() {
return onlinePlayers;
}
public void setOnlinePlayers(int onlinePlayers) {
this.onlinePlayers = onlinePlayers;
}
public long getLastPing() {
return lastPing;
}
public void setLastPing(long lastPing) {
this.lastPing = lastPing;
}
public long getLastRequest() {
return lastRequest;
}
public void setLastRequest(long lastRequest) {
this.lastRequest = lastRequest;
}
public void setOnline(boolean online) {
this.isOnline = online;
}
public boolean isOnline() {
return isOnline;
}
}

View File

@ -0,0 +1,104 @@
package com.gmail.filoghost.holograms.bungee;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
import com.gmail.filoghost.holograms.HolographicDisplays;
public class ServerInfoTimer {
private static Map<String, ServerInfo> trackedServers = new HashMap<String, ServerInfo>();
private static int taskID = -1;
private static int refreshSeconds = 3;
public static void resetTrackedServers() {
trackedServers.clear();
}
public static void track(String server) {
if (!trackedServers.containsKey(server)) {
ServerInfo info = new ServerInfo(0, false, 0);
info.setLastRequest(System.currentTimeMillis());
trackedServers.put(server, info);
BungeeChannel.instance().askPlayerCount(server);
}
}
public static void untrack(String server) {
trackedServers.remove(server);
}
public static void setRefreshSeconds(int seconds) {
if (seconds < 1) {
refreshSeconds = 1;
} else {
refreshSeconds = seconds;
}
}
// Handle a successful ping.
public static void handlePing(String server, int online) {
ServerInfo info = trackedServers.get(server);
if (info == null) {
info = new ServerInfo(online, true, System.currentTimeMillis());
trackedServers.put(server, info);
} else {
info.setLastPing(System.currentTimeMillis());
info.setOnline(true);
info.setOnlinePlayers(online);
}
}
public static void handleOffline(String server) {
ServerInfo info = trackedServers.get(server);
if (info != null) {
info.setOnlinePlayers(0);
info.setOnline(false);
}
}
public static int getPlayersOnline(String server) {
ServerInfo 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 boolean getOnlineStatus(String server) {
ServerInfo info = trackedServers.get(server);
if (info != null) {
info.setLastRequest(System.currentTimeMillis());
return info.isOnline();
} else {
// It was not tracked, add it.
track(server);
return false;
}
}
public static Map<String, ServerInfo> getMap() {
return trackedServers;
}
public static void startTask() {
if (taskID != -1) {
Bukkit.getScheduler().cancelTask(taskID);
}
taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(HolographicDisplays.getInstance(), new Runnable() {
public void run() {
for (String server : trackedServers.keySet()) {
BungeeChannel.instance().askPlayerCount(server);
}
}
}, 0, refreshSeconds * 20);
}
}

View File

@ -0,0 +1,91 @@
package com.gmail.filoghost.holograms.commands;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holograms.exception.CommandException;
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 {
String copy = input;
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 {
input = input.replace("_", "").replace("-", "").toLowerCase();
for (Material mat : Material.values()) {
if (mat.toString().replace("_", "").toLowerCase().equals(input)) {
match = mat;
break;
}
}
}
if (match == null) {
throw new CommandException("Invalid material: " + copy);
}
return new ItemStack(match, 1, (short) dataValue);
}
}

View File

@ -0,0 +1,13 @@
package com.gmail.filoghost.holograms.commands;
import org.bukkit.ChatColor;
public class Messages {
public static final String NO_SUCH_FLOATING_ITEM = ChatColor.RED + "A floating item with that name doesn't exist.";
public static final String NO_SUCH_HOLOGRAM = ChatColor.RED + "A hologram with that name doesn't exist.";
public static final String FAILED_TO_SPAWN_HERE = ChatColor.GRAY + "(The entities failed to spawn. You MUST allow mobs to spawn here.)";
public static final String MAIN_PERMISSION = "holograms.admin";
}

View File

@ -0,0 +1,72 @@
package com.gmail.filoghost.holograms.commands.main;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.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[] 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,91 @@
package com.gmail.filoghost.holograms.commands.main;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.bukkit.ChatColor.*;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.HolographicDisplays;
import com.gmail.filoghost.holograms.commands.main.subs.*;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.utils.Format;
public class HologramsCommandHandler implements CommandExecutor {
private List<HologramSubCommand> subCommands;
public HologramsCommandHandler() {
subCommands = new ArrayList<HologramSubCommand>();
registerSubCommand(new AddlineCommand());
registerSubCommand(new CreateCommand());
registerSubCommand(new DeleteCommand());
registerSubCommand(new EditCommand());
registerSubCommand(new ListCommand());
registerSubCommand(new NearCommand());
registerSubCommand(new TeleportCommand());
registerSubCommand(new MovehereCommand());
registerSubCommand(new FixCommand());
registerSubCommand(new SaveCommand());
registerSubCommand(new ReloadCommand());
registerSubCommand(new RemovelineCommand());
registerSubCommand(new SetlineCommand());
registerSubCommand(new InsertlineCommand());
registerSubCommand(new ReadtextCommand());
registerSubCommand(new ReadimageCommand());
registerSubCommand(new HelpCommand());
}
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("");
sender.sendMessage(Format.formatTitle("Holographic Displays"));
sender.sendMessage(Format.HIGHLIGHT + "Version: §7" + HolographicDisplays.getInstance().getDescription().getVersion());
sender.sendMessage(Format.HIGHLIGHT + "Developer: §7filoghost");
sender.sendMessage(Format.HIGHLIGHT + "Commands: §7/hd help");
return true;
}
for (HologramSubCommand subCommand : subCommands) {
if (subCommand.isValidTrigger(args[0])) {
if (!subCommand.hasPermission(sender)) {
sender.sendMessage("§cYou don't have permission.");
return true;
}
if (args.length - 1 >= subCommand.getMinimumArguments()) {
try {
subCommand.execute(sender, Arrays.copyOfRange(args, 1, args.length));
} catch (CommandException e) {
sender.sendMessage(RED + e.getMessage());
}
} else {
sender.sendMessage("§cUsage: /" + label + " " + subCommand.getName() + " " + subCommand.getPossibleArguments());
}
return true;
}
}
sender.sendMessage("§cUnknown sub-command. Type \"/hd help\" for a list of commands.");
return true;
}
}

View File

@ -0,0 +1,64 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
import com.gmail.filoghost.holograms.utils.StringUtils;
public class AddlineCommand extends HologramSubCommand {
public AddlineCommand() {
super("addline");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName> <text>";
}
@Override
public int getMinimumArguments() {
return 2;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
if (args[1].equalsIgnoreCase("{empty}")) {
hologram.addLine("");
} else {
hologram.addLine(StringUtils.toReadableFormat(StringUtils.join(args, " ", 1, args.length)));
}
if (!hologram.update()) {
sender.sendMessage(Messages.FAILED_TO_SPAWN_HERE);
}
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
sender.sendMessage(Format.HIGHLIGHT + "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,86 @@
package com.gmail.filoghost.holograms.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.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.exception.InvalidCharactersException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
import com.gmail.filoghost.holograms.utils.StringUtils;
public class CreateCommand extends HologramSubCommand {
public CreateCommand() {
super("create");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName> [text]";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
try {
Player player = CommandValidator.getPlayerSender(sender);
String name = StringUtils.validateName(args[0].toLowerCase());
CommandValidator.isTrue(!HologramManager.isExistingHologram(name), "A hologram with that name already exists.");
CraftHologram hologram = new CraftHologram(name, player.getLocation());
HologramManager.addHologram(hologram);
if (args.length > 1) {
hologram.addLine(StringUtils.toReadableFormat(StringUtils.join(args, " ", 1, args.length)));
sender.sendMessage("§7(Change the lines with /hd edit " + hologram.getName() + ")");
} else {
hologram.addLine("Default hologram. Change it with " + Format.HIGHLIGHT + "/hd edit " + hologram.getName());
}
if (!hologram.forceUpdate()) {
player.sendMessage(Messages.FAILED_TO_SPAWN_HERE);
}
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
Location look = player.getLocation();
look.setPitch(90);
player.teleport(look, TeleportCause.PLUGIN);
player.sendMessage(Format.HIGHLIGHT + "You created a hologram named '" + hologram.getName() + "'.");
} catch (InvalidCharactersException ex) {
throw new CommandException("The hologram's name must be alphanumeric. '" + ex.getMessage() + "' is not allowed.");
}
}
@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,57 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
public class DeleteCommand extends HologramSubCommand {
public DeleteCommand() {
super("delete", "remove");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
hologram.hide();
HologramManager.remove(hologram);
HologramDatabase.deleteHologram(hologram);
HologramDatabase.trySaveToDisk();
sender.sendMessage(Format.HIGHLIGHT + "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,96 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import static org.bukkit.ChatColor.AQUA;
import static org.bukkit.ChatColor.BOLD;
import static org.bukkit.ChatColor.GOLD;
import static org.bukkit.ChatColor.ITALIC;
import static org.bukkit.ChatColor.UNDERLINE;
import static org.bukkit.ChatColor.WHITE;
import static org.bukkit.ChatColor.YELLOW;
import java.util.Arrays;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holograms.HolographicDisplays;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
import com.gmail.filoghost.holograms.utils.ItemUtils;
public class EditCommand extends HologramSubCommand {
public EditCommand() {
super("edit");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
String name = args[0].toLowerCase();
CraftHologram hologram = HologramManager.getHologram(name);
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
sender.sendMessage("");
sender.sendMessage(Format.formatTitle("How to edit the hologram '" + name + "'"));
for (HologramSubCommand subCommand : HolographicDisplays.getInstance().getMainCommandHandler().getSubCommands()) {
if (subCommand.getType() == SubCommandType.EDIT_LINES) {
String usage = "/hd " + subCommand.getName() + (subCommand.getPossibleArguments().length() > 0 ? " " + subCommand.getPossibleArguments().replace("<hologramName>", hologram.getName()).replace("<hologram>", hologram.getName()) : "");
if (CommandValidator.isPlayerSender(sender)) {
HolographicDisplays.nmsManager.newFancyMessage(usage)
.color(AQUA)
.suggest(usage)
.itemTooltip(ItemUtils.getStone("§b" + usage, subCommand.getTutorial(), ChatColor.GRAY))
.send((Player) sender);
} else {
sender.sendMessage("§b" + usage);
}
}
}
if (CommandValidator.isPlayerSender(sender) && HolographicDisplays.nmsManager.hasChatHoverFeature()) {
sender.sendMessage("");
HolographicDisplays.nmsManager.newFancyMessage("[").color(GOLD)
.then("Tip").style(BOLD).color(YELLOW)
.then("]").color(GOLD)
.then(" Try to ").color(WHITE)
.then("hover").color(WHITE).style(ITALIC, UNDERLINE)
.tooltip("§dHover on the commands to get info about them.")
.then(" or ")
.then("click").color(WHITE).style(ITALIC, UNDERLINE)
.tooltip("§dClick on the commands to insert them in the chat.")
.then(" on the commands!")
.send((Player) 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.holograms.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.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
public class FixCommand extends HologramSubCommand {
public FixCommand() {
super("fix", "light");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
if (args.length <= 1) {
sender.sendMessage(Format.HIGHLIGHT + "This command will put a glowstone 16 blocks above the hologram to fix the lightning.");
sender.sendMessage(Format.HIGHLIGHT + "If you're sure, type §f/hd fix " + args[0].toLowerCase() + " confirm");
return;
}
if (args[1].equalsIgnoreCase("confirm")) {
Block block = hologram.getWorld().getBlockAt(hologram.getBlockX(), hologram.getBlockY() + 16, hologram.getBlockZ());
String oldType = block.getType().toString().replace("_", " ").toLowerCase();
block.setType(Material.GLOWSTONE);
sender.sendMessage(Format.HIGHLIGHT + "Changed the block 16 block above the hologram (" + oldType + ") to glowstone!");
} else {
sender.sendMessage("§c" + 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.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,85 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import static org.bukkit.ChatColor.*;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holograms.HolographicDisplays;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.utils.Format;
import com.gmail.filoghost.holograms.utils.ItemUtils;
public class HelpCommand extends HologramSubCommand {
public HelpCommand() {
super("help");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "";
}
@Override
public int getMinimumArguments() {
return 0;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
sender.sendMessage("");
sender.sendMessage(Format.formatTitle("Holographic Displays Commands"));
for (HologramSubCommand subCommand : HolographicDisplays.getInstance().getMainCommandHandler().getSubCommands()) {
if (subCommand.getType() == SubCommandType.GENERIC) {
String usage = "/hd " + subCommand.getName() + (subCommand.getPossibleArguments().length() > 0 ? " " + subCommand.getPossibleArguments() : "");
if (CommandValidator.isPlayerSender(sender)) {
HolographicDisplays.nmsManager.newFancyMessage(usage)
.color(AQUA)
.suggest(usage)
.itemTooltip(ItemUtils.getStone("§b" + usage, subCommand.getTutorial(), ChatColor.GRAY))
.send((Player) sender);
} else {
sender.sendMessage("§b" + usage);
}
}
}
if (CommandValidator.isPlayerSender(sender) && HolographicDisplays.nmsManager.hasChatHoverFeature()) {
sender.sendMessage("");
HolographicDisplays.nmsManager.newFancyMessage("[").color(GOLD)
.then("Tip").style(BOLD).color(YELLOW)
.then("]").color(GOLD)
.then(" Try to ").color(WHITE)
.then("hover").color(WHITE).style(ITALIC, UNDERLINE)
.tooltip("§dHover on the commands to get info about them.")
.then(" or ")
.then("click").color(WHITE).style(ITALIC, UNDERLINE)
.tooltip("§dClick on the commands to insert them in the chat.")
.then(" on the commands!")
.send((Player) sender);
}
}
@Override
public List<String> getTutorial() {
return null;
}
@Override
public SubCommandType getType() {
return SubCommandType.HIDDEN;
}
}

View File

@ -0,0 +1,81 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
import com.gmail.filoghost.holograms.utils.StringUtils;
public class InsertlineCommand extends HologramSubCommand {
public InsertlineCommand() {
super("insertline");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName> <lineNumber> <text>";
}
@Override
public int getMinimumArguments() {
return 3;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
int insertAfter = CommandValidator.getInteger(args[1]);
int oldLinesAmount = hologram.getLinesLength();
CommandValidator.isTrue(insertAfter >= 0 && insertAfter <= oldLinesAmount, "The number must be between 0 and " + hologram.getLinesLength() + "(amount of lines of the hologram).");
if (args[2].equalsIgnoreCase("{empty}")) {
hologram.insertLine(insertAfter, "");
} else {
hologram.insertLine(insertAfter, StringUtils.toReadableFormat(StringUtils.join(args, " ", 2, args.length)));
}
if (!hologram.update()) {
sender.sendMessage(Messages.FAILED_TO_SPAWN_HERE);
}
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
if (insertAfter == 0) {
sender.sendMessage(Format.HIGHLIGHT + "Line inserted before line n.1!");
} else if (insertAfter == oldLinesAmount) {
sender.sendMessage(Format.HIGHLIGHT + "Line appended at the end!");
sender.sendMessage("§7[Tip] Next time use /hd addline to add a line at the end.");
} else {
sender.sendMessage(Format.HIGHLIGHT + "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.holograms.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
public class ListCommand extends HologramSubCommand {
private static final int HOLOGRAMS_PER_PAGE = 10;
public ListCommand() {
super("list");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "[page]";
}
@Override
public int getMinimumArguments() {
return 0;
}
@Override
public void execute(CommandSender sender, 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 = HologramManager.size() / HOLOGRAMS_PER_PAGE;
if (HologramManager.size() % HOLOGRAMS_PER_PAGE != 0) {
totalPages++;
}
if (HologramManager.size() == 0) {
throw new CommandException("There are no holograms yet. Create one with /hd create.");
}
sender.sendMessage("");
sender.sendMessage(Format.formatTitle("Holograms list §f(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 < HologramManager.size()) {
CraftHologram hologram = HologramManager.get(i);
sender.sendMessage("§3- §f'" + hologram.getName() + "' §7at x: " + hologram.getBlockX() + ", y: " + hologram.getBlockY() + ", z: " + hologram.getBlockZ() + " (" + hologram.getLinesLength() + " lines, world: \"" + hologram.getWorld().getName() + "\")");
}
}
if (page < totalPages) {
sender.sendMessage("§f[Tip] §7See the next page with /holograms 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,73 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Bukkit;
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.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.event.HologramMoveEvent;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
public class MovehereCommand extends HologramSubCommand {
public MovehereCommand() {
super("movehere");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
Player player = CommandValidator.getPlayerSender(sender);
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
hologram.setLocation(player.getLocation());
if (!hologram.update()) {
player.sendMessage(Messages.FAILED_TO_SPAWN_HERE);
}
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
Location to = player.getLocation();
to.setPitch(90);
player.teleport(to, TeleportCause.PLUGIN);
player.sendMessage(Format.HIGHLIGHT + "You moved the hologram '" + hologram.getName() + "' near to you.");
// Call the event.
Bukkit.getPluginManager().callEvent(new HologramMoveEvent(hologram));
}
@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.holograms.commands.main.subs;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
public class NearCommand extends HologramSubCommand {
public NearCommand() {
super("near");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<radius>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, 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.");
int radiusSquared = radius * radius;
List<CraftHologram> nearHolograms = new ArrayList<CraftHologram>();
for (CraftHologram hologram : HologramManager.getHolograms()) {
if (hologram.getLocation().distanceSquared(player.getLocation()) <= radiusSquared) {
nearHolograms.add(hologram);
}
}
if (nearHolograms.size() > 0) {
player.sendMessage(Format.formatTitle("Near holograms"));
for (CraftHologram nearHologram : nearHolograms) {
player.sendMessage("§3- §f'" + nearHologram.getName() + "' §7at x: " + nearHologram.getBlockX() + ", y: " + nearHologram.getBlockY() + ", z: " + nearHologram.getBlockZ() + " (lines: " + nearHologram.getLinesLength() + ")");
}
} else {
player.sendMessage("§cThere are no holograms in the given radius.");
}
}
@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,112 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.exception.TooWideException;
import com.gmail.filoghost.holograms.exception.UnreadableImageException;
import com.gmail.filoghost.holograms.image.ImageMessage;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.FileUtils;
import com.gmail.filoghost.holograms.utils.Format;
public class ReadimageCommand extends HologramSubCommand {
public ReadimageCommand() {
super("readimage", "image");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologram> <imageWithExtension> <width>";
}
@Override
public int getMinimumArguments() {
return 3;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
int width = CommandValidator.getInteger(args[2]);
CommandValidator.isTrue(width >= 3, "The width of the image must be 3 or greater.");
try {
BufferedImage image = FileUtils.readImage(args[1]);
hologram.clearLines();
ImageMessage imageMessage = new ImageMessage(image, width);
String[] newLines = imageMessage.getLines();
for (int i = 0; i < newLines.length; i++) {
hologram.addLine(newLines[i]);
}
if (!hologram.update()) {
sender.sendMessage(Messages.FAILED_TO_SPAWN_HERE);
}
if (newLines.length < 5) {
sender.sendMessage("§6[§eTip§6] §fSeems that the image has a very low height. You can increase it by increasing the width.");
}
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
sender.sendMessage(Format.HIGHLIGHT + "The image was drawn in the hologram!");
} 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 100 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. 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. §fTutorial:",
"1) Move the image in the plugin's folder",
"2) Do not use spaces in the name",
"3) Do /hd read <hologram> <image> <width>",
"4) Choose <width> to automatically resize the image",
"",
"§fExample: §7you have an image named §f'logo.png'§7, you want",
"to paste it in the hologram named §f'test'§7, with a width of 50",
"pixels. In this case you would execute the following command:",
"§e/hd readimage test logo.png 50",
"",
"The symbols used to create the image are taken from the config.yml.",
"",
"§c§l§nNOTE:§f Do not use big images, as they can cause lag to clients.");
}
@Override
public SubCommandType getType() {
return SubCommandType.EDIT_LINES;
}
}

View File

@ -0,0 +1,110 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.FileUtils;
import com.gmail.filoghost.holograms.utils.Format;
import com.gmail.filoghost.holograms.utils.StringUtils;
public class ReadtextCommand extends HologramSubCommand {
public ReadtextCommand() {
super("readtext", "readlines");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName> <fileWithExtension>";
}
@Override
public int getMinimumArguments() {
return 2;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
try {
List<String> lines = FileUtils.readLines(args[1]);
hologram.clearLines();
int linesAmount = lines.size();
if (linesAmount > 40) {
sender.sendMessage("§eThe file contained more than 40 lines, that have been limited.");
linesAmount = 40;
}
for (int i = 0; i < linesAmount; i++) {
hologram.addLine(StringUtils.toReadableFormat(lines.get(i)));
}
if (!hologram.update()) {
sender.sendMessage(Messages.FAILED_TO_SPAWN_HERE);
}
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
if (args[1].contains(".")) {
if (isImageExtension(args[1].substring(args[1].lastIndexOf('.') + 1))) {
sender.sendMessage("§eSeems that the file read was an image. If so, you should use /hd readimage.");
}
}
sender.sendMessage(Format.HIGHLIGHT + "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. §fTutorial:",
"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 /hd readlines <hologramName> <fileWithExtension>",
"",
"§fExample: §7you have a file named §f'info.txt'§7, and you want",
"to paste it in the hologram named §f'test'§7. In this case you",
"would execute §e/hd readlines test info.txt");
}
@Override
public SubCommandType getType() {
return SubCommandType.EDIT_LINES;
}
private boolean isImageExtension(String input) {
String[] imageExtensions = new String[]{"jpg", "png", "jpeg", "gif"};
for (String ext : imageExtensions) {
if (input.equalsIgnoreCase(ext)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,102 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.Configuration;
import com.gmail.filoghost.holograms.HolographicDisplays;
import com.gmail.filoghost.holograms.bungee.ServerInfoTimer;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.exception.HologramNotFoundException;
import com.gmail.filoghost.holograms.exception.InvalidLocationException;
import com.gmail.filoghost.holograms.exception.WorldNotFoundException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.placeholders.AnimationManager;
import com.gmail.filoghost.holograms.placeholders.StaticPlaceholders;
import com.gmail.filoghost.holograms.utils.Format;
public class ReloadCommand extends HologramSubCommand {
public ReloadCommand() {
super("reload");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "";
}
@Override
public int getMinimumArguments() {
return 0;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
try {
long startMillis = System.currentTimeMillis();
HolographicDisplays.getInstance().reloadConfig();
HolographicDisplays.getInstance().loadConfiguration();
ServerInfoTimer.setRefreshSeconds(Configuration.bungeeRefreshSeconds);
ServerInfoTimer.startTask();
StaticPlaceholders.load();
HologramDatabase.initialize();
HologramManager.clearAll();
AnimationManager.loadAnimations();
Set<String> savedHolograms = HologramDatabase.getHolograms();
if (savedHolograms != null && savedHolograms.size() > 0) {
for (String singleSavedHologram : savedHolograms) {
try {
CraftHologram singleHologramEntity = HologramDatabase.loadHologram(singleSavedHologram);
HologramManager.addHologram(singleHologramEntity);
} catch (HologramNotFoundException e) {
Format.sendWarning(sender, "Hologram '" + singleSavedHologram + "' not found, skipping it.");
} catch (InvalidLocationException e) {
Format.sendWarning(sender, "Hologram '" + singleSavedHologram + "' has an invalid location format.");
} catch (WorldNotFoundException e) {
Format.sendWarning(sender, "Hologram '" + singleSavedHologram + "' was in the world '" + e.getMessage() + "' but it wasn't loaded.");
}
}
}
for (CraftHologram hologram : HologramManager.getHolograms()) {
if (!hologram.update()) {
sender.sendMessage("§c[ ! ] §7Unable to spawn entities for the hologram '" + hologram.getName() + "'.");
}
}
long endMillis = System.currentTimeMillis();
sender.sendMessage("§bConfiguration 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,68 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
public class RemovelineCommand extends HologramSubCommand {
public RemovelineCommand() {
super("removeline");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName> <lineNumber>";
}
@Override
public int getMinimumArguments() {
return 2;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
int lineNumber = CommandValidator.getInteger(args[1]);
CommandValidator.isTrue(lineNumber >= 1 && lineNumber <= hologram.getLinesLength(), "The line number must be between 1 and " + hologram.getLinesLength() + ".");
int index = lineNumber - 1;
CommandValidator.isTrue(hologram.getLinesLength() > 1, "The hologram should have at least 1 line.");
hologram.removeLine(index);
if (!hologram.update()) {
sender.sendMessage(Messages.FAILED_TO_SPAWN_HERE);
}
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
sender.sendMessage(Format.HIGHLIGHT + "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,56 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.utils.Format;
public class SaveCommand extends HologramSubCommand {
public SaveCommand() {
super("save");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "";
}
@Override
public int getMinimumArguments() {
return 0;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
try {
HologramDatabase.saveToDisk();
sender.sendMessage(Format.HIGHLIGHT + "Holograms saved!");
} catch (IOException e) {
e.printStackTrace();
throw new CommandException("Unable to save holograms to database.yml! Was the file in use? Look the console for more info.");
}
}
@Override
public List<String> getTutorial() {
return Arrays.asList("Saves all the holograms to the database. You usually",
"don't need to use this command, because the holograms",
"are automatically saved to disk every 10 minutes.");
}
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
}
}

View File

@ -0,0 +1,72 @@
package com.gmail.filoghost.holograms.commands.main.subs;
import java.util.Arrays;
import java.util.List;
import org.bukkit.command.CommandSender;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.database.HologramDatabase;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
import com.gmail.filoghost.holograms.utils.StringUtils;
public class SetlineCommand extends HologramSubCommand {
public SetlineCommand() {
super("setline");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName> <lineNumber> <newText>";
}
@Override
public int getMinimumArguments() {
return 3;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
int lineNumber = CommandValidator.getInteger(args[1]);
CommandValidator.isTrue(lineNumber >= 1 && lineNumber <= hologram.getLinesLength(), "The line number must be between 1 and " + hologram.getLinesLength() + ".");
int index = lineNumber - 1;
if (args[2].equalsIgnoreCase("{empty}")) {
hologram.setLine(index, "");
} else {
hologram.setLine(index, StringUtils.toReadableFormat(org.apache.commons.lang.StringUtils.join(args, " ", 2, args.length)));
}
if (!hologram.update()) {
sender.sendMessage(Messages.FAILED_TO_SPAWN_HERE);
}
HologramDatabase.saveHologram(hologram);
HologramDatabase.trySaveToDisk();
sender.sendMessage(Format.HIGHLIGHT + "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,59 @@
package com.gmail.filoghost.holograms.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.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.commands.main.HologramSubCommand;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramManager;
import com.gmail.filoghost.holograms.utils.Format;
public class TeleportCommand extends HologramSubCommand {
public TeleportCommand() {
super("teleport", "tp");
setPermission(Messages.MAIN_PERMISSION);
}
@Override
public String getPossibleArguments() {
return "<hologramName>";
}
@Override
public int getMinimumArguments() {
return 1;
}
@Override
public void execute(CommandSender sender, String[] args) throws CommandException {
Player player = CommandValidator.getPlayerSender(sender);
CraftHologram hologram = HologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Messages.NO_SUCH_HOLOGRAM);
Location loc = hologram.getLocation();
loc.setPitch(90);
player.teleport(loc, TeleportCause.PLUGIN);
player.sendMessage(Format.HIGHLIGHT + "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,95 @@
package com.gmail.filoghost.holograms.database;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import com.gmail.filoghost.holograms.HolographicDisplays;
import com.gmail.filoghost.holograms.exception.HologramNotFoundException;
import com.gmail.filoghost.holograms.exception.InvalidLocationException;
import com.gmail.filoghost.holograms.exception.WorldNotFoundException;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.utils.LocationUtils;
import com.gmail.filoghost.holograms.utils.StringUtils;
public class HologramDatabase {
private static File file;
private static FileConfiguration config;
private HologramDatabase() { }
public static void initialize() {
file = new File(HolographicDisplays.getInstance().getDataFolder(), "database.yml");
if (!file.exists()) {
HolographicDisplays.getInstance().saveResource("database.yml", false);
}
config = YamlConfiguration.loadConfiguration(file);
}
public static CraftHologram loadHologram(String name) throws HologramNotFoundException, InvalidLocationException, WorldNotFoundException {
List<String> lines = config.getStringList(name + ".lines");
String locationString = config.getString(name + ".location");
if (lines == null || locationString == null || lines.size() == 0) {
throw new HologramNotFoundException();
}
Location loc;
try {
loc = LocationUtils.locationFromString(locationString);
} catch (WorldNotFoundException ex) {
throw ex;
} catch (Exception ex) {
throw new InvalidLocationException();
}
CraftHologram hologram = new CraftHologram(name, loc);
for (int i = 0; i < lines.size(); i++) {
hologram.addLine(StringUtils.toReadableFormat(lines.get(i)));
}
return hologram;
}
public static void deleteHologram(CraftHologram hologram) {
config.set(hologram.getName(), null);
}
public static void saveHologram(CraftHologram hologram) {
config.set(hologram.getName() + ".location", LocationUtils.locationToString(hologram.getLocation()));
List<String> lines = new ArrayList<String>();
for (String hologramLine : hologram.getLines()) {
lines.add(StringUtils.toSaveableFormat(hologramLine));
}
config.set(hologram.getName() + ".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,33 @@
package com.gmail.filoghost.holograms.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import com.gmail.filoghost.holograms.api.Hologram;
/**
* Called after that a hologram is moved with /hd movehere <hologram>
*/
public class HologramMoveEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private Hologram hologram;
public HologramMoveEvent(Hologram hologram) {
this.hologram = hologram;
}
public Hologram getHologram() {
return hologram;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -0,0 +1,10 @@
package com.gmail.filoghost.holograms.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.holograms.exception;
public class HologramNotFoundException extends Exception {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,10 @@
package com.gmail.filoghost.holograms.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.holograms.exception;
public class InvalidLocationException extends Exception {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,11 @@
package com.gmail.filoghost.holograms.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.holograms.exception;
public class SpawnFailedException extends Exception {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,17 @@
package com.gmail.filoghost.holograms.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.holograms.exception;
public class UnreadableImageException extends Exception {
private static final long serialVersionUID = 1L;
}

View File

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

View File

@ -0,0 +1,180 @@
package com.gmail.filoghost.holograms.image;
import org.bukkit.ChatColor;
import com.gmail.filoghost.holograms.Configuration;
import com.gmail.filoghost.holograms.exception.TooWideException;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
/**
* 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 {
private static final int MAX_WIDTH = 100;
private final Color[] colors = {
new Color(0, 0, 0),
new Color(0, 0, 170),
new Color(0, 170, 0),
new Color(0, 170, 170),
new Color(170, 0, 0),
new Color(170, 0, 170),
new Color(255, 170, 0),
new Color(170, 170, 170),
new Color(85, 85, 85),
new Color(85, 85, 255),
new Color(85, 255, 85),
new Color(85, 255, 255),
new Color(255, 85, 85),
new Color(255, 85, 255),
new Color(255, 255, 85),
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_AREA_AVERAGING));
}
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;
int index = 0;
double best = -1;
for (int i = 0; i < colors.length; i++) {
if (areIdentical(colors[i], color)) {
return ChatColor.values()[i];
}
}
for (int i = 0; i < colors.length; i++) {
double distance = getDistance(color, colors[i]);
if (distance < best || best == -1) {
best = distance;
index = i;
}
}
// Minecraft has 15 colors
return ChatColor.values()[index];
}
public String[] getLines() {
return lines;
}
}

View File

@ -0,0 +1,99 @@
package com.gmail.filoghost.holograms.listener;
import org.bukkit.Chunk;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
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.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import com.gmail.filoghost.holograms.Configuration;
import com.gmail.filoghost.holograms.commands.Messages;
import com.gmail.filoghost.holograms.nms.interfaces.NmsManager;
import com.gmail.filoghost.holograms.object.APIHologramManager;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramBase;
import com.gmail.filoghost.holograms.object.HologramManager;
public class MainListener implements Listener {
private NmsManager nmsManager;
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()) {
HologramBase multiEntity = nmsManager.getParentHologram(entity);
if (multiEntity != null) {
multiEntity.hide();
}
}
}
}
@EventHandler (priority = EventPriority.MONITOR)
public void onChunkLoad(ChunkLoadEvent event) {
Chunk chunk = event.getChunk();
HologramManager.onChunkLoad(chunk);
APIHologramManager.onChunkLoad(chunk);
}
@EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onCreatureSpawn(CreatureSpawnEvent event) {
if (nmsManager.isBasicEntityNMS(event.getEntity())) {
if (event.isCancelled()) {
event.setCancelled(false);
}
}
}
@EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onProjectileLaunch(ProjectileLaunchEvent event) {
if (nmsManager.isBasicEntityNMS(event.getEntity())) {
if (event.isCancelled()) {
event.setCancelled(false);
}
}
}
@EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onItemSpawn(ItemSpawnEvent event) {
if (nmsManager.isBasicEntityNMS(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) {
CraftHologram hologram = nmsManager.getParentHologram(event.getRightClicked());
if (hologram != null && hologram.hasTouchHandler()) {
hologram.getTouchHandler().onTouch(hologram, event.getPlayer());
}
}
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
if (Configuration.updateNotification && Configuration.newVersion != null) {
if (event.getPlayer().hasPermission(Messages.MAIN_PERMISSION)) {
event.getPlayer().sendMessage("§3[HolographicDisplays] §bFound an update: " + Configuration.newVersion + ". Download:");
event.getPlayer().sendMessage("§3>> §bhttp://dev.bukkit.org/bukkit-plugins/holographic-displays");
}
}
}
}

View File

@ -0,0 +1,513 @@
/*
* 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.holograms.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
*/
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,17 @@
package com.gmail.filoghost.holograms.nms.interfaces;
public interface BasicEntityNMS {
// Locks the tick of the entities.
public void setLockTick(boolean lock);
// Kills the entity through NMS.
public void killEntityNMS();
// 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();
}

View File

@ -0,0 +1,9 @@
package com.gmail.filoghost.holograms.nms.interfaces;
import org.bukkit.inventory.ItemStack;
public interface CustomItem extends HologramComponent {
public void setItemStackNMS(ItemStack stack);
}

View File

@ -0,0 +1,80 @@
package com.gmail.filoghost.holograms.nms.interfaces;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.json.JSONException;
import org.json.JSONWriter;
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 achievementTooltip(final String name);
public FancyMessage itemTooltip(final String itemJSON);
public FancyMessage itemTooltip(final ItemStack itemStack);
public FancyMessage tooltip(final String text);
public FancyMessage then(final Object obj);
public String toJSONString();
public void send(Player player);
public 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 JSONException {
json.object().key("text").value(text);
if (color != null) {
json.key("color").value(color.name().toLowerCase());
}
if (styles != null) {
for (final ChatColor style : styles) {
json.key(style == ChatColor.UNDERLINE ? "underlined" : style.name().toLowerCase()).value(true);
}
}
if (clickActionName != null && clickActionData != null) {
json.key("clickEvent")
.object()
.key("action").value(clickActionName)
.key("value").value(clickActionData)
.endObject();
}
if (hoverActionName != null && hoverActionData != null) {
json.key("hoverEvent")
.object()
.key("action").value(hoverActionName)
.key("value").value(hoverActionData)
.endObject();
}
return json.endObject();
}
}
}

View File

@ -0,0 +1,14 @@
package com.gmail.filoghost.holograms.nms.interfaces;
import com.gmail.filoghost.holograms.object.CraftHologram;
// Represents an entity that is part of a hologram.
public interface HologramComponent extends BasicEntityNMS {
// Returns the linked BaseMultiEntity. Can be null.
public CraftHologram getParentHologram();
// Sets the linked BaseMultiEntity.
public void setParentHologram(CraftHologram hologram);
}

View File

@ -0,0 +1,9 @@
package com.gmail.filoghost.holograms.nms.interfaces;
public interface HologramHorse extends HologramComponent {
public void forceSetCustomName(String name);
public String getCustomNameNMS();
}

View File

@ -0,0 +1,13 @@
package com.gmail.filoghost.holograms.nms.interfaces;
import org.bukkit.entity.Entity;
public interface HologramWitherSkull extends HologramComponent {
// Sets the passenger of this entity through NMS.
public void setPassengerNMS(BasicEntityNMS passenger);
// Sets the passenger of this entity through NMS.
public void setPassengerNMS(Entity bukkitEntity);
}

View File

@ -0,0 +1,31 @@
package com.gmail.filoghost.holograms.nms.interfaces;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holograms.exception.SpawnFailedException;
import com.gmail.filoghost.holograms.object.CraftHologram;
public interface NmsManager {
public void registerCustomEntities() throws Exception;
public HologramHorse spawnHologramHorse(org.bukkit.World world, double x, double y, double z) throws SpawnFailedException;
public HologramWitherSkull spawnHologramWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException;
public CustomItem spawnCustomItem(org.bukkit.World bukkitWorld, double x, double y, double z, ItemStack stack) throws SpawnFailedException;
public TouchSlime spawnTouchSlime(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException;
public boolean isHologramComponent(org.bukkit.entity.Entity bukkitEntity);
public boolean isBasicEntityNMS(org.bukkit.entity.Entity bukkitEntity);
// Return null if not a hologram's part.
public CraftHologram getParentHologram(org.bukkit.entity.Entity bukkitEntity);
public FancyMessage newFancyMessage(String text);
public boolean hasChatHoverFeature();
}

View File

@ -0,0 +1,5 @@
package com.gmail.filoghost.holograms.nms.interfaces;
public interface TouchSlime extends HologramComponent {
}

View File

@ -0,0 +1,40 @@
package com.gmail.filoghost.holograms.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 CraftCustomItem extends CraftItem {
public CraftCustomItem(CraftServer server, EntityCustomItem 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,64 @@
package com.gmail.filoghost.holograms.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 CraftHologramHorse extends CraftHorse {
public CraftHologramHorse(CraftServer server, EntityHologramHorse 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,46 @@
package com.gmail.filoghost.holograms.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 CraftHologramWitherSkull extends CraftWitherSkull {
public CraftHologramWitherSkull(CraftServer server, EntityHologramWitherSkull 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,47 @@
package com.gmail.filoghost.holograms.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 CraftTouchSlime extends CraftSlime {
public CraftTouchSlime(CraftServer server, EntityTouchSlime 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,119 @@
package com.gmail.filoghost.holograms.nms.v1_6_R3;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_6_R3.inventory.CraftItemStack;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.CustomItem;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_6_R3.EntityItem;
import net.minecraft.server.v1_6_R3.NBTTagCompound;
import net.minecraft.server.v1_6_R3.World;
public class EntityCustomItem extends EntityItem implements CustomItem, BasicEntityNMS {
private boolean lockTick;
private CraftHologram parent;
public EntityCustomItem(World world) {
super(world);
super.pickupDelay = Integer.MAX_VALUE;
}
@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 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 CraftCustomItem(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) {
setItemStack( CraftItemStack.asNMSCopy(stack) );
}
@Override
public CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,150 @@
package com.gmail.filoghost.holograms.nms.v1_6_R3;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.HologramHorse;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_6_R3.EntityHorse;
import net.minecraft.server.v1_6_R3.NBTTagCompound;
import net.minecraft.server.v1_6_R3.World;
public class EntityHologramHorse extends EntityHorse implements HologramHorse {
private boolean lockTick;
private CraftHologram parent;
public EntityHologramHorse(World world) {
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.
}
@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 forceSetCustomName(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 CraftHologramHorse(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 CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,138 @@
package com.gmail.filoghost.holograms.nms.v1_6_R3;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.HologramWitherSkull;
import com.gmail.filoghost.holograms.object.CraftHologram;
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.World;
public class EntityHologramWitherSkull extends EntityWitherSkull implements HologramWitherSkull {
private boolean lockTick;
private CraftHologram parent;
public EntityHologramWitherSkull(World world) {
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);
}
@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_() {
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 CraftHologramWitherSkull(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);
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void setPassengerNMS(BasicEntityNMS passenger) {
if (passenger instanceof Entity) {
((Entity) passenger).setPassengerOf(this);
}
}
@Override
public void setPassengerNMS(org.bukkit.entity.Entity bukkitEntity) {
((CraftEntity) bukkitEntity).getHandle().setPassengerOf(this);
}
@Override
public CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,137 @@
package com.gmail.filoghost.holograms.nms.v1_6_R3;
import org.bukkit.craftbukkit.v1_6_R3.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.TouchSlime;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_6_R3.EntitySlime;
import net.minecraft.server.v1_6_R3.NBTTagCompound;
import net.minecraft.server.v1_6_R3.World;
public class EntityTouchSlime extends EntitySlime implements TouchSlime {
private boolean lockTick;
private CraftHologram parent;
public EntityTouchSlime(World world) {
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);
}
@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 CraftTouchSlime(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 CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,99 @@
package com.gmail.filoghost.holograms.nms.v1_6_R3;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holograms.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));
}
public FancyMessageImpl color(final ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color");
}
latest().color = color;
return this;
}
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;
}
public FancyMessageImpl file(final String path) {
return this;
}
public FancyMessageImpl link(final String url) {
return this;
}
public FancyMessageImpl suggest(final String command) {
return this;
}
public FancyMessageImpl command(final String command) {
return this;
}
public FancyMessageImpl achievementTooltip(final String name) {
return this;
}
public FancyMessageImpl itemTooltip(final String itemJSON) {
return this;
}
public FancyMessageImpl itemTooltip(final ItemStack itemStack) {
return this;
}
public FancyMessageImpl tooltip(final String text) {
return this;
}
public FancyMessageImpl then(final Object obj) {
messageParts.add(new MessagePart(obj.toString()));
return this;
}
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();
}
public void send(Player player) {
player.sendMessage(toJSONString());
}
private MessagePart latest() {
return messageParts.get(messageParts.size() - 1);
}
}

View File

@ -0,0 +1,125 @@
package com.gmail.filoghost.holograms.nms.v1_6_R3;
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.holograms.exception.SpawnFailedException;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.CustomItem;
import com.gmail.filoghost.holograms.nms.interfaces.FancyMessage;
import com.gmail.filoghost.holograms.nms.interfaces.HologramHorse;
import com.gmail.filoghost.holograms.nms.interfaces.HologramWitherSkull;
import com.gmail.filoghost.holograms.nms.interfaces.HologramComponent;
import com.gmail.filoghost.holograms.nms.interfaces.NmsManager;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.utils.ReflectionUtils;
import com.gmail.filoghost.holograms.utils.VersionUtils;
import net.minecraft.server.v1_6_R3.Entity;
import net.minecraft.server.v1_6_R3.EntityTypes;
import net.minecraft.server.v1_6_R3.WorldServer;
public class NmsManagerImpl implements NmsManager {
@Override
public void registerCustomEntities() throws Exception {
registerCustomEntity(EntityHologramHorse.class, "EntityHorse", 100);
registerCustomEntity(EntityHologramWitherSkull.class, "WitherSkull", 19);
registerCustomEntity(EntityCustomItem.class, "Item", 1);
registerCustomEntity(EntityTouchSlime.class, "Slime", 55);
}
@SuppressWarnings("rawtypes")
public void registerCustomEntity(Class entityClass, String name, int id) throws Exception {
if (VersionUtils.isMCPC() || VersionUtils.isCauldron()) {
// 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 HologramHorse spawnHologramHorse(org.bukkit.World world, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
EntityHologramHorse invisibleHorse = new EntityHologramHorse(nmsWorld);
invisibleHorse.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(invisibleHorse, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return invisibleHorse;
}
@Override
public HologramWitherSkull spawnHologramWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityHologramWitherSkull staticWitherSkull = new EntityHologramWitherSkull(nmsWorld);
staticWitherSkull.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(staticWitherSkull, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return staticWitherSkull;
}
@Override
public CustomItem spawnCustomItem(org.bukkit.World bukkitWorld, double x, double y, double z, ItemStack stack) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityCustomItem customItem = new EntityCustomItem(nmsWorld);
customItem.setLocationNMS(x, y, z);
customItem.setItemStackNMS(stack);
if (!nmsWorld.addEntity(customItem, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return customItem;
}
@Override
public EntityTouchSlime spawnTouchSlime(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityTouchSlime touchSlime = new EntityTouchSlime(nmsWorld);
touchSlime.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(touchSlime, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return touchSlime;
}
@Override
public boolean isHologramComponent(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof HologramComponent;
}
@Override
public boolean isBasicEntityNMS(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof BasicEntityNMS;
}
@Override
public CraftHologram getParentHologram(org.bukkit.entity.Entity bukkitEntity) {
Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle();
if (nmsEntity instanceof HologramComponent) {
return ((HologramComponent) nmsEntity).getParentHologram();
}
return null;
}
@Override
public FancyMessage newFancyMessage(String text) {
return new FancyMessageImpl(text);
}
@Override
public boolean hasChatHoverFeature() {
return false;
}
}

View File

@ -0,0 +1,40 @@
package com.gmail.filoghost.holograms.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 CraftCustomItem extends CraftItem {
public CraftCustomItem(CraftServer server, EntityCustomItem 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,64 @@
package com.gmail.filoghost.holograms.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 CraftHologramHorse extends CraftHorse {
public CraftHologramHorse(CraftServer server, EntityHologramHorse 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,46 @@
package com.gmail.filoghost.holograms.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 CraftHologramWitherSkull extends CraftWitherSkull {
public CraftHologramWitherSkull(CraftServer server, EntityHologramWitherSkull 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,48 @@
package com.gmail.filoghost.holograms.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 CraftTouchSlime extends CraftSlime {
public CraftTouchSlime(CraftServer server, EntityTouchSlime 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,120 @@
package com.gmail.filoghost.holograms.nms.v1_7_R1;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R1.util.CraftMagicNumbers;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.CustomItem;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_7_R1.EntityItem;
import net.minecraft.server.v1_7_R1.ItemStack;
import net.minecraft.server.v1_7_R1.NBTTagCompound;
import net.minecraft.server.v1_7_R1.World;
public class EntityCustomItem extends EntityItem implements CustomItem, BasicEntityNMS {
private boolean lockTick;
private CraftHologram parent;
public EntityCustomItem(World world) {
super(world);
super.pickupDelay = Integer.MAX_VALUE;
}
@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 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 CraftCustomItem(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) {
setItemStack( new ItemStack(CraftMagicNumbers.getItem(stack.getType()), 1, stack.getDurability()) );
}
@Override
public CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,150 @@
package com.gmail.filoghost.holograms.nms.v1_7_R1;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.HologramHorse;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_7_R1.EntityHorse;
import net.minecraft.server.v1_7_R1.NBTTagCompound;
import net.minecraft.server.v1_7_R1.World;
public class EntityHologramHorse extends EntityHorse implements HologramHorse {
private boolean lockTick;
private CraftHologram parent;
public EntityHologramHorse(World world) {
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.
}
@Override
public void h() {
// Checks every 20 ticks.
if (super.ticksLived % 20 == 0) {
// The horse dies without a valid vehicle.
if (super.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 forceSetCustomName(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) {
super.bukkitEntity = new CraftHologramHorse(this.world.getServer(), this);
}
return super.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return this.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 CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,136 @@
package com.gmail.filoghost.holograms.nms.v1_7_R1;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.HologramWitherSkull;
import com.gmail.filoghost.holograms.object.CraftHologram;
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.World;
public class EntityHologramWitherSkull extends EntityWitherSkull implements HologramWitherSkull {
private boolean lockTick;
private CraftHologram parent;
public EntityHologramWitherSkull(World world) {
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);
}
@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 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 CraftHologramWitherSkull(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);
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void setPassengerNMS(BasicEntityNMS passenger) {
if (passenger instanceof Entity) {
((Entity) passenger).setPassengerOf(this);
}
}
@Override
public void setPassengerNMS(org.bukkit.entity.Entity bukkitEntity) {
((CraftEntity) bukkitEntity).getHandle().setPassengerOf(this);
}
@Override
public CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,137 @@
package com.gmail.filoghost.holograms.nms.v1_7_R1;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.TouchSlime;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_7_R1.EntitySlime;
import net.minecraft.server.v1_7_R1.NBTTagCompound;
import net.minecraft.server.v1_7_R1.World;
public class EntityTouchSlime extends EntitySlime implements TouchSlime {
private boolean lockTick;
private CraftHologram parent;
public EntityTouchSlime(World world) {
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);
}
@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 CraftTouchSlime(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 CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,152 @@
package com.gmail.filoghost.holograms.nms.v1_7_R1;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.server.v1_7_R1.ChatSerializer;
import net.minecraft.server.v1_7_R1.NBTTagCompound;
import net.minecraft.server.v1_7_R1.PacketPlayOutChat;
import org.bukkit.ChatColor;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_7_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.json.JSONException;
import org.json.JSONStringer;
import com.gmail.filoghost.holograms.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));
}
public FancyMessageImpl color(final ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color");
}
latest().color = color;
return this;
}
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;
}
public FancyMessageImpl file(final String path) {
onClick("open_file", path);
return this;
}
public FancyMessageImpl link(final String url) {
onClick("open_url", url);
return this;
}
public FancyMessageImpl suggest(final String command) {
onClick("suggest_command", command);
return this;
}
public FancyMessageImpl command(final String command) {
onClick("run_command", command);
return this;
}
public FancyMessageImpl achievementTooltip(final String name) {
onHover("show_achievement", "achievement." + name);
return this;
}
public FancyMessageImpl itemTooltip(final String itemJSON) {
onHover("show_item", itemJSON);
return this;
}
public FancyMessageImpl itemTooltip(final ItemStack itemStack) {
return itemTooltip(CraftItemStack.asNMSCopy(itemStack).save(new NBTTagCompound()).toString());
}
public FancyMessageImpl tooltip(final String text) {
final String[] lines = text.split("\\n");
if (lines.length <= 1) {
onHover("show_text", text);
} else {
itemTooltip(makeMultilineTooltip(lines));
}
return this;
}
public FancyMessageImpl then(final Object obj) {
messageParts.add(new MessagePart(obj.toString()));
return this;
}
public String toJSONString() {
final JSONStringer json = new JSONStringer();
try {
if (messageParts.size() == 1) {
latest().writeJson(json);
} else {
json.object().key("text").value("").key("extra").array();
for (final MessagePart part : messageParts) {
part.writeJson(json);
}
json.endArray().endObject();
}
} catch (final JSONException e) {
throw new RuntimeException("invalid message");
}
return json.toString();
}
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 String makeMultilineTooltip(final String[] lines) {
final JSONStringer json = new JSONStringer();
try {
json.object().key("id").value(1);
json.key("tag").object().key("display").object();
json.key("Name").value("\\u00A7f" + lines[0].replace("\"", "\\\""));
json.key("Lore").array();
for (int i = 1; i < lines.length; i++) {
final String line = lines[i];
json.value(line.isEmpty() ? " " : line.replace("\"", "\\\""));
}
json.endArray().endObject().endObject().endObject();
} catch (final JSONException e) {
throw new RuntimeException("invalid tooltip");
}
return json.toString();
}
private void onClick(final String name, final String data) {
final MessagePart latest = latest();
latest.clickActionName = name;
latest.clickActionData = data;
}
private void onHover(final String name, final String data) {
final MessagePart latest = latest();
latest.hoverActionName = name;
latest.hoverActionData = data;
}
}

View File

@ -0,0 +1,124 @@
package com.gmail.filoghost.holograms.nms.v1_7_R1;
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.holograms.exception.SpawnFailedException;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.CustomItem;
import com.gmail.filoghost.holograms.nms.interfaces.FancyMessage;
import com.gmail.filoghost.holograms.nms.interfaces.HologramHorse;
import com.gmail.filoghost.holograms.nms.interfaces.HologramWitherSkull;
import com.gmail.filoghost.holograms.nms.interfaces.HologramComponent;
import com.gmail.filoghost.holograms.nms.interfaces.NmsManager;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.utils.ReflectionUtils;
import com.gmail.filoghost.holograms.utils.VersionUtils;
import net.minecraft.server.v1_7_R1.EntityTypes;
import net.minecraft.server.v1_7_R1.WorldServer;
import net.minecraft.server.v1_7_R1.Entity;
public class NmsManagerImpl implements NmsManager {
@Override
public void registerCustomEntities() throws Exception {
registerCustomEntity(EntityHologramHorse.class, "EntityHorse", 100);
registerCustomEntity(EntityHologramWitherSkull.class, "WitherSkull", 19);
registerCustomEntity(EntityCustomItem.class, "Item", 1);
registerCustomEntity(EntityTouchSlime.class, "Slime", 55);
}
@SuppressWarnings("rawtypes")
public void registerCustomEntity(Class entityClass, String name, int id) throws Exception {
if (VersionUtils.isMCPC() || VersionUtils.isCauldron()) {
// 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 HologramHorse spawnHologramHorse(org.bukkit.World world, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
EntityHologramHorse invisibleHorse = new EntityHologramHorse(nmsWorld);
invisibleHorse.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(invisibleHorse, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return invisibleHorse;
}
@Override
public HologramWitherSkull spawnHologramWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityHologramWitherSkull staticWitherSkull = new EntityHologramWitherSkull(nmsWorld);
staticWitherSkull.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(staticWitherSkull, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return staticWitherSkull;
}
@Override
public CustomItem spawnCustomItem(org.bukkit.World bukkitWorld, double x, double y, double z, ItemStack stack) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityCustomItem customItem = new EntityCustomItem(nmsWorld);
customItem.setLocationNMS(x, y, z);
customItem.setItemStackNMS(stack);
if (!nmsWorld.addEntity(customItem, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return customItem;
}
@Override
public EntityTouchSlime spawnTouchSlime(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityTouchSlime touchSlime = new EntityTouchSlime(nmsWorld);
touchSlime.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(touchSlime, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return touchSlime;
}
@Override
public boolean isHologramComponent(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof HologramComponent;
}
@Override
public boolean isBasicEntityNMS(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof BasicEntityNMS;
}
@Override
public CraftHologram getParentHologram(org.bukkit.entity.Entity bukkitEntity) {
Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle();
if (nmsEntity instanceof HologramComponent) {
return ((HologramComponent) nmsEntity).getParentHologram();
}
return null;
}
@Override
public FancyMessage newFancyMessage(String text) {
return new FancyMessageImpl(text);
}
@Override
public boolean hasChatHoverFeature() {
return true;
}
}

View File

@ -0,0 +1,41 @@
package com.gmail.filoghost.holograms.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 CraftCustomItem extends CraftItem {
public CraftCustomItem(CraftServer server, EntityCustomItem 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,64 @@
package com.gmail.filoghost.holograms.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 CraftHologramHorse extends CraftHorse {
public CraftHologramHorse(CraftServer server, EntityHologramHorse 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,45 @@
package com.gmail.filoghost.holograms.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 CraftHologramWitherSkull extends CraftWitherSkull {
public CraftHologramWitherSkull(CraftServer server, EntityHologramWitherSkull 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,48 @@
package com.gmail.filoghost.holograms.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 CraftTouchSlime extends CraftSlime {
public CraftTouchSlime(CraftServer server, EntityTouchSlime 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,120 @@
package com.gmail.filoghost.holograms.nms.v1_7_R2;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R2.util.CraftMagicNumbers;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.CustomItem;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_7_R2.EntityItem;
import net.minecraft.server.v1_7_R2.ItemStack;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.World;
public class EntityCustomItem extends EntityItem implements CustomItem, BasicEntityNMS {
private boolean lockTick;
private CraftHologram parent;
public EntityCustomItem(World world) {
super(world);
super.pickupDelay = Integer.MAX_VALUE;
}
@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 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 CraftCustomItem(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) {
setItemStack( new ItemStack(CraftMagicNumbers.getItem(stack.getType()), 1, stack.getDurability()) );
}
@Override
public CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,150 @@
package com.gmail.filoghost.holograms.nms.v1_7_R2;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.HologramHorse;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_7_R2.EntityHorse;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.World;
public class EntityHologramHorse extends EntityHorse implements HologramHorse {
private boolean lockTick;
private CraftHologram parent;
public EntityHologramHorse(World world) {
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.
}
@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 forceSetCustomName(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 CraftHologramHorse(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return this.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 CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,137 @@
package com.gmail.filoghost.holograms.nms.v1_7_R2;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.HologramWitherSkull;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_7_R2.Entity;
import net.minecraft.server.v1_7_R2.EntityWitherSkull;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.World;
public class EntityHologramWitherSkull extends EntityWitherSkull implements HologramWitherSkull {
private boolean lockTick;
private CraftHologram parent;
public EntityHologramWitherSkull(World world) {
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);
}
@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 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 CraftHologramWitherSkull(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);
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void setPassengerNMS(BasicEntityNMS passenger) {
if (passenger instanceof Entity) {
((Entity) passenger).setPassengerOf(this);
}
}
@Override
public void setPassengerNMS(org.bukkit.entity.Entity bukkitEntity) {
((CraftEntity) bukkitEntity).getHandle().setPassengerOf(this);
}
@Override
public CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,136 @@
package com.gmail.filoghost.holograms.nms.v1_7_R2;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.TouchSlime;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_7_R2.EntitySlime;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.World;
public class EntityTouchSlime extends EntitySlime implements TouchSlime {
private boolean lockTick;
private CraftHologram parent;
public EntityTouchSlime(World world) {
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);
}
@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 CraftTouchSlime(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 CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,152 @@
package com.gmail.filoghost.holograms.nms.v1_7_R2;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.server.v1_7_R2.ChatSerializer;
import net.minecraft.server.v1_7_R2.NBTTagCompound;
import net.minecraft.server.v1_7_R2.PacketPlayOutChat;
import org.bukkit.ChatColor;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_7_R2.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.json.JSONException;
import org.json.JSONStringer;
import com.gmail.filoghost.holograms.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));
}
public FancyMessageImpl color(final ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color");
}
latest().color = color;
return this;
}
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;
}
public FancyMessageImpl file(final String path) {
onClick("open_file", path);
return this;
}
public FancyMessageImpl link(final String url) {
onClick("open_url", url);
return this;
}
public FancyMessageImpl suggest(final String command) {
onClick("suggest_command", command);
return this;
}
public FancyMessageImpl command(final String command) {
onClick("run_command", command);
return this;
}
public FancyMessageImpl achievementTooltip(final String name) {
onHover("show_achievement", "achievement." + name);
return this;
}
public FancyMessageImpl itemTooltip(final String itemJSON) {
onHover("show_item", itemJSON);
return this;
}
public FancyMessageImpl itemTooltip(final ItemStack itemStack) {
return itemTooltip(CraftItemStack.asNMSCopy(itemStack).save(new NBTTagCompound()).toString());
}
public FancyMessageImpl tooltip(final String text) {
final String[] lines = text.split("\\n");
if (lines.length <= 1) {
onHover("show_text", text);
} else {
itemTooltip(makeMultilineTooltip(lines));
}
return this;
}
public FancyMessageImpl then(final Object obj) {
messageParts.add(new MessagePart(obj.toString()));
return this;
}
public String toJSONString() {
final JSONStringer json = new JSONStringer();
try {
if (messageParts.size() == 1) {
latest().writeJson(json);
} else {
json.object().key("text").value("").key("extra").array();
for (final MessagePart part : messageParts) {
part.writeJson(json);
}
json.endArray().endObject();
}
} catch (final JSONException e) {
throw new RuntimeException("invalid message");
}
return json.toString();
}
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 String makeMultilineTooltip(final String[] lines) {
final JSONStringer json = new JSONStringer();
try {
json.object().key("id").value(1);
json.key("tag").object().key("display").object();
json.key("Name").value("\\u00A7f" + lines[0].replace("\"", "\\\""));
json.key("Lore").array();
for (int i = 1; i < lines.length; i++) {
final String line = lines[i];
json.value(line.isEmpty() ? " " : line.replace("\"", "\\\""));
}
json.endArray().endObject().endObject().endObject();
} catch (final JSONException e) {
throw new RuntimeException("invalid tooltip");
}
return json.toString();
}
private void onClick(final String name, final String data) {
final MessagePart latest = latest();
latest.clickActionName = name;
latest.clickActionData = data;
}
private void onHover(final String name, final String data) {
final MessagePart latest = latest();
latest.hoverActionName = name;
latest.hoverActionData = data;
}
}

View File

@ -0,0 +1,128 @@
package com.gmail.filoghost.holograms.nms.v1_7_R2;
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.holograms.exception.SpawnFailedException;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.CustomItem;
import com.gmail.filoghost.holograms.nms.interfaces.FancyMessage;
import com.gmail.filoghost.holograms.nms.interfaces.HologramHorse;
import com.gmail.filoghost.holograms.nms.interfaces.HologramWitherSkull;
import com.gmail.filoghost.holograms.nms.interfaces.HologramComponent;
import com.gmail.filoghost.holograms.nms.interfaces.NmsManager;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.utils.ReflectionUtils;
import com.gmail.filoghost.holograms.utils.VersionUtils;
import net.minecraft.server.v1_7_R2.Entity;
import net.minecraft.server.v1_7_R2.EntityTypes;
import net.minecraft.server.v1_7_R2.WorldServer;
public class NmsManagerImpl implements NmsManager {
@Override
public void registerCustomEntities() throws Exception {
registerCustomEntity(EntityHologramHorse.class, "EntityHorse", 100);
registerCustomEntity(EntityHologramWitherSkull.class, "WitherSkull", 19);
registerCustomEntity(EntityCustomItem.class, "Item", 1);
registerCustomEntity(EntityTouchSlime.class, "Slime", 55);
}
@SuppressWarnings("rawtypes")
public void registerCustomEntity(Class entityClass, String name, int id) throws Exception {
if (VersionUtils.isMCPC() || VersionUtils.isCauldron()) {
// 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 HologramHorse spawnHologramHorse(org.bukkit.World world, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
EntityHologramHorse invisibleHorse = new EntityHologramHorse(nmsWorld);
invisibleHorse.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(invisibleHorse, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return invisibleHorse;
}
@Override
public HologramWitherSkull spawnHologramWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityHologramWitherSkull staticWitherSkull = new EntityHologramWitherSkull(nmsWorld);
staticWitherSkull.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(staticWitherSkull, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return staticWitherSkull;
}
@Override
public CustomItem spawnCustomItem(org.bukkit.World bukkitWorld, double x, double y, double z, ItemStack stack) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityCustomItem customItem = new EntityCustomItem(nmsWorld);
customItem.setLocationNMS(x, y, z);
customItem.setItemStackNMS(stack);
if (!nmsWorld.addEntity(customItem, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return customItem;
}
@Override
public EntityTouchSlime spawnTouchSlime(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityTouchSlime touchSlime = new EntityTouchSlime(nmsWorld);
touchSlime.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(touchSlime, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return touchSlime;
}
@Override
public boolean isHologramComponent(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof HologramComponent;
}
@Override
public boolean isBasicEntityNMS(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof BasicEntityNMS;
}
@Override
public CraftHologram getParentHologram(org.bukkit.entity.Entity bukkitEntity) {
Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle();
if (nmsEntity instanceof HologramComponent) {
return ((HologramComponent) nmsEntity).getParentHologram();
}
return null;
}
@Override
public FancyMessage newFancyMessage(String text) {
return new FancyMessageImpl(text);
}
@Override
public boolean hasChatHoverFeature() {
return true;
}
}

View File

@ -0,0 +1,40 @@
package com.gmail.filoghost.holograms.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 CraftCustomItem extends CraftItem {
public CraftCustomItem(CraftServer server, EntityCustomItem 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,64 @@
package com.gmail.filoghost.holograms.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 CraftHologramHorse extends CraftHorse {
public CraftHologramHorse(CraftServer server, EntityHologramHorse 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,45 @@
package com.gmail.filoghost.holograms.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 CraftHologramWitherSkull extends CraftWitherSkull {
public CraftHologramWitherSkull(CraftServer server, EntityHologramWitherSkull 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,48 @@
package com.gmail.filoghost.holograms.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 CraftTouchSlime extends CraftSlime {
public CraftTouchSlime(CraftServer server, EntityTouchSlime 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,121 @@
package com.gmail.filoghost.holograms.nms.v1_7_R3;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R3.util.CraftMagicNumbers;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.CustomItem;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_7_R3.EntityItem;
import net.minecraft.server.v1_7_R3.ItemStack;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.World;
public class EntityCustomItem extends EntityItem implements CustomItem, BasicEntityNMS {
private boolean lockTick;
private CraftHologram parent;
public EntityCustomItem(World world) {
super(world);
super.pickupDelay = Integer.MAX_VALUE;
}
@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 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 CraftCustomItem(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) {
setItemStack( new ItemStack(CraftMagicNumbers.getItem(stack.getType()), 1, stack.getDurability()) );
}
@Override
public CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,150 @@
package com.gmail.filoghost.holograms.nms.v1_7_R3;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.HologramHorse;
import com.gmail.filoghost.holograms.object.CraftHologram;
import net.minecraft.server.v1_7_R3.EntityHorse;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.World;
public class EntityHologramHorse extends EntityHorse implements HologramHorse {
private boolean lockTick;
private CraftHologram parent;
public EntityHologramHorse(World world) {
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.
}
@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 forceSetCustomName(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 CraftHologramHorse(this.world.getServer(), this);
}
return this.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return this.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 CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,141 @@
package com.gmail.filoghost.holograms.nms.v1_7_R3;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.HologramWitherSkull;
import com.gmail.filoghost.holograms.object.CraftHologram;
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.World;
public class EntityHologramWitherSkull extends EntityWitherSkull implements HologramWitherSkull {
private boolean lockTick;
private CraftHologram parent;
public EntityHologramWitherSkull(World world) {
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);
}
@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 h() {
if (!lockTick) {
super.h();
}
}
@Override
public void makeSound(String sound, float f1, float f2) {
// Remove sounds.
}
public void callSuperTick() {
super.h();
}
@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 CraftHologramWitherSkull(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);
}
@Override
public boolean isDeadNMS() {
return this.dead;
}
@Override
public void setPassengerNMS(BasicEntityNMS passenger) {
if (passenger instanceof Entity) {
((Entity) passenger).setPassengerOf(this);
}
}
@Override
public void setPassengerNMS(org.bukkit.entity.Entity bukkitEntity) {
((CraftEntity) bukkitEntity).getHandle().setPassengerOf(this);
}
@Override
public CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,139 @@
package com.gmail.filoghost.holograms.nms.v1_7_R3;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import com.gmail.filoghost.holograms.nms.interfaces.TouchSlime;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.object.HologramBase;
import net.minecraft.server.v1_7_R3.EntitySlime;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.World;
public class EntityTouchSlime extends EntitySlime implements TouchSlime {
private boolean lockTick;
private CraftHologram parent;
public EntityTouchSlime(World world) {
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);
}
@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.
}
public void setLockTick(boolean lock) {
lockTick = lock;
}
public void die() {
setLockTick(false);
super.die();
}
public HologramBase getParent() {
return parent;
}
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
this.bukkitEntity = new CraftTouchSlime(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 CraftHologram getParentHologram() {
return parent;
}
@Override
public void setParentHologram(CraftHologram hologram) {
this.parent = hologram;
}
}

View File

@ -0,0 +1,152 @@
package com.gmail.filoghost.holograms.nms.v1_7_R3;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.server.v1_7_R3.ChatSerializer;
import net.minecraft.server.v1_7_R3.NBTTagCompound;
import net.minecraft.server.v1_7_R3.PacketPlayOutChat;
import org.bukkit.ChatColor;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_7_R3.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.json.JSONException;
import org.json.JSONStringer;
import com.gmail.filoghost.holograms.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));
}
public FancyMessageImpl color(final ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color");
}
latest().color = color;
return this;
}
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;
}
public FancyMessageImpl file(final String path) {
onClick("open_file", path);
return this;
}
public FancyMessageImpl link(final String url) {
onClick("open_url", url);
return this;
}
public FancyMessageImpl suggest(final String command) {
onClick("suggest_command", command);
return this;
}
public FancyMessageImpl command(final String command) {
onClick("run_command", command);
return this;
}
public FancyMessageImpl achievementTooltip(final String name) {
onHover("show_achievement", "achievement." + name);
return this;
}
public FancyMessageImpl itemTooltip(final String itemJSON) {
onHover("show_item", itemJSON);
return this;
}
public FancyMessageImpl itemTooltip(final ItemStack itemStack) {
return itemTooltip(CraftItemStack.asNMSCopy(itemStack).save(new NBTTagCompound()).toString());
}
public FancyMessageImpl tooltip(final String text) {
final String[] lines = text.split("\\n");
if (lines.length <= 1) {
onHover("show_text", text);
} else {
itemTooltip(makeMultilineTooltip(lines));
}
return this;
}
public FancyMessageImpl then(final Object obj) {
messageParts.add(new MessagePart(obj.toString()));
return this;
}
public String toJSONString() {
final JSONStringer json = new JSONStringer();
try {
if (messageParts.size() == 1) {
latest().writeJson(json);
} else {
json.object().key("text").value("").key("extra").array();
for (final MessagePart part : messageParts) {
part.writeJson(json);
}
json.endArray().endObject();
}
} catch (final JSONException e) {
throw new RuntimeException("invalid message");
}
return json.toString();
}
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 String makeMultilineTooltip(final String[] lines) {
final JSONStringer json = new JSONStringer();
try {
json.object().key("id").value(1);
json.key("tag").object().key("display").object();
json.key("Name").value("\\u00A7f" + lines[0].replace("\"", "\\\""));
json.key("Lore").array();
for (int i = 1; i < lines.length; i++) {
final String line = lines[i];
json.value(line.isEmpty() ? " " : line.replace("\"", "\\\""));
}
json.endArray().endObject().endObject().endObject();
} catch (final JSONException e) {
throw new RuntimeException("invalid tooltip");
}
return json.toString();
}
private void onClick(final String name, final String data) {
final MessagePart latest = latest();
latest.clickActionName = name;
latest.clickActionData = data;
}
private void onHover(final String name, final String data) {
final MessagePart latest = latest();
latest.hoverActionName = name;
latest.hoverActionData = data;
}
}

View File

@ -0,0 +1,128 @@
package com.gmail.filoghost.holograms.nms.v1_7_R3;
import org.bukkit.craftbukkit.v1_7_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holograms.exception.SpawnFailedException;
import com.gmail.filoghost.holograms.nms.interfaces.BasicEntityNMS;
import com.gmail.filoghost.holograms.nms.interfaces.CustomItem;
import com.gmail.filoghost.holograms.nms.interfaces.FancyMessage;
import com.gmail.filoghost.holograms.nms.interfaces.HologramHorse;
import com.gmail.filoghost.holograms.nms.interfaces.HologramWitherSkull;
import com.gmail.filoghost.holograms.nms.interfaces.HologramComponent;
import com.gmail.filoghost.holograms.nms.interfaces.NmsManager;
import com.gmail.filoghost.holograms.object.CraftHologram;
import com.gmail.filoghost.holograms.utils.ReflectionUtils;
import com.gmail.filoghost.holograms.utils.VersionUtils;
import net.minecraft.server.v1_7_R3.Entity;
import net.minecraft.server.v1_7_R3.EntityTypes;
import net.minecraft.server.v1_7_R3.WorldServer;
public class NmsManagerImpl implements NmsManager {
@Override
public void registerCustomEntities() throws Exception {
registerCustomEntity(EntityHologramHorse.class, "EntityHorse", 100);
registerCustomEntity(EntityHologramWitherSkull.class, "WitherSkull", 19);
registerCustomEntity(EntityCustomItem.class, "Item", 1);
registerCustomEntity(EntityTouchSlime.class, "Slime", 55);
}
@SuppressWarnings("rawtypes")
public void registerCustomEntity(Class entityClass, String name, int id) throws Exception {
if (VersionUtils.isMCPC() || VersionUtils.isCauldron()) {
// MCPC+ / Cauldron entity registration.
Class<?> entityTypesClass = Class.forName("net.minecraft.server.v1_7_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, "d", entityClass, name);
ReflectionUtils.putInPrivateStaticMap(EntityTypes.class, "f", entityClass, Integer.valueOf(id));
}
}
@Override
public HologramHorse spawnHologramHorse(org.bukkit.World world, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
EntityHologramHorse invisibleHorse = new EntityHologramHorse(nmsWorld);
invisibleHorse.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(invisibleHorse, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return invisibleHorse;
}
@Override
public HologramWitherSkull spawnHologramWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityHologramWitherSkull staticWitherSkull = new EntityHologramWitherSkull(nmsWorld);
staticWitherSkull.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(staticWitherSkull, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return staticWitherSkull;
}
@Override
public CustomItem spawnCustomItem(org.bukkit.World bukkitWorld, double x, double y, double z, ItemStack stack) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityCustomItem customItem = new EntityCustomItem(nmsWorld);
customItem.setLocationNMS(x, y, z);
customItem.setItemStackNMS(stack);
if (!nmsWorld.addEntity(customItem, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return customItem;
}
@Override
public EntityTouchSlime spawnTouchSlime(org.bukkit.World bukkitWorld, double x, double y, double z) throws SpawnFailedException {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityTouchSlime touchSlime = new EntityTouchSlime(nmsWorld);
touchSlime.setLocationNMS(x, y, z);
if (!nmsWorld.addEntity(touchSlime, SpawnReason.CUSTOM)) {
throw new SpawnFailedException();
}
return touchSlime;
}
@Override
public boolean isHologramComponent(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof HologramComponent;
}
@Override
public boolean isBasicEntityNMS(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof BasicEntityNMS;
}
@Override
public CraftHologram getParentHologram(org.bukkit.entity.Entity bukkitEntity) {
Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle();
if (nmsEntity instanceof HologramComponent) {
return ((HologramComponent) nmsEntity).getParentHologram();
}
return null;
}
@Override
public FancyMessage newFancyMessage(String text) {
return new FancyMessageImpl(text);
}
@Override
public boolean hasChatHoverFeature() {
return true;
}
}

View File

@ -0,0 +1,65 @@
package com.gmail.filoghost.holograms.object;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bukkit.Chunk;
import org.bukkit.plugin.Plugin;
import com.gmail.filoghost.holograms.api.Hologram;
/**
* This class is only used by the plugin itself. Other plugins should just use the API.
*/
public class APIHologramManager {
private static Map<Plugin, List<CraftHologram>> apiHolograms = new HashMap<Plugin, List<CraftHologram>>();
public static void onChunkLoad(Chunk chunk) {
for (List<CraftHologram> pluginHologramList : apiHolograms.values()) {
for (CraftHologram hologram : pluginHologramList) {
if (hologram.isInChunk(chunk)) {
hologram.forceUpdate();
}
}
}
}
public static void onChunkUnload(Chunk chunk) {
for (List<CraftHologram> pluginHologramList : apiHolograms.values()) {
for (CraftHologram hologram : pluginHologramList) {
if (hologram.isInChunk(chunk)) {
hologram.hide();
}
}
}
}
public static void addHologram(Plugin plugin, CraftHologram hologram) {
List<CraftHologram> pluginHologramList = apiHolograms.get(plugin);
if (pluginHologramList == null) {
pluginHologramList = new ArrayList<CraftHologram>();
apiHolograms.put(plugin, pluginHologramList);
}
pluginHologramList.add(hologram);
}
public static void remove(Hologram hologram) {
for (List<CraftHologram> pluginHologramList : apiHolograms.values()) {
pluginHologramList.remove(hologram);
}
}
public static Hologram[] getHolograms(Plugin plugin) {
List<CraftHologram> pluginHologramList = apiHolograms.get(plugin);
if (pluginHologramList == null) {
return new Hologram[0];
} else {
return pluginHologramList.toArray(new Hologram[pluginHologramList.size()]);
// It's a copy of the original list. Holograms should be removed with hologram.delete()
}
}
}

View File

@ -0,0 +1,218 @@
package com.gmail.filoghost.holograms.object;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holograms.Configuration;
import com.gmail.filoghost.holograms.HolographicDisplays;
import com.gmail.filoghost.holograms.api.Hologram;
import com.gmail.filoghost.holograms.api.TouchHandler;
import com.gmail.filoghost.holograms.commands.CommandValidator;
import com.gmail.filoghost.holograms.exception.CommandException;
import com.gmail.filoghost.holograms.exception.SpawnFailedException;
import com.gmail.filoghost.holograms.utils.Validator;
import com.gmail.filoghost.holograms.utils.VisibilityManager;
/**
* This class is only used by the plugin itself. Other plugins should just use the API.
*/
public class CraftHologram extends HologramBase implements Hologram {
private List<FloatingDoubleEntity> linesEntities;
private List<String> textLines;
private VisibilityManager visibilityManager;
private long creationTimestamp;
private FloatingTouchSlime touchSlimeEntity;
private TouchHandler touchHandler;
public CraftHologram(String name, Location source) {
super(name, source);
linesEntities = new ArrayList<FloatingDoubleEntity>();
textLines = new ArrayList<String>();
touchSlimeEntity = new FloatingTouchSlime();
creationTimestamp = System.currentTimeMillis();
}
public void addLine(String message) {
if (message == null) {
message = "";
}
textLines.add(message);
}
public void insertLine(int index, String message) {
if (message == null) {
message = "";
}
textLines.add(index, message);
}
public String[] getLines() {
return textLines.toArray(new String[textLines.size()]);
}
public void setLine(int index, String text) {
if (text == null) {
text = "";
}
textLines.set(index, text);
}
public void clearLines() {
textLines.clear();
}
public void removeLine(int index) {
textLines.remove(index);
}
public int getLinesLength() {
return textLines.size();
}
@Override
public long getCreationTimestamp() {
return creationTimestamp;
}
public void setVisibilityManager(VisibilityManager visibilityManager) {
this.visibilityManager = visibilityManager;
}
public boolean hasVisibilityManager() {
return visibilityManager != null;
}
public VisibilityManager getVisibilityManager() {
return visibilityManager;
}
public void setTouchHandler(TouchHandler touchHandler) {
this.touchHandler = touchHandler;
if (touchHandler != null && !touchSlimeEntity.isSpawned()) {
try {
touchSlimeEntity.spawn(this, bukkitWorld, x, y, z);
} catch (SpawnFailedException e) { }
} else if (touchHandler == null && touchSlimeEntity.isSpawned()) {
touchSlimeEntity.despawn();
}
}
public boolean hasTouchHandler() {
return touchHandler != null;
}
public TouchHandler getTouchHandler() {
return touchHandler;
}
public boolean update() {
if (isInLoadedChunk()) {
return forceUpdate();
}
return true;
}
/**
* Updates the hologram without checking if it's in a loaded chunk.
*/
public boolean forceUpdate() {
Validator.checkState(!isDeleted(), "Hologram already deleted");
// Remove previous entities.
hide();
try {
double lineSpacing = Configuration.verticalLineSpacing;
// While iterating we change this var.
double currentY = this.y;
for (String text : textLines) {
if (text.length() >= 5 && text.substring(0, 5).toLowerCase().equals("icon:")) {
// It's a floating icon!
ItemStack icon;
try {
icon = CommandValidator.matchItemStack(text.substring(5).trim());
} catch (CommandException e) {
icon = new ItemStack(Material.BEDROCK);
}
// If the current Y has been changed, the item is NOT on top of the hologram.
if (currentY != this.y) {
// Extra space for the floating item...
currentY -= 0.27;
}
FloatingItem lineEntity = new FloatingItem(icon);
lineEntity.spawn(this, bukkitWorld, x, currentY, z);
linesEntities.add(lineEntity);
// And some more space below.
currentY -= 0.05;
} else {
HologramLine lineEntity = new HologramLine(text);
lineEntity.spawn(this, bukkitWorld, x, currentY, z);
linesEntities.add(lineEntity);
// Placeholders.
HolographicDisplays.getPlaceholderManager().trackIfNecessary(lineEntity.getHorse());
}
currentY -= lineSpacing;
}
if (touchHandler != null) {
touchSlimeEntity.spawn(this, bukkitWorld, x, y, z);
}
} catch (SpawnFailedException ex) {
// Kill the entities and return false.
hide();
return false;
}
return true;
}
public void hide() {
for (FloatingDoubleEntity lineEntity : linesEntities) {
lineEntity.despawn();
}
linesEntities.clear();
if (touchSlimeEntity.isSpawned()) {
touchSlimeEntity.despawn();
}
}
@Override
public void onDeleteEvent() {
hide();
HologramManager.remove(this);
APIHologramManager.remove(this);
}
public String toString() {
return "CraftHologram{lines=" + textLines.toString() + ",x=" + x + ",y=" + y + ",z=" + z + ",world=" + bukkitWorld.getName() + "}";
}
}

View File

@ -0,0 +1,14 @@
package com.gmail.filoghost.holograms.object;
import org.bukkit.World;
import com.gmail.filoghost.holograms.exception.SpawnFailedException;
// Represents an object associated with a hologram, made of a wither skull with a passenger.
public abstract class FloatingDoubleEntity {
public abstract void spawn(CraftHologram parent, World bukkitWorld, double x, double y, double z) throws SpawnFailedException;
public abstract void despawn();
}

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