diff --git a/core/src/main/java/github/nighter/smartspawner/migration/SpawnerDataMigration.java b/core/src/main/java/github/nighter/smartspawner/migration/SpawnerDataMigration.java index 478b6a36..39272548 100644 --- a/core/src/main/java/github/nighter/smartspawner/migration/SpawnerDataMigration.java +++ b/core/src/main/java/github/nighter/smartspawner/migration/SpawnerDataMigration.java @@ -1,6 +1,7 @@ package github.nighter.smartspawner.migration; import github.nighter.smartspawner.SmartSpawner; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; @@ -15,6 +16,13 @@ public class SpawnerDataMigration { private static final String DATA_FILE = "spawners_data.yml"; private static final String BACKUP_FILE = "spawners_data_backup.yml"; private static final String MIGRATION_FLAG = "data_version"; + private static final int DEFAULT_MAX_STACK_SIZE = 10; + private static final int VERSION_3_SETTINGS_FIELD_COUNT = 13; + // Version 2 can have 11 or 12 fields (12 if allowEquipmentItems was included) + private static final int VERSION_2_MIN_SETTINGS_FIELD_COUNT = 11; + private static final int VERSION_2_MAX_SETTINGS_FIELD_COUNT = 12; + // Version 2 has first 10 fields before maxStackSize is inserted + private static final int VERSION_2_FIELDS_BEFORE_MAX_STACK = 10; private final int CURRENT_VERSION; public SpawnerDataMigration(SmartSpawner plugin) { @@ -38,27 +46,58 @@ public boolean checkAndMigrateData() { try { needsMigration = false; - // Check if data_version exists - if (!config.contains(MIGRATION_FLAG)) { - config.set(MIGRATION_FLAG, CURRENT_VERSION); - try { - config.save(dataFile); - } catch (IOException e) { - plugin.getLogger().warning("Could not save data_version flag: " + e.getMessage()); - } + // Check if data_version exists and compare with current version + int dataVersion = config.getInt(MIGRATION_FLAG, 0); + + if (dataVersion == 0) { + // data_version doesn't exist, check the structure to determine if migration is needed + plugin.getLogger().info("No data_version found. Checking data structure..."); + needsMigration = true; + } else if (dataVersion < CURRENT_VERSION) { + // data_version exists but is outdated + plugin.getLogger().info("Data version " + dataVersion + " is outdated. Current version is " + CURRENT_VERSION + "."); + needsMigration = true; } - // Validate the spawners section - if (config.contains("spawners")) { - for (String spawnerId : config.getConfigurationSection("spawners").getKeys(false)) { - String spawnerPath = "spawners." + spawnerId; - // Check if the spawner data is in the new format - if (!config.contains(spawnerPath + ".location") || - !config.contains(spawnerPath + ".settings") || - !config.contains(spawnerPath + ".inventory")) { - needsMigration = true; - break; + // If version check indicates migration is needed, validate by checking structure + if (needsMigration && config.contains("spawners")) { + // Double-check by validating the spawners section structure + boolean hasNewFormat = true; + ConfigurationSection spawnersSection = config.getConfigurationSection("spawners"); + if (spawnersSection != null) { + for (String spawnerId : spawnersSection.getKeys(false)) { + String spawnerPath = "spawners." + spawnerId; + // Check if the spawner data is in the new format + if (!config.contains(spawnerPath + ".location") || + !config.contains(spawnerPath + ".settings") || + !config.contains(spawnerPath + ".inventory")) { + hasNewFormat = false; + break; + } + + // Also check if settings string has the correct number of fields for version 3 + String settingsString = config.getString(spawnerPath + ".settings"); + if (settingsString != null) { + String[] settings = settingsString.split(","); + // Version 3 requires 13 fields (including maxStackSize and isAtCapacity) + if (settings.length < VERSION_3_SETTINGS_FIELD_COUNT) { + hasNewFormat = false; + break; + } + } + } + } + + // If structure is already in new format, just update version + if (hasNewFormat) { + plugin.getLogger().info("Data structure is already in current format. Updating version flag..."); + config.set(MIGRATION_FLAG, CURRENT_VERSION); + try { + config.save(dataFile); + } catch (IOException e) { + plugin.getLogger().warning("Could not save data_version flag: " + e.getMessage()); } + needsMigration = false; } } @@ -126,6 +165,17 @@ private void restoreFromBackup(File dataFile) { private boolean migrateData(FileConfiguration oldConfig, File dataFile) { try { + // Default to 0 to indicate no version set (older than version 1) + // This ensures all unversioned data goes through migration + int oldVersion = oldConfig.getInt(MIGRATION_FLAG, 0); + + // Check if this is a version 2 to version 3 migration + if (oldVersion == 2 && oldConfig.contains("spawners")) { + plugin.getLogger().info("Migrating from version 2 to version 3..."); + return migrateVersion2ToVersion3(oldConfig, dataFile); + } + + // Otherwise, handle old format to new format migration // Create new data file FileConfiguration newConfig = new YamlConfiguration(); @@ -146,4 +196,65 @@ private boolean migrateData(FileConfiguration oldConfig, File dataFile) { return false; } } + + private boolean migrateVersion2ToVersion3(FileConfiguration config, File dataFile) { + try { + ConfigurationSection spawnersSection = config.getConfigurationSection("spawners"); + if (spawnersSection == null) { + plugin.getLogger().warning("No spawners section found in version 2 data"); + return false; + } + + int migratedCount = 0; + for (String spawnerId : spawnersSection.getKeys(false)) { + String settingsPath = "spawners." + spawnerId + ".settings"; + String settingsString = config.getString(settingsPath); + + if (settingsString != null) { + String[] settings = settingsString.split(","); + + // Version 2 can have 11 or 12 fields (12 if allowEquipmentItems was included) + if (settings.length >= VERSION_2_MIN_SETTINGS_FIELD_COUNT && + settings.length <= VERSION_2_MAX_SETTINGS_FIELD_COUNT) { + // Migrate version 2 (11-12 fields) to version 3 (13 fields) + // Version 2 (11): exp,active,range,stop,delay,maxLoot,maxExp,minMobs,maxMobs,stack,lastSpawnTime + // Version 2 (12): exp,active,range,stop,delay,maxLoot,maxExp,minMobs,maxMobs,stack,lastSpawnTime,allowEquipmentItems + // Version 3 (13): exp,active,range,stop,delay,maxLoot,maxExp,minMobs,maxMobs,stack,maxStack,lastSpawnTime,isAtCapacity + + // Get the default maxStackSize from config or use constant + int defaultMaxStackSize = plugin.getConfig().getInt("spawner.max_stack_size", DEFAULT_MAX_STACK_SIZE); + + // Build new settings string with maxStackSize inserted at position 10 + StringBuilder newSettingsBuilder = new StringBuilder(); + for (int i = 0; i < VERSION_2_FIELDS_BEFORE_MAX_STACK; i++) { + if (i > 0) newSettingsBuilder.append(","); + newSettingsBuilder.append(settings[i]); + } + newSettingsBuilder.append(",").append(defaultMaxStackSize); // maxStackSize (NEW at position 10) + newSettingsBuilder.append(",").append(settings[10]); // lastSpawnTime (moved from 10 to 11) + // For isAtCapacity, use allowEquipmentItems if it exists (position 11 in 12-field version), otherwise false + boolean isAtCapacity = settings.length == 12 ? Boolean.parseBoolean(settings[11]) : false; + newSettingsBuilder.append(",").append(isAtCapacity); // isAtCapacity (NEW at position 12) + + config.set(settingsPath, newSettingsBuilder.toString()); + migratedCount++; + } + } + } + + // Update version flag + config.set(MIGRATION_FLAG, CURRENT_VERSION); + + // Save the updated config + config.save(dataFile); + + plugin.getLogger().info("Successfully migrated " + migratedCount + " spawners from version 2 to version 3"); + return true; + + } catch (Exception e) { + plugin.getLogger().severe("Failed to migrate from version 2 to version 3: " + e.getMessage()); + e.printStackTrace(); + return false; + } + } } \ No newline at end of file