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 2019-07-28 21:09:15 -04:00
parent cd826f7bcf
commit ae09fc6b6d
No known key found for this signature in database
GPG key ID: 8EB3DF749553B1B7
6 changed files with 146 additions and 0 deletions

View file

@ -29,6 +29,7 @@ import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.server.command.ConfigCommand;
import net.minecraftforge.server.command.ForgeCommand; import net.minecraftforge.server.command.ForgeCommand;
import net.minecraftforge.versions.forge.ForgeVersion; import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.versions.mcp.MCPVersion; import net.minecraftforge.versions.mcp.MCPVersion;
@ -181,6 +182,7 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
public void serverStarting(FMLServerStartingEvent evt) public void serverStarting(FMLServerStartingEvent evt)
{ {
new ForgeCommand(evt.getCommandDispatcher()); new ForgeCommand(evt.getCommandDispatcher());
ConfigCommand.register(evt.getCommandDispatcher());
} }
public void serverStopping(FMLServerStoppingEvent evt) public void serverStopping(FMLServerStoppingEvent evt)

View file

@ -22,6 +22,7 @@ package net.minecraftforge.fml.config;
import com.electronwill.nightconfig.core.CommentedConfig; import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.file.CommentedFileConfig; import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.toml.TomlFormat; import com.electronwill.nightconfig.toml.TomlFormat;
import it.unimi.dsi.fastutil.bytes.Byte2ByteOpenCustomHashMap;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.network.FMLHandshakeMessages; import net.minecraftforge.fml.network.FMLHandshakeMessages;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.fml.network.NetworkEvent;
@ -54,10 +55,12 @@ public class ConfigTracker {
public static final ConfigTracker INSTANCE = new ConfigTracker(); public static final ConfigTracker INSTANCE = new ConfigTracker();
private final ConcurrentHashMap<String, ModConfig> fileMap; private final ConcurrentHashMap<String, ModConfig> fileMap;
private final EnumMap<ModConfig.Type, Set<ModConfig>> configSets; private final EnumMap<ModConfig.Type, Set<ModConfig>> configSets;
private ConcurrentHashMap<String, Map<ModConfig.Type, ModConfig>> configsByMod;
private ConfigTracker() { private ConfigTracker() {
this.fileMap = new ConcurrentHashMap<>(); this.fileMap = new ConcurrentHashMap<>();
this.configSets = new EnumMap<>(ModConfig.Type.class); 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.CLIENT, Collections.synchronizedSet(new LinkedHashSet<>()));
this.configSets.put(ModConfig.Type.COMMON, Collections.synchronizedSet(new LinkedHashSet<>())); this.configSets.put(ModConfig.Type.COMMON, Collections.synchronizedSet(new LinkedHashSet<>()));
// this.configSets.put(ModConfig.Type.PLAYER, new ConcurrentSkipListSet<>()); // this.configSets.put(ModConfig.Type.PLAYER, new ConcurrentSkipListSet<>());
@ -71,6 +74,7 @@ public class ConfigTracker {
} }
this.fileMap.put(config.getFileName(), config); this.fileMap.put(config.getFileName(), config);
this.configSets.get(config.getType()).add(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()); LOGGER.debug(CONFIG, "Config file {} for {} tracking", config.getFileName(), config.getModId());
} }
@ -115,4 +119,9 @@ public class ConfigTracker {
modConfig.fireEvent(new ModConfig.Loading(modConfig)); 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);
}
} }

View file

@ -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;
}
}
}

View file

@ -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());
}
}

View file

@ -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;
}
}

View file

@ -98,6 +98,8 @@
"commands.forge.tracking.timing_entry": "{0} - {1} [{2}, {3}, {4}]: {5}", "commands.forge.tracking.timing_entry": "{0} - {1} [{2}, {3}, {4}]: {5}",
"commands.forge.tracking.no_data": "No data has been recorded yet.", "commands.forge.tracking.no_data": "No data has been recorded yet.",
"commands.config.getwithtype": "Config for %s of type %s found at %s",
"commands.config.noconfig": "Config for %s of type %s not found",
"forge.update.beta.1": "%sWARNING: %sForge Beta", "forge.update.beta.1": "%sWARNING: %sForge Beta",
"forge.update.beta.2": "Major issues may arise, verify before reporting.", "forge.update.beta.2": "Major issues may arise, verify before reporting.",