Skip to content

Creating custom sidebar components

PXAV edited this page Jan 27, 2021 · 1 revision

This page teaches you how to create your own sidebar components for the sidebar system in kelp-v0.1.0 and above.

Creating your own components might be useful if you have to display complex or highly customizable content, where it is useful to separate code operations across different component classes instead of cluttering everything into your sidebar creation method.

Creating a component class

Every component is stored in an own class and has to extend from SidebarComponent, which provides the essential render method. This method is called by Kelp when the component is rendered or updated.

public class TestComponent extends SidebarComponent {
  
  @Override
  public Map<Integer, String> render() {
    return null;
  }
  
}

As you can see it uses a map to export the contents, which means that a component can render multiple lines at once if needed, where

  • The key of the map (Integer) is the absolute position/line of the
  • The value (String), which is the actual content displayed on this line.

The fact that the line ids are absolute means that every line returned by any component on a sidebar has to be unique. If there are two entries with the same line, this might lead to a weird/buggy behaviour.

Making your component stateless

Stateless components are components that have static contents and do not change after an update. Making them is really simple. You just have to return the same result every time the component is rendered. For example:

public class TestComponent extends SidebarComponent {

  private int line;
  private String chapter;
  
  // static factory to create new instances of your component
  public static TestComponent create() {
    return new TestComponent();
  }
  
  public TestComponent line(int line) {
    this.line = line;
    return this;
  }
  
  public TestComponent chapter(String chapter) {
    this.chapter = chapter;
    return this;
  }
  
  @Override
  public Map<Integer, String> render() {
    Map<Integer, String> output = Maps.newHashMap();
    output.put(line, "§6>§e> §6§l" + chapter);
    return output;
  }

}

This component always adds a prefix to a given String. This is useful if you want to display something like this:

YOUR SIDEBAR TITLE
----------------------

>> Your coins         <- our component
-> 200

But what if we would want to handle the coin value as well with our component? For that, we have to make it stateful.

Making your component stateful

Stateful means that the component has variable content that is loaded each time it is updated and might change with each update. The major difference here is that we don't use a simple String, but a Supplier<T>.

public class TestComponent extends SidebarComponent {

  private int line;
  private String chapter;
  private Supplier<Object> value;

  // static factory to create new instances of your component
  public static TestComponent create() {
    return new TestComponent();
  }

  public TestComponent line(int line) {
    this.line = line;
    return this;
  }

  public TestComponent chapter(String chapter) {
    this.chapter = chapter;
    return this;
  }
  
  public TestComponent value(Supplier<Object> value) {
    this.value = value;
    return this;
  }

  @Override
  public Map<Integer, String> render() {
    Map<Integer, String> output = Maps.newHashMap();
    output.put(line, "§6>§e> §6§l" + chapter);
    output.put(line - 1, "§8> §7" + value.get().toString()); // one line below the header, we insert the value
    return output;
  }

}

Example usage of this would look as follows:

sidebar.addComponent(TestComponent.create()
      .line(10)
      .chapter("Your coins")
      .value(() -> player.getExperience()));

The main advantage of using this component is that if we have multiple chapters and we want to change the color codes, for example, we do not have to change them manually for every category (coins, kills, deaths, etc.) but we simply do it in the component class and the rest is done automatically.

Further information

If you think your component is universal to use and other developers might benefit from it, feel free to create a pull request with it.

Clone this wiki locally