KELP FRAMEWORK | Cross version plugins & boilerplate reduction kelp-v0.4.0

Cross version API for NPCs, Scoreboards, Inventories, Prompts, Particles, and more!

  1. PXAV
    Native Minecraft Version:
    1.16
    Tested Minecraft Versions:
    • 1.8
    Source Code:
    https://github.com/PXAV/kelp
    Contributors:
    pxav, Etrayed, Paul2708, Shatuxy, DSeeLP
    title.png

    Kelp is a spigot framework that aims to reduce boilerplate code and make your plugin compatible with multiple server versions easily. This massively reduces maintenance costs for your plugins and allows developers to focus on their creative work and write more readable code in less time.

    The problem with the current spigot plugin development process
    The Spigot API has limited backwards compatibility. Material and sound names change over the versions, NMS packages are named after their version and require reflections to make them compatible, etc. Adjusting old code to new API versions requires lots of time & effort, which is why many developers don't upgrade their plugins anymore, although many server owners still rely on them. So server owners won't upgrade to the latest Minecraft versions and new ideas can't be realized.

    Furthermore, developers have to use lots of workarounds to achieve certain goals. If you want to create a non-flickering sidebar, you have to save the updateable content into a team prefix, put it into the sidebar and update the prefix. New developers might not understand why there are teams in the scoreboard, which often causes confusion.

    How Kelp solves all these problems
    Kelp is built modularly. It consists of one core module, which only contains Java-logic and no version-specific code, so it will run on every spigot server version. It contains so-called template classes, which are basically dummies with empty methods doing version specific stuff. The server owner then puts a version-implementation module in a specific folder. This file contains implementations of all the template classes from the core module. It is detected by the core module and every template class is replaced with its version implementation class. So the core module can load version implementations for every version and can run on any version without changing any line in the code-base.




    features.png
    • Inventories: Create stunning inventories with animations and widget-based design. Instead of just putting items into an inventory, you put in widgets handling calculations that are needed to create a pagination or toggleable buttons/... You can create your own widgets as well!
    • Schedulers: A complete redesign of the Bukkit scheduler library simplifying asynchronous operations and especially synchronization with the server's main thread to handle non-thread-safe operations easier.
    • NPCs: An intuitive and simple to use NPC library for spawning NPCs and giving them abilities such as constantly looking at a specific player or sneaking at given times, etc.
    • Sidebars: Kelp's sidebar library allows you to create sidebars without thinking about how to update them flicker-free and lightweight in performance.
    • Prompts: Query user input with Anvil GUIs, Sign Editors, or the chat box in a simple way.
    • Interactive Messages: Create clickable and hoverable messages with unlimited color codes and components
    • Boss Bar: Show boss bars to players without worrying about handling the boss entity for 1.8 versions, Kelp handles everything for you!
    • Entities: Version-independent entity library with own entity classes.
    • Particle Engine: Create stunning particle effects based on mathematical templates for particle calculation and create your own particle algorithms with ease. All particles you send are version-independent of course!
    • Configurations: Automate your configuration files with kelp and use cached values so save long-term server performance
    • And much more...

    But please note that Kelp is still under heavy development and will contain bugs. Plugins you develop with the current version of Kelp might not work with future releases as the API code still subjects to change.

    So Kelp should not be used in production environments yet, but only for testing purposes. I would really appreciate some people testing it and giving feedback on performance, usability, and code design to improve the framework and bring it to its first stable release.




    demo.png
    Below you can find some demos on what Kelp can do now and how the code roughly looks like.

    2021-01-02_22.05.42.png
    Code (Java):
    @EventHandler
      public void handlePlayerJoin(PlayerJoinEvent event) {
        KelpPlayer player = playerRepository.getKelpPlayer(event.getPlayer());

        // create new npc instance
        KelpNpc kelpNpc = npcFactory.newKelpNpc()
          .spawnLocation(player.getLocation())
          .itemInHand(kelpItemFactory.newKelpItem() // the NPC is holding an apple
            .material(KelpMaterial.APPLE))    // in its hand
          .addTitleLine("§bThis is an epic NPC") // set titles above the npc
          .addTitleLine("§7Create as many lines as you want")
          .skinTexture("ewogICJ0aW1lc3RhbXAiIDogMTYwOTYyMDczMTk4OSwKICAicHJvZmlsZUlkIiA6ICI4NThmZGJiNjg3MWM0OGZhYjhlODY5YmY2NmM2YTEwMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJweGF2IiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2YyZmVhZThkMzFlYzc0NTQ4MTE5Y2E0NThmNWRhNTc2MzU0ZmE5NzUxYWE0YWU2M2Y1NDYwODJmODA2NTFiMmIiCiAgICB9CiAgfQp9")
          .skinSignature("M8SC4wdKlAlAx4NjaWEFZV1qQfcnqRvZb9YKikVs7eOLHMbwlPb64TfiTq2eYb1vEg+4QbU0LTBk/FAl5WXILq0OAzicX9Sh2z6x9/tuVy3oRuSqJKUoqYvG8vg8I2r2426okLE7iznkLv7AplX1V0cKZjjg8mwb+9IpdM1/ai3hilBr84oLUWpI3s8WtXY45qpDnMgkJFFSKc9ZY13SmYK4DtgGPPpkN043OCsOoaADEmiUTWuNdQRqA4dDVTPODqn5qvhG2rZK58t7tK3xYqeARIMH522GQMYAi8g6cOF8CiL4WQuZQYsT0hUlZtNwFhT+odCoJqXZPuY8sHNRPaTj+65ZJXEzjDsVPzxP1HHHSy3fQk9RyhTqOB7pgcXlseGLMsWcu5rgJLvdc+QcFfItGJHAFW5Ysv025fmo/qwQJ3RrMX8DZ3IotSpWekrIx/8ACf0jxuyTDhIzFtJPArFnYq4ELDsgWMShmOUGY0YGvfryYEShH7S4p02zAf4TgwUve6OrRfh0yTmg5qFKKAADQg+MoCCdRIj6ubcW0FjKf22WA3EH+wtdmkf5LZTldvvj8dyFd+0mvrl9c/eUggqZFeyvnRwEL9rBkVuWw8PXxaVPPf7yyZVuqL+fzGHBbb3Lu6Exk2ywdatqdKmHLVKJU6ZDP5NN9hrSeaH4iDM=")
          .imitateSneaking() // the npc will sneak when the player sneaks
          .followHeadRotation(); // the npc will always look at the player

        // finally make the npc visible to the player
        kelpNpc.spawn(player);

      }

    DeepinScreenshot_select-area_20210102221419.png
    Code (Java):
    @EventHandler
      public void handleInteract(PlayerInteractEvent event) {
        KelpPlayer player = playerRepository.getKelpPlayer(event.getPlayer());

        AnimatedInventory inventory = kelpInventoryFactory.newAnimatedInventory();
        inventory
          .size(54)
          .title(textAnimationFactory.newBuildingTextAnimation()
            .text("§aFOOD SELECTION")
            .ignoreSpaces());
        inventory.addWidget(widgetFactory.newToggleableWidget()
          .player(player)
          .slot(42)
          .condition(() -> player.getBukkitPlayer().getGameMode() == GameMode.CREATIVE)
          .whenFalse(kelpItemFactory.newKelpItem()
            .material(KelpMaterial.RED_WOOL)
            .displayName("§cIn Survival Mode")
            .cancelInteractions(),
            () -> {
              player.sendMessage("Your Gamemode has been updated");
              player.getBukkitPlayer().setGameMode(GameMode.CREATIVE);
            })
          .whenTrue(kelpItemFactory.newKelpItem()
            .material(KelpMaterial.GREEN_WOOL)
            .displayName("§cIn creative mode")
            .cancelInteractions(),
            () -> {
              player.sendMessage("Your Gamemode has been updated.");
              player.getBukkitPlayer().setGameMode(GameMode.SURVIVAL);
            }));

        inventory.addWidget(widgetFactory.newPagination()
          .player(player)
          .contentSlots(3, 1, 2, 12, 10, 11)
          .contentItems(kelpItemFactory.newKelpItem().displayName("§6Cooked Beef").material(KelpMaterial.COOKED_BEEF),
            kelpItemFactory.newKelpItem().displayName("§fCooked Chicken").material(KelpMaterial.COOKED_CHICKEN),
            kelpItemFactory.newKelpItem().displayName("§cCooked Fish").material(KelpMaterial.COOKED_SALMON),
            kelpItemFactory.newKelpItem().displayName("§fCooked Mutton").material(KelpMaterial.COOKED_MUTTON),
            kelpItemFactory.newKelpItem().displayName("§6Golden Apple").material(KelpMaterial.GOLDEN_APPLE),
            kelpItemFactory.newKelpItem().displayName("§cApple").material(KelpMaterial.APPLE),
            kelpItemFactory.newKelpItem().displayName("§6Soup").material(KelpMaterial.MUSHROOM_STEW))
          .nextButton(kelpItemFactory.newKelpItem().slot(21).displayName("§eNext Page").material(KelpMaterial.ARROW).cancelInteractions(),
            () -> player.sendMessage("§cYou are already on last page"))
          .previousButton(kelpItemFactory.newKelpItem().slot(19).displayName("§eVorherige Seite").material(KelpMaterial.ARROW).cancelInteractions(),
            () -> player.sendMessage("§cYou are already on first page"))
        );

        inventory.addWidget(widgetFactory.newPagination()
          .player(player)
          .contentSlots(5, 6, 7, 14, 15, 16)
          .contentItems(kelpItemFactory.newKelpItem().displayName("§bDiamond Sword").material(KelpMaterial.DIAMOND_SWORD),
            kelpItemFactory.newKelpItem().displayName("§bDiamond Shovel").material(KelpMaterial.DIAMOND_SHOVEL),
            kelpItemFactory.newKelpItem().displayName("§bDiamond Axe").material(KelpMaterial.DIAMOND_AXE),
            kelpItemFactory.newKelpItem().displayName("§7Iron Sword").material(KelpMaterial.IRON_SWORD),
            kelpItemFactory.newKelpItem().displayName("§7Chainmail Chestplate").material(KelpMaterial.CHAINMAIL_CHESTPLATE),
            kelpItemFactory.newKelpItem().displayName("§7Iron ingot").material(KelpMaterial.IRON_INGOT),
            kelpItemFactory.newKelpItem().displayName("§6Gold").material(KelpMaterial.GOLD_INGOT))
          .nextButton(kelpItemFactory.newKelpItem().slot(25).displayName("§eNext Page").material(KelpMaterial.ARROW).cancelInteractions(),
            () -> player.sendMessage("§cYou are already on last page"))
          .previousButton(kelpItemFactory.newKelpItem().slot(23).displayName("§ePrevious Page").material(KelpMaterial.ARROW).cancelInteractions(),
            () -> player.sendMessage("§cYou are already on first page"))
        );

        inventory.addWidget(widgetFactory.newItemWidget()
          .player(player)
          .item(kelpItemFactory.newKelpItem()
            .material(KelpMaterial.BOOK)
            .slot(38)
            .displayName("§6§lA book"))
          .addItemListener(event1 -> player.sendMessage("You clicked the item.")));


        player.openInventory(inventory);
      }

    DeepinScreenshot_select-area_20210102222514.png
    Code (Java):
    @EventHandler
      public void handleIncomingReport(PlayerInteractEvent event) {
        KelpPlayer player = playerRepository.getKelpPlayer(event.getPlayer());
        String reportTarget = "§axX_ItzHackerPvP_Xx";
        player.sendMessage("§8[§2Kelp§8] §7A new report has been created!");
        player.sendMessage("§8[§2Kelp§8] §7Reason: §aHacking");
        player.sendMessage("§8[§2Kelp§8] §7Accused: §axX_ItzHackerPvP_Xx");
        player.sendMessage("§8[§2Kelp§8] §7Please select an action§8:");

        player.sendInteractiveMessage(
          InteractiveMessage.create()
            .addComponent(MessageComponent.create()
              .text("§8[§2Kelp§8] ")) // prefix component (not clickable/hoverable)
            .addComponent(MessageComponent.create()
              .text("§3§l● WATCH PLAYER  ")
              .showMessageOnHover("§aTeleport yourself to the player to validate the report")
              .executeCommandOnClick("teleport " + reportTarget))
            .addComponent(MessageComponent.create()
              .text("§c§l✖ BAN PLAYER  ")
              .showMessageOnHover("§cBan the player immediately without confirming the report")
              .suggestCommandOnClick("ban " + reportTarget + " " + "Hacking"))
            // only suggests the command to the player to that it can be modified by an admin optionally
            .addComponent(MessageComponent.create()
              .text("§b§l✚ INFO  ")
              .showMessageOnHover("§bOpens the web interface showing more information about the player")
              .openURLOnClick("https://interface.your-server.com/info/" + reportTarget))
        );

      }

    DeepinScreenshot_select-area_20210102223120.png
    Code (Java):
    @EventHandler
      public void handleIncomingReport(PlayerInteractEvent event) {
        KelpPlayer player = playerRepository.getKelpPlayer(event.getPlayer());

        player.openAnvilPrompt()
          .sourceMaterial(KelpMaterial.NAME_TAG)
          .initialText("Enter nickname...")
          .withAsyncTimeout(30, TimeUnit.SECONDS,
            () -> player.sendMessage("§cYou timed out of the prompt"))
          .onClose(() -> player.sendMessage("§cYou exited the prompt manually."))
          .handle(input -> {
            if (input.length() > 16) {
              player.sendMessage("§cA name may not be longer than 16 chars!");
              return PromptResponseType.TRY_AGAIN;
            }

            player.sendMessage("§aYour nickname has been set!");
            return PromptResponseType.ACCEPTED;
          });

      }

    More demos will follow in the future, feel free to experiment with the features by yourself!


    installation.png

    Requirements:
    • Java 8 or higher
    • A server using Windows/Linux (MacOS not tested)
    • In the current pre-release version, only spigot server jars 1.8 is supported. In the near future, 1.9 - 1.16 will follow
    • Kelp has also been tested with PaperMC servers

    The installation of Kelp is pretty simple. At first, you need the latest "core"-Module file, which you can download from GitHub (the SpigotMC Download link will redirect you to the latest release on GitHub).

    • Drag that core module file into the normal "plugins" folder of your spigot server
    • Reload the server and wait for an error message to pop up and some new directories to create.
    • In your server's main folder you should now see a "kelp_versions" folder. Download the corresponding version implementation for your server from GitHub and put it into this folder.
    • Reload the server again. Kelp should now work properly. You can install any Kelp plugin by putting the .jar file in the "kelp_plugins" folder, not in the normal plugins folder of bukkit!

    wiki.png

    Kelp has a detailed wiki page for developers, which is constantly updated with the latest features. There you can find code examples and in-depth explanations of the different features and how kelp works under the hood.

    If you plan to use Kelp in your plugins, I recommend reading it:
    Kelp Wiki on GitHub

    If you encountered a bug with kelp or have a feature suggestion, please post it to the GitHub Issue Tracker so that we have a better overview in development. We also accept contributions / pull request to the plugin, so feel free to create one or contact me about this.

Recent Reviews

  1. Mher
    Mher
    5/5,
    Version: kelp-v0.4.0
    Nice framework there was a problem with dependency but the developer fix it so fast, keep up!!
    1. PXAV
      Author's Response
      Thank you for the review! Glad I could help, have you been able to successfully compile your project now? ^^
  2. hawkfalcon
    hawkfalcon
    5/5,
    Version: kelp-v0.2.0
    Can't wait to use this when it goes 1.0, looks great so far. Thanks for this utility!
    1. PXAV
      Author's Response
      Thank you for your positive review! We are working hard to push it to the 1.0 release as soon as possible.
  3. ComicHD
    ComicHD
    5/5,
    Version: kelp-v0.2.0
    I hope that in the future even more people will work for the future in Mincraft Development. So that something like this is standard.

    greetings from Frankfurt <3
    1. PXAV
      Author's Response
      Thank you, I appreciate the positive review! I definitely think that more people will be engaged in such projects in the future. The Spigot community still has unused potential that can be unlocked.
  4. adamk523
    adamk523
    5/5,
    Version: kelp-v0.1.1
    Not a developer, but really really hope this takes off, and maybe even becomes a standard part of most plugins. Updating to 1.13+ was a waking nightmare that could have been made so much easier with a framework like this to bridge the gap. Keep up the great work!
    1. PXAV
      Author's Response
      Yes, I totally agree! This might also encourage servers to upgrade to the newer versions because the plugins are upgrading automatically. Thank you for the review and the support.
  5. TaskID
    TaskID
    5/5,
    Version: kelp-v0.0.5
    Underrated. Completely underrated. But unfortunately, it's not that useful if not many people use it :(
    1. PXAV
      Author's Response
      Thank you for your review! I really appreciate the support in this early stage of the project. Hopefully more people start using it once the 1.0 release has been published :)