Skip to content

Context Providers

Redempt edited this page Aug 20, 2022 · 2 revisions

Context providers allow you to pass in context about the sender or environment, potentially doing checks first - essentially, arguments that don't get parsed from command input. There is one provided by default, self, which just returns the sender. This may not seem particularly useful at first, but we'll get to it later.

To define a context provider, you can just call ContextProvider.create, then call CommandParser#addContextProviders:

SpigotCommandManager.getInstance(this).getParser()
	.addContextProviders(ContextProvider.create("world", "You are not in a world!", Player::getWorld))
	...

Worth noting here is that each context provider must include an error to be shown to the user if the context provider returns null. Since Player#getWorld can never return null, it would be safe to pass null in this context, but the error message is included for clarity. To use this context provider, you just use the context tag in your command file:

example {
	context = world
	hook = example
}

Now, the context will be passed as a parameter to the method hook, prior to all other arguments. But there are several other ways to use context providers that make them much more useful. If you want to use multiple context providers in one command, you can simply separate them with a space in the context tag.

The first useful way to use context providers is as asserters. It's often not especially useful to get a property we already know is on the sender, since you could do that from your method hook anyways. But if you need to assert something about the command's execution context, you can use context providers for that. Let's say you wanted to create an assertion that made sure only players in creative mode could run the command. You could create the asserter with ContextProvider.asserter, which will return true if the condition passes and null otherwise to show the error:

ContextProvider.asserter("creative", "You must be in creative mode to use this command!", ctx -> ctx.sender() instanceof Player player && player.getGameMode() == GameMode.CREATIVE)

Which is used in the command file like this:

example {
	assert = creative
	hook = example
}

Now, when the command is run, if the player is not in creative mode, they will be shown an error message.

The other way to use context providers is even more useful: You can use them to supply default values for optional arguments. You do this much like the normal way of specifying a default value, except using context followed by the name of the context provider as the default. Suddenly, our world provider has become much more useful:

info world:world?(context world) {
	help = Gets info about the given world
	hook = worldInfo
}

Assuming we registered it, this will use the world context provider to supply the default value if the sender does not specify it.

Clone this wiki locally