Skip to content
This repository was archived by the owner on Feb 27, 2024. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SpongeAPI
Submodule SpongeAPI updated 61 files
+1 −1 build.gradle
+2 −2 gradle/java.gradle
+2 −2 gradle/wrapper/gradle-wrapper.properties
+10 −8 src/main/java/org/spongepowered/api/GameRegistry.java
+2 −2 src/main/java/org/spongepowered/api/data/DataHolder.java
+70 −0 src/main/java/org/spongepowered/api/data/DataManipulatorBuilder.java
+62 −0 src/main/java/org/spongepowered/api/data/DataManipulatorRegistry.java
+3 −3 src/main/java/org/spongepowered/api/entity/player/Player.java
+11 −9 src/main/java/org/spongepowered/api/event/SpongeEventFactory.java
+4 −3 src/main/java/org/spongepowered/api/event/inventory/ItemDropEvent.java
+19 −0 src/main/java/org/spongepowered/api/event/message/CommandEvent.java
+28 −8 src/main/java/org/spongepowered/api/service/command/CommandService.java
+88 −58 src/main/java/org/spongepowered/api/service/command/SimpleCommandService.java
+65 −0 src/main/java/org/spongepowered/api/service/command/TranslationPlaceholder.java
+50 −0 src/main/java/org/spongepowered/api/util/StartsWithPredicate.java
+100 −0 src/main/java/org/spongepowered/api/util/TextMessageException.java
+31 −18 src/main/java/org/spongepowered/api/util/command/CommandCallable.java
+7 −21 src/main/java/org/spongepowered/api/util/command/CommandException.java
+60 −0 src/main/java/org/spongepowered/api/util/command/CommandMessageFormatting.java
+62 −0 src/main/java/org/spongepowered/api/util/command/CommandPermissionException.java
+211 −0 src/main/java/org/spongepowered/api/util/command/CommandResult.java
+2 −2 src/main/java/org/spongepowered/api/util/command/ImmutableCommandMapping.java
+0 −129 src/main/java/org/spongepowered/api/util/command/InvalidUsageException.java
+4 −28 src/main/java/org/spongepowered/api/util/command/InvocationCommandException.java
+65 −0 src/main/java/org/spongepowered/api/util/command/TranslationPlaceholder.java
+122 −0 src/main/java/org/spongepowered/api/util/command/args/ArgumentParseException.java
+189 −0 src/main/java/org/spongepowered/api/util/command/args/ChildCommandElementExecutor.java
+216 −0 src/main/java/org/spongepowered/api/util/command/args/CommandArgs.java
+115 −0 src/main/java/org/spongepowered/api/util/command/args/CommandContext.java
+122 −0 src/main/java/org/spongepowered/api/util/command/args/CommandElement.java
+395 −0 src/main/java/org/spongepowered/api/util/command/args/CommandFlags.java
+1,148 −0 src/main/java/org/spongepowered/api/util/command/args/GenericArguments.java
+104 −0 src/main/java/org/spongepowered/api/util/command/args/PatternMatchingCommandElement.java
+65 −0 src/main/java/org/spongepowered/api/util/command/args/TranslationPlaceholder.java
+1 −1 src/main/java/org/spongepowered/api/util/command/args/package-info.java
+43 −0 src/main/java/org/spongepowered/api/util/command/args/parsing/InputTokenizer.java
+64 −0 src/main/java/org/spongepowered/api/util/command/args/parsing/InputTokenizers.java
+144 −0 src/main/java/org/spongepowered/api/util/command/args/parsing/QuotedStringTokenizer.java
+8 −10 src/main/java/org/spongepowered/api/util/command/args/parsing/RawStringInputTokenizer.java
+74 −0 src/main/java/org/spongepowered/api/util/command/args/parsing/SingleArg.java
+48 −0 src/main/java/org/spongepowered/api/util/command/args/parsing/SpaceSplitInputTokenizer.java
+71 −0 src/main/java/org/spongepowered/api/util/command/args/parsing/TokenizerState.java
+25 −0 src/main/java/org/spongepowered/api/util/command/args/parsing/package-info.java
+45 −0 src/main/java/org/spongepowered/api/util/command/dispatcher/Disambiguator.java
+18 −3 src/main/java/org/spongepowered/api/util/command/dispatcher/Dispatcher.java
+157 −110 src/main/java/org/spongepowered/api/util/command/dispatcher/SimpleDispatcher.java
+65 −0 src/main/java/org/spongepowered/api/util/command/dispatcher/TranslationPlaceholder.java
+1 −19 src/main/java/org/spongepowered/api/util/command/source/CommandBlockSource.java
+20 −13 src/main/java/org/spongepowered/api/util/command/source/LocatedSource.java
+11 −19 src/main/java/org/spongepowered/api/util/command/spec/CommandExecutor.java
+369 −0 src/main/java/org/spongepowered/api/util/command/spec/CommandSpec.java
+65 −0 src/main/java/org/spongepowered/api/util/command/spec/TranslationPlaceholder.java
+25 −0 src/main/java/org/spongepowered/api/util/command/spec/package-info.java
+0 −7 src/main/java/org/spongepowered/api/world/Dimension.java
+15 −0 src/main/java/org/spongepowered/api/world/Location.java
+26 −9 src/main/java/org/spongepowered/api/world/gen/WorldGeneratorModifier.java
+67 −0 src/test/java/org/spongepowered/api/util/command/ChildCommandsTest.java
+67 −0 src/test/java/org/spongepowered/api/util/command/CommandSpecTest.java
+76 −0 src/test/java/org/spongepowered/api/util/command/args/CommandFlagsTest.java
+206 −0 src/test/java/org/spongepowered/api/util/command/args/GenericArgumentsTest.java
+100 −0 src/test/java/org/spongepowered/api/util/command/args/parsing/QuotedStringParserTest.java
6 changes: 3 additions & 3 deletions src/main/java/org/spongepowered/mod/SpongeCoremod.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ public class SpongeCoremod implements IFMLLoadingPlugin {
public SpongeCoremod() {
// Let's get this party started
MixinBootstrap.init();

// Add pre-init mixins
MixinEnvironment.getEnvironment(Phase.PREINIT)
.addConfiguration("mixins.sponge.base.json");

// Add default mixins
MixinEnvironment.getDefaultEnvironment()
.addConfiguration("mixins.sponge.core.json")
Expand All @@ -53,7 +53,7 @@ public SpongeCoremod() {
Launch.classLoader.addClassLoaderExclusion("org.spongepowered.api.event.cause.CauseTracked");
Launch.classLoader.addClassLoaderExclusion("org.spongepowered.api.event.Cancellable");
Launch.classLoader.addClassLoaderExclusion("org.spongepowered.api.util.event.callback.CallbackList");

// Transformer exclusions
Launch.classLoader.addTransformerExclusion("ninja.leaping.configurate.");
Launch.classLoader.addTransformerExclusion("org.apache.commons.lang3.");
Expand Down
9 changes: 4 additions & 5 deletions src/main/java/org/spongepowered/mod/SpongeMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.event.FMLServerStoppedEvent;
import net.minecraftforge.fml.relauncher.Side;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.objectweb.asm.Type;
import org.spongepowered.api.Game;
import org.spongepowered.api.plugin.Plugin;
Expand All @@ -68,7 +68,7 @@
import org.spongepowered.api.world.DimensionType;
import org.spongepowered.mod.command.CommandSponge;
import org.spongepowered.mod.command.MinecraftCommandWrapper;
import org.spongepowered.mod.event.SpongeEventBus;
import org.spongepowered.mod.command.SpongeCommandDisambiguator;
import org.spongepowered.mod.event.SpongeEventHooks;
import org.spongepowered.mod.guice.SpongeGuiceModule;
import org.spongepowered.mod.interfaces.IMixinServerCommandManager;
Expand Down Expand Up @@ -113,9 +113,8 @@ public SpongeMod() {
this.game = this.spongeInjector.getInstance(Game.class);
this.registry = (SpongeGameRegistry) this.game.getRegistry();
try {
SimpleCommandService commandService = new SimpleCommandService(this.game.getPluginManager());
SimpleCommandService commandService = new SimpleCommandService(this.game, new SpongeCommandDisambiguator(this.game));
this.game.getServiceManager().setProvider(this, CommandService.class, commandService);
((SpongeEventBus) this.game.getEventManager()).register(this, commandService);
} catch (ProviderExistsException e) {
logger.warn("Non-Sponge CommandService already registered: " + e.getLocalizedMessage());
}
Expand All @@ -137,6 +136,7 @@ public SpongeMod() {
} catch (ProviderExistsException e2) {
logger.warn("Non-Sponge SerializationService already registered: " + e2.getLocalizedMessage());
}
this.game.getCommandDispatcher().register(this, CommandSponge.getCommand(this), "sponge", "sp");
}

@Override
Expand Down Expand Up @@ -238,7 +238,6 @@ public void onServerStarting(FMLServerStartingEvent e) {
try {
// Register vanilla-style commands (if necessary -- not necessary on client)
((IMixinServerCommandManager) MinecraftServer.getServer().getCommandManager()).registerEarlyCommands(this.game);
e.registerServerCommand(new CommandSponge());
} catch (Throwable t) {
this.controller.errorOccurred(this, t);
}
Expand Down
582 changes: 264 additions & 318 deletions src/main/java/org/spongepowered/mod/command/CommandSponge.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
*/
package org.spongepowered.mod.command;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandHandler;
import net.minecraft.command.CommandResultStats;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.PlayerSelector;
Expand All @@ -36,11 +36,13 @@
import net.minecraftforge.fml.common.ModContainer;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.Texts;
import org.spongepowered.api.text.format.TextColors;
import org.spongepowered.api.text.translation.Translation;
import org.spongepowered.api.util.command.CommandCallable;
import org.spongepowered.api.util.command.CommandException;
import org.spongepowered.api.util.command.CommandPermissionException;
import org.spongepowered.api.util.command.CommandResult;
import org.spongepowered.api.util.command.CommandSource;
import org.spongepowered.api.util.command.InvocationCommandException;
import org.spongepowered.mod.SpongeMod;

import java.util.List;
Expand All @@ -54,63 +56,67 @@ public class MinecraftCommandWrapper implements CommandCallable {
private final ModContainer activeMod;
private final ICommand command;

public MinecraftCommandWrapper(ModContainer activeMod, ICommand command) {
public MinecraftCommandWrapper(final ModContainer activeMod, final ICommand command) {
this.activeMod = activeMod;
this.command = command;
}

private static ICommandSender sourceToSender(CommandSource source) {
return source instanceof ICommandSender ? (ICommandSender) source : new WrapperICommandSender(source);
}

private String[] splitArgs(String arguments) {
return arguments.isEmpty() ? new String[0] : arguments.split(" +");
}

@Override
public boolean call(CommandSource source, String arguments, List<String> parents) throws CommandException {
public Optional<CommandResult> process(CommandSource source, String arguments) throws CommandException {

if (!testPermission(source)) {
throw new CommandPermissionException(Texts.of(SpongeMod.instance.getGame().getRegistry()
.getTranslationById(TRANSLATION_NO_PERMISSION).get()));
}

CommandHandler handler = (CommandHandler) MinecraftServer.getServer().getCommandManager();
final ICommandSender mcSender = source instanceof ICommandSender ? (ICommandSender) source : new WrapperICommandSender(source);
final String[] args = splitArgs(arguments);
int usernameIndex = handler.getUsernameIndex(this.command, args);
final ICommandSender mcSender = sourceToSender(source);
final String[] splitArgs = splitArgs(arguments);
int usernameIndex = handler.getUsernameIndex(this.command, splitArgs);
int successCount = 0;


// Below this is copied from CommandHandler.execute. This might need to be updated between versions.
if (testPermission(source)) {
net.minecraftforge.event.CommandEvent event = new net.minecraftforge.event.CommandEvent(this.command, mcSender, args);
if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event)) {
if (event.exception != null) {
com.google.common.base.Throwables.propagateIfPossible(event.exception);
}
return false;
net.minecraftforge.event.CommandEvent event = new net.minecraftforge.event.CommandEvent(this.command, mcSender, splitArgs);
if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event)) {
if (event.exception != null) {
throw new InvocationCommandException(Texts.of("Error while firing Forge event"), event.exception);
}
return Optional.of(CommandResult.empty());
}
int affectedEntities = 1;
if (usernameIndex > -1) {
@SuppressWarnings("unchecked")
List<Entity> list = PlayerSelector.matchEntities(mcSender, splitArgs[usernameIndex], Entity.class);
String previousNameVal = splitArgs[usernameIndex];
affectedEntities = list.size();

if (usernameIndex > -1) {
@SuppressWarnings("unchecked")
List<Entity> list = PlayerSelector.matchEntities(mcSender, args[usernameIndex], Entity.class);
String previousNameVal = args[usernameIndex];
mcSender.setCommandStat(CommandResultStats.Type.AFFECTED_ENTITIES, list.size());

for (Entity entity : list) {
args[usernameIndex] = entity.getUniqueID().toString();

if (handler.tryExecute(mcSender, args, this.command, arguments)) {
++successCount;
}
}
args[usernameIndex] = previousNameVal;
} else {
mcSender.setCommandStat(CommandResultStats.Type.AFFECTED_ENTITIES, 1);
for (Entity entity : list) {
splitArgs[usernameIndex] = entity.getUniqueID().toString();

if (handler.tryExecute(mcSender, args, this.command, arguments)) {
if (handler.tryExecute(mcSender, splitArgs, this.command, arguments)) {
++successCount;
}
}
splitArgs[usernameIndex] = previousNameVal;
} else {
source.sendMessage(Texts
.builder(SpongeMod.instance.getGame().getRegistry().getTranslationById(TRANSLATION_NO_PERMISSION).get(), new Object[0])
.color(TextColors.RED)
.build());
if (handler.tryExecute(mcSender, splitArgs, this.command, arguments)) {
++successCount;
}
}

mcSender.setCommandStat(CommandResultStats.Type.SUCCESS_COUNT, successCount);
return successCount > 0;
return Optional.of(CommandResult.builder()
.affectedEntities(affectedEntities)
.successCount(successCount)
.build());
}

public int getPermissionLevel() {
Expand All @@ -121,6 +127,10 @@ public String getCommandPermission() {
return this.activeMod.getModId().toLowerCase() + ".command." + this.command.getCommandName();
}

public ModContainer getMod() {
return this.activeMod;
}

@Override
public boolean testPermission(CommandSource source) {
if (source instanceof ICommandSender) {
Expand All @@ -131,31 +141,31 @@ public boolean testPermission(CommandSource source) {
}

@Override
public String getShortDescription(CommandSource source) {
return null;
public Optional<Text> getShortDescription(CommandSource source) {
return Optional.absent();
}

@Override
public Text getHelp(CommandSource source) {
return null;
public Optional<Text> getHelp(CommandSource source) {
return Optional.absent();
}

@Override
public String getUsage(CommandSource source) {
final ICommandSender mcSender = source instanceof ICommandSender ? (ICommandSender) source : new WrapperICommandSender(source);
return this.command.getCommandUsage(mcSender);
public Text getUsage(CommandSource source) {
final ICommandSender mcSender =
source instanceof ICommandSender ? (ICommandSender) source : new WrapperICommandSender(source);
String usage = this.command.getCommandUsage(mcSender);
if (usage.startsWith("/") && usage.contains(" ")) {
usage = usage.substring(usage.indexOf(" "));
}
return Texts.of(SpongeMod.instance.getGame().getRegistry().getTranslationById(usage).get());
}

@Override
@SuppressWarnings("unchecked")
public List<String> getSuggestions(CommandSource source, String arguments) throws CommandException {
return this.command.addTabCompletionOptions((ICommandSender) source, splitArgs(arguments), null);
}

public ModContainer getMod() {
return this.activeMod;
}

@SuppressWarnings("unchecked")
public List<String> getNames() {
return ImmutableList.<String>builder().add(this.command.getCommandName()).addAll(this.command.getCommandAliases()).build();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* This file is part of Sponge, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* 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 org.spongepowered.mod.command;

import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import org.spongepowered.api.Game;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.util.annotation.NonnullByDefault;
import org.spongepowered.api.util.command.CommandMapping;
import org.spongepowered.api.util.command.CommandSource;
import org.spongepowered.api.util.command.dispatcher.Disambiguator;
import org.spongepowered.api.util.command.dispatcher.SimpleDispatcher;
import org.spongepowered.mod.SpongeMod;
import org.spongepowered.mod.mixin.plugin.CoreMixinPlugin;

import java.util.List;
import java.util.Set;

public class SpongeCommandDisambiguator implements Disambiguator {
private final Game game;

/**
* Disambiguator that takes preferences from the global configuration, falling back to {@link SimpleDispatcher#FIRST_DISAMBIGUATOR}.
*
* @param game The game instance to be used
*/
public SpongeCommandDisambiguator(Game game) {
this.game = game;
}

@Override
@NonnullByDefault
public Optional<CommandMapping> disambiguate(CommandSource source, String aliasUsed, List<CommandMapping> availableOptions) {
if (availableOptions.size() > 1) {
final String chosenPlugin = CoreMixinPlugin.getGlobalConfig().getConfig().getCommands().getAliases().get(aliasUsed.toLowerCase());
if (chosenPlugin != null) {
Optional<PluginContainer> container = this.game.getPluginManager().getPlugin(chosenPlugin);
if (!container.isPresent()) {
SpongeMod.instance.getLogger().warn("Unable to find plugin '" + chosenPlugin + "' for command '" + aliasUsed + "', falling back"
+ " to default");
} else {
final Set<CommandMapping> ownedCommands = this.game.getCommandDispatcher().getOwnedBy(container.get());
final List<CommandMapping> ownedMatchingCommands = ImmutableList.copyOf(Iterables.filter(availableOptions,
Predicates.in(ownedCommands)));
if (ownedMatchingCommands.isEmpty()) {
SpongeMod.instance.getLogger().warn("Plugin " + container.get().getName() + " was specified as the preferred owner for "
+ aliasUsed + ", but does not have any such command!");
} else if (ownedMatchingCommands.size() > 1) {
throw new IllegalStateException("Plugin " + container.get().getName() + " seems to have multiple commands registered as "
+ aliasUsed + "! This is a programming error!");
} else {
return Optional.of(ownedMatchingCommands.get(0));
}

}
}
}
return SimpleDispatcher.FIRST_DISAMBIGUATOR.disambiguate(source, aliasUsed, availableOptions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,12 @@
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.Entity;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import org.spongepowered.api.text.Texts;
import org.spongepowered.api.util.command.CommandSource;
import org.spongepowered.mod.text.SpongeChatComponent;
import org.spongepowered.mod.text.SpongeText;

/**
* Wrapper around a CommandSource that is not part of the base game to allow it to access MC commands.
Expand All @@ -53,7 +52,7 @@ public String getCommandSenderName() {

@Override
public IChatComponent getDisplayName() {
return ((SpongeText) Texts.of(this.source.getName())).toComponent();
return new ChatComponentText(this.source.getName());
}

@Override
Expand All @@ -68,12 +67,12 @@ public boolean canCommandSenderUseCommand(int permLevel, String commandName) {

@Override
public BlockPos getPosition() {
return null;
return BlockPos.ORIGIN;
}

@Override
public Vec3 getPositionVector() {
return null;
return new Vec3(0, 0, 0);
}

@Override
Expand Down
Loading