Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions leaf-server/src/main/java/org/dreeam/leaf/config/ConfigMigrator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package org.dreeam.leaf.config;

import io.github.thatsmusic99.configurationmaster.api.ConfigFile;
import io.github.thatsmusic99.configurationmaster.api.ConfigSection;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class ConfigMigrator {

private static final String BACKUP_PREFIX = "backup-migration-";

public void migrate() throws Exception {
File oldConfigFile = new File(LeafConfig.I_CONFIG_FOLDER, LeafConfig.I_GLOBAL_CONFIG_FILE);
if (!oldConfigFile.exists()) {
return;
}

// Ensure config/leaf directory exists
LeafConfig.createDirectory(LeafConfig.I_LEAF_CONFIG_FOLDER);

// Load the old config
ConfigFile oldConfig = ConfigFile.loadConfig(oldConfigFile);

// Create backup
createBackup(oldConfigFile);

// Create separate config files for each category in config/leaf folder
Map<EnumConfigCategory, ConfigFile> newConfigs = new HashMap<>();

for (EnumConfigCategory category : EnumConfigCategory.getCategoryValues()) {
File newConfigFile = new File(LeafConfig.I_LEAF_CONFIG_FOLDER, category.getFileName());
ConfigFile newConfig = ConfigFile.loadConfig(newConfigFile);
newConfigs.put(category, newConfig);

// Set up basic structure
newConfig.set("config-version", "3.0");
newConfig.addComments("config-version", String.format("Leaf %s Config\nGitHub Repo: https://github.com/Winds-Studio/Leaf", category.name()));
}

// Migrate data from old config to new configs
migrateConfigData(oldConfig, newConfigs);

// Save all new config files
for (ConfigFile newConfig : newConfigs.values()) {
newConfig.save();
}

LeafConfig.LOGGER.info("Config migration completed. Old config backed up.");
LeafConfig.LOGGER.info("New config files created in config/leaf/ folder.");
}

private void createBackup(File oldConfigFile) throws Exception {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss");
String timestamp = dateFormat.format(new Date());
String backupName = BACKUP_PREFIX + timestamp + "-" + oldConfigFile.getName();
Path backupPath = oldConfigFile.toPath().resolveSibling(backupName);

Files.copy(oldConfigFile.toPath(), backupPath, StandardCopyOption.REPLACE_EXISTING);
LeafConfig.LOGGER.info("Created backup: {}", backupName);
}

private void migrateConfigData(ConfigFile oldConfig, Map<EnumConfigCategory, ConfigFile> newConfigs) {
// Iterate through each category and migrate relevant sections
for (EnumConfigCategory category : EnumConfigCategory.getCategoryValues()) {
ConfigFile newConfig = newConfigs.get(category);
String basePath = category.getBaseKeyName();

// Get the section from old config
ConfigSection oldSection = oldConfig.getConfigSection(basePath);
if (oldSection != null) {
// Copy all values from the old section to the new config
copySection(oldSection, newConfig, basePath);
LeafConfig.LOGGER.debug("Migrated {} section to {}", basePath, category.getFileName());
}
}
}

private void copySection(ConfigSection source, ConfigFile target, String basePath) {
// Get all keys from the source section (shallow keys only)
for (String key : source.getKeys(false)) {
String fullPath = basePath + "." + key;
Object value = source.get(key);

if (value instanceof ConfigSection) {
// Recursively copy subsections
copySection((ConfigSection) value, target, fullPath);
} else {
// Copy the value
target.set(fullPath, value);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,32 @@ public abstract class ConfigModules extends LeafConfig {

private static final Set<ConfigModules> MODULES = new HashSet<>();

public LeafGlobalConfig config;
public LeafCategoryConfig config;
private EnumConfigCategory category;

public ConfigModules() {
this.config = LeafConfig.config();
// Determine category from the module's base path
this.category = determineCategory();
this.config = LeafConfig.config(this.category);
}

// Abstract method that modules must implement to specify their base path
public abstract String getBasePath();

// Determine category from base path
private EnumConfigCategory determineCategory() {
String basePath = getBasePath();
for (EnumConfigCategory cat : EnumConfigCategory.getCategoryValues()) {
if (basePath.startsWith(cat.getBaseKeyName())) {
return cat;
}
}
// Fallback to MISC if no category matches
return EnumConfigCategory.MISC;
}

public EnumConfigCategory getCategory() {
return category;
}

public static void initModules() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Expand All @@ -38,7 +60,8 @@ public static void initModules() throws NoSuchMethodException, InvocationTargetE
}

if (!enabledExperimentalModules.isEmpty()) {
LeafConfig.LOGGER.warn("You have following experimental module(s) enabled: {}, please proceed with caution!", enabledExperimentalModules.stream().map(f -> f.getDeclaringClass().getSimpleName() + "." + f.getName()).toList());
LeafConfig.LOGGER.warn("You have following experimental module(s) enabled: {}, please proceed with caution!",
enabledExperimentalModules.stream().map(f -> f.getDeclaringClass().getSimpleName() + "." + f.getName()).toList());
}
}

Expand All @@ -47,11 +70,13 @@ public static void loadAfterBootstrap() {
module.onPostLoaded();
}

// Save config to disk
try {
LeafConfig.config().saveConfig();
} catch (Exception e) {
LeafConfig.LOGGER.error("Failed to save config file!", e);
// Save all config files to disk
for (EnumConfigCategory category : EnumConfigCategory.getCategoryValues()) {
try {
LeafConfig.config(category).saveConfig();
} catch (Exception e) {
LeafConfig.LOGGER.error("Failed to save config file for category {}!", category.name(), e);
}
}
}

Expand Down
39 changes: 39 additions & 0 deletions leaf-server/src/main/java/org/dreeam/leaf/config/ConfigStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.dreeam.leaf.config;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

public class ConfigStatus {

public static Map<String, Object> getStatus() {
Map<String, Object> status = new HashMap<>();

File oldConfigFile = new File(LeafConfig.I_CONFIG_FOLDER, LeafConfig.I_GLOBAL_CONFIG_FILE);
status.put("oldConfigExists", oldConfigFile.exists());
status.put("oldConfigFile", LeafConfig.I_GLOBAL_CONFIG_FILE);

Map<String, Boolean> categoryFiles = new HashMap<>();
for (EnumConfigCategory category : EnumConfigCategory.getCategoryValues()) {
File categoryFile = new File(LeafConfig.I_CONFIG_FOLDER, category.getFileName());
categoryFiles.put(category.getFileName(), categoryFile.exists());
}
status.put("categoryFiles", categoryFiles);

boolean needsMigration = oldConfigFile.exists() && !allCategoryFilesExist();
status.put("needsMigration", needsMigration);
status.put("multiFileSystemReady", allCategoryFilesExist());

return status;
}

private static boolean allCategoryFilesExist() {
for (EnumConfigCategory category : EnumConfigCategory.getCategoryValues()) {
File categoryFile = new File(LeafConfig.I_CONFIG_FOLDER, category.getFileName());
if (!categoryFile.exists()) {
return false;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
package org.dreeam.leaf.config;

public enum EnumConfigCategory {
ASYNC("async"),
PERF("performance"),
FIXES("fixes"),
GAMEPLAY("gameplay-mechanisms"),
NETWORK("network"),
MISC("misc");
ASYNC("async", "leaf-async.yml"),
PERF("performance", "leaf-performance.yml"),
FIXES("fixes", "leaf-fixes.yml"),
GAMEPLAY("gameplay-mechanisms", "leaf-gameplay.yml"),
NETWORK("network", "leaf-network.yml"),
MISC("misc", "leaf-misc.yml");

private final String baseKeyName;
private final String fileName;
private static final EnumConfigCategory[] VALUES = EnumConfigCategory.values();

EnumConfigCategory(String baseKeyName) {
EnumConfigCategory(String baseKeyName, String fileName) {
this.baseKeyName = baseKeyName;
this.fileName = fileName;
}

public String getBaseKeyName() {
return this.baseKeyName;
}

public String getFileName() {
return this.fileName;
}

public static EnumConfigCategory[] getCategoryValues() {
return VALUES;
}

public static EnumConfigCategory fromBaseKeyName(String baseKeyName) {
for (EnumConfigCategory category : VALUES) {
if (category.baseKeyName.equals(baseKeyName)) {
return category;
}
}
return null;
}
}
Loading