Register a config command. Currently one subcommand: showfile, which

when passed a modid and a type (CLIENT, COMMON or SERVER) will display
a link in the caller's chat to open that file in the OS file viewer of choice.

Signed-off-by: cpw <cpw+github@weeksfamily.ca>
This commit is contained in:
cpw committed 2019-07-28 21:09:15 -04:00
1 parent cd826f7bcf
commit ae09fc6b6d
6 files changed
+146

No files matched your search

@@ -29,6 +29,7 @@ import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.server.command.ConfigCommand;
import net.minecraftforge.server.command.ForgeCommand;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.versions.mcp.MCPVersion;
@@ -181,6 +182,7 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
public void serverStarting(FMLServerStartingEvent evt)
{
new ForgeCommand(evt.getCommandDispatcher());
ConfigCommand.register(evt.getCommandDispatcher());
}
public void serverStopping(FMLServerStoppingEvent evt)
@@ -22,6 +22,7 @@ package net.minecraftforge.fml.config;
import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.toml.TomlFormat;
import it.unimi.dsi.fastutil.bytes.Byte2ByteOpenCustomHashMap;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.network.FMLHandshakeMessages;
import net.minecraftforge.fml.network.NetworkEvent;
@@ -54,10 +55,12 @@ public class ConfigTracker {
public static final ConfigTracker INSTANCE = new ConfigTracker();
private final ConcurrentHashMap<String, ModConfig> fileMap;
private final EnumMap<ModConfig.Type, Set<ModConfig>> configSets;
private ConcurrentHashMap<String, Map<ModConfig.Type, ModConfig>> configsByMod;
private ConfigTracker() {
this.fileMap = new ConcurrentHashMap<>();
this.configSets = new EnumMap<>(ModConfig.Type.class);
this.configsByMod = new ConcurrentHashMap<>();
this.configSets.put(ModConfig.Type.CLIENT, Collections.synchronizedSet(new LinkedHashSet<>()));
this.configSets.put(ModConfig.Type.COMMON, Collections.synchronizedSet(new LinkedHashSet<>()));
// this.configSets.put(ModConfig.Type.PLAYER, new ConcurrentSkipListSet<>());
@@ -71,6 +74,7 @@ public class ConfigTracker {
}
this.fileMap.put(config.getFileName(), config);
this.configSets.get(config.getType()).add(config);
this.configsByMod.computeIfAbsent(config.getModId(), (k)->new EnumMap<>(ModConfig.Type.class)).put(config.getType(), config);
LOGGER.debug(CONFIG, "Config file {} for {} tracking", config.getFileName(), config.getModId());
}
@@ -115,4 +119,9 @@ public class ConfigTracker {
modConfig.fireEvent(new ModConfig.Loading(modConfig));
});
}
public String getConfigFileName(String modId, ModConfig.Type type) {
return Optional.ofNullable(configsByMod.getOrDefault(modId, Collections.emptyMap()).getOrDefault(type, null)).
map(ModConfig::getFullPath).map(Object::toString).orElse(null);
}
}
@@ -0,0 +1,54 @@
package net.minecraftforge.server.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraftforge.fml.config.ConfigTracker;
import net.minecraftforge.fml.config.ModConfig;
import java.io.File;
public class ConfigCommand {
public static void register(CommandDispatcher<CommandSource> dispatcher) {
dispatcher.register(
Commands.literal("config").
then(ShowFile.register())
);
}
public static class ShowFile {
static ArgumentBuilder<CommandSource, ?> register() {
return Commands.literal("showfile").
requires(cs->cs.hasPermissionLevel(0)).
then(Commands.argument("mod", ModIdArgument.modIdArgument()).
then(Commands.argument("type", EnumArgument.enumArgument(ModConfig.Type.class)).
executes(ShowFile::showFile)
)
);
}
private static int showFile(final CommandContext<CommandSource> context) {
final String modId = context.getArgument("mod", String.class);
final ModConfig.Type type = context.getArgument("type", ModConfig.Type.class);
final String configFileName = ConfigTracker.INSTANCE.getConfigFileName(modId, type);
if (configFileName != null) {
File f = new File(configFileName);
context.getSource().sendFeedback(new TranslationTextComponent("commands.config.getwithtype",
modId, type,
new StringTextComponent(f.getName()).applyTextStyle(TextFormatting.UNDERLINE).
applyTextStyle((style) -> style.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, f.getAbsolutePath())))
), true);
} else {
context.getSource().sendFeedback(new TranslationTextComponent("commands.config.noconfig", modId, type),
true);
}
return 0;
}
}
}
@@ -0,0 +1,40 @@
package net.minecraftforge.server.command;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.command.ISuggestionProvider;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class EnumArgument<T extends Enum<T>> implements ArgumentType<T> {
private final Class<T> enumClass;
public static <R extends Enum<R>> EnumArgument<R> enumArgument(Class<R> enumClass) {
return new EnumArgument<>(enumClass);
}
private EnumArgument(final Class<T> enumClass) {
this.enumClass = enumClass;
}
@Override
public T parse(final StringReader reader) throws CommandSyntaxException {
return Enum.valueOf(enumClass, reader.readUnquotedString());
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
return ISuggestionProvider.suggest(Stream.of(enumClass.getEnumConstants()).map(Object::toString), builder);
}
@Override
public Collection<String> getExamples() {
return Stream.of(enumClass.getEnumConstants()).map(Object::toString).collect(Collectors.toList());
}
}
@@ -0,0 +1,39 @@
package net.minecraftforge.server.command;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.command.ISuggestionProvider;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class ModIdArgument implements ArgumentType<String> {
private static final List<String> EXAMPLES = Arrays.asList("forge", "inventorysorter");
public static ModIdArgument modIdArgument() {
return new ModIdArgument();
}
@Override
public String parse(final StringReader reader) throws CommandSyntaxException {
return reader.readUnquotedString();
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
return ISuggestionProvider.suggest(ModList.get().applyForEachModContainer(ModContainer::getModId), builder);
}
@Override
public Collection<String> getExamples() {
return EXAMPLES;
}
}