Initial command registration setup. Pretty hacky, subcommands do not work, some arguments missing.

This commit is contained in:
Kenzie Togami 2019-03-04 18:31:20 -08:00
parent a0f127813d
commit 9ee0f00030
No known key found for this signature in database
GPG Key ID: 5D200B325E157A81
9 changed files with 153 additions and 95 deletions

View File

@ -14,7 +14,7 @@ buildscript {
apply plugin: 'net.minecraftforge.gradle'
def minecraftVersion = "1.13.2"
def forgeVersion = "25.0.34"
def forgeVersion = "25.0.70"
dependencies {
compile project(':worldedit-core')

View File

@ -19,60 +19,123 @@
package com.sk89q.worldedit.forge;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.util.command.CommandMapping;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.server.MinecraftServer;
import com.sk89q.worldedit.util.command.Parameter;
import net.minecraft.command.CommandSource;
import net.minecraft.entity.player.EntityPlayerMP;
import java.util.Arrays;
import java.util.List;
import java.util.LinkedList;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer;
import static net.minecraft.command.Commands.argument;
import static net.minecraft.command.Commands.literal;
public class CommandWrapper extends CommandBase {
private CommandMapping command;
public class CommandWrapper {
protected CommandWrapper(CommandMapping command) {
this.command = command;
}
public static void register(CommandDispatcher<CommandSource> dispatcher, CommandMapping command) {
LiteralArgumentBuilder<CommandSource> base = literal(command.getPrimaryAlias());
LinkedList<ArgumentBuilder<CommandSource, ?>> parameterStack = new LinkedList<>();
LinkedList<ArgumentBuilder<CommandSource, ?>> optionalParameterStack = new LinkedList<>();
boolean hasFlag = false;
for (Parameter parameter : command.getDescription().getParameters()) {
if (parameter.isValueFlag()) {
if (!hasFlag) {
hasFlag = true;
optionalParameterStack.push(argument("flags", StringArgumentType.string()));
}
} else if (parameter.isOptional()) {
optionalParameterStack.push(argument(parameter.getName(), StringArgumentType.string()));
} else {
parameterStack.push(argument(parameter.getName(), StringArgumentType.string()));
}
}
@Override
public String getName() {
return command.getPrimaryAlias();
}
@Override
public List<String> getAliases() {
return Arrays.asList(command.getAllAliases());
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
}
@Override
public String getUsage(ICommandSender icommandsender) {
return "/" + command.getPrimaryAlias() + " " + command.getDescription().getUsage();
}
@Override
public int getRequiredPermissionLevel() {
return 0;
}
@Override
public boolean checkPermission(MinecraftServer server, ICommandSender sender) {
return true;
}
@Override
public int compareTo(@Nullable ICommand o) {
if (o == null) {
return 0;
ArgumentBuilder<CommandSource, ?> argument = buildChildNodes(parameterStack, optionalParameterStack, command);
if (argument != null) {
base.then(argument);
} else {
return super.compareTo(o);
base.executes(commandFor(command));
}
LiteralCommandNode<CommandSource> registered =
dispatcher.register(
base.requires(requirementsFor(command))
);
for (String alias : command.getAllAliases()) {
dispatcher.register(
literal(alias).redirect(registered)
);
}
}
/**
* Make the appropriate {@code then()} and {@code execute()} calls to emulate required and
* optional parameters, given the argument orders.
*
* @param parameterStack required parameters
* @param optionalParameterStack optional parameters
* @return the node with all calls chained
*/
private static ArgumentBuilder<CommandSource, ?> buildChildNodes(LinkedList<ArgumentBuilder<CommandSource, ?>> parameterStack,
LinkedList<ArgumentBuilder<CommandSource, ?>> optionalParameterStack,
CommandMapping mapping) {
ArgumentBuilder<CommandSource, ?> currentChild = null;
Command<CommandSource> command = commandFor(mapping);
while (!optionalParameterStack.isEmpty()) {
ArgumentBuilder<CommandSource, ?> next = optionalParameterStack.removeLast();
if (currentChild != null) {
next.then(currentChild.executes(command));
}
currentChild = next;
}
boolean requiredExecute = false;
while (!parameterStack.isEmpty()) {
ArgumentBuilder<CommandSource, ?> next = parameterStack.removeLast();
if (currentChild != null) {
next.then(currentChild);
}
if (!requiredExecute) {
// first required parameter also gets execute
requiredExecute = true;
next.executes(command);
}
currentChild = next;
}
return currentChild;
}
private static Command<CommandSource> commandFor(CommandMapping mapping) {
return ctx -> {
EntityPlayerMP player = ctx.getSource().asPlayer();
if (player.world.isRemote()) {
return 0;
}
WorldEdit.getInstance().getEventBus().post(new CommandEvent(
adaptPlayer(player),
ctx.getRange().get(ctx.getInput())
));
return 1;
};
}
private static Predicate<CommandSource> requirementsFor(CommandMapping mapping) {
return ctx -> {
ForgePermissionsProvider permsProvider = ForgeWorldEdit.inst.getPermissionsProvider();
return ctx.getEntity() instanceof EntityPlayerMP &&
mapping.getDescription().getPermissions().stream()
.allMatch(perm -> permsProvider.hasPermission(
(EntityPlayerMP) ctx.getEntity(), perm
));
};
}
}

View File

@ -40,6 +40,7 @@ import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@ -59,7 +60,9 @@ import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
final class ForgeAdapter {
import static com.google.common.base.Preconditions.checkNotNull;
public final class ForgeAdapter {
private ForgeAdapter() {
}
@ -154,7 +157,7 @@ final class ForgeAdapter {
private static IBlockState applyProperties(StateContainer<Block, IBlockState> stateContainer, IBlockState newState, Map<Property<?>, Object> states) {
for (Map.Entry<Property<?>, Object> state : states.entrySet()) {
IProperty<?> property = stateContainer.getProperty(state.getKey().getName());
IProperty property = stateContainer.getProperty(state.getKey().getName());
Comparable value = (Comparable) state.getValue();
// we may need to adapt this value, depending on the source prop
if (property instanceof DirectionProperty) {
@ -212,4 +215,15 @@ final class ForgeAdapter {
CompoundTag tag = NBTConverter.fromNative(itemStack.serializeNBT());
return new BaseItemStack(adapt(itemStack.getItem()), tag, itemStack.getCount());
}
/**
* Get the WorldEdit proxy for the given player.
*
* @param player the player
* @return the WorldEdit player
*/
public static ForgePlayer adaptPlayer(EntityPlayerMP player) {
checkNotNull(player);
return new ForgePlayer(player);
}
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.forge;
import net.minecraft.command.ICommand;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.world.GameType;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
@ -28,7 +27,7 @@ public interface ForgePermissionsProvider {
boolean hasPermission(EntityPlayerMP player, String permission);
void registerPermission(ICommand command, String permission);
void registerPermission(String permission);
class VanillaPermissionsProvider implements ForgePermissionsProvider {
@ -47,7 +46,7 @@ public interface ForgePermissionsProvider {
}
@Override
public void registerPermission(ICommand command, String permission) {}
public void registerPermission(String permission) {}
}
// TODO Re-add when Sponge for 1.13 is out

View File

@ -29,7 +29,7 @@ import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.registry.Registries;
import net.minecraft.command.ServerCommandManager;
import net.minecraft.command.Commands;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.PlayerList;
@ -37,14 +37,13 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
class ForgePlatform extends AbstractPlatform implements MultiUserPlatform {
private final ForgeWorldEdit mod;
@ -120,15 +119,13 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform {
@Override
public void registerCommands(Dispatcher dispatcher) {
if (server == null) return;
ServerCommandManager mcMan = (ServerCommandManager) server.getCommandManager();
Commands mcMan = server.getCommandManager();
for (final CommandMapping command : dispatcher.getCommands()) {
CommandWrapper wrapper = new CommandWrapper(command);
mcMan.registerCommand(wrapper);
CommandWrapper.register(mcMan.getDispatcher(), command);
if (command.getDescription().getPermissions().size() > 0) {
ForgeWorldEdit.inst.getPermissionsProvider().registerPermission(wrapper, command.getDescription().getPermissions().get(0));
for (int i = 1; i < command.getDescription().getPermissions().size(); i++) {
ForgeWorldEdit.inst.getPermissionsProvider().registerPermission(null, command.getDescription().getPermissions().get(i));
ForgeWorldEdit.inst.getPermissionsProvider().registerPermission(command.getDescription().getPermissions().get(i));
}
}
}

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.forge;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer;
import com.google.common.base.Joiner;
import com.sk89q.worldedit.LocalSession;
@ -92,9 +93,6 @@ public class ForgeWorldEdit {
inst = this;
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverAboutToStart);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverStopping);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverStarted);
MinecraftForge.EVENT_BUS.register(ThreadSafeCache.getInstance());
MinecraftForge.EVENT_BUS.register(this);
@ -123,6 +121,7 @@ public class ForgeWorldEdit {
LOGGER.info("WorldEdit for Forge (version " + getInternalVersion() + ") is loaded");
}
@SubscribeEvent
public void serverAboutToStart(FMLServerAboutToStartEvent event) {
if (this.platform != null) {
LOGGER.warn("FMLServerStartingEvent occurred when FMLServerStoppingEvent hasn't");
@ -165,29 +164,18 @@ public class ForgeWorldEdit {
}
}
@SubscribeEvent
public void serverStopping(FMLServerStoppingEvent event) {
WorldEdit worldEdit = WorldEdit.getInstance();
worldEdit.getSessionManager().unload();
worldEdit.getPlatformManager().unregister(platform);
}
@SubscribeEvent
public void serverStarted(FMLServerStartedEvent event) {
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
}
@SubscribeEvent
public void onCommandEvent(CommandEvent event) {
if ((event.getSender() instanceof EntityPlayerMP)) {
if (((EntityPlayerMP) event.getSender()).world.isRemote) return;
String[] split = new String[event.getParameters().length + 1];
System.arraycopy(event.getParameters(), 0, split, 1, event.getParameters().length);
split[0] = event.getCommand().getName();
com.sk89q.worldedit.event.platform.CommandEvent weEvent =
new com.sk89q.worldedit.event.platform.CommandEvent(wrap((EntityPlayerMP) event.getSender()), Joiner.on(" ").join(split));
WorldEdit.getInstance().getEventBus().post(weEvent);
}
}
@SubscribeEvent
public void onPlayerInteract(PlayerInteractEvent event) {
if (platform == null) {
@ -215,7 +203,7 @@ public class ForgeWorldEdit {
}
WorldEdit we = WorldEdit.getInstance();
ForgePlayer player = wrap((EntityPlayerMP) event.getEntityPlayer());
ForgePlayer player = adaptPlayer((EntityPlayerMP) event.getEntityPlayer());
ForgeWorld world = getWorld(event.getEntityPlayer().world);
if (event instanceof PlayerInteractEvent.LeftClickEmpty) {
@ -259,17 +247,6 @@ public class ForgeWorldEdit {
return this.config;
}
/**
* Get the WorldEdit proxy for the given player.
*
* @param player the player
* @return the WorldEdit player
*/
public ForgePlayer wrap(EntityPlayerMP player) {
checkNotNull(player);
return new ForgePlayer(player);
}
/**
* Get the session for a player.
*
@ -278,7 +255,7 @@ public class ForgeWorldEdit {
*/
public LocalSession getSession(EntityPlayerMP player) {
checkNotNull(player);
return WorldEdit.getInstance().getSessionManager().get(wrap(player));
return WorldEdit.getInstance().getSessionManager().get(adaptPlayer(player));
}
/**

View File

@ -32,6 +32,8 @@ import net.minecraftforge.fml.network.event.EventNetworkChannel;
import java.nio.charset.Charset;
import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer;
public class WECUIPacketHandler {
public static final Charset UTF_8_CHARSET = Charset.forName("UTF-8");
private static final String PROTOCOL_VERSION = Integer.toString(1);
@ -57,7 +59,7 @@ public class WECUIPacketHandler {
String text = event.getPayload().toString(UTF_8_CHARSET);
session.handleCUIInitializationMessage(text);
session.describeCUI(ForgeWorldEdit.inst.wrap(player));
session.describeCUI(adaptPlayer(player));
}
public static void callProcessPacket(NetworkEvent.ClientCustomPayloadEvent event) {

View File

@ -15,7 +15,7 @@ authors="sk89q, wizjany, TomyLobo, kenzierocks, Me4502"
# The modid of the mod
modId="worldedit"
# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
version="${internalVersion}"
version="${version}"
# A display name for the mod
displayName="WorldEdit"
# The description text for the mod (multi line!)
@ -23,11 +23,11 @@ description='''
WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single- and multi-player.
'''
[[dependencies.worldedit]]
modId="minecraft"
modId="forge"
mandatory=true
versionRange="[1.13.2]"
versionRange="[${forge_version},)"
ordering="NONE"
side="SERVER"
side="BOTH"
[[dependencies.worldedit]]
modId="sponge"
mandatory=false

View File

@ -0,0 +1,6 @@
{
"pack": {
"description": "WorldEdit Resources",
"pack_format": 4
}
}