Code Patterns

Copy-paste examples for common plugin tasks. Commands, events, ECS, GUI, and more.

← Back to Patterns
command

Async Command with GUI

Create async commands that open custom GUIs. Use CompletableFuture.runAsync with world executor.

Example Code

java
public class MenuCommand extends AbstractAsyncCommand {

    public MenuCommand() {
        super("menu", "Opens the menu GUI");
        this.requirePermission("myplugin.menu");
    }

    @Override
    protected CompletableFuture<Void> executeAsync(CommandContext context) {
        CommandSender sender = context.sender();

        if (sender instanceof Player player) {
            Ref<EntityStore> ref = player.getReference();

            if (ref != null && ref.isValid()) {
                Store<EntityStore> store = ref.getStore();
                World world = store.getExternalData().getWorld();

                return CompletableFuture.runAsync(() -> {
                    PlayerRef playerRef = store.getComponent(ref, PlayerRef.getComponentType());
                    player.getPageManager().openCustomPage(
                        ref, store,
                        new MyMenuGui(playerRef, CustomPageLifetime.CanDismiss)
                    );
                }, world);  // Run on world executor
            }
        }

        return CompletableFuture.completedFuture(null);
    }
}

Thread Safety

Use CompletableFuture.runAsync(lambda, world) to run on world thread.

Common Mistakes

Opening GUI outside world executor. Not checking ref.isValid().