Resource RadioBoard - A new packet-based map library

Discussion in 'Spigot Plugin Development' started by BananaPuncher714, Nov 8, 2018.

  1. RadioBoard - Redefining boards
    [​IMG]

    Useful links:
    What is this?
    RadioBoard is a fast packet-based map library that's a bit like @RubbaBoy 's MapCanvasAPI but better. :p RadioBoard supports multiple map boards, as well as accurate pixel click detection. The packets sent by RadioBoard are also minimized as small as possible so that only areas that changed get updated. The ImageUtil coded by @jetp250 performs incredibly fast dithering and with this library, it is possible to play videos and gifs at 25+ fps(except then the client would timeout).

    Ok, so why do I need this?
    It is free, and a new way for people to present information, via a map board. You can easily integrate this into your plugin with something as simple as a status box, or a billboard for players. RadioBoard also comes with a player click detection system and manages the map boards without any extra code. It is easy for server owners to set up and offers an easy way to add/remove boards/displays in-game.

    How to start:
    RadioBoard is split into two parts, the physical map/item frame wall, and the virtual display. The thing that you will want to use is the virtual display. At the lowest level, there is the MapDisplay, which is responsible for sending updates to the player and keeping track of who is observing it. Then, there is the MapDisplayProvider, which is what creates and sends frames to the MapDisplay for sending to players.

    You will want to make a MapDisplayProvider to display custom content. A MapDisplayProvider is also responsible for receiving left/right/ clicks and acting on those. First, we will create a class that implements MapDisplayProvider, and fill out the methods for getting and setting the MapDisplay.
    Code (Java):
    public class ExampleMapDisplayProvider implements MapDisplayProvider {
        private MapDisplay display;
       
        @Override
        public Frame getSource() {
            return null;
        }

        @Override
        public void interactAt( Entity entity, DisplayInteract action, int x, int y ) {

        }

        @Override
        public void provideFor( MapDisplay display ) {
            this.display = display;
        }

        @Override
        public void stopProviding() {
            display = null;
        }
    }
    The MapDisplayProvider#provideFor() method is the entry point into our provider. When a MapDisplay sets our class as the source, provideFor() is called and that is when we know we can start updating the map, if we want to do so on a timer(see GifPlayer). Now that we have our ExampleMapDisplayProvider, let's make it display different colors that cycle each time a player left-clicks on our board.
    Code (Java):
    public class ExampleMapDisplayProvider implements MapDisplayProvider {
        private MapDisplay display;
        private Color[] colors;
        private int colorIndex = 0;
       
        public ExampleMapDisplayProvider( Color... colors ) {
            Validate.isTrue( colors.length > 0, "At least 1 color must be provided!" );
            this.colors = colors.clone();
        }
       
        @Override
        public Frame getSource() {
            if ( display != null ) {
                // Get the width and height of the MapDisplay in pixels
                int width = display.getMapWidth() << 7;
                int height = display.getMapHeight() << 7;
                // Create a new int to fill with color
                int[] colorArray = new int[ width * height ];
                Arrays.fill( colorArray, colors[ colorIndex ].getRGB() );
               
                // Convert it to Minecraft's limited color palette
                byte[] minecraftColorArray = JetpImageUtil.dither( width, colorArray );
                // Create our frame with an offset of 0, 0 and send
                Frame frame = new Frame( 0, 0, minecraftColorArray, width );
               
                return frame;
            }
            return null;
        }

        @Override
        public void interactAt( Entity entity, DisplayInteract action, int x, int y ) {
            // If and only if a player left clicked our display
            if ( action == DisplayInteract.LEFT_CLICK ) {
                colorIndex = ( colorIndex + 1 ) % colors.length;
                            display.update();
            }
        }

        @Override
        public void provideFor( MapDisplay display ) {
            this.display = display;
            display.update();
        }

        @Override
        public void stopProviding() {
            display = null;
        }
    }
    MapDisplay#update() is called which in turn gets a frame with our getSource() method. We return a Frame object. A Frame object consists of an X and Y offset from the top left corner of our display, a byte array of Minecraft's limited color palette, and the width of our image. Now that we have our MapDisplayProvider, we can create a MapDisplay and set our MapDisplayProvider as the source. Thankfully, there is already an implementation of MapDisplay, RBoard:
    Code (Java):
    public class RadioBoardExample extends JavaPlugin {
        @Override
        public void onEnable() {
            // Construct a new MapDisplay with a map id starting at 0, and width and height of 6
            MapDisplay display = new RBoard( "color_example", 0, 6, 6 );
            // Register our display
            FrameManager.INSTANCE.registerDisplay( display );
           
            // Let all online players see what is being displayed
            for ( Player player : Bukkit.getOnlinePlayers() ) {
                display.addObserver( new RadioObserver( player.getUniqueId() ) );
            }
           
            // Set our provider
            display.setSource( new ExampleMapDisplayProvider( Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA, Color.BLACK, Color.WHITE ) );
        }
    }
    The result looks like this:

    [​IMG]
    Higher level elements
    It is also possible to make slightly higher level but more modular components called a RadioIcon which allows more placement options and customization since you can put multiple RadioIcons together on one canvas. RadioCanvases also support multiple layers of transparency:
    [​IMG]
    If I missed anything that doesn't seem to make sense, or if I did something wrong, please tell me so I can fix any mistakes I made.
     
    • Like Like x 3
    • Winner Winner x 3
    • Useful Useful x 1
    • Optimistic Optimistic x 1
  2. I think this is a cool and useful idea, but ATM I don't think there is such a big need for a custom API like this. However, I really think this has some good ability to becoming a nice standard API for these kinda tasks!
     
    • Friendly Friendly x 1
  3. Looks amazing
     
    • Like Like x 1

Share This Page