ConfigEvents - the beginning.
Signed-off-by: cpw <cpw+github@weeksfamily.ca>
This commit is contained in:
parent
2918864248
commit
7a02ccc3a8
10 changed files with 288 additions and 29 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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?
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
132
src/main/java/net/minecraftforge/fml/config/ModConfig.java
Normal file
132
src/main/java/net/minecraftforge/fml/config/ModConfig.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue