Displaying an Image On A Map

Discussion in 'Plugin Development' started by BungeeTheCookie, Dec 27, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    BungeeTheCookie

    I want to make a command that when you are holding a map, it sets an image on it. Like a .png or .jpg file. How do you do this? Thanks.
     
  2. Offline

    XvBaseballkidvX

    1:You need to Listen to the MapInitializeEvent
    2.Remove all the Map renderers (use a for loop)
    3. Add a new MapRenderer.
     
  3. Offline

    BungeeTheCookie

    I need an example please, and I don't want to remove all of the map renderers. Just the one on the map the player is holding. NathanWolf
     
  4. Offline

    NathanWolf

    He just meant remove all the map renderers attached to that one map before you add your own (each map id gets its own set of renderers).

    The tricky part here is you need to save off the ids of your special maps so you can hook the renderers back up on reload.

    I'm still working out some bugs in my own code, but feel free to use it- this link is "live" so as I update the code it will update:

    https://github.com/elBukkit/MagicPl...om/elmakers/mine/bukkit/utilities/URLMap.java

    This class is completely self-contained. To use it, just call URLMap.load(yourPluginInstance); on enable.. for some reason you need to delay it a bit, like this:

    Code:java
    1. Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
    2. public void run() {
    3. URLMap.resetAll();
    4. URLMap.load(plugin);
    5. }
    6. }, 20);


    The resetAll() is probably not necessary, I just have that in there to handle reloads in the case that you've edited the urlmaps.yml file manually (like deleted a map), so this is a "clean" reload.

    I guess if you use this class it's probably best to rename it, or at least put it in your own package. The reason is it's a static class (I should probably make it a singleton instead), so if two plugins were using the same class they'd be fighting over who is responsible for the maps. I may refactor it to be a singleton eventually :)

    The main bug I'm trying to squash is that, sometimes, when creating a new instance of an existing map, they all blank out until reload.

    The class has some functions to get around this, you can programmatically force a single map reload whenever you create a map, but that's really inefficient, the idea is it should only retrieve the image and render it once, then all maps use that renderer... but something's wrong there and I haven't had a chance to fix it :)

    Of course you're also more than welcome to just cannabalize that code to your liking :D

    EDIT: Heh, I happened to notice this thread before you fixed the tag... in case it seemed like I replied to that super fast ;)
     
    XvBaseballkidvX likes this.
  5. Offline

    Syd

    MapCanvas#drawImage(java.awt.Image) is your friend. ;)
    It makes drawing an Image fairly easy.

    To get a Image object from an file: ImageIO#read(File).

    How you handle the whole map stuff is up to you.
     
  6. Offline

    BungeeTheCookie

    NathanWolf Syd
    Thanks. So, do I just use a MapInitializeEvent, get all the map renderers on a map, clear them, and just make a new renderer, and then call the event in my command? Could I have an example please?
     
  7. Offline

    Conarnar

  8. Offline

    BungeeTheCookie

    How does that help me at all if he isn't even online? I would like this solved this year.
     
  9. Offline

    Conarnar

    He will come online eventually. Also, he was the only who created this plugin http://dev.bukkit.org/bukkit-plugins/imgmap/
     
  10. Offline

    BungeeTheCookie

    I would prefer this problem solved as soon as possible. And not depend on someone offline, even though Cirno is a boss.
     
  11. Offline

    Ivan

  12. Offline

    BungeeTheCookie

    I believe that is outdated because it uses the old register events format and the GitHub page that is there comes from two years ago. Can I have a better example than that?
     
  13. Offline

    Ivan

    Why would that be outdated :confused: ? Nothing in the BukkitAPI has changed so that wont work anymore. I'm going to give it a try myself and I'll report back in a second.
     
  14. Offline

    BungeeTheCookie

    I still don't like using things that come from a year or more ago. ;)
     
  15. Offline

    TomTheDeveloper

    BungeeTheCookie You can still read it and use it as an information source.
     
  16. Offline

    Ivan

    Show Spoiler
    [​IMG]

    Code:java
    1.  
    2. public class TestRenderer extends MapRenderer {
    3. @Override
    4. public void render(MapView mapView, MapCanvas mapCanvas, Player player) {
    5. try {
    6.  
    7. img = ImageIO.read(new File(Bukkit.getWorldContainer(),"test.png"));
    8. } catch (IOException e) {
    9. e.printStackTrace();
    10. return;
    11. }
    12. mapView.setScale(MapView.Scale.NORMAL);
    13. mapCanvas.drawImage(5,5,img);
    14. }
    15.  
    16. }
    17.  

    There you go, that's what I used to create that. :p
     
    Edrynaath and AguilaAudaz like this.
  17. Offline

    NathanWolf

    BungeeTheCookie

    You can use the code I gave you outright. It does exactly what you want. Or look at it if you want examples.

    I don't know what the map initialize event is for, but I don't use it and it doesn't seem necessary.
     
  18. Offline

    Syd

    BungeeTheCookie
    How I would try to solve the problem "command that shows an image on the sender's map":

    1. Create a own, contextual, MapRenderer implementation to display the image
    (You may need the name of the player, the image is displayed to, and the actual image/file)
    2. When someone executes the command, check if he is a player, holds a map and has permissions
    3. If everything is fine with the command, add a new instance of the custom MapRenderer to the map, the player is currently holding.
    (Server#getMap(short id) and Player#getItemInHand().getDurability() will help you to get the MapView).
    4. Implement some kind of control mechanism to remove the MapRenderer when it's not needed anymore.

    This only works if a later added renderer got an higher priority. I havn't tested it, but after a look in CB source it should work this way.

    In the end you would have a pretty neat solution. When someone executes the command one the sender will see the image, even if 100 other people look at the same map.
    Also, when another player uses the command on the same map, it will not interfere with the first executor.


    Maps are just awsome, I think I should do even more with them. :D

    PS: sk89q's wiki entry to maps IS severly outdated. Almost nothing there is useable anymore.
     
  19. Offline

    Cirno

    spoonfeed time:
    Code:java
    1. package net.yukkuricraft.tenko.render;
    2.  
    3. import java.awt.image.BufferedImage;
    4. import java.io.IOException;
    5. import java.lang.ref.SoftReference;
    6. import java.net.URL;
    7.  
    8. import javax.imageio.ImageIO;
    9.  
    10. import net.yukkuricraft.tenko.ImgMap;
    11.  
    12. import org.bukkit.ChatColor;
    13. import org.bukkit.entity.Player;
    14. import org.bukkit.map.MapCanvas;
    15. import org.bukkit.map.MapRenderer;
    16. import org.bukkit.map.MapView;
    17.  
    18. public class ImageRenderer extends MapRenderer {
    19.  
    20. // So fancy.
    21. private SoftReference<BufferedImage> cacheImage;
    22. private boolean hasRendered = false;
    23.  
    24. public ImageRenderer(String url) throws IOException {
    25. this.cacheImage = new SoftReference<>(this.getImage(url));
    26. }
    27.  
    28. @SuppressWarnings("deprecation")
    29. @Override
    30. public void render(MapView view, MapCanvas canvas, Player player){
    31. if(this.hasRendered){
    32. return;
    33. }
    34.  
    35. if(this.cacheImage.get() != null){
    36. canvas.drawImage(0, 0, this.cacheImage.get());
    37. this.hasRendered = true;
    38. }else{
    39. player.sendMessage(ChatColor.RED + "Attempted to render the image, but the cached image was null!");
    40. ImgMap.logMessage(ChatColor.RED + "While rendering image map ID #" + view.getId() + ", cacheImage was garbage collected.");
    41. this.hasRendered = true;
    42. }
    43. }
    44.  
    45. public BufferedImage getImage(String url) throws IOException{
    46. boolean useCache = ImageIO.getUseCache();
    47.  
    48. // Temporarily disable cache, if it isn't already,
    49. // so we can get the latest image.
    50. ImageIO.setUseCache(false);
    51.  
    52. BufferedImage image = ImageIO.read(new URL(url));
    53. RenderUtils.resizeImage(image);
    54.  
    55. // Renable it with the old value.
    56. ImageIO.setUseCache(useCache);
    57.  
    58. return image;
    59. }
    60.  
    61. }
    62.  

    Code:java
    1. MapView view = Bukkit.getMap(plyr.getItemInHand().getDurability());
    2. Iterator<MapRenderer> iter = view.getRenderers().iterator();
    3. while(iter.hasNext()){
    4. view.removeRenderer(iter.next());
    5. }
    6.  
    7. try{
    8. ImageRenderer renderer = new ImageRenderer(args[0]);
    9. view.addRenderer(renderer);
    10. cs.sendMessage(ChatColor.AQUA + "[ImgMap] Rendering " + args[0] + "!");
    11. }catch (IOException e){
    12. cs.sendMessage(ChatColor.RED + "[ImgMap] An error occured! Is the URL correct?");
    13. e.printStackTrace();
    14. }


    All of this was taken from the latest private build of ImgMap.
     
    adde likes this.
  20. Offline

    Paxination

    Cirno Whats the import for RenderUtils?
     
  21. Offline

    Cirno

    It just resizes it; you can easily use Google for that...
     
  22. Offline

    Paxination

    http://stackoverflow.com/questions/18550284/java-resize-image-from-an-url

    Just so any one knows, that suggestion there works great.

    Cirno I am having one issue tho. Its only changing the image of the same map! Not the one im holding. I have it copied/pasted just like you have it there with the exception of the resizeimage method I added in.

    Code:java
    1. package net.charter.orion_pax.OasisExtras.Commands;
    2.  
    3. import java.io.IOException;
    4. import java.util.Iterator;
    5.  
    6. import net.charter.orion_pax.OasisExtras.ImageRenderer;
    7. import net.charter.orion_pax.OasisExtras.OasisExtras;
    8.  
    9. import org.bukkit.Bukkit;
    10. import org.bukkit.ChatColor;
    11. import org.bukkit.command.Command;
    12. import org.bukkit.command.CommandExecutor;
    13. import org.bukkit.command.CommandSender;
    14. import org.bukkit.entity.Player;
    15. import org.bukkit.map.MapRenderer;
    16. import org.bukkit.map.MapView;
    17.  
    18. public class MapCommand implements CommandExecutor {
    19.  
    20. private OasisExtras plugin;
    21. public MapCommand(OasisExtras plugin) {
    22. this.plugin = plugin;
    23. }
    24.  
    25. @Override
    26. public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
    27. Player player = (Player) sender;
    28. if(args.length==1){
    29. MapView view = Bukkit.getMap(player.getItemInHand().getDurability());
    30. Iterator<MapRenderer> iter = view.getRenderers().iterator();
    31. while(iter.hasNext()){
    32. view.removeRenderer(iter.next());
    33. }
    34.  
    35. try{
    36. ImageRenderer renderer = new ImageRenderer(args[0]);
    37. view.addRenderer(renderer);
    38. player.sendMessage(ChatColor.AQUA + "[ImgMap] Rendering " + args[0] + "!");
    39. }catch (IOException e){
    40. player.sendMessage(ChatColor.RED + "[ImgMap] An error occured! Is the URL correct?");
    41. }
    42. return true;
    43. }
    44. return false;
    45. }
    46.  
    47. }


    Code:java
    1. package net.charter.orion_pax.OasisExtras;
    2.  
    3. import java.awt.Dimension;
    4. import java.awt.Graphics2D;
    5. import java.awt.image.BufferedImage;
    6. import java.io.IOException;
    7. import java.lang.ref.SoftReference;
    8. import java.net.URL;
    9.  
    10. import javax.imageio.ImageIO;
    11.  
    12. import org.bukkit.ChatColor;
    13. import org.bukkit.entity.Player;
    14. import org.bukkit.map.MapCanvas;
    15. import org.bukkit.map.MapRenderer;
    16. import org.bukkit.map.MapView;
    17.  
    18. public class ImageRenderer extends MapRenderer {
    19.  
    20. // So fancy.
    21. private SoftReference<BufferedImage> cacheImage;
    22. private boolean hasRendered = false;
    23.  
    24. public ImageRenderer(String url) throws IOException {
    25. this.cacheImage = new SoftReference<BufferedImage>(this.getImage(url));
    26. }
    27.  
    28. @SuppressWarnings("deprecation")
    29. @Override
    30. public void render(MapView view, MapCanvas canvas, Player player){
    31. if(this.hasRendered){
    32. return;
    33. }
    34.  
    35. if(this.cacheImage.get() != null){
    36. canvas.drawImage(0, 0, this.cacheImage.get());
    37. this.hasRendered = true;
    38. }else{
    39. player.sendMessage(ChatColor.RED + "Attempted to render the image, but the cached image was null!");
    40. this.hasRendered = true;
    41. }
    42. }
    43.  
    44. public BufferedImage getImage(String url) throws IOException{
    45. boolean useCache = ImageIO.getUseCache();
    46.  
    47. // Temporarily disable cache, if it isn't already,
    48. // so we can get the latest image.
    49. ImageIO.setUseCache(false);
    50.  
    51. BufferedImage image = resize(new URL(url), new Dimension(128,128));
    52. // TODO find import for RenderUtils
    53. //RenderUtils.resizeImage(image);
    54.  
    55. // Renable it with the old value.
    56. ImageIO.setUseCache(useCache);
    57.  
    58. return image;
    59. }
    60.  
    61. public BufferedImage resize(final URL url, final Dimension size) throws IOException{
    62. final BufferedImage image = ImageIO.read(url);
    63. final BufferedImage resized = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
    64. final Graphics2D g = resized.createGraphics();
    65. g.drawImage(image, 0, 0, size.width, size.height, null);
    66. g.dispose();
    67. return resized;
    68. }
    69.  
    70. }
    71.  
    72.  
    73.  
     
  23. Offline

    Cirno

    Can you println() the durability of the item in hand? May be because it's the same durability.
     
  24. Offline

    Paxination

    I did dupe it with creative and not crafted it. So that might be why!
     
Thread Status:
Not open for further replies.

Share This Page