diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfigManager.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfigManager.java
index 727413ec..fad20d91 100644
--- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfigManager.java
+++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/ConfigManager.java
@@ -18,14 +18,18 @@ import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemoryConfiguration;
import org.bukkit.plugin.Plugin;
import fr.neatmonster.nocheatplus.actions.ActionFactory;
import fr.neatmonster.nocheatplus.logging.StaticLog;
+import fr.neatmonster.nocheatplus.utilities.StringUtil;
/**
* Central location for everything that's described in the configuration file(s).
@@ -205,6 +209,9 @@ public class ConfigManager {
// Try to obtain and parse the global configuration file.
final File globalFile = new File(plugin.getDataFolder(), "config.yml");
final ConfigFile defaultConfig = new DefaultConfig();
+ final int maxBuildContained = Math.max(DefaultConfig.buildNumber,
+ defaultConfig.getMaxLastChangedBuildNumber());
+ // TODO: Detect changes to the configuration (only save back if necessary.).
PathUtils.processPaths(globalFile, "global config", false);
final ConfigFile globalConfig = new ConfigFile();
globalConfig.setDefaults(defaultConfig);
@@ -215,11 +222,21 @@ public class ConfigManager {
// Quick shallow ugly fix: only save back if loading was successful.
try {
if (globalConfig.getBoolean(ConfPaths.SAVEBACKCONFIG)){
+ boolean overrideCreated = false;
if (!globalConfig.contains(ConfPaths.CONFIGVERSION_CREATED)){
// Workaround.
- globalConfig.set(ConfPaths.CONFIGVERSION_CREATED, DefaultConfig.buildNumber);
+ overrideCreated = true;
}
- globalConfig.set(ConfPaths.CONFIGVERSION_SAVED, DefaultConfig.buildNumber);
+ if (!overrideCreated && globalConfig.getInt(ConfPaths.CONFIGVERSION_CREATED, 0) >= 0
+ && ConfigManager.isConfigUpToDate(globalConfig) == null) {
+ // Workaround: Update the created build number, to not warn on further changes.
+ overrideCreated = true;
+ }
+ globalConfig.set(ConfPaths.CONFIGVERSION_SAVED, maxBuildContained);
+ if (overrideCreated) {
+ globalConfig.set(ConfPaths.CONFIGVERSION_CREATED, maxBuildContained);
+ }
+ // TODO: Only save back if really changed?
globalConfig.save(globalFile);
}
} catch (final Exception e) {
@@ -235,8 +252,8 @@ public class ConfigManager {
globalConfig.options().header("This configuration was auto-generated by NoCheatPlus.");
globalConfig.options().copyHeader(true);
try {
- globalConfig.set(ConfPaths.CONFIGVERSION_CREATED, DefaultConfig.buildNumber);
- globalConfig.set(ConfPaths.CONFIGVERSION_SAVED, DefaultConfig.buildNumber);
+ globalConfig.set(ConfPaths.CONFIGVERSION_CREATED, maxBuildContained);
+ globalConfig.set(ConfPaths.CONFIGVERSION_SAVED, maxBuildContained);
globalConfig.save(globalFile);
} catch (final Exception e) {
StaticLog.logSevere(e);
@@ -271,7 +288,9 @@ public class ConfigManager {
worldConfig.load(worldFile);
newWorldsMap.put(worldEntry.getKey(), worldConfig);
try{
- if (worldConfig.getBoolean(ConfPaths.SAVEBACKCONFIG)) worldConfig.save(worldFile);
+ if (worldConfig.getBoolean(ConfPaths.SAVEBACKCONFIG)) {
+ worldConfig.save(worldFile);
+ }
} catch (final Exception e){
StaticLog.logSevere("Couldn't save back world-specific configuration for " + worldEntry.getKey() + " (see exception below).");
StaticLog.logSevere(e);
@@ -288,6 +307,68 @@ public class ConfigManager {
isInitialized = true;
}
+ /**
+ *
+ * @param globalConfig
+ * @return null if everything is fine, a string with a message stating problems otherwise.
+ */
+ public static String isConfigUpToDate(ConfigFile globalConfig) {
+ Object created_o = globalConfig.get(ConfPaths.CONFIGVERSION_CREATED);
+ int buildCreated = -1;
+ if (created_o != null && created_o instanceof Integer) {
+ buildCreated = ((Integer) created_o).intValue();
+ }
+ // Silence version checking with a value < 0.
+ if (buildCreated < 0) {
+ return null;
+ }
+ final int maxBuildContained = Math.max(DefaultConfig.buildNumber,
+ globalConfig.getMaxLastChangedBuildNumber());
+ // Legacy build number comparison.
+ if (buildCreated < DefaultConfig.buildNumber) {
+ // Potentially outdated Configuration.
+ return "Your configuration might be outdated.\n" + "Some settings could have changed, you should regenerate it!";
+ }
+ else if (buildCreated > maxBuildContained) {
+ // Installed an older version of NCP.
+ return "Your configuration seems to be created by a newer plugin version.\n" + "Some settings could have changed, you should regenerate it!";
+ }
+ // So far so good... test individual paths.
+ final List problems = new LinkedList();
+ final ConfigFile defaultConfig = new DefaultConfig();
+ final Map lastChangedBuildNumbers = defaultConfig.getLastChangedBuildNumbers();
+ // TODO: Consider some behavior for entire nodes ?
+ for (final Entry entry : lastChangedBuildNumbers.entrySet()) {
+ final int defaultBuild = entry.getValue();
+ if (defaultBuild <= buildCreated) {
+ // Ignore, might've been changed on purpose.
+ continue;
+ }
+ final String path = entry.getKey();
+ final Object defaultValue = defaultConfig.get(path);
+ if (defaultValue instanceof ConfigurationSection) {
+ problems.add("Changed with build " + defaultBuild + ", can not handle entire configuration sections yet: " + path);
+ continue;
+ }
+ final Object currentValue = globalConfig.get(path);
+ if (currentValue == null || defaultValue == null) {
+ // To be handled elsewhere (@Moved / whatever).
+ continue;
+ }
+ if (defaultBuild > buildCreated && !defaultValue.equals(currentValue)) {
+ problems.add("Changed with build " + defaultBuild + ": " + path);
+ continue;
+ }
+ }
+ if (!problems.isEmpty()) {
+ problems.add(0, "The following configuration default values have changed:");
+ problems.add("(Remove/update individual values or set configversion.created to " + maxBuildContained + " to ignore all, then reload the configuration with the 'ncp reload' command.)");
+ return StringUtil.join(problems, "\n");
+ }
+ // No errors could be determined (or versions coudl not be determined): ignore.
+ return null;
+ }
+
/**
* Informal test if the init method completed (no details are reflected).
* @return
diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/RawConfigFile.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/RawConfigFile.java
index 4f6ca79e..2852513e 100644
--- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/RawConfigFile.java
+++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/RawConfigFile.java
@@ -346,8 +346,14 @@ public class RawConfigFile extends YamlConfiguration {
*
* @param path
* @param value
+ * Must be greater than zero.
+ * @throws IllegalArgumentException
+ * If the value is equal to or smaller than zero.
*/
public void setLastChangedBuildNumber(String path, int value) {
+ if (value <= 0) {
+ throw new IllegalArgumentException("Build number must be greater than zero. Got " + value + " for path: " + path);
+ }
lastChangedBuildNumbers.put(path, value);
}
@@ -363,4 +369,20 @@ public class RawConfigFile extends YamlConfiguration {
return lastChangedBuildNumbers;
}
+ /**
+ * Get the maximum of all last-changed-build-number values, stored for
+ * individual paths (default to 0).
+ *
+ * @return
+ */
+ public int getMaxLastChangedBuildNumber() {
+ int max = 0;
+ for (Integer v : lastChangedBuildNumbers.values()) {
+ if (v != null) {
+ max = Math.max(max, v);
+ }
+ }
+ return max;
+ }
+
}
diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/NoCheatPlus.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/NoCheatPlus.java
index 9c6b6c4c..553e1922 100644
--- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/NoCheatPlus.java
+++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/NoCheatPlus.java
@@ -121,7 +121,6 @@ import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.players.PlayerData;
import fr.neatmonster.nocheatplus.players.PlayerMessageSender;
import fr.neatmonster.nocheatplus.stats.Counters;
-import fr.neatmonster.nocheatplus.updates.Updates;
import fr.neatmonster.nocheatplus.utilities.ColorUtil;
import fr.neatmonster.nocheatplus.utilities.OnDemandTickListener;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
@@ -1194,7 +1193,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
* @param config
*/
private void setInstanceMembers(final ConfigFile config) {
- configProblems = Updates.isConfigUpToDate(config);
+ configProblems = ConfigManager.isConfigUpToDate(config);
useSubscriptions = config.getBoolean(ConfPaths.LOGGING_BACKEND_INGAMECHAT_SUBSCRIPTIONS);
clearExemptionsOnJoin = config.getBoolean(ConfPaths.COMPATIBILITY_EXEMPTIONS_REMOVE_JOIN);
clearExemptionsOnLeave = config.getBoolean(ConfPaths.COMPATIBILITY_EXEMPTIONS_REMOVE_LEAVE);
diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/updates/Updates.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/updates/Updates.java
index 2d87d603..87918091 100644
--- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/updates/Updates.java
+++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/updates/Updates.java
@@ -14,80 +14,8 @@
*/
package fr.neatmonster.nocheatplus.updates;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.bukkit.configuration.ConfigurationSection;
-
-import fr.neatmonster.nocheatplus.config.ConfPaths;
-import fr.neatmonster.nocheatplus.config.ConfigFile;
-import fr.neatmonster.nocheatplus.config.DefaultConfig;
-import fr.neatmonster.nocheatplus.utilities.StringUtil;
-
public class Updates {
- /**
- *
- * @param globalConfig
- * @return null if everything is fine, a string with a message stating problems otherwise.
- */
- public static String isConfigUpToDate(ConfigFile globalConfig) {
- Object created_o = globalConfig.get(ConfPaths.CONFIGVERSION_CREATED);
- int buildCreated = -1;
- if (created_o != null && created_o instanceof Integer) {
- buildCreated = ((Integer) created_o).intValue();
- }
- if (buildCreated < 0) {
- return null;
- }
- if (buildCreated < DefaultConfig.buildNumber) {
- // Potentially outdated Configuration.
- return "Your configuration might be outdated.\n" + "Some settings could have changed, you should regenerate it!";
- }
- else if (buildCreated > DefaultConfig.buildNumber) {
- // Installed an older version of NCP.
- return "Your configuration seems to be created by a newer plugin version.\n" + "Some settings could have changed, you should regenerate it!";
- }
- // So far so good... test individual paths.
- final List problems = new LinkedList();
- final ConfigFile defaultConfig = new DefaultConfig();
- final Map lastChangedBuildNumbers = defaultConfig.getLastChangedBuildNumbers();
- int maxBuild = DefaultConfig.buildNumber;
- // TODO: Consider some behavior for entire nodes ?
- for (final Entry entry : lastChangedBuildNumbers.entrySet()) {
- final int defaultBuild = entry.getValue();
- if (defaultBuild <= buildCreated) {
- // Ignore, might've been changed on purpose.
- continue;
- }
- final String path = entry.getKey();
- final Object defaultValue = defaultConfig.get(path);
- if (defaultValue instanceof ConfigurationSection) {
- problems.add("Changed with build " + defaultBuild + ", can not handle entire configuration sections yet: " + path);
- continue;
- }
- final Object currentValue = globalConfig.get(path);
- if (currentValue == null || defaultValue == null) {
- // To be handled elsewhere (@Moved / whatever).
- continue;
- }
- if (defaultBuild > buildCreated && !defaultValue.equals(currentValue)) {
- problems.add("Changed with build " + defaultBuild + ": " + path);
- maxBuild = Math.max(defaultBuild, maxBuild);
- continue;
- }
- }
- if (!problems.isEmpty()) {
- problems.add(0, "The following configuration default values have changed:");
- problems.add("(Remove/update individual values or set configversion.created to " + maxBuild + " to ignore all, then reload the configuration with the 'ncp reload' command.)");
- return StringUtil.join(problems, "\n");
- }
- // No errors could be determined (or versions coudl not be determined): ignore.
- return null;
- }
-
/**
* To be called from an async task.
* @param versionString Current version string (getDescription().getVersion()).