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:
parent
cd826f7bcf
commit
ae09fc6b6d
6 changed files with 146 additions and 0 deletions
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.",
|
||||||
|
|
Loading…
Reference in a new issue