Skip to content

Commit

Permalink
Fixing and cleaning up configs (#40)
Browse files Browse the repository at this point in the history
* Simplify config event firing and handling
* Cleanup `ConfigFileTypeHandler` a bit
* Reset to default config if loading the config fails (instead of crashing the game)
* Allow disabling config watcher
  • Loading branch information
dima-dencep authored Dec 1, 2023
1 parent 2e8cb5b commit a43f00e
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 53 deletions.
7 changes: 0 additions & 7 deletions core/src/main/java/net/neoforged/fml/ModContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import net.neoforged.bus.api.Event;
import net.neoforged.bus.api.EventPriority;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.config.IConfigEvent;
import net.neoforged.fml.config.ModConfig;
import net.neoforged.fml.event.IModBusEvent;
import net.neoforged.fml.loading.progress.ProgressMeter;
Expand Down Expand Up @@ -57,8 +56,6 @@ public abstract class ModContainer
protected final Map<ModLoadingStage, Runnable> activityMap = new HashMap<>();
protected final Map<Class<? extends IExtensionPoint<?>>, Supplier<?>> extensionPoints = new IdentityHashMap<>();
protected final EnumMap<ModConfig.Type, ModConfig> configs = new EnumMap<>(ModConfig.Type.class);
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
protected Optional<Consumer<IConfigEvent>> configHandler = Optional.empty();

public ModContainer(IModInfo info)
{
Expand Down Expand Up @@ -159,10 +156,6 @@ public void addConfig(final ModConfig modConfig) {
configs.put(modConfig.getType(), modConfig);
}

public void dispatchConfigEvent(IConfigEvent event) {
configHandler.ifPresent(configHandler->configHandler.accept(event));
}

/**
* Does this mod match the supplied mod?
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,44 +25,62 @@

public class ConfigFileTypeHandler {
private static final Logger LOGGER = LogUtils.getLogger();
static ConfigFileTypeHandler TOML = new ConfigFileTypeHandler();
public final static ConfigFileTypeHandler TOML = new ConfigFileTypeHandler();
private static final Path defaultConfigPath = FMLPaths.GAMEDIR.get().resolve(FMLConfig.getConfigValue(FMLConfig.ConfigValue.DEFAULT_CONFIG_PATH));

public Function<ModConfig, CommentedFileConfig> reader(Path configBasePath) {
return (c) -> {
final Path configPath = configBasePath.resolve(c.getFileName());
final CommentedFileConfig configData = CommentedFileConfig.builder(configPath).sync().
preserveInsertionOrder().
autosave().
onFileNotFound((newfile, configFormat)-> setupConfigFile(c, newfile, configFormat)).
writingMode(WritingMode.REPLACE).
build();
LOGGER.debug(CONFIG, "Built TOML config for {}", configPath.toString());
final CommentedFileConfig configData = CommentedFileConfig.builder(configPath)
.sync()
.preserveInsertionOrder()
.autosave()
.onFileNotFound((newfile, configFormat) -> setupConfigFile(c, newfile, configFormat))
.writingMode(WritingMode.REPLACE)
.build();
LOGGER.debug(CONFIG, "Built TOML config for {}", configPath);
try
{
configData.load();
}
catch (ParsingException ex)
{
throw new ConfigLoadingException(c, ex);
LOGGER.warn(CONFIG, "Attempting to recreate {}", configPath);
try
{
backUpConfig(configData.getNioPath(), 5);
Files.delete(configData.getNioPath());

configData.load();
}
catch (Throwable t)
{
ex.addSuppressed(t);

throw new ConfigLoadingException(c, ex);
}
}
LOGGER.debug(CONFIG, "Loaded TOML config file {}", configPath.toString());
try {
FileWatcher.defaultInstance().addWatch(configPath, new ConfigWatcher(c, configData, Thread.currentThread().getContextClassLoader()));
LOGGER.debug(CONFIG, "Watching TOML config file {} for changes", configPath.toString());
} catch (IOException e) {
throw new RuntimeException("Couldn't watch config file", e);
LOGGER.debug(CONFIG, "Loaded TOML config file {}", configPath);
if (!FMLConfig.getBoolConfigValue(FMLConfig.ConfigValue.DISABLE_CONFIG_WATCHER)) {
try {
FileWatcher.defaultInstance().addWatch(configPath, new ConfigWatcher(c, configData, Thread.currentThread().getContextClassLoader()));
LOGGER.debug(CONFIG, "Watching TOML config file {} for changes", configPath);
} catch (IOException e) {
throw new RuntimeException("Couldn't watch config file", e);
}
}
return configData;
};
}

public void unload(Path configBasePath, ModConfig config) {
if (FMLConfig.getBoolConfigValue(FMLConfig.ConfigValue.DISABLE_CONFIG_WATCHER))
return;
Path configPath = configBasePath.resolve(config.getFileName());
try {
FileWatcher.defaultInstance().removeWatch(configBasePath.resolve(config.getFileName()));
FileWatcher.defaultInstance().removeWatch(configPath);
} catch (RuntimeException e) {
LOGGER.error("Failed to remove config {} from tracker!", configPath.toString(), e);
LOGGER.error("Failed to remove config {} from tracker!", configPath, e);
}
}

Expand All @@ -86,9 +104,14 @@ public static void backUpConfig(final CommentedFileConfig commentedFileConfig)

public static void backUpConfig(final CommentedFileConfig commentedFileConfig, final int maxBackups)
{
Path bakFileLocation = commentedFileConfig.getNioPath().getParent();
String bakFileName = FilenameUtils.removeExtension(commentedFileConfig.getFile().getName());
String bakFileExtension = FilenameUtils.getExtension(commentedFileConfig.getFile().getName()) + ".bak";
backUpConfig(commentedFileConfig.getNioPath(), maxBackups);
}

public static void backUpConfig(final Path commentedFileConfig, final int maxBackups)
{
Path bakFileLocation = commentedFileConfig.getParent();
String bakFileName = FilenameUtils.removeExtension(commentedFileConfig.getFileName().toString());
String bakFileExtension = FilenameUtils.getExtension(commentedFileConfig.getFileName().toString()) + ".bak";
Path bakFile = bakFileLocation.resolve(bakFileName + "-1" + "." + bakFileExtension);
try
{
Expand All @@ -103,11 +126,11 @@ public static void backUpConfig(final CommentedFileConfig commentedFileConfig, f
Files.move(oldBak, bakFileLocation.resolve(bakFileName + "-" + (i + 1) + "." + bakFileExtension));
}
}
Files.copy(commentedFileConfig.getNioPath(), bakFile);
Files.copy(commentedFileConfig, bakFile);
}
catch (IOException exception)
{
LOGGER.warn(CONFIG, "Failed to back up config file {}", commentedFileConfig.getNioPath(), exception);
LOGGER.warn(CONFIG, "Failed to back up config file {}", commentedFileConfig, exception);
}
}

Expand Down Expand Up @@ -144,7 +167,7 @@ public void run() {
}
LOGGER.debug(CONFIG, "Config file {} changed, sending notifies", this.modConfig.getFileName());
this.modConfig.getSpec().afterReload();
this.modConfig.fireEvent(IConfigEvent.reloading(this.modConfig));
IConfigEvent.reloading(this.modConfig).post();
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions core/src/main/java/net/neoforged/fml/config/ConfigTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,20 @@ public void unloadConfigs(ModConfig.Type type, Path configBasePath) {

private void openConfig(final ModConfig config, final Path configBasePath) {
LOGGER.trace(CONFIG, "Loading config file type {} at {} for {}", config.getType(), config.getFileName(), config.getModId());
final CommentedFileConfig configData = config.getHandler().reader(configBasePath).apply(config);
final CommentedFileConfig configData = ConfigFileTypeHandler.TOML.reader(configBasePath).apply(config);
config.setConfigData(configData);
config.fireEvent(IConfigEvent.loading(config));
IConfigEvent.loading(config).post();
config.save();
}

private void closeConfig(final ModConfig config, final Path configBasePath) {
if (config.getConfigData() != null) {
LOGGER.trace(CONFIG, "Closing config file type {} at {} for {}", config.getType(), config.getFileName(), config.getModId());
// stop the filewatcher before we save the file and close it, so reload doesn't fire
config.getHandler().unload(configBasePath, config);
ConfigFileTypeHandler.TOML.unload(configBasePath, config);
var unloading = IConfigEvent.unloading(config);
if (unloading != null)
config.fireEvent(unloading);
unloading.post();
config.save();
config.setConfigData(null);
}
Expand All @@ -81,7 +81,7 @@ public void loadDefaultServerConfigs() {
final CommentedConfig commentedConfig = CommentedConfig.inMemory();
modConfig.getSpec().correct(commentedConfig);
modConfig.setConfigData(commentedConfig);
modConfig.fireEvent(IConfigEvent.loading(modConfig));
IConfigEvent.loading(modConfig).post();
});
}

Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/net/neoforged/fml/config/IConfigEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package net.neoforged.fml.config;

import net.neoforged.bus.api.Event;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.Bindings;

import java.util.function.Function;
Expand All @@ -28,6 +29,14 @@ static IConfigEvent loading(ModConfig modConfig) {
}
ModConfig getConfig();

default void post() {
IEventBus bus = getConfig().container.getEventBus();

if (bus != null) {
bus.post(self());
}
}

@SuppressWarnings("unchecked")
default <T extends Event & IConfigEvent> T self() {
return (T) this;
Expand Down
23 changes: 6 additions & 17 deletions core/src/main/java/net/neoforged/fml/config/ModConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,28 @@
package net.neoforged.fml.config;

import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.core.file.FileConfig;
import com.electronwill.nightconfig.toml.TomlFormat;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.loading.StringUtils;

import java.io.ByteArrayInputStream;
import java.nio.file.Path;
import java.util.Locale;
import java.util.concurrent.Callable;

public class ModConfig
{
private final Type type;
private final IConfigSpec<?> spec;
private final String fileName;
private final ModContainer container;
private final ConfigFileTypeHandler configHandler;
protected final ModContainer container;
private CommentedConfig configData;
private Callable<Void> saveHandler;

public ModConfig(final Type type, final IConfigSpec<?> spec, final ModContainer container, final String fileName) {
this.type = type;
this.spec = spec;
this.fileName = fileName;
this.container = container;
this.configHandler = ConfigFileTypeHandler.TOML;
ConfigTracker.INSTANCE.trackConfig(this);
}

Expand All @@ -43,6 +39,7 @@ private static String defaultConfigName(Type type, String modId) {
// config file name would be "forge-client.toml" and "forge-server.toml"
return String.format(Locale.ROOT, "%s-%s.toml", modId, type.extension());
}

public Type getType() {
return type;
}
Expand All @@ -51,10 +48,6 @@ public String getFileName() {
return fileName;
}

public ConfigFileTypeHandler getHandler() {
return configHandler;
}

@SuppressWarnings("unchecked")
public <T extends IConfigSpec<T>> IConfigSpec<T> getSpec() {
return (IConfigSpec<T>) spec;
Expand All @@ -73,21 +66,17 @@ void setConfigData(final CommentedConfig configData) {
this.spec.acceptConfig(this.configData);
}

void fireEvent(final IConfigEvent configEvent) {
this.container.dispatchConfigEvent(configEvent);
}

public void save() {
((CommentedFileConfig)this.configData).save();
((FileConfig)this.configData).save();
}

public Path getFullPath() {
return ((CommentedFileConfig)this.configData).getNioPath();
return ((FileConfig)this.configData).getNioPath();
}

public void acceptSyncedConfig(byte[] bytes) {
setConfigData(TomlFormat.instance().createParser().parse(new ByteArrayInputStream(bytes)));
fireEvent(IConfigEvent.reloading(this));
IConfigEvent.reloading(this).post();
}

public enum Type {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public FMLModContainer(IModInfo info, String className, ModFileScanData modFileS
.markerType(IModBusEvent.class)
.allowPerPhasePost()
.build();
this.configHandler = Optional.of(ce->this.eventBus.post(ce.self()));
final FMLJavaModLoadingContext contextExtension = new FMLJavaModLoadingContext(this);
this.contextExtension = () -> contextExtension;
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
public class FMLConfig
{
public enum ConfigValue {
DISABLE_CONFIG_WATCHER("disableConfigWatcher", Boolean.FALSE, "Disables File Watcher. Used to automatically update config if its file has been modified."),
EARLY_WINDOW_CONTROL("earlyWindowControl", Boolean.TRUE, "Should we control the window. Disabling this disables new GL features and can be bad for mods that rely on them."),
MAX_THREADS("maxThreads", -1, "Max threads for early initialization parallelism, -1 is based on processor count", FMLConfig::maxThreads),
VERSION_CHECK("versionCheck", Boolean.TRUE, "Enable NeoForge global version checking"),
Expand Down

0 comments on commit a43f00e

Please sign in to comment.