Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*******************************************************************************
* Copyright 2018, 2021 Jorel Ali (Skepter) - MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/
package dev.jorel.commandapi;
import java.awt.Component;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.ParsedArgument;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import dev.jorel.commandapi.arguments.AbstractArgument;
import dev.jorel.commandapi.arguments.ArgumentSuggestions;
import dev.jorel.commandapi.arguments.CustomProvidedArgument;
import dev.jorel.commandapi.arguments.Literal;
import dev.jorel.commandapi.arguments.MultiLiteral;
import dev.jorel.commandapi.arguments.PreviewInfo;
import dev.jorel.commandapi.arguments.Previewable;
import dev.jorel.commandapi.commandsenders.AbstractCommandSender;
import dev.jorel.commandapi.executors.CommandArguments;
import dev.jorel.commandapi.executors.ExecutionInfo;
import dev.jorel.commandapi.preprocessor.RequireField;
import dev.jorel.commandapi.wrappers.PreviewableFunction;
/**
* The "brains" behind the CommandAPI.
* Handles command registration
*
* @param The implementation of AbstractArgument being used
* @param The class for running platform commands
* @param The class for running Brigadier commands
*/
@RequireField(in = CommandContext.class, name = "arguments", ofType = Map.class)
public class CommandAPIHandler
/// @endcond
, CommandSender, Source> {
private static final SafeVarHandle, Map>> commandContextArguments;
// Compute all var handles all in one go so we don't do this during main server
// runtime
static {
commandContextArguments = SafeVarHandle.ofOrNull(CommandContext.class, "arguments", "arguments", Map.class);
}
/**
* Returns the raw input for an argument for a given command context and its
* key. This effectively returns the string value that is currently typed for
* this argument
*
* @param the command source type
* @param cmdCtx the command context which is used to run this
* command
* @param key the node name for the argument
* @return the raw input string for this argument
*/
public static String getRawArgumentInput(CommandContext cmdCtx, String key) {
final ParsedArgument, ?> parsedArgument = commandContextArguments.get(cmdCtx).get(key);
// TODO: Issue #310: Parsing this argument via /execute run doesn't have the value in
// the arguments for this command context (most likely because it's a redirected command).
// We need to figure out how to handle this case.
if (parsedArgument != null) {
// Sanity check: See https://github.com/JorelAli/CommandAPI/wiki/Implementation-details#chatcomponentargument-raw-arguments
StringRange range = parsedArgument.getRange();
if (range.getEnd() > cmdCtx.getInput().length()) {
range = StringRange.between(range.getStart(), cmdCtx.getInput().length());
}
return range.get(cmdCtx.getInput());
} else {
return "";
}
}
// TODO: Need to ensure this can be safely "disposed of" when we're done (e.g. on reloads).
// I hiiiiiiighly doubt we're storing class caches of classes that can be unloaded at runtime,
// but this IS a generic class caching system and we don't want derpy memory leaks
private static final Map FIELDS = new HashMap<>();
final CommandAPIPlatform platform;
final TreeMap registeredPermissions = new TreeMap<>();
final List registeredCommands; // Keep track of what has been registered for type checking
final Map, Previewable, ?>> previewableArguments; // Arguments with previewable chat
static final Pattern NAMESPACE_PATTERN = Pattern.compile("[0-9a-z_.-]+");
private static CommandAPIHandler, ?, ?> instance;
protected CommandAPIHandler(CommandAPIPlatform platform) {
this.platform = platform;
this.registeredCommands = new ArrayList<>();
this.previewableArguments = new HashMap<>();
CommandAPIHandler.instance = this;
}
public void onLoad(CommandAPIConfig> config) {
checkDependencies();
platform.onLoad(config);
}
private void checkDependencies() {
// Check for common dependencies
try {
Class.forName("com.mojang.brigadier.CommandDispatcher");
} catch (ClassNotFoundException e) {
new ClassNotFoundException("Could not hook into Brigadier (Are you running Minecraft 1.13 or above?)")
.printStackTrace();
}
}
public void onEnable() {
platform.onEnable();
}
public void onDisable() {
platform.onDisable();
CommandAPIHandler.resetInstance();
}
private static void resetInstance() {
CommandAPIHandler.instance = null;
}
public static CommandAPIHandler, ?, ?> getInstance() {
if(CommandAPIHandler.instance != null) {
return CommandAPIHandler.instance;
} else {
throw new IllegalStateException("Tried to access CommandAPIHandler instance, but it was null! Are you using CommandAPI features before calling CommandAPI#onLoad?");
}
}
public CommandAPIPlatform getPlatform() {
return this.platform;
}
/**
* Generates a command to be registered by the CommandAPI.
*
* @param args set of ordered argument pairs which contain the prompt text
* and their argument types
* @param executor code to be ran when the command is executed
* @param converted True if this command is being converted from another plugin, and false otherwise
* @return a brigadier command which is registered internally
* @throws CommandSyntaxException if an error occurs when the command is ran
*/
Command generateCommand(Argument[] args, CommandAPIExecutor> executor, boolean converted) {
// Generate our command from executor
return cmdCtx -> {
AbstractCommandSender extends CommandSender> sender = platform.getSenderForCommand(cmdCtx, executor.isForceNative());
CommandArguments commandArguments = argsToCommandArgs(cmdCtx, args);
ExecutionInfo> executionInfo = new ExecutionInfo<>() {
@Override
public CommandSender sender() {
return sender.getSource();
}
@Override
public AbstractCommandSender extends CommandSender> senderWrapper() {
return sender;
}
@Override
public CommandArguments args() {
return commandArguments;
}
};
if (converted) {
int resultValue = 0;
// Return a String[] of arguments for converted commands
String[] argsAndCmd = cmdCtx.getRange().get(cmdCtx.getInput()).split(" ");
String[] result = new String[argsAndCmd.length - 1];
ExecutionInfo> convertedExecutionInfo = new ExecutionInfo<>() {
@Override
public CommandSender sender() {
return sender.getSource();
}
@Override
public AbstractCommandSender extends CommandSender> senderWrapper() {
return sender;
}
@Override
public CommandArguments args() {
return new CommandArguments(result, new LinkedHashMap<>(), result, new LinkedHashMap<>(), "/" + cmdCtx.getInput());
}
};
System.arraycopy(argsAndCmd, 1, result, 0, argsAndCmd.length - 1);
// As stupid as it sounds, it's more performant and safer to use
// a List>[] instead of a List>, due to NPEs and AIOOBEs.
@SuppressWarnings("unchecked")
List[] entityNamesForArgs = new List[args.length];
for (int i = 0; i < args.length; i++) {
entityNamesForArgs[i] = args[i].getEntityNames(commandArguments.get(i));
}
List> product = CartesianProduct.getDescartes(Arrays.asList(entityNamesForArgs));
// These objects in obj are List
for (List strings : product) {
// We assume result.length == strings.size
if (result.length == strings.size()) {
for (int i = 0; i < result.length; i++) {
if (strings.get(i) != null) {
result[i] = strings.get(i);
}
}
}
resultValue += executor.execute(convertedExecutionInfo);
}
return resultValue;
} else {
return executor.execute(executionInfo);
}
};
}
/**
* Converts the List<Argument> into a {@link CommandArguments} for command execution
*
* @param cmdCtx the command context that will execute this command
* @param args the map of strings to arguments
* @return an CommandArguments object which can be used in (sender, args) ->
* @throws CommandSyntaxException
*/
CommandArguments argsToCommandArgs(CommandContext cmdCtx, Argument[] args)
throws CommandSyntaxException {
// Array for arguments for executor
List