Skip to content

Context Providers

Redempt edited this page Apr 9, 2021 · 6 revisions

Sometimes a command needs more context than just the arguments the player passed. And sometimes this results in a lot of needlessly copy-pasted code. For example, you might need to get the item the player is holding. You would need to retrieve this, ensure it's not null, and send the player a message if it is. Command manager saves you from having to do that.

Similarly to ArgType, you can create a ContextProvider which will provide that context and send an error message if it's not available. Let's assume you need to get the team the player is on, and you have a Team class already made:

ContextProvider<Team> teamProvider = new ContextProvider<>("team",
	ChatColor.RED + "You are not on a team!",
	Team::getTeam);

The first argument there is the name of the context provider. The second is the error message that will be shown to players if the ContextProvider returns null, and the third is a Function<Player, T> with T being the type being provided. Note that it takes a Player, meaning commands that use context providers may only be run by players. Now that you've created a ContextProvider, you have to register it with the CommandParser, just like ArgType:

new CommandParser(this.getResource("command.rdcml"))
	.setContextProviders(teamProvider)
	.parse().register("prefix", this);

And once you've done that, you're ready to specify it in your command file:

tchat string...:message {
	help Sends a message to your team
	user player
	context team
	hook tchat
}

After specifying it in the command file, you can take it as an argument in your command hook:

@CommandHook("tchat")
public void teamChat(Player sender, String message, Team team) {
	team.broadcast(sender.getName() + ": " + message);
}

You must always take all context arguments after all command arguments. You can use multiple context arguments in a single command by simply separating them with a space, then taking them in the same order you listed them in your command hook method. If Team.getTeam(sender) returns null, then the command hook method will not be called, and the player will be shown the ContextProvider's error message instead.

Sometimes, though, you just want to make sure that a condition is true before the command can be run. An example is that you might want to ensure a player is within a certain area when running the command, or has a certain item in their inventory. However, you don't actually need to do anything with this data after ensuring its presence. If you wanted to ensure that the player is on a team, but don't need to do anything with the Team object, you can use the assert tag instead of context in your command file:

commandname {
	hook hookname
	assert team
}

Now, the command manager will ensure that the Team context provider doesn't return null before executing your method hook. If it is null, the player will be shown the error message in the context provider. Since you're asserting this condition rather than requesting it as context, you don't need to take it as an argument in your command hook method.

A helpful method for creating ContextProviders which are mainly intended for assertion is ContextProvider.assertProvider. It takes a name and a Predicate<Player>, and spits out a ContextProvider<Player, Boolean> which will return true if the condition passes, and null otherwise. If you wanted to ensure a player is above Y=100 when running your command, you could create a ContextProvider like this:

ContextProvider.assertProvider("altitude", p -> p.getLocation().getY() > 100);

The last way that context providers can be used is to supply default values for optional arguments. By default, there is one context provider included called self, which will reference the player who ran the command. This is only useful for this case:

give player:target?(context self) int:amount?(1) {
	help Gives you the coolest item
	hook give
}

Here, the target will be assumed to be the command sender if it is not passed. If this command is run from console and the target argument is not supplied, console will be shown an error stating that it must be provided, since context providers can only be used for players.

Clone this wiki locally