Created
February 21, 2014 22:27
-
-
Save aadnk/9144914 to your computer and use it in GitHub Desktop.
Display a floating image with name tags. Screenshot: http://imgur.com/gF0qyzj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.comphenix.example; | |
import java.awt.image.BufferedImage; | |
import java.io.File; | |
import java.io.IOException; | |
import javax.imageio.ImageIO; | |
import org.bukkit.ChatColor; | |
import org.bukkit.command.Command; | |
import org.bukkit.command.CommandSender; | |
import org.bukkit.entity.Player; | |
import org.bukkit.event.Listener; | |
import org.bukkit.plugin.java.JavaPlugin; | |
import com.comphenix.example.nametags.ImageChar; | |
import com.comphenix.example.nametags.NameTagMessage; | |
// Screenshot: | |
// http://imgur.com/gF0qyzj | |
public class DisplayFloatingImage extends JavaPlugin implements Listener { | |
private NameTagMessage message; | |
private BufferedImage image; | |
@Override | |
public void onEnable() { | |
// Must be placed in the data folder | |
File file = new File(getDataFolder(), "tux.png"); | |
try { | |
image = ImageIO.read(file); | |
message = new NameTagMessage(image, 30, ImageChar.BLOCK.getChar()); | |
} catch (IOException e) { | |
throw new RuntimeException("Cannot read image " + file, e); | |
} | |
} | |
@Override | |
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { | |
if (sender instanceof Player) { | |
Player player = (Player) sender; | |
if (message != null) | |
message.sendToPlayer(player, player.getLocation().add(0, 5, 0)); | |
else | |
sender.sendMessage(ChatColor.RED + "No image loaded."); | |
} | |
return true; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.comphenix.example.nametags; | |
/** | |
* User: bobacadodl | |
* Date: 1/25/14 | |
* Time: 11:03 PM | |
*/ | |
public enum ImageChar { | |
BLOCK('\u2588'), | |
DARK_SHADE('\u2593'), | |
MEDIUM_SHADE('\u2592'), | |
LIGHT_SHADE('\u2591'); | |
private char c; | |
ImageChar(char c) { | |
this.c = c; | |
} | |
public char getChar() { | |
return c; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.comphenix.example.nametags; | |
import org.bukkit.ChatColor; | |
import org.bukkit.entity.Player; | |
import org.bukkit.util.ChatPaginator; | |
import java.awt.*; | |
import java.awt.image.BufferedImage; | |
/** | |
* User: bobacadodl | |
* Date: 1/25/14 | |
* Time: 10:28 PM | |
*/ | |
public class ImageMessage { | |
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), | |
}; | |
protected String[] lines; | |
public ImageMessage(BufferedImage image, int height, char imgChar) { | |
ChatColor[][] chatColors = toChatColorArray(image, height); | |
lines = toImgMessage(chatColors, imgChar); | |
} | |
public ImageMessage(ChatColor[][] chatColors, char imgChar) { | |
lines = toImgMessage(chatColors, imgChar); | |
} | |
public ImageMessage(String... imgLines) { | |
lines = imgLines; | |
} | |
public ImageMessage appendText(String... text) { | |
for (int y = 0; y < lines.length; y++) { | |
if (text.length > y) { | |
lines[y] += " " + text[y]; | |
} | |
} | |
return this; | |
} | |
public ImageMessage appendCenteredText(String... text) { | |
for (int y = 0; y < lines.length; y++) { | |
if (text.length > y) { | |
int len = ChatPaginator.AVERAGE_CHAT_PAGE_WIDTH - lines[y].length(); | |
lines[y] = lines[y] + center(text[y], len); | |
} else { | |
return this; | |
} | |
} | |
return this; | |
} | |
private ChatColor[][] toChatColorArray(BufferedImage image, int height) { | |
double ratio = (double) image.getHeight() / image.getWidth(); | |
int width = (int) (height / ratio); | |
if (width > 10) width = 10; | |
BufferedImage resized = resizeImage(image, (int) (height / ratio), 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); | |
ChatColor closest = getClosestChatColor(new Color(rgb)); | |
chatImg[x][y] = closest; | |
} | |
} | |
return chatImg; | |
} | |
private String[] toImgMessage(ChatColor[][] colors, char imgchar) { | |
String[] lines = new String[colors[0].length]; | |
for (int y = 0; y < colors[0].length; y++) { | |
String line = ""; | |
for (int x = 0; x < colors.length; x++) { | |
line += colors[x][y].toString() + imgchar; | |
} | |
lines[y] = line + ChatColor.RESET; | |
} | |
return lines; | |
} | |
private BufferedImage resizeImage(BufferedImage originalImage, int width, int height) { | |
BufferedImage resizedImage = new BufferedImage(width, height, 6); | |
Graphics2D g = resizedImage.createGraphics(); | |
g.drawImage(originalImage, 0, 0, width, height, null); | |
g.dispose(); | |
g.setComposite(AlphaComposite.Src); | |
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); | |
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); | |
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | |
return resizedImage; | |
} | |
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() < 128) return ChatColor.BLACK; | |
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]; | |
} | |
private String center(String s, int length) { | |
if (s.length() > length) { | |
return s.substring(0, length); | |
} else if (s.length() == length) { | |
return s; | |
} else { | |
int leftPadding = (length - s.length()) / 2; | |
StringBuilder leftBuilder = new StringBuilder(); | |
for (int i = 0; i < leftPadding; i++) { | |
leftBuilder.append(" "); | |
} | |
return leftBuilder.toString() + s; | |
} | |
} | |
public String[] getLines() { | |
return lines; | |
} | |
public void sendToPlayer(Player player) { | |
for (String line : lines) { | |
player.sendMessage(line); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.comphenix.example.nametags; | |
import java.awt.image.BufferedImage; | |
import org.bukkit.ChatColor; | |
import org.bukkit.Location; | |
import org.bukkit.entity.Player; | |
import com.google.common.base.Preconditions; | |
public class NameTagMessage extends ImageMessage { | |
private NameTagSpawner spawner; | |
private Location location; | |
private double lineSpacing = 0.25d; | |
public NameTagMessage(BufferedImage image, int height, char imgChar) { | |
super(image, height, imgChar); | |
initialize(height); | |
} | |
public NameTagMessage(ChatColor[][] chatColors, char imgChar) { | |
super(chatColors, imgChar); | |
this.location = Preconditions.checkNotNull(location, "location cannot be NULL"); | |
initialize(chatColors.length); | |
} | |
public NameTagMessage(String... imgLines) { | |
super(imgLines); | |
initialize(imgLines.length); | |
} | |
private void initialize(int height) { | |
this.spawner = new NameTagSpawner(height); | |
} | |
@Override | |
public NameTagMessage appendCenteredText(String... text) { | |
super.appendCenteredText(text); | |
return this; | |
} | |
@Override | |
public NameTagMessage appendText(String... text) { | |
super.appendText(text); | |
return this; | |
} | |
public void setLocation(Location location) { | |
this.location = location; | |
} | |
public Location getLocation() { | |
return location; | |
} | |
/** | |
* Retrieve the default amount of meters in the y-axis between each name tag. | |
* @return The line spacing. | |
*/ | |
public double getLineSpacing() { | |
return lineSpacing; | |
} | |
/** | |
* Set the default amount of meters in the y-axis between each name tag. | |
* @param lineSpacing - the name spacing. | |
*/ | |
public void setLineSpacing(double lineSpacing) { | |
this.lineSpacing = lineSpacing; | |
} | |
@Override | |
public void sendToPlayer(Player player) { | |
sendToPlayer(player, location != null ? location : player.getLocation()); | |
} | |
/** | |
* Send a floating image message to the given player at the specified starting location. | |
* @param player - the player. | |
* @param location - the starting location. | |
*/ | |
public void sendToPlayer(Player player, Location location) { | |
for (int i = 0; i < lines.length; i++) { | |
spawner.setNameTag(i, player, location, -i * lineSpacing, lines[i]); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment