ConfigEvents - the beginning.

Signed-off-by: cpw <cpw+github@weeksfamily.ca>
This commit is contained in:
cpw 2019-01-28 22:42:37 -05:00
parent 2918864248
commit 7a02ccc3a8
No known key found for this signature in database
GPG key ID: 8EB3DF749553B1B7
10 changed files with 288 additions and 29 deletions

View file

@ -28,6 +28,8 @@ import java.util.List;
import javax.annotation.Nullable;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.config.ModConfig;
import org.apache.logging.log4j.LogManager;
import com.electronwill.nightconfig.core.CommentedConfig;
@ -130,7 +132,6 @@ public class ForgeConfig
}
public static class Client {
public final BooleanValue zoomInMissingModelTextInGui;
public final BooleanValue forgeCloudsEnabled;
@ -183,7 +184,7 @@ public class ForgeConfig
}
}
private static final ForgeConfigSpec spec = BUILDER.build();
static final ForgeConfigSpec spec = BUILDER.build();
private static final ForgeConfigSpec.Builder CHUNK_BUILDER = new ForgeConfigSpec.Builder();
@ -279,18 +280,15 @@ public class ForgeConfig
public static final ForgeConfigSpec chunk_spec = CHUNK_BUILDER.build();
private static void loadFrom(final Path configRoot) {
Path configFile = configRoot.resolve("forge.toml");
spec.setConfigFile(configFile);
LogManager.getLogger().debug(FORGEMOD, "Loaded Forge config from {}", configFile);
configFile = configRoot.resolve("forge_chunks.toml");
chunk_spec.setConfigFile(configFile);
LogManager.getLogger().debug(FORGEMOD, "Loaded Forge Chunk config from {}", configFile);
@SubscribeEvent
public static void onLoad(final ModConfig.Loading configEvent) {
LogManager.getLogger().debug(FORGEMOD, "Loaded forge config file {}", configEvent.getConfig().getFileName());
}
public static void load() {
loadFrom(FMLPaths.CONFIGDIR.get());
@SubscribeEvent
public static void onFileChange(final ModConfig.ConfigReloading configEvent) {
LogManager.getLogger().fatal(CORE, "Forge config just got changed on the file system!");
}
//General

View file

@ -73,19 +73,8 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<Config>
this.levelComments = levelComments;
}
public void setConfigFile(Path path) {
setConfig(CommentedFileConfig.builder(path).sync()
.autosave()
//.autoreload()
.writingMode(WritingMode.REPLACE)
.build());
}
public void setConfig(CommentedConfig config) {
this.childConfig = config;
if (config instanceof FileConfig) {
((FileConfig) config).load();
}
if (!isCorrect(config)) {
String configName = config instanceof FileConfig ? ((FileConfig) config).getNioPath().toString() : config.toString();
LogManager.getLogger().warn(CORE, "Configuration file {} is not correct. Correcting", configName);

View file

@ -22,6 +22,7 @@ package net.minecraftforge.common;
import net.minecraftforge.fml.FMLWorldPersistenceHook;
import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.fml.WorldPersistenceHooks;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
import net.minecraftforge.fml.event.lifecycle.FMLModIdMappingEvent;
@ -84,7 +85,9 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
MinecraftForge.EVENT_BUS.addListener(this::serverStarting);
MinecraftForge.EVENT_BUS.addListener(this::playerLogin);
MinecraftForge.EVENT_BUS.addListener(this::serverStopping);
ForgeConfig.load();
FMLModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ForgeConfig.spec);
FMLModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ForgeConfig.chunk_spec);
FMLModLoadingContext.get().getModEventBus().register(ForgeConfig.class);
}
/*

View file

@ -19,14 +19,10 @@
package net.minecraftforge.fml;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.forgespi.language.IModInfo;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -51,6 +47,9 @@ public abstract class ModContainer
protected ModLoadingStage modLoadingStage;
protected final Map<ModLoadingStage, Consumer<LifecycleEventProvider.LifecycleEvent>> triggerMap;
protected final Map<ExtensionPoint, Supplier<?>> extensionPoints = new IdentityHashMap<>();
protected final EnumMap<ModConfig.Type, ModConfig> configs = new EnumMap<>(ModConfig.Type.class);
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
protected Optional<Consumer<ModConfig.ModConfigEvent>> configHandler = Optional.empty();
public ModContainer(IModInfo info)
{
@ -125,6 +124,14 @@ public abstract class ModContainer
extensionPoints.put(point, extension);
}
public void addConfig(final ModConfig modConfig) {
configs.put(modConfig.getType(), modConfig);
}
public void dispatchConfigEvent(ModConfig.ModConfigEvent event) {
configHandler.ifPresent(configHandler->configHandler.accept(event));
}
/**
* Does this mod match the supplied mod?
*

View file

@ -24,6 +24,9 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.fml.config.ConfigTracker;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.loading.FMLPaths;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.LoadingModList;
@ -127,6 +130,7 @@ public class ModLoader
ObjectHolderRegistry.findObjectHolders();
CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData());
GameData.fireRegistryEvents(rl->true, LifecycleEventProvider.LOAD_REGISTRIES, this::dispatchAndHandleError);
DistExecutor.runWhenOn(Dist.CLIENT, ()->()-> ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.CLIENT, FMLPaths.CONFIGDIR.get()));
dispatchAndHandleError(LifecycleEventProvider.SETUP);
DistExecutor.runWhenOn(Dist.CLIENT, ModLoader::fireClientEvents);
dispatchAndHandleError(LifecycleEventProvider.SIDED_SETUP);

View file

@ -0,0 +1,55 @@
package net.minecraftforge.fml.config;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.core.file.FileWatcher;
import com.electronwill.nightconfig.core.io.WritingMode;
import net.minecraftforge.fml.loading.FMLPaths;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.file.Path;
import java.util.function.Function;
import static net.minecraftforge.fml.config.ConfigTracker.CONFIG;
public class ConfigFileTypeHandler {
private static final Logger LOGGER = LogManager.getLogger();
static ConfigFileTypeHandler TOML = new ConfigFileTypeHandler();
public Function<ModConfig, CommentedFileConfig> reader(Path configBasePath) {
return (c) -> {
final Path configPath = configBasePath.resolve(c.getFileName());
final CommentedFileConfig configData = CommentedFileConfig.builder(configPath).sync().
autosave().
writingMode(WritingMode.REPLACE).
build();
LOGGER.debug(CONFIG, "Built TOML config for {}", configPath.toString());
try {
FileWatcher.defaultInstance().addWatch(configPath, new ConfigWatcher(c, configData));
LOGGER.debug(CONFIG, "Watching TOML config file {} for changes", configPath.toString());
} catch (IOException e) {
throw new RuntimeException("Couldn't watch config file", e);
}
configData.load();
LOGGER.debug(CONFIG, "Loaded TOML config file {}", configPath.toString());
return configData;
};
}
private static class ConfigWatcher implements Runnable {
private final ModConfig modConfig;
private final CommentedFileConfig commentedFileConfig;
ConfigWatcher(final ModConfig modConfig, final CommentedFileConfig commentedFileConfig) {
this.modConfig = modConfig;
this.commentedFileConfig = commentedFileConfig;
}
@Override
public void run() {
LOGGER.debug(CONFIG, "Config file {} changed, sending notifies", this.modConfig.getFileName());
this.modConfig.fireEvent(new ModConfig.ConfigReloading(this.modConfig));
}
}
}

View file

@ -0,0 +1,52 @@
package net.minecraftforge.fml.config;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import java.nio.file.Path;
import java.util.EnumMap;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
public class ConfigTracker {
private static final Logger LOGGER = LogManager.getLogger();
static final Marker CONFIG = MarkerManager.getMarker("CONFIG");
public static final ConfigTracker INSTANCE = new ConfigTracker();
private final ConcurrentHashMap<String, ModConfig> fileMap;
private final EnumMap<ModConfig.Type, Set<ModConfig>> configSets;
private ConfigTracker() {
this.fileMap = new ConcurrentHashMap<>();
this.configSets = new EnumMap<>(ModConfig.Type.class);
this.configSets.put(ModConfig.Type.CLIENT, new ConcurrentSkipListSet<>());
// this.configSets.put(ModConfig.Type.PLAYER, new ConcurrentSkipListSet<>());
this.configSets.put(ModConfig.Type.SERVER, new ConcurrentSkipListSet<>());
}
void trackConfig(final ModConfig config) {
if (this.fileMap.containsKey(config.getFileName())) {
LOGGER.error(CONFIG,"Detected config file conflict {} between {} and {}", config.getFileName(), this.fileMap.get(config.getFileName()).getModId(), config.getModId());
throw new RuntimeException("Config conflict detected!");
}
this.fileMap.put(config.getFileName(), config);
this.configSets.get(config.getType()).add(config);
LOGGER.debug(CONFIG, "Config file {} for {} tracking", config.getFileName(), config.getModId());
}
public void loadConfigs(ModConfig.Type type, Path configBasePath) {
LOGGER.debug(CONFIG, "Loading configs type {}", type);
this.configSets.get(type).forEach(config -> openConfig(config, configBasePath));
}
private void openConfig(final ModConfig config, final Path configBasePath) {
LOGGER.debug(CONFIG, "Loading config file type {} at {} for {}", config.getType(), config.getFileName(), config.getModId());
final CommentedFileConfig configData = config.getHandler().reader(configBasePath).apply(config);
config.setConfigData(configData);
config.fireEvent(new ModConfig.Loading(config));
config.getConfigData().save();
}
}

View file

@ -0,0 +1,132 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.config;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.loading.StringUtils;
public class ModConfig
{
private final Type type;
private final ForgeConfigSpec spec;
private final String fileName;
private final ModContainer container;
private final ConfigFileTypeHandler configHandler;
private CommentedFileConfig configData;
public ModConfig(final Type type, final ForgeConfigSpec 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);
}
public ModConfig(final Type type, final ForgeConfigSpec spec, final ModContainer activeContainer) {
this(type, spec, activeContainer, defaultConfigName(type, activeContainer.getModId()));
}
private static String defaultConfigName(Type type, String modId) {
// config file name would be "forge-client.toml" and "forge-server.toml"
return String.format("%s-%s.toml", modId, type.extension());
}
public Type getType() {
return type;
}
public String getFileName() {
return fileName;
}
public ConfigFileTypeHandler getHandler() {
return configHandler;
}
public ForgeConfigSpec getSpec() {
return spec;
}
public String getModId() {
return container.getModId();
}
public CommentedFileConfig getConfigData() {
return this.configData;
}
void setConfigData(final CommentedFileConfig configData) {
this.configData = configData;
this.spec.setConfig(this.configData);
}
void fireEvent(final ModConfigEvent configEvent) {
this.container.dispatchConfigEvent(configEvent);
}
public enum Type {
/**
* Client type config is exclusively for configuration affecting the client state.
* Graphical options, for example.
*/
CLIENT,
// /**
// * Player type config is configuration that is associated with a player.
// * Preferences around machine states, for example.
// */
// PLAYER,
/**
* Server type config is configuration that is associated with a server instance.
* It will be synced from a server to the client on connection.
*/
SERVER;
public String extension() {
return StringUtils.toLowerCase(name());
}
}
public static class ModConfigEvent extends Event {
private final ModConfig config;
ModConfigEvent(final ModConfig config) {
this.config = config;
}
public ModConfig getConfig() {
return config;
}
}
public static class Loading extends ModConfigEvent {
Loading(final ModConfig config) {
super(config);
}
}
public static class ConfigReloading extends ModConfigEvent {
ConfigReloading(final ModConfig config) {
super(config);
}
}
}

View file

@ -19,8 +19,10 @@
package net.minecraftforge.fml.javafmlmod;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.ExtensionPoint;
import net.minecraftforge.fml.config.ModConfig;
import java.util.function.Supplier;
@ -36,6 +38,14 @@ public class FMLModLoadingContext
getActiveContainer().registerExtensionPoint(point, extension);
}
public void registerConfig(ModConfig.Type type, ForgeConfigSpec spec) {
activeContainer.addConfig(new ModConfig(type, spec, activeContainer));
}
public void registerConfig(ModConfig.Type type, ForgeConfigSpec spec, String fileName) {
activeContainer.addConfig(new ModConfig(type, spec, activeContainer, fileName));
}
public IEventBus getModEventBus()
{
return getActiveContainer().getEventBus();

View file

@ -29,11 +29,15 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.LogicalSidedProvider;
import net.minecraftforge.fml.config.ConfigTracker;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
import net.minecraftforge.fml.loading.FMLPaths;
import net.minecraftforge.fml.loading.FileUtils;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.fml.packs.ResourcePackLoader;
import org.apache.logging.log4j.LogManager;
@ -41,6 +45,8 @@ import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
@ -56,6 +62,9 @@ public class ServerLifecycleHooks
{
currentServer = server;
LogicalSidedProvider.setServer(()->server);
final Path serverConfig = server.getActiveAnvilConverter().getFile(server.getFolderName(), "serverconfig").toPath();
FileUtils.getOrCreateDirectory(serverConfig, "serverconfig");
ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.SERVER, serverConfig);
ResourcePackLoader.loadResourcePacks(currentServer.getResourcePacks());
return !MinecraftForge.EVENT_BUS.post(new FMLServerAboutToStartEvent(server));
}