Rename plugin to MagicGem Reforged

This commit is contained in:
Coldsmiles
2026-10-04 23:42:44 +08:00
parent 95e3ed05ea
commit 953c15e380
18 changed files with 291 additions and 634 deletions
@@ -94,7 +94,7 @@ public class CMagicGem extends JavaPlugin {
+ ", PlayerPoints=" + points.status()
+ ", PlaceholderAPI=" + placeholders.status()
+ ", MythicMobs=" + mythic.status());
getLogger().info("MagicGem 已启用,命令 /mgem,加载 " + gemRegistry.all().size() + " 颗宝石。");
getLogger().info("MagicGem Reforged 已启用,命令 /mgem,加载 " + gemRegistry.all().size() + " 颗宝石。");
}
public void reloadAll() {
@@ -88,7 +88,7 @@ public final class CMagicGemCommand implements CommandExecutor, TabCompleter {
}
private boolean help(CommandSender sender) {
sender.sendMessage(itemCodec.color("&6MagicGem &7- &f/mgem"));
sender.sendMessage(itemCodec.color("&6MagicGem Reforged &7- &f/mgem"));
List<String> help = languages.section("command.help");
if (help.isEmpty()) help = List.of("&e/mgem give <玩家> <宝石> [数量]",
"&e/mgem apply <玩家> <宝石> [槽位]", "&e/mgem remove <玩家> <宝石> [槽位]",
@@ -155,7 +155,7 @@ public final class CMagicGemCommand implements CommandExecutor, TabCompleter {
String fallback = switch (scope) {
case "gem" -> "&a宝石配置已重载,共加载 {amount} 颗宝石。";
case "skill" -> "&a技能配置已重载。";
default -> "&aMagicGem 已安全重载,共加载 {amount} 颗宝石。";
default -> "&aMagicGem Reforged 已安全重载,共加载 {amount} 颗宝石。";
};
sender.sendMessage(itemCodec.color(languages.text("cmagic.command.reload_" + scope, fallback,
"amount", registry.all().size())));
@@ -3,11 +3,10 @@ package cn.infstar.cmagicgem.config;
import org.bukkit.configuration.file.FileConfiguration;
public record PluginSettings(boolean workbench, boolean backpack, boolean gemLore, boolean gemCraft,
boolean skillEngine, boolean skillEngineLoreColor, boolean legacyMigration) {
boolean skillEngine, boolean skillEngineLoreColor) {
public static PluginSettings load(FileConfiguration config) {
return new PluginSettings(config.getBoolean("workbench", true), config.getBoolean("backpack", false),
config.getBoolean("gem-lore", false), config.getBoolean("gem-craft", false),
config.getBoolean("skill-engine", true), config.getBoolean("skill-engine-lore-color", false),
config.getBoolean("legacy-migration", true));
config.getBoolean("skill-engine", true), config.getBoolean("skill-engine-lore-color", false));
}
}
@@ -41,9 +41,6 @@ public final class ItemCodec {
private final NamespacedKey dataVersionKey;
private final NamespacedKey embeddedKey;
private final NamespacedKey skillsKey;
private final NamespacedKey cMagicGemNameKey;
private final NamespacedKey cMagicGemEmbeddedKey;
private final NamespacedKey cMagicGemSkillsKey;
private final LegacyItemMigrator legacyMigrator;
public ItemCodec(JavaPlugin plugin, GemRegistry registry) {
@@ -52,9 +49,6 @@ public final class ItemCodec {
this.dataVersionKey = new NamespacedKey(plugin, "data_version");
this.embeddedKey = new NamespacedKey(plugin, "embedded_gems");
this.skillsKey = new NamespacedKey(plugin, "skills");
this.cMagicGemNameKey = new NamespacedKey("cmagicgem", "gem_name");
this.cMagicGemEmbeddedKey = new NamespacedKey("cmagicgem", "embedded_gems");
this.cMagicGemSkillsKey = new NamespacedKey("cmagicgem", "skills");
this.legacyMigrator = new LegacyItemMigrator(registry);
}
@@ -141,7 +135,6 @@ public final class ItemCodec {
if (item == null || item.getType().isAir() || !item.hasItemMeta()) return Optional.empty();
ItemMeta meta = item.getItemMeta();
String name = meta.getPersistentDataContainer().get(gemNameKey, PersistentDataType.STRING);
if (name == null) name = meta.getPersistentDataContainer().get(cMagicGemNameKey, PersistentDataType.STRING);
Optional<GemDefinition> direct = registry.find(name);
if (direct.isPresent()) return direct;
LegacyItemMigrator.LegacyData legacy = legacyMigrator.inspect(item);
@@ -169,7 +162,6 @@ public final class ItemCodec {
if (item == null || !item.hasItemMeta()) return Map.of();
PersistentDataContainer data = item.getItemMeta().getPersistentDataContainer();
String encoded = data.get(embeddedKey, PersistentDataType.STRING);
if (encoded == null) encoded = data.get(cMagicGemEmbeddedKey, PersistentDataType.STRING);
Map<String, Integer> result = new LinkedHashMap<>();
if (encoded == null || encoded.isBlank()) {
LegacyItemMigrator.LegacyData legacy = legacyMigrator.inspect(item);
@@ -224,7 +216,6 @@ public final class ItemCodec {
if (item == null || !item.hasItemMeta()) return new ArrayList<>();
PersistentDataContainer data = item.getItemMeta().getPersistentDataContainer();
String value = data.get(skillsKey, PersistentDataType.STRING);
if (value == null) value = data.get(cMagicGemSkillsKey, PersistentDataType.STRING);
if (value == null || value.isBlank()) {
List<String> legacy = new ArrayList<>(legacyMigrator.inspect(item).skills());
if (!legacy.isEmpty()) writeSkills(item, legacy);
@@ -1,8 +1,5 @@
package cn.infstar.cmagicgem.migration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.IOException;
@@ -15,234 +12,124 @@ import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
/** Imports files left by the previous CMagicGem reimplementation without touching the source directory. */
/** Imports the original MagicGem data directory into MagicGem Reforged once. */
public final class LegacyDirectoryImporter {
private static final String LEGACY_PLUGIN_DIRECTORY = "CMagicGem";
private static final String LEGACY_PLUGIN_DIRECTORY = "MagicGem";
private static final String TARGET_BACKUP_DIRECTORY = "MagicGem";
private static final List<String> DATA_DIRECTORIES = List.of("gems", "skills", "gui", "languages");
private static final String MARKER = ".migration-cmagicgem-v1.complete";
private static final String MARKER = ".migration-magicgem-reforged-v1.complete";
private final Path pluginsDirectory;
private final Path targetDirectory;
private final Runnable saveDefaultConfig;
private final Logger logger;
public LegacyDirectoryImporter(JavaPlugin plugin) {
this(plugin.getDataFolder().toPath().toAbsolutePath().normalize().getParent(),
plugin.getDataFolder().toPath().toAbsolutePath().normalize(),
plugin::saveDefaultConfig, plugin.getLogger());
plugin.getDataFolder().toPath().toAbsolutePath().normalize(), plugin.getLogger());
}
LegacyDirectoryImporter(Path pluginsDirectory, Path targetDirectory,
Runnable saveDefaultConfig, Logger logger) {
LegacyDirectoryImporter(Path pluginsDirectory, Path targetDirectory, Logger logger) {
this.pluginsDirectory = Objects.requireNonNull(pluginsDirectory).toAbsolutePath().normalize();
this.targetDirectory = Objects.requireNonNull(targetDirectory).toAbsolutePath().normalize();
this.saveDefaultConfig = Objects.requireNonNull(saveDefaultConfig);
this.logger = Objects.requireNonNull(logger);
}
public ImportResult importIfPresent() {
if (targetDirectory.equals(pluginsDirectory.resolve(LEGACY_PLUGIN_DIRECTORY).normalize())) {
Path sourceDirectory = pluginsDirectory.resolve(LEGACY_PLUGIN_DIRECTORY).normalize();
if (targetDirectory.equals(sourceDirectory) || !Files.isDirectory(sourceDirectory)) {
return ImportResult.none();
}
Path sourceDirectory = pluginsDirectory.resolve(LEGACY_PLUGIN_DIRECTORY).normalize();
if (!Files.isDirectory(sourceDirectory)) return ImportResult.none();
Path marker = targetDirectory.resolve(MARKER);
if (Files.exists(marker)) return new ImportResult(0, 0, 0, false, true);
if (Files.exists(marker)) return new ImportResult(0, 0, true);
int copiedFiles = 0;
int mergedFiles = 0;
int conflictFiles = 0;
boolean configImported = false;
List<Conflict> conflicts = new ArrayList<>();
try {
Files.createDirectories(targetDirectory);
for (String directory : DATA_DIRECTORIES) {
ImportCounts counts = importDirectory(sourceDirectory.resolve(directory), targetDirectory.resolve(directory),
Path.of(directory), conflicts);
ImportCounts counts = importDirectory(sourceDirectory.resolve(directory),
targetDirectory.resolve(directory), Path.of(directory), conflicts);
copiedFiles += counts.copiedFiles;
mergedFiles += counts.mergedFiles;
conflictFiles += counts.conflictFiles;
}
Path sourceConfig = sourceDirectory.resolve("config.yml");
Path targetConfig = targetDirectory.resolve("config.yml");
if (Files.isRegularFile(sourceConfig)) {
boolean targetConfigExisted = Files.isRegularFile(targetConfig);
if (!targetConfigExisted) saveDefaultConfig.run();
MergeResult result = mergeYaml(sourceConfig, targetConfig, Path.of("config.yml"),
!targetConfigExisted, conflicts);
configImported = result.changed;
if (result.changed) mergedFiles++;
if (result.conflicted) conflictFiles++;
ImportCounts counts = importFile(sourceConfig, targetDirectory.resolve("config.yml"),
Path.of("config.yml"), conflicts);
copiedFiles += counts.copiedFiles;
conflictFiles += counts.conflictFiles;
}
writeConflictBackups(sourceDirectory, conflicts);
Files.writeString(marker, "Imported from plugins/CMagicGem. Source directory remains unchanged.\n");
if (!conflicts.isEmpty()) {
for (Conflict conflict : conflicts) {
logger.warning("CMagicGem migration kept the MagicGem value for "
+ conflict.sourceRelative() + " (" + conflict.key() + ")"
+ "; the original source file was saved under migration-backup/CMagicGem.");
}
Files.writeString(marker, "Imported from plugins/MagicGem. Source directory remains unchanged.\n");
for (Conflict conflict : conflicts) {
logger.warning("MagicGem Reforged kept the target file for " + conflict.relativePath()
+ "; the original file was saved under migration-backup/MagicGem.");
}
logger.info("Imported plugins/CMagicGem into plugins/MagicGem: " + copiedFiles + " files copied, "
+ mergedFiles + " files merged, " + conflictFiles + " files with conflicts. "
+ "The source directory was left untouched.");
return new ImportResult(copiedFiles, mergedFiles, conflictFiles, configImported, false);
} catch (IOException | InvalidConfigurationException exception) {
logger.log(Level.SEVERE, "Could not finish importing plugins/CMagicGem. No source files were deleted; "
+ "the migration will be retried on the next startup.", exception);
return new ImportResult(copiedFiles, mergedFiles, conflictFiles, configImported, false);
logger.info("Imported original plugins/MagicGem into " + targetDirectory.getFileName()
+ ": " + copiedFiles + " files copied, " + conflictFiles + " conflicts. "
+ "The original directory was left untouched.");
return new ImportResult(copiedFiles, conflictFiles, false);
} catch (IOException exception) {
logger.log(Level.SEVERE, "Could not finish importing original plugins/MagicGem. "
+ "The original directory was not deleted; migration will be retried on the next startup.", exception);
return new ImportResult(copiedFiles, conflictFiles, false);
}
}
private ImportCounts importDirectory(Path source, Path target, Path sourcePrefix, List<Conflict> conflicts)
throws IOException, InvalidConfigurationException {
if (!Files.isDirectory(source)) return new ImportCounts(0, 0, 0);
private ImportCounts importDirectory(Path source, Path target, Path prefix, List<Conflict> conflicts)
throws IOException {
if (!Files.isDirectory(source)) return new ImportCounts(0, 0);
int copied = 0;
int merged = 0;
int conflicted = 0;
int conflictCount = 0;
Path normalizedTarget = target.toAbsolutePath().normalize();
try (var paths = Files.walk(source)) {
for (Path path : paths.toList()) {
Path relative = source.relativize(path);
Path destination = normalizedTarget.resolve(relative).normalize();
if (!destination.startsWith(normalizedTarget)) continue;
if (Files.isDirectory(path)) {
Files.createDirectories(destination);
continue;
}
if (!Files.isRegularFile(path)) continue;
if (!Files.exists(destination)) {
Files.createDirectories(destination.getParent());
Files.copy(path, destination, StandardCopyOption.COPY_ATTRIBUTES);
copied++;
continue;
}
if (isYaml(path)) {
MergeResult result = mergeYaml(path, destination,
sourcePrefix.resolve(source.relativize(path)), false, conflicts);
if (result.changed) merged++;
if (result.conflicted) conflicted++;
} else if (Files.mismatch(path, destination) != -1) {
conflicts.add(new Conflict(sourcePrefix.resolve(source.relativize(path)), "<binary content>"));
conflicted++;
}
if (Files.isDirectory(path) || !Files.isRegularFile(path)) continue;
Path relative = prefix.resolve(source.relativize(path));
ImportCounts counts = importFile(path, normalizedTarget.resolve(source.relativize(path)).normalize(),
relative, conflicts);
copied += counts.copiedFiles;
conflictCount += counts.conflictFiles;
}
}
return new ImportCounts(copied, merged, conflicted);
return new ImportCounts(copied, conflictCount);
}
private MergeResult mergeYaml(Path source, Path destination, Path sourceRelative,
boolean preferSource, List<Conflict> conflicts)
throws IOException, InvalidConfigurationException {
if (!Files.exists(destination)) {
Files.createDirectories(destination.getParent());
Files.copy(source, destination, StandardCopyOption.COPY_ATTRIBUTES);
return new MergeResult(true, false);
private ImportCounts importFile(Path source, Path target, Path relative, List<Conflict> conflicts)
throws IOException {
if (!target.normalize().startsWith(targetDirectory)) return new ImportCounts(0, 0);
if (!Files.exists(target)) {
Files.createDirectories(target.getParent());
Files.copy(source, target, StandardCopyOption.COPY_ATTRIBUTES);
return new ImportCounts(1, 0);
}
YamlConfiguration sourceYaml = new YamlConfiguration();
sourceYaml.load(source.toFile());
YamlConfiguration destinationYaml = new YamlConfiguration();
destinationYaml.load(destination.toFile());
List<String> fileConflicts = new ArrayList<>();
boolean changed = mergeSections(sourceYaml, destinationYaml, "", preferSource, fileConflicts);
if (source.getFileName().toString().equalsIgnoreCase("config.yml")) {
String legacyLanguage = sourceYaml.getString("language", sourceYaml.getString("lang"));
if (legacyLanguage != null && (preferSource || !destinationYaml.contains("language"))) {
if (!Objects.equals(destinationYaml.getString("language"), legacyLanguage)) {
destinationYaml.set("language", legacyLanguage);
changed = true;
}
}
if (Files.mismatch(source, target) != -1) {
conflicts.add(new Conflict(relative));
return new ImportCounts(0, 1);
}
if (changed) destinationYaml.save(destination.toFile());
for (String conflict : fileConflicts) conflicts.add(new Conflict(sourceRelative, conflict));
return new MergeResult(changed, !fileConflicts.isEmpty());
}
private boolean mergeSections(ConfigurationSection source, ConfigurationSection destination,
String prefix, boolean preferSource, List<String> conflicts) {
boolean changed = false;
for (String key : source.getKeys(false)) {
String path = prefix.isEmpty() ? key : prefix + "." + key;
ConfigurationSection sourceSection = source.getConfigurationSection(key);
ConfigurationSection destinationSection = destination.getConfigurationSection(key);
if (sourceSection != null && destinationSection == null) {
if (!destination.contains(key)) {
destination.createSection(key);
changed = true;
} else {
if (preferSource) {
destination.set(key, null);
destination.createSection(key);
changed = true;
} else {
conflicts.add(path);
}
}
destinationSection = destination.getConfigurationSection(key);
if (destinationSection != null) {
changed |= mergeSections(sourceSection, destinationSection, path, preferSource, conflicts);
}
continue;
}
if (sourceSection == null && destinationSection != null) {
if (preferSource) {
destination.set(key, source.get(key));
changed = true;
} else {
conflicts.add(path);
}
continue;
}
if (sourceSection != null) {
changed |= mergeSections(sourceSection, destinationSection, path, preferSource, conflicts);
continue;
}
Object sourceValue = source.get(key);
if (!destination.contains(key)) {
destination.set(key, sourceValue);
changed = true;
} else if (!Objects.equals(sourceValue, destination.get(key))) {
if (preferSource) {
destination.set(key, sourceValue);
changed = true;
} else {
conflicts.add(path);
}
}
}
return changed;
return new ImportCounts(0, 0);
}
private void writeConflictBackups(Path sourceDirectory, List<Conflict> conflicts) throws IOException {
for (Path relative : conflicts.stream().map(Conflict::sourceRelative).distinct().toList()) {
Path sourceFile = sourceDirectory.resolve(relative).normalize();
if (!sourceFile.startsWith(sourceDirectory) || !Files.isRegularFile(sourceFile)) continue;
Path backup = targetDirectory.resolve("migration-backup").resolve(LEGACY_PLUGIN_DIRECTORY).resolve(relative);
for (Path relative : conflicts.stream().map(Conflict::relativePath).distinct().toList()) {
Path source = sourceDirectory.resolve(relative).normalize();
if (!source.startsWith(sourceDirectory) || !Files.isRegularFile(source)) continue;
Path backup = targetDirectory.resolve("migration-backup").resolve(TARGET_BACKUP_DIRECTORY).resolve(relative);
Files.createDirectories(backup.getParent());
Files.copy(sourceFile, backup, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
Files.copy(source, backup, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
}
}
private boolean isYaml(Path path) {
String name = path.getFileName().toString().toLowerCase(java.util.Locale.ROOT);
return name.endsWith(".yml") || name.endsWith(".yaml");
}
public record ImportResult(int copiedFiles, int mergedFiles, int conflictFiles,
boolean configImported, boolean alreadyMigrated) {
public record ImportResult(int copiedFiles, int conflictFiles, boolean alreadyMigrated) {
private static ImportResult none() {
return new ImportResult(0, 0, 0, false, false);
return new ImportResult(0, 0, false);
}
}
private record ImportCounts(int copiedFiles, int mergedFiles, int conflictFiles) { }
private record MergeResult(boolean changed, boolean conflicted) { }
private record Conflict(Path sourceRelative, String key) { }
private record ImportCounts(int copiedFiles, int conflictFiles) { }
private record Conflict(Path relativePath) { }
}
@@ -0,0 +1,27 @@
package cn.infstar.magicgemreforged;
import pku.yim.magicgem.MagicGem;
/** Paper entry point for MagicGem Reforged. The superclass keeps the original public API available. */
public final class MagicGemReforged extends MagicGem {
public static MagicGemReforged instance;
public static MagicGemReforged getInstance() {
return instance;
}
@Override
public void onEnable() {
instance = this;
super.onEnable();
}
@Override
public void onDisable() {
try {
super.onDisable();
} finally {
if (instance == this) instance = null;
}
}
}
+2 -2
View File
@@ -5,8 +5,8 @@ import cn.infstar.cmagicgem.config.PluginSettings;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
/** Legacy entry point retained for plugins that resolve MagicGem by class name. */
public final class MagicGem extends CMagicGem {
/** Compatibility base class retained for plugins compiled against the original MagicGem API. */
public class MagicGem extends CMagicGem {
public static MagicGem instance;
public static boolean placeholderapi;
public static boolean MMCorMMA;
-1
View File
@@ -5,7 +5,6 @@ gem-lore: false
gem-craft: false
skill-engine: true
skill-engine-lore-color: false
legacy-migration: true
potion-global-limit: {}
integrations:
mythicmobs:
+1 -1
View File
@@ -4,7 +4,7 @@
Material: EMERALD
Display: "&a示例生命宝石"
Tips:
- "&7用于验证 CMagicGem 基础功能"
- "&7用于验证 MagicGem Reforged 基础功能"
Require:
- ARMOR
Success: 100
+1 -1
View File
@@ -1,5 +1,5 @@
default:
Title: "&8CMagicGem 镶嵌台 &7%page%"
Title: "&8MagicGem Reforged 镶嵌台 &7%page%"
Page: 1
Locations: []
Slots:
+5 -5
View File
@@ -1,6 +1,6 @@
version: 1.10
plugin:
prefix: "&9&l[&e&lMagicGem&9&l]&r"
prefix: "&9&l[&e&lMagicGem Reforged&9&l]&r"
read_file: "&eReading "
dupe_gem: "&cDuplicated gems find! Name: "
extract: "&eExtracting resource files"
@@ -13,7 +13,7 @@ plugin:
accept: "&cPlugin licensed. Thank you for purchasing!"
busy: "&cThe license server is busy. Will try again later"
wrong_info: "&cLicense request failed, plugin file may be corrupted"
wrong_user: "&cPlease specify correct account in MagicGem/config.yml (For example, user: Bob), and then use /mgem reload."
wrong_user: "&cPlease specify correct account in MagicGem-Reforged/config.yml (For example, user: Bob), and then use /mgem reload."
help: "&aFor support, please contact QQ: 386029724 or email liyi20129@gmail.com"
gem:
tip:
@@ -187,8 +187,8 @@ reward:
type: "Potion Effect"
duration: "Duration"
skill:
add: "Add MagicGem Skill"
change: "Change MagicGem Skill"
add: "Add MagicGem Reforged Skill"
change: "Change MagicGem Reforged Skill"
remove: "Remove MaticGem Skill"
unbreakable:
type: "Unbreakable"
@@ -276,7 +276,7 @@ cmagic:
gem_not_found: "&cUnknown gem: {gem}"
not_embedded: "&cThat gem is not embedded in this item"
command:
reload: "&aMagicGem reloaded safely; {amount} gems loaded."
reload: "&aMagicGem Reforged reloaded safely; {amount} gems loaded."
give: "&aGave {player} {amount} {gem}"
list: "&6Loaded gems (&e{amount}&6):"
signal_all: "&aSent the skill signal to every online player."
+1 -1
View File
@@ -276,7 +276,7 @@ cmagic:
gem_not_found: "&c未知宝石: {gem}"
not_embedded: "&c装备未镶嵌该宝石"
command:
reload: "&aMagicGem 已安全重载,共加载 {amount} 颗宝石。"
reload: "&aMagicGem Reforged 已安全重载,共加载 {amount} 颗宝石。"
give: "&a已给予 {player} {amount} 个 {gem}"
list: "&6已加载宝石 (&e{amount}&6):"
signal_all: "&a已向所有在线玩家发送技能信号。"
+4 -4
View File
@@ -1,13 +1,13 @@
name: MagicGem
name: MagicGem-Reforged
version: '${version}'
description: Paper 1.21.x compatible MagicGem reimplementation
main: pku.yim.magicgem.MagicGem
description: MagicGem Reforged for Paper 1.21.x
main: cn.infstar.magicgemreforged.MagicGemReforged
api-version: '1.21'
authors: [ Coldsmile_7 ]
softdepend: [PlaceholderAPI, Vault, PlayerPoints, MythicMobs, MMOItems, MythicArtifacts, MythicCrucible, Residence, PvPManager, EcoEnchants, GoldenEnchants]
commands:
mgem:
description: MagicGem main command
description: MagicGem Reforged main command
usage: /mgem help
aliases: [cmgem, cmg]
permissions:
@@ -1,10 +1,8 @@
package cn.infstar.cmagicgem.migration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.logging.Logger;
@@ -18,81 +16,71 @@ class LegacyDirectoryImporterTest {
Path temporaryDirectory;
@Test
void mergesOldDirectoryWithoutOverwritingTargetAndKeepsConflictBackup() throws Exception {
void importsOriginalMagicGemDirectoryIntoReforgedTarget() throws Exception {
Path plugins = Files.createDirectory(temporaryDirectory.resolve("plugins"));
Path source = Files.createDirectories(plugins.resolve("CMagicGem/gems"));
Path target = Files.createDirectories(plugins.resolve("MagicGem/gems"));
Path oldGem = source.resolve("Shared.yml");
Path currentGem = target.resolve("Shared.yml");
Files.writeString(oldGem, "Shared:\n Name: Old Name\n Material: DIAMOND\n OldOnly: retained\n");
Files.writeString(currentGem, "Shared:\n Name: Current Name\n Material: DIAMOND\n CurrentOnly: retained\n");
Path source = Files.createDirectories(plugins.resolve("MagicGem/gems"));
Path target = plugins.resolve("MagicGem-Reforged");
Files.writeString(source.resolve("Custom.yml"), "Custom:\n Name: Imported\n");
Files.writeString(source.getParent().resolve("config.yml"), "language: en_US\nbackpack: true\nold-option: kept\n");
Files.writeString(target.getParent().resolve("config.yml"), "language: zh_CN\nbackpack: false\n");
Files.writeString(source.getParent().resolve("config.yml"), "language: en_US\nbackpack: true\n");
LegacyDirectoryImporter importer = importer(plugins, plugins.resolve("MagicGem"), () -> { });
LegacyDirectoryImporter.ImportResult result = importer.importIfPresent();
LegacyDirectoryImporter.ImportResult result = importer(plugins, target).importIfPresent();
YamlConfiguration mergedGem = load(currentGem);
YamlConfiguration mergedConfig = load(target.getParent().resolve("config.yml"));
assertEquals("Current Name", mergedGem.getString("Shared.Name"));
assertEquals("retained", mergedGem.getString("Shared.OldOnly"));
assertEquals("retained", mergedGem.getString("Shared.CurrentOnly"));
assertTrue(Files.isRegularFile(target.resolve("Custom.yml")));
assertEquals("zh_CN", mergedConfig.getString("language"));
assertEquals(false, mergedConfig.getBoolean("backpack"));
assertEquals("kept", mergedConfig.getString("old-option"));
assertTrue(Files.isRegularFile(plugins.resolve("MagicGem/migration-backup/CMagicGem/gems/Shared.yml")));
assertEquals("Old Name", load(oldGem).getString("Shared.Name"));
assertTrue(result.copiedFiles() >= 1);
assertTrue(result.mergedFiles() >= 2);
assertTrue(result.conflictFiles() >= 1);
assertTrue(Files.isRegularFile(target.resolve("gems/Custom.yml")));
assertTrue(Files.isRegularFile(target.resolve("config.yml")));
assertEquals("Custom:\n Name: Imported\n", Files.readString(target.resolve("gems/Custom.yml")));
assertEquals("language: en_US\nbackpack: true\n", Files.readString(target.resolve("config.yml")));
assertTrue(Files.isDirectory(source.getParent()));
assertTrue(result.copiedFiles() >= 2);
assertEquals(0, result.conflictFiles());
assertFalse(result.alreadyMigrated());
}
@Test
void preservesTargetFilesAndBacksUpConflicts() throws Exception {
Path plugins = Files.createDirectory(temporaryDirectory.resolve("plugins"));
Path source = Files.createDirectories(plugins.resolve("MagicGem/gems"));
Path target = Files.createDirectories(plugins.resolve("MagicGem-Reforged/gems"));
Files.writeString(source.resolve("Shared.yml"), "Shared:\n Name: Original\n");
Files.writeString(target.resolve("Shared.yml"), "Shared:\n Name: Reforged\n");
LegacyDirectoryImporter.ImportResult result = importer(plugins, target.getParent()).importIfPresent();
assertEquals("Shared:\n Name: Reforged\n", Files.readString(target.resolve("Shared.yml")));
assertEquals("Shared:\n Name: Original\n",
Files.readString(target.getParent().resolve("migration-backup/MagicGem/gems/Shared.yml")));
assertEquals(1, result.conflictFiles());
}
@Test
void markerMakesMigrationIdempotent() throws Exception {
Path plugins = Files.createDirectory(temporaryDirectory.resolve("plugins"));
Path source = Files.createDirectories(plugins.resolve("MagicGem"));
Path target = plugins.resolve("MagicGem-Reforged");
Files.writeString(source.resolve("config.yml"), "language: zh_CN\n");
LegacyDirectoryImporter importer = importer(plugins, target);
importer.importIfPresent();
LegacyDirectoryImporter.ImportResult repeated = importer.importIfPresent();
assertTrue(repeated.alreadyMigrated());
assertEquals(0, repeated.copiedFiles());
assertEquals(0, repeated.conflictFiles());
}
@Test
void oldConfigurationOverridesBundledDefaultsWhenTargetHasNoConfig() throws Exception {
void missingOriginalDirectoryDoesNothing() throws Exception {
Path plugins = Files.createDirectory(temporaryDirectory.resolve("plugins"));
Path source = Files.createDirectories(plugins.resolve("CMagicGem"));
Path target = plugins.resolve("MagicGem");
Files.writeString(source.resolve("config.yml"), "lang: en_US\nbackpack: true\n");
Runnable createDefaults = () -> {
try {
Files.createDirectories(target);
Files.writeString(target.resolve("config.yml"), "language: zh_CN\nbackpack: false\nworkbench: true\n");
} catch (IOException exception) {
throw new IllegalStateException(exception);
}
};
Path target = plugins.resolve("MagicGem-Reforged");
LegacyDirectoryImporter.ImportResult result = importer(plugins, target, createDefaults).importIfPresent();
YamlConfiguration config = load(target.resolve("config.yml"));
assertEquals("en_US", config.getString("language"));
assertEquals(true, config.getBoolean("backpack"));
assertEquals(true, config.getBoolean("workbench"));
assertTrue(result.configImported());
}
@Test
void originalMagicGemDirectoryIsTreatedAsTheActiveTarget() throws Exception {
Path plugins = Files.createDirectory(temporaryDirectory.resolve("plugins"));
Path target = Files.createDirectory(plugins.resolve("MagicGem"));
LegacyDirectoryImporter.ImportResult result = importer(plugins, target, () -> { }).importIfPresent();
LegacyDirectoryImporter.ImportResult result = importer(plugins, target).importIfPresent();
assertEquals(0, result.copiedFiles());
assertEquals(0, result.conflictFiles());
assertFalse(result.alreadyMigrated());
assertFalse(Files.exists(target.resolve(".migration-cmagicgem-v1.complete")));
assertFalse(Files.exists(target));
}
private LegacyDirectoryImporter importer(Path plugins, Path target, Runnable saveDefaults) {
return new LegacyDirectoryImporter(plugins, target, saveDefaults, Logger.getLogger("migration-test"));
}
private YamlConfiguration load(Path path) {
return YamlConfiguration.loadConfiguration(path.toFile());
private LegacyDirectoryImporter importer(Path plugins, Path target) {
return new LegacyDirectoryImporter(plugins, target, Logger.getLogger("migration-test"));
}
}
@@ -23,11 +23,11 @@ class BundledConfigurationTest {
private final DirectiveParser parser = new DirectiveParser();
@Test
void pluginDescriptorKeepsLegacyCommandAndPermissionCompatibility() {
void pluginDescriptorUsesReforgedEntryPointAndKeepsCompatibility() {
YamlConfiguration descriptor = YamlConfiguration.loadConfiguration(new File("src/main/resources/plugin.yml"));
assertTrue(descriptor.getString("name").equalsIgnoreCase("MagicGem"));
assertTrue(descriptor.getString("main").equals("pku.yim.magicgem.MagicGem"));
assertTrue(descriptor.getString("name").equalsIgnoreCase("MagicGem-Reforged"));
assertTrue(descriptor.getString("main").equals("cn.infstar.magicgemreforged.MagicGemReforged"));
assertNotNull(descriptor.getConfigurationSection("commands.mgem"));
assertTrue(descriptor.getStringList("commands.mgem.aliases").contains("cmg"));
assertTrue(descriptor.getStringList("commands.mgem.aliases").contains("cmgem"));