Finish up clone command

This commit is contained in:
Ben Woo 2023-09-07 12:07:01 +08:00
parent 3ef72a993a
commit 6427881c98
No known key found for this signature in database
GPG Key ID: FB2A3645536E12C8
4 changed files with 176 additions and 26 deletions

View File

@ -5,18 +5,29 @@ import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandCompletion;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Optional;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandValueFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import com.onarandombox.MultiverseCore.worldnew.MVWorld;
import com.onarandombox.MultiverseCore.worldnew.WorldManager;
import com.onarandombox.MultiverseCore.worldnew.options.CloneWorldOptions;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
import java.util.Collections;
import java.util.Random;
@Service
@CommandAlias("mv")
public class CloneCommand extends MultiverseCommand {
@ -27,6 +38,18 @@ public class CloneCommand extends MultiverseCommand {
public CloneCommand(@NotNull MVCommandManager commandManager, @NotNull WorldManager worldManager) {
super(commandManager);
this.worldManager = worldManager;
registerFlagGroup(CommandFlagGroup.builder("mvclone")
.add(CommandFlag.builder("--reset-world-config")
.addAlias("-wc")
.build())
.add(CommandFlag.builder("--reset-gamerules")
.addAlias("-gm")
.build())
.add(CommandFlag.builder("--reset-world-border")
.addAlias("-wb")
.build())
.build());
}
@Subcommand("clone")
@ -34,19 +57,35 @@ public class CloneCommand extends MultiverseCommand {
@CommandCompletion("@mvworlds:scope=both @empty")
@Syntax("<world> <new world name>")
@Description("{@@mv-core.clone.description}")
public void onCloneCommand(CommandIssuer issuer,
public void onCloneCommand(MVCommandIssuer issuer,
@Syntax("<world>")
@Description("{@@mv-core.clone.world.description}")
MVWorld world,
@Single
@Syntax("<new world name>")
@Description("{@@mv-core.clone.newWorld.description}")
String newWorldName
String newWorldName,
@Optional
@Syntax("") // TODO
@Description("{@@mv-core.regen.other.description}")
String[] flags
) {
ParsedCommandFlags parsedFlags = parseFlags(flags);
issuer.sendInfo(MVCorei18n.CLONE_CLONING, "{world}", world.getName(), "{newWorld}", newWorldName);
worldManager.cloneWorld(world, newWorldName);
worldManager.cloneWorld(CloneWorldOptions.fromTo(world, newWorldName)
.keepWorldConfig(!parsedFlags.hasFlag("--reset-world-config"))
.keepGameRule(!parsedFlags.hasFlag("--reset-gamerules"))
.keepWorldBorder(!parsedFlags.hasFlag("--reset-world-border"))
).onSuccess((success) -> {
Logging.fine("World remove success: " + success);
issuer.sendInfo(success.getReasonMessage());
}).onFailure((failure) -> {
Logging.fine("World remove failure: " + failure);
issuer.sendError(failure.getReasonMessage());
});
issuer.sendInfo(MVCorei18n.CLONE_SUCCESS, "{world}", newWorldName);
}
}

View File

@ -10,13 +10,14 @@ import com.onarandombox.MultiverseCore.utils.result.Result;
import com.onarandombox.MultiverseCore.worldnew.config.WorldConfig;
import com.onarandombox.MultiverseCore.worldnew.config.WorldsConfigManager;
import com.onarandombox.MultiverseCore.worldnew.generators.GeneratorProvider;
import com.onarandombox.MultiverseCore.worldnew.helpers.DataStore;
import com.onarandombox.MultiverseCore.worldnew.helpers.DataStore.GameRulesStore;
import com.onarandombox.MultiverseCore.worldnew.helpers.DataTransfer;
import com.onarandombox.MultiverseCore.worldnew.helpers.FilesManipulator;
import com.onarandombox.MultiverseCore.worldnew.options.CloneWorldOptions;
import com.onarandombox.MultiverseCore.worldnew.options.CreateWorldOptions;
import com.onarandombox.MultiverseCore.worldnew.options.ImportWorldOptions;
import com.onarandombox.MultiverseCore.worldnew.options.RegenWorldOptions;
import com.onarandombox.MultiverseCore.worldnew.results.CloneWorldResult;
import com.onarandombox.MultiverseCore.worldnew.results.CreateWorldResult;
import com.onarandombox.MultiverseCore.worldnew.results.DeleteWorldResult;
import com.onarandombox.MultiverseCore.worldnew.results.ImportWorldResult;
@ -470,47 +471,55 @@ public class WorldManager {
/**
* Clones an existing multiverse world.
*
* @param world The multiverse world to clone.
* @param newWorldName The name of the new world.
* @param options The options for customizing the cloning of a world.
*/
public void cloneWorld(@NotNull MVWorld world, @NotNull String newWorldName) {
public Result<CloneWorldResult.Success, CloneWorldResult.Failure> cloneWorld(@NotNull CloneWorldOptions options) {
MVWorld world = options.world();
String newWorldName = options.newWorldName();
if (!worldNameChecker.isValidWorldName(newWorldName)) {
Logging.severe("Invalid world name: " + newWorldName);
return;
return Result.failure(CloneWorldResult.Failure.INVALID_WORLDNAME, replace("{world}").with(newWorldName));
}
if (isOfflineWorld(newWorldName)) {
Logging.severe("World already exist offline: " + newWorldName);
return;
if (worldNameChecker.isValidWorldFolder(newWorldName)) {
return Result.failure(CloneWorldResult.Failure.WORLD_EXIST_FOLDER, replace("{world}").with(newWorldName));
}
if (isMVWorld(newWorldName)) {
Logging.severe("World already loaded: " + newWorldName);
return;
return Result.failure(CloneWorldResult.Failure.WORLD_EXIST_LOADED, replace("{world}").with(newWorldName));
}
if (worldNameChecker.isValidWorldFolder(newWorldName)) {
Logging.severe("World folder already exist: " + newWorldName);
return;
if (isOfflineWorld(newWorldName)) {
Logging.severe("World already exist offline: " + newWorldName);
return Result.failure(CloneWorldResult.Failure.WORLD_EXIST_OFFLINE, replace("{world}").with(newWorldName));
}
// TODO: Configure option on whether to copy these
// GameRulesStore gameRulesStore = GameRulesStore.createAndCopyFrom(world);
// WorldConfigStore worldConfigStore = WorldConfigStore.createAndCopyFrom(world);
DataTransfer<MVWorld> dataTransfer = new DataTransfer<>();
if (options.keepWorldConfig()) {
dataTransfer.addDataStore(new WorldConfigStore(), world);
}
if (options.keepGameRule()) {
dataTransfer.addDataStore(new GameRulesStore(), world);
}
if (options.keepWorldBorder()) {
dataTransfer.addDataStore(new WorldBorderStore(), world);
}
File worldFolder = world.getBukkitWorld().map(World::getWorldFolder).getOrNull(); // TODO: Check null?
File newWorldFolder = new File(Bukkit.getWorldContainer(), newWorldName);
FileUtils.copyFolder(worldFolder, newWorldFolder, CLONE_IGNORE_FILES);
// TODO: Error handling
importWorld(ImportWorldOptions.worldName(newWorldName)
var importResult = importWorld(ImportWorldOptions.worldName(newWorldName)
.environment(world.getEnvironment())
.generator(world.getGenerator())
);
.generator(world.getGenerator()));
if (importResult.isFailure()) {
return Result.failure(CloneWorldResult.Failure.IMPORT_FAILED, importResult.getReasonMessage());
}
// TODO: Error handling
getMVWorld(newWorldName).peek(newWorld -> {
// gameRulesStore.pasteTo(newWorld);
// worldConfigStore.pasteTo(newWorld);
dataTransfer.pasteAllTo(newWorld);
saveWorldsConfig();
});
return Result.success(CloneWorldResult.Success.CLONED, replace("{world}").with(world.getName()));
}
/**

View File

@ -0,0 +1,57 @@
package com.onarandombox.MultiverseCore.worldnew.options;
import com.onarandombox.MultiverseCore.worldnew.MVWorld;
import org.jetbrains.annotations.NotNull;
public class CloneWorldOptions {
public static CloneWorldOptions fromTo(MVWorld world, String newWorldName) {
return new CloneWorldOptions(world, newWorldName);
}
private final MVWorld world;
private final String newWorldName;
private boolean keepGameRule = true;
private boolean keepWorldConfig = true;
private boolean keepWorldBorder = true;
public CloneWorldOptions(MVWorld world, String newWorldName) {
this.world = world;
this.newWorldName = newWorldName;
}
public MVWorld world() {
return world;
}
public String newWorldName() {
return newWorldName;
}
public @NotNull CloneWorldOptions keepGameRule(boolean keepGameRule) {
this.keepGameRule = keepGameRule;
return this;
}
public boolean keepGameRule() {
return keepGameRule;
}
public @NotNull CloneWorldOptions keepWorldConfig(boolean keepWorldConfig) {
this.keepWorldConfig = keepWorldConfig;
return this;
}
public boolean keepWorldConfig() {
return keepWorldConfig;
}
public @NotNull CloneWorldOptions keepWorldBorder(boolean keepWorldBorder) {
this.keepWorldBorder = keepWorldBorder;
return this;
}
public boolean keepWorldBorder() {
return keepWorldBorder;
}
}

View File

@ -0,0 +1,45 @@
package com.onarandombox.MultiverseCore.worldnew.results;
import co.aikar.locales.MessageKey;
import co.aikar.locales.MessageKeyProvider;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import com.onarandombox.MultiverseCore.utils.result.FailureReason;
import com.onarandombox.MultiverseCore.utils.result.SuccessReason;
public class CloneWorldResult {
public enum Success implements SuccessReason {
CLONED(MVCorei18n.GENERIC_SUCCESS)
;
private final MessageKeyProvider message;
Success(MessageKeyProvider message) {
this.message = message;
}
@Override
public MessageKey getMessageKey() {
return message.getMessageKey();
}
}
public enum Failure implements FailureReason {
INVALID_WORLDNAME(MVCorei18n.CREATEWORLD_INVALIDWORLDNAME),
WORLD_EXIST_FOLDER(MVCorei18n.CREATEWORLD_WORLDEXISTFOLDER),
WORLD_EXIST_OFFLINE(MVCorei18n.CREATEWORLD_WORLDEXISTOFFLINE),
WORLD_EXIST_LOADED(MVCorei18n.CREATEWORLD_WORLDEXISTLOADED),
IMPORT_FAILED(null),
;
private final MessageKeyProvider message;
Failure(MessageKeyProvider message) {
this.message = message;
}
@Override
public MessageKey getMessageKey() {
return message.getMessageKey();
}
}
}