Skip to content

Implement multiverse generator plugin hook#506

Merged
duplexsystem merged 6 commits intoPolyhedralDev:masterfrom
benwoo1110:feat/multiverse-hook
Jun 17, 2025
Merged

Implement multiverse generator plugin hook#506
duplexsystem merged 6 commits intoPolyhedralDev:masterfrom
benwoo1110:feat/multiverse-hook

Conversation

@benwoo1110
Copy link
Copy Markdown
Contributor

Pull Request

Description

Fixes #46. Hooks into multiverse to provide basic information and tab complete with the correct packs install when using Terra with Multiverse-Core. Terra will always be initialized before multiverse, so I used PluginEnableEvent to hook into Multiverse-Core. I wasn't too sure where to put the event listener, I saw an existing CommonListener class already there, so I just added to that, hope that's fine!

Screenshot 2025-06-09 at 10 55 41 PM Screenshot 2025-06-09 at 10 57 16 PM

Changelog

  • Implement multiverse generator plugin hook

Checklist

Mandatory checks

  • The base branch of this PR is an unreleased version branch (that has a ver/ prefix)
    or is a branch that is intended to be merged into a version branch.
  • There are no already existing PRs that provide the same changes.
  • The PR is within the scope of Terra (i.e. is something a configurable terrain generator should be doing).
  • Changes follow the code style for this project.
  • I have read the CONTRIBUTING.md
    document in the root of the git repository.

Types of changes

  • Bug Fix
  • Build system
  • Documentation
  • New Feature
  • Performance
  • Refactoring
  • Repository
  • Revert
  • Style
  • Tests
  • Translation

Compatibility

  • Introduces a breaking change
  • Introduces new functionality in a backwards compatible way.
  • Introduces bug fixes

Documentation

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

Testing

  • I have added tests to cover my changes.
  • All new and existing tests passed.

Licensing

  • I am the original author of this code, and I am willing to
    release it under GPLv3.
  • I am not the original author of this code, but it is in public domain or
    released under GPLv3 or a compatible license.

Copy link
Copy Markdown
Member

@solonovamax solonovamax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not need to add

softdepend:
  - "Multiverse-Core"
loadbefore:
  - "Multiverse-Core"

to the plugin.yml?

without softdepend afaik the classloaders would be isolated & we wouldn't be able to load any multiverse classes, and without loadbefore afaik we would never receive the PluginEnableEvent (though I could be wrong on that last one)

Comment thread platforms/bukkit/common/build.gradle.kts
@solonovamax
Copy link
Copy Markdown
Member

Also, is there any way to customize the way that help menu shows? It would be nice to be able to do that (for example, making the url into an actual link, etc.), though I do also understand wanting to restrict the level of customization that is offered.

@benwoo1110
Copy link
Copy Markdown
Contributor Author

At least on papermc 1.21.5 that I tested, there is no issues with classloader (or not I won't have those tab-complete screenshots if it didn't load)

I am open to ideas on how you think can be done better in terms of customization (Terra is the first plugin using this api). As for the url, afaik it already works, see screenshot:
Screenshot 2025-06-10 at 12 00 09 PM

@solonovamax
Copy link
Copy Markdown
Member

solonovamax commented Jun 13, 2025

At least on papermc 1.21.5 that I tested, there is no issues with classloader (or not I won't have those tab-complete screenshots if it didn't load)

hmm, I was under the impression that there was classloader isolation between plugins

I am open to ideas on how you think can be done better in terms of customization (Terra is the first plugin using this api). As for the url, afaik it already works, see screenshot:
Screenshot 2025-06-10 at 12 00 09 PM

offering the ability to return adventure text components at a minimum would be great because then we could customize those how we wish

@benwoo1110
Copy link
Copy Markdown
Contributor Author

benwoo1110 commented Jun 13, 2025

Also, interesting idea on the adventure text components. I have been playing around with them tbh. The main issue is multiverse still need to support spigot and other older version, so we can't use the paper built in ones. Maybe we can shade it, but currently not the top priority list.

@solonovamax
Copy link
Copy Markdown
Member

solonovamax commented Jun 13, 2025

offering the ability to return adventure text components at a minimum would be great because then we could customize those how we wish

thinking about it a bit more: adventure text components are probably overkill.
Although, offering the ability to return a Component for the name & the example usages would be useful as for the name you could use a server-side translation & for the usage you could add tooltips where deemed necessary.
I would suggest the following changes to the api:

  • Collection<String> getExampleUsages() -> Collection<Component> getExampleUsages()
  • String getPluginName() -> Component getPluginName()
  • String getInfoLink() -> URL getInfoLink()

because 5.0 has already been release and you most likely don't want to break api, these can be added in one of two ways:

  1. add default methods:
    default Collection<Component> getExampleUsagesComponents() {
        return this.getExampleUsages().stream().map(Component::text);
    }
    
    default Collection<Component> getPluginNameComponent() {
        return Component.text(this.getPluginName());
    }
    
    default URL getInfoLinkUrl() {
        return URI.create(this.getInfoLink()).toURL();
    }
    and then create an interface GeneratorPluginComponent (or something, that name doesn't sound the best to me and it would definitely need to be refined) which extends GeneratorPlugin and stubs out getExampleUsages(), getPluginName(), and getInfoLink() with empty versions, and then makes it so getExampleUsagesComponents(), getPluginNameComponent(), and getInfoLinkUrl() no longer have a default implementation.
  2. do the inverse of the above where you have an interface GeneratorPluginComponent which provides the getExampleUsagesComponents(), getPluginNameComponent(), and getInfoLinkUrl() methods with no implementation and then GeneratorPlugin extends GeneratorPluginComponent and gives them default implementations

I would recommend changing the message format from

issuer.sendMessage(ChatColor.RESET + "Generator Plugin: " + generatorPlugin.getPluginName());
issuer.sendMessage(ChatColor.RESET + "Example usages: ");
issuer.sendMessage(ChatColor.RESET + StringFormatter.join(generatorPlugin.getExampleUsages(), "\n"));
issuer.sendMessage(ChatColor.RESET + "Link to more info: " + generatorPlugin.getInfoLink());

to

TextComponent message = Component.text(builder -> {
    builder.append(Component.text("Generator: "))
            .append(Component.text(generatorPlugin.getPluginName(), NamedTextColor.DARK_GREEN))
            .appendNewline()
            .appendNewline();

    builder.append(Component.text("Examples: "))
            .appendNewline();

    Style usageStyle = Style.style()
            .color(NamedTextColor.YELLOW)
            .hoverEvent(HoverEvent.showText(Component.text("Click to insert")))
            .build();

    for (String usage : generatorPlugin.getExampleUsages()) {
        builder.append(Component.text("- ", NamedTextColor.GRAY))
                .append(Component.text(usage, usageStyle).clickEvent(ClickEvent.suggestCommand(usage)))
                .appendNewline();
    }

    builder.appendNewline();

    String link = generatorPlugin.getInfoLink();

    Style style = Style.style()
            .color(NamedTextColor.BLUE)
            .decorate(TextDecoration.UNDERLINED)
            .clickEvent(ClickEvent.openUrl(link))
            .build();

    builder.append(Component.text("More info: "))
            .append(Component.text(link, style));
});

issuer.sendMessage(message);

if you want to play around with the message format in a more visual way, you can use the minimessage web viewer with the following input message:

Generator: <dark_green>Terra</dark_green>

Examples:
<gray>- </gray><yellow><click:suggest_command:'/mv create ex NORMAL -g Terra:overworld'><hover:show_text:'Click to insert'>/mv create ex NORMAL -g Terra:overworld</hover></click></yellow>
<gray>- </gray><yellow><click:suggest_command:'/mv create ex NORMAL -g Terra:tartarus'><hover:show_text:'Click to insert'>/mv create ex NORMAL -g Terra:tartarus</hover></click></yellow>

More info: <blue><u><click:open_url:'https://terra.polydev.org'>https://terra.polydev.org</click></u></blue>

@solonovamax
Copy link
Copy Markdown
Member

solonovamax commented Jun 13, 2025

The main issue is multiverse still need to support spigot and other older version, so we can't use the paper built in ones. Maybe we can shade it, but currently not the top priority list.

hmmm, I see

I noticed you're also using aikar's command framework, which I'm unsure if it supports sending adventure components

looking at the api quickly, I think you'd have to do something like issuer.getIssuer().sendMessage(message) so that you're sending it to bukkit's CommandSender rather than a BukkitCommandIssuer.

however, this would only apply to paper. (if you have any stats & see that only a very tiny % of people are using spigot & whatnot, you could always consider hard depending on paper, as there are several benefits to paper)
also I checked and since you're currently targetting 1.18.2 and onward, paper 1.18.2 does support adventure.

however if you want to use bukkit, you'd shade the core adventure library + adventure-platform-bukkit, and then you can use BukkitAudiences#sender(CommandSender) to get an Audience from the CommandSender. this could be integrated directly into your MVCommandIssuer class via an audience method. (or alternatively you could implement the ForwardingAudience.Single interface from your MVCommandIssuer class:

public class MVCommandIssuer extends BukkitCommandIssuer {

    private final MVCommandManager commandManager;
    private final Audience audience;

    MVCommandIssuer(@NotNull MVCommandManager commandManager, @NotNull CommandSender sender) {
        super(commandManager, sender);
        this.commandManager = commandManager;
        this.audience = sender instanceof Audience ? (Audience) sender : commandManager.getBukkitAudiences().sender(sender);
    }

    @Override
    public Audience audience() {
        return audience;
    }

    // ...
}

see here for how to get a BukkitAudiences.

@benwoo1110
Copy link
Copy Markdown
Contributor Author

Thanks for the ideas, if multiverse didn't need spigot support, using adventure will all be way easier lol. I will think about it, Im very close to just dropping spigot support tbh.

that being said - I think this pr is good enough as it is, as the main issue is to solve Terra not appearing at all in our generator list and tab-complete.

@duplexsystem duplexsystem merged commit 1d95e7a into PolyhedralDev:master Jun 17, 2025
@benwoo1110 benwoo1110 deleted the feat/multiverse-hook branch June 17, 2025 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Exchange knowledge of loaded packs with Multiverse

4 participants