mirror of
https://github.com/Multiverse/Multiverse-Core.git
synced 2026-11-04 16:50:03 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
112505bc93 | ||
|
|
e27fe73faa | ||
|
|
9bc2b4dfaf | ||
|
|
3ba8beefc5 | ||
|
|
05b6b380e0 | ||
|
|
b58ea2e04b | ||
|
|
f4405874d1 | ||
|
|
247685c93d | ||
|
|
490107b5d5 | ||
|
|
122e35103a | ||
|
|
25eeefbc77 | ||
|
|
6b5ce2aebb | ||
|
|
e9905ca281 | ||
|
|
e002282b13 | ||
|
|
39711527fa | ||
|
|
8d9b29ff87 | ||
|
|
82fe350afa | ||
|
|
a7b4b9bbda | ||
|
|
15f511b660 | ||
|
|
8347cf8fbb | ||
|
|
4c27fea26b | ||
|
|
4111da8fd6 | ||
|
|
5dfb098d5c |
No files matched your search
@@ -107,7 +107,7 @@ jobs:
|
||||
files: '["${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar"]'
|
||||
name: ${{ steps.release-info.outputs.tag_name }}
|
||||
changelog: ${{ steps.release-artifact.outputs.body }}
|
||||
game_versions: 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
|
||||
game_versions: 26.1.1, 26.1, 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
|
||||
version_type: ${{ steps.parse-release-type.outputs.release_type }}
|
||||
loaders: bukkit, spigot, paper, purpur
|
||||
dependencies: ${{ inputs.modrinth_dependencies }}
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
changelog: ${{ steps.release-artifact.outputs.body }}
|
||||
changelog_type: markdown
|
||||
display_name: ${{ steps.release-info.outputs.tag_name }}
|
||||
game_versions: 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
|
||||
game_versions: 26.1.1, 26.1, 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
|
||||
release_type: ${{ steps.parse-release-type.outputs.release_type }}
|
||||
project_relations: ${{ inputs.dbo_project_relations }}
|
||||
file_path: ${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar
|
||||
@@ -136,5 +136,5 @@ jobs:
|
||||
channel: ${{ steps.parse-release-type.outputs.release_type }}
|
||||
files: '[{"path": "${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar", "platforms": ["PAPER"]}]'
|
||||
description: ${{ steps.release-artifact.outputs.body }}
|
||||
platform_dependencies: '{"PAPER": ["1.18.2-1.21.11"]}'
|
||||
platform_dependencies: '{"PAPER": ["1.18.2-26.1.1"]}'
|
||||
plugin_dependencies: ${{ inputs.hangar_plugin_dependencies }}
|
||||
@@ -226,11 +226,12 @@ public class MultiverseCore extends MultiverseModule {
|
||||
* Logs the enable message.
|
||||
*/
|
||||
private void logEnableMessage() {
|
||||
Logging.config("\u001B[32mVersion %s (API v%s) Enabled - By %s\u001B[39m",
|
||||
Logging.config("\u001B[32mVersion %s (API v%s) Enabled - By %s\u001B[0m",
|
||||
this.getDescription().getVersion(), getVersionAsNumber(), StringFormatter.joinAnd(getDescription().getAuthors()));
|
||||
|
||||
if (configProvider.get().isShowingDonateMessage()) {
|
||||
Logging.config("\u001B[32mLoving Multiverse-Core? Please consider supporting the project with a small donation: https://github.com/sponsors/Multiverse\u001B[39m");
|
||||
Logging.config("\u001B[32mLoving Multiverse-Core? Please consider supporting the project with a " +
|
||||
"small donation: https://github.com/sponsors/Multiverse\u001B[0m");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,6 +150,7 @@ final class PlaceholderExpansionHook extends PlaceholderExpansion {
|
||||
case "gamemode" -> world.getGameMode().toString().toLowerCase();
|
||||
case "generator" -> world.getGenerator();
|
||||
case "hunger" -> String.valueOf(world.isHunger());
|
||||
case "isloaded" -> String.valueOf(world.isLoaded());
|
||||
case "monstersspawn" -> String.valueOf(world.getEntitySpawnConfig()
|
||||
.getSpawnCategoryConfig(SpawnCategory.MONSTER)
|
||||
.isSpawn());
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.options.CloneWorldOptions;
|
||||
|
||||
@@ -48,7 +48,7 @@ class CloneCommand extends CoreCommand {
|
||||
|
||||
@Syntax("<world>")
|
||||
@Description("{@@mv-core.clone.world.description}")
|
||||
LoadedMultiverseWorld world,
|
||||
MultiverseWorld world,
|
||||
|
||||
@Syntax("<new-world-name>")
|
||||
@Description("{@@mv-core.clone.newWorld.description}")
|
||||
@@ -114,7 +114,7 @@ class CloneCommand extends CoreCommand {
|
||||
|
||||
@Override
|
||||
@CommandAlias("mvcl|mvclone")
|
||||
void onCloneCommand(MVCommandIssuer issuer, LoadedMultiverseWorld world, String newWorldName, String[] flags) {
|
||||
void onCloneCommand(MVCommandIssuer issuer, MultiverseWorld world, String newWorldName, String[] flags) {
|
||||
super.onCloneCommand(issuer, world, newWorldName, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
|
||||
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
|
||||
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
|
||||
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
|
||||
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
|
||||
import org.mvplugins.multiverse.core.command.flags.RemovePlayerFlags;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
@@ -38,7 +38,7 @@ class LoadCommand extends CoreCommand {
|
||||
|
||||
@Subcommand("load")
|
||||
@CommandPermission("multiverse.core.load")
|
||||
@CommandCompletion("@mvworlds:scope=unloaded")
|
||||
@CommandCompletion("@mvworlds:scope=unloaded @flags:groupName=" + Flags.NAME)
|
||||
@Syntax("<world>")
|
||||
@Description("{@@mv-core.load.description}")
|
||||
void onLoadCommand(
|
||||
@@ -49,7 +49,7 @@ class LoadCommand extends CoreCommand {
|
||||
MultiverseWorld world,
|
||||
|
||||
@Optional
|
||||
@Syntax("[--remove-players]")
|
||||
@Syntax("[--skip-folder-check]")
|
||||
@Description("")
|
||||
String[] flagArray) {
|
||||
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
|
||||
@@ -67,9 +67,9 @@ class LoadCommand extends CoreCommand {
|
||||
}
|
||||
|
||||
@Service
|
||||
private static final class Flags extends RemovePlayerFlags {
|
||||
private static final class Flags extends FlagBuilder {
|
||||
|
||||
private static final String NAME = "mvunload";
|
||||
private static final String NAME = "mvload";
|
||||
|
||||
@Inject
|
||||
private Flags(@NotNull CommandFlagsManager flagsManager) {
|
||||
|
||||
@@ -220,7 +220,10 @@ final class CoreConfigNodes {
|
||||
|
||||
final ConfigNode<PassengerModes> passengerMode = node(ConfigNode.builder("teleport.passenger-mode", PassengerModes.class)
|
||||
.comment("")
|
||||
.comment("Configures how passengers and vehicles are handled when an entity is teleported.")
|
||||
.comment("Configures how passengers and vehicles are handled when an entity is teleported. This config is")
|
||||
.comment("only applied to /mvtp, join-destination and first-spawn-override. It will not touch any other")
|
||||
.comment("teleport by other plugins or commands.")
|
||||
.comment("========= Available options: =========")
|
||||
.comment(" default: Server will handle passengers and vehicles. On papermc 1.21.10+, all will be retained by default.")
|
||||
.comment(" On older versions, all will be dismounted if world changes.")
|
||||
.comment(" dismount_passengers: Passengers will be removed from the parent entity before the teleport.")
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package org.mvplugins.multiverse.core.event.world;
|
||||
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
|
||||
/**
|
||||
* Called when a world has been successfully cloned.
|
||||
@@ -10,14 +13,24 @@ import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
public final class MVWorldClonedEvent extends MultiverseWorldEvent<LoadedMultiverseWorld> {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final LoadedMultiverseWorld fromWorld;
|
||||
private final MultiverseWorld fromWorld;
|
||||
|
||||
public MVWorldClonedEvent(LoadedMultiverseWorld world, LoadedMultiverseWorld fromWorld) {
|
||||
public MVWorldClonedEvent(LoadedMultiverseWorld world, MultiverseWorld fromWorld) {
|
||||
super(world);
|
||||
this.fromWorld = fromWorld;
|
||||
}
|
||||
|
||||
public LoadedMultiverseWorld getFromWorld() {
|
||||
/**
|
||||
* @deprecated Cloning can be done from unloaded worlds as well. Use {@link #getSourceWorld()} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "5.6")
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
|
||||
public @Nullable LoadedMultiverseWorld getFromWorld() {
|
||||
return fromWorld.asLoadedWorld().getOrNull();
|
||||
}
|
||||
|
||||
@ApiStatus.AvailableSince("5.6")
|
||||
public @NotNull MultiverseWorld getSourceWorld() {
|
||||
return fromWorld;
|
||||
}
|
||||
|
||||
@@ -37,5 +50,4 @@ public final class MVWorldClonedEvent extends MultiverseWorldEvent<LoadedMultive
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -244,7 +244,7 @@ final class MVPlayerListener implements CoreListener {
|
||||
}
|
||||
|
||||
private void teleportToDestinationOnJoin(Player player, DestinationInstance<?, ?> destination) {
|
||||
asyncSafetyTeleporter.to(destination).teleportSingle(player)
|
||||
asyncSafetyTeleporter.to(destination).passengerMode(config.getPassengerMode()).teleportSingle(player)
|
||||
.onSuccess(result -> Logging.fine("Player %s has been teleported on join",
|
||||
player.getName()))
|
||||
.onFailure(failure -> Logging.warning("Failed to teleport player %s on join: %s",
|
||||
|
||||
@@ -292,6 +292,7 @@ public enum MVCorei18n implements MessageKeyProvider {
|
||||
CLONEWORLD_WORLDEXISTFOLDER,
|
||||
CLONEWORLD_WORLDEXISTUNLOADED,
|
||||
CLONEWORLD_WORLDEXISTLOADED,
|
||||
CLONEWORLD_FROMWORLDFOLDERINVALID,
|
||||
CLONEWORLD_COPYFAILED,
|
||||
|
||||
CREATEWORLD_INVALIDWORLDNAME,
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
@@ -25,6 +26,7 @@ import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
|
||||
@@ -210,16 +212,19 @@ public final class FileUtils {
|
||||
|
||||
private final Path sourceDir;
|
||||
private final Path targetDir;
|
||||
private final List<String> excludeFiles;
|
||||
private final List<Path> excludeFiles;
|
||||
|
||||
private CopyDirFileVisitor(@NotNull Path sourceDir, @NotNull Path targetDir, @NotNull List<String> excludeFiles) {
|
||||
this.sourceDir = sourceDir;
|
||||
this.targetDir = targetDir;
|
||||
this.excludeFiles = excludeFiles;
|
||||
this.excludeFiles = excludeFiles.stream()
|
||||
.map(sourceDir::resolve)
|
||||
.toList();
|
||||
Logging.finest(this.excludeFiles.stream().map(Path::toString).collect(Collectors.joining(", ", "Exclude files: [", "]")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FileVisitResult preVisitDirectory(Path dir, @NotNull BasicFileAttributes attrs) throws IOException {
|
||||
public @NotNull FileVisitResult preVisitDirectory(@NonNull Path dir, @NotNull BasicFileAttributes attrs) throws IOException {
|
||||
Path newDir = targetDir.resolve(sourceDir.relativize(dir));
|
||||
if (!Files.isDirectory(newDir)) {
|
||||
Files.createDirectory(newDir);
|
||||
@@ -228,10 +233,10 @@ public final class FileUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FileVisitResult visitFile(Path file, @NotNull BasicFileAttributes attrs) throws IOException {
|
||||
public @NotNull FileVisitResult visitFile(@NonNull Path file, @NotNull BasicFileAttributes attrs) throws IOException {
|
||||
// Pass files that are set to ignore
|
||||
if (excludeFiles.contains(file.getFileName().toString())) {
|
||||
Logging.finest("Ignoring file: " + file.getFileName());
|
||||
if (excludeFiles.contains(file)) {
|
||||
Logging.finest("Ignoring file: " + file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
// Copy the files
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package org.mvplugins.multiverse.core.utils.compatibility;
|
||||
|
||||
import io.vavr.control.Option;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.mvplugins.multiverse.core.utils.ReflectHelper;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Compatibility class used to handle API changes in {@link Bukkit} class.
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.6")
|
||||
public final class BukkitCompatibility {
|
||||
|
||||
private static final Option<Method> GET_LEVEL_DIRECTORY_METHOD;
|
||||
private static final Option<Method> GET_WORLD_NAMESPACED_KEY_METHOD;
|
||||
|
||||
static {
|
||||
GET_LEVEL_DIRECTORY_METHOD = Option.of(ReflectHelper.getMethod(Server.class, "getLevelDirectory"));
|
||||
GET_WORLD_NAMESPACED_KEY_METHOD = Option.of(ReflectHelper.getMethod(Bukkit.class, "getWorld", NamespacedKey.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the folder where all the worlds will be store. Before 26.1, all worlds are stored in the root directory
|
||||
* of the server, which can be obtained by {@link Server#getWorldContainer()}.
|
||||
* <br />
|
||||
* After 26.1, PaperMC changed all worlds are stored in the "[level]/dimensions/minecraft" folder under the world
|
||||
* level directory, which needs to be manually parsed.
|
||||
*
|
||||
* @return The location where all the worlds folders should be, depending on server's mc version.
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.6")
|
||||
@NotNull
|
||||
public static Path getWorldFoldersDirectory() {
|
||||
Server server = Bukkit.getServer();
|
||||
return GET_LEVEL_DIRECTORY_METHOD.map(method -> ReflectHelper.invokeMethod(server, method))
|
||||
.filter(Path.class::isInstance)
|
||||
.map(Path.class::cast)
|
||||
.map(path -> path.resolve("dimensions/minecraft"))
|
||||
.getOrElse(() -> server.getWorldContainer().toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the world with the given name or namespaced key (e.g. minecraft:overworld) exists,
|
||||
* and return it if it does.
|
||||
* <br />
|
||||
* Note that some default world names have different namespaced key matched with them.
|
||||
* E.g.: world -> minecraft:overworld, world_nether -> minecraft:the_nether, world_the_end -> minecraft:the_end.
|
||||
*
|
||||
* @param nameOrKey Either a name or namespaced key string representation.
|
||||
* @return The world if it exists
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.6")
|
||||
@NotNull
|
||||
public static Option<World> getWorldByNameOrKey(@NotNull String nameOrKey) {
|
||||
return Option.of(Bukkit.getWorld(nameOrKey))
|
||||
.orElse(() -> GET_WORLD_NAMESPACED_KEY_METHOD
|
||||
.map(method -> ReflectHelper.invokeMethod(null, method, NamespacedKey.fromString(nameOrKey)))
|
||||
.filter(World.class::isInstance)
|
||||
.map(World.class::cast));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Contains classes to handle compatibility due to differing API methods across different server versions and the
|
||||
* API gaps between PaperMC and Spigot.
|
||||
*/
|
||||
package org.mvplugins.multiverse.core.utils.compatibility;
|
||||
@@ -396,7 +396,7 @@ final class WorldConfig {
|
||||
/**
|
||||
* Migrates the entry fee settings. Assumes entry fee is disabled if currency is not set.
|
||||
*/
|
||||
static final class EntryFeeMigrator implements MigratorAction {
|
||||
private static final class EntryFeeMigrator implements MigratorAction {
|
||||
@Override
|
||||
public void migrate(ConfigurationSection config) {
|
||||
String currency = config.getString("entry-fee.currency", "");
|
||||
|
||||
@@ -20,8 +20,10 @@ import io.vavr.control.Option;
|
||||
import io.vavr.control.Try;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldBorder;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
@@ -49,6 +51,7 @@ import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.utils.CaseInsensitiveStringMap;
|
||||
import org.mvplugins.multiverse.core.utils.ReflectHelper;
|
||||
import org.mvplugins.multiverse.core.utils.ServerProperties;
|
||||
import org.mvplugins.multiverse.core.utils.compatibility.BukkitCompatibility;
|
||||
import org.mvplugins.multiverse.core.utils.result.Attempt;
|
||||
import org.mvplugins.multiverse.core.utils.result.FailureReason;
|
||||
import org.mvplugins.multiverse.core.utils.FileUtils;
|
||||
@@ -86,7 +89,11 @@ import static org.mvplugins.multiverse.core.world.helpers.DataStore.WorldConfigS
|
||||
@Service // SUPPRESS CHECKSTYLE: ClassFanOutComplexity This is the world manager, it's going to be complex.
|
||||
public final class WorldManager {
|
||||
|
||||
private static final List<String> CLONE_IGNORE_FILES = Arrays.asList("uid.dat", "session.lock");
|
||||
private static final List<String> CLONE_IGNORE_FILES = List.of(
|
||||
"uid.dat", "session.lock", // All pre 26.1 format
|
||||
"data/paper/metadata.dat" // New papermc format for 26.1+
|
||||
);
|
||||
|
||||
private static final DimensionFormat DEFAULT_NETHER_FORMAT = new DimensionFormat("%overworld%_nether");
|
||||
private static final DimensionFormat DEFAULT_END_FORMAT = new DimensionFormat("%overworld%_the_end");
|
||||
|
||||
@@ -699,6 +706,7 @@ public final class WorldManager {
|
||||
private Attempt<File, DeleteFailureReason> validateWorldToDelete(
|
||||
@NotNull LoadedMultiverseWorld world) {
|
||||
return world.getBukkitWorld().map(World::getWorldFolder)
|
||||
.peek(folder -> Logging.finer("World folder for world %s is at: %s", world.getName(), folder.getPath()))
|
||||
.filter(worldNameChecker::isValidWorldFolder)
|
||||
.map(this::<File, DeleteFailureReason>worldActionResult)
|
||||
.getOrElse(() -> {
|
||||
@@ -719,18 +727,19 @@ public final class WorldManager {
|
||||
.mapAttempt(validatedOptions -> {
|
||||
ImportWorldOptions importWorldOptions = ImportWorldOptions
|
||||
.worldName(validatedOptions.newWorldName())
|
||||
.biome(validatedOptions.world().getBiome())
|
||||
.environment(validatedOptions.world().getEnvironment())
|
||||
.generator(validatedOptions.world().getGenerator());
|
||||
.biome(validatedOptions.fromWorld().getBiome())
|
||||
.environment(validatedOptions.fromWorld().getEnvironment())
|
||||
.generator(validatedOptions.fromWorld().getGenerator());
|
||||
return importWorld(importWorldOptions).transform(CloneFailureReason.IMPORT_FAILED);
|
||||
})
|
||||
.onSuccess(newWorld -> {
|
||||
cloneWorldTransferData(options, newWorld);
|
||||
if (options.keepWorldConfig()) {
|
||||
newWorld.setSpawnLocation(options.world().getSpawnLocation());
|
||||
// Special case for spawn location as it's considered a hidden config
|
||||
newWorld.setSpawnLocation(options.fromWorld().getSpawnLocation());
|
||||
}
|
||||
saveWorldsConfig();
|
||||
pluginManager.callEvent(new MVWorldClonedEvent(newWorld, options.world()));
|
||||
pluginManager.callEvent(new MVWorldClonedEvent(newWorld, options.fromWorld()));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -752,19 +761,24 @@ public final class WorldManager {
|
||||
if (worldNameChecker.hasWorldFolder(newWorldName)) {
|
||||
return worldActionResult(CloneFailureReason.WORLD_EXIST_FOLDER, newWorldName);
|
||||
}
|
||||
if (!worldNameChecker.isValidWorldFolder(options.fromWorld().getName())) {
|
||||
return worldActionResult(CloneFailureReason.FROM_WORLD_FOLDER_INVALID, options.fromWorld().getName());
|
||||
}
|
||||
return worldActionResult(options);
|
||||
}
|
||||
|
||||
private Attempt<CloneWorldOptions, CloneFailureReason> cloneWorldCopyFolder(@NotNull CloneWorldOptions options) {
|
||||
if (options.saveBukkitWorld()) {
|
||||
Logging.finer("Saving bukkit world before cloning: " + options.world().getName());
|
||||
options.world().getBukkitWorld().peek(this::saveWorldWithFlush);
|
||||
options.fromWorld().asLoadedWorld().peek(loadedWorld -> {
|
||||
Logging.finer("Saving world before cloning: " + loadedWorld.getName());
|
||||
loadedWorld.getBukkitWorld().peek(this::saveWorldWithFlush);
|
||||
});
|
||||
}
|
||||
File worldFolder = options.world().getBukkitWorld().map(World::getWorldFolder).get();
|
||||
File newWorldFolder = new File(Bukkit.getWorldContainer(), options.newWorldName());
|
||||
File worldFolder = BukkitCompatibility.getWorldFoldersDirectory().resolve(options.fromWorld().getName()).toFile();
|
||||
File newWorldFolder = BukkitCompatibility.getWorldFoldersDirectory().resolve(options.newWorldName()).toFile();
|
||||
return fileUtils.copyFolder(worldFolder, newWorldFolder, CLONE_IGNORE_FILES).fold(
|
||||
exception -> worldActionResult(CloneFailureReason.COPY_FAILED,
|
||||
options.world().getName(), exception),
|
||||
options.fromWorld().getName(), exception),
|
||||
success -> worldActionResult(options));
|
||||
}
|
||||
|
||||
@@ -780,25 +794,30 @@ public final class WorldManager {
|
||||
}
|
||||
|
||||
private void cloneWorldTransferData(@NotNull CloneWorldOptions options, @NotNull LoadedMultiverseWorld newWorld) {
|
||||
DataTransfer<LoadedMultiverseWorld> dataTransfer = transferData(options, options.world());
|
||||
dataTransfer.pasteAllTo(newWorld);
|
||||
}
|
||||
|
||||
private DataTransfer<LoadedMultiverseWorld> transferData(
|
||||
@NotNull KeepWorldSettingsOptions options, @NotNull LoadedMultiverseWorld world) {
|
||||
DataTransfer<LoadedMultiverseWorld> 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);
|
||||
new DataTransfer<MultiverseWorld>()
|
||||
.addDataStore(new WorldConfigStore<>(), options.fromWorld())
|
||||
.pasteAllTo(newWorld);
|
||||
}
|
||||
|
||||
return dataTransfer;
|
||||
newWorld.getBukkitWorld().peek(bukkitWorld -> {
|
||||
if (!options.keepWorldBorder()) {
|
||||
WorldBorder worldBorder = bukkitWorld.getWorldBorder();
|
||||
worldBorder.reset();
|
||||
}
|
||||
|
||||
if (!options.keepGameRule()) {
|
||||
Arrays.stream(bukkitWorld.getGameRules())
|
||||
.map(gameRuleName -> GameRule.getByName(gameRuleName))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(gameRule -> {
|
||||
Object gameRuleDefault = bukkitWorld.getGameRuleDefault(gameRule);
|
||||
if (gameRuleDefault != null) {
|
||||
bukkitWorld.setGameRule(gameRule, gameRuleDefault);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -809,11 +828,12 @@ public final class WorldManager {
|
||||
*/
|
||||
public Attempt<LoadedMultiverseWorld, RegenFailureReason> regenWorld(@NotNull RegenWorldOptions options) {
|
||||
LoadedMultiverseWorld world = options.world();
|
||||
DataTransfer<LoadedMultiverseWorld> dataTransfer = transferData(options, world);
|
||||
DataTransfer<LoadedMultiverseWorld> dataTransfer = regenWorldTransferData(options, world);
|
||||
boolean shouldKeepSpawnLocation = options.keepWorldConfig() && options.seed() == world.getSeed();
|
||||
Location spawnLocation = world.getSpawnLocation();
|
||||
|
||||
CreateWorldOptions createWorldOptions = CreateWorldOptions.worldName(world.getName())
|
||||
.biome(world.getBiome())
|
||||
.environment(world.getEnvironment())
|
||||
.generateStructures(world.canGenerateStructures().getOrElse(true))
|
||||
.generator(world.getGenerator())
|
||||
@@ -837,6 +857,23 @@ public final class WorldManager {
|
||||
});
|
||||
}
|
||||
|
||||
private DataTransfer<LoadedMultiverseWorld> regenWorldTransferData(
|
||||
@NotNull KeepWorldSettingsOptions options, @NotNull LoadedMultiverseWorld world) {
|
||||
DataTransfer<LoadedMultiverseWorld> 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);
|
||||
}
|
||||
|
||||
return dataTransfer;
|
||||
}
|
||||
|
||||
private <T, F extends FailureReason> Attempt<T, F> worldActionResult(@NotNull T value) {
|
||||
return Attempt.success(value);
|
||||
}
|
||||
@@ -946,12 +983,12 @@ public final class WorldManager {
|
||||
* @return A list of all potential worlds.
|
||||
*/
|
||||
public List<String> getPotentialWorlds() {
|
||||
File[] files = Bukkit.getWorldContainer().listFiles();
|
||||
File[] files = BukkitCompatibility.getWorldFoldersDirectory().toFile().listFiles();
|
||||
if (files == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.stream(files)
|
||||
.filter(file -> !isWorld(file.getName()))
|
||||
.filter(file -> BukkitCompatibility.getWorldByNameOrKey(file.getName()).isEmpty())
|
||||
.filter(worldNameChecker::isValidWorldFolder)
|
||||
.map(File::getName)
|
||||
.toList();
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.bukkit.World;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.config.handle.StringPropertyHandle;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
|
||||
/**
|
||||
* A data store for storing and restoring data from an object.
|
||||
@@ -90,14 +91,14 @@ public interface DataStore<T> {
|
||||
/**
|
||||
* A {@link DataStore} for storing and restoring world properties for a multiverse world.
|
||||
*/
|
||||
class WorldConfigStore implements DataStore<LoadedMultiverseWorld> {
|
||||
class WorldConfigStore<T extends MultiverseWorld> implements DataStore<T> {
|
||||
private Map<String, Object> configMap;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public WorldConfigStore copyFrom(LoadedMultiverseWorld world) {
|
||||
public WorldConfigStore<T> copyFrom(T world) {
|
||||
this.configMap = new HashMap<>();
|
||||
StringPropertyHandle worldPropertyHandler = world.getStringPropertyHandle();
|
||||
worldPropertyHandler.getAllPropertyNames().forEach(name -> worldPropertyHandler.getProperty(name)
|
||||
@@ -111,7 +112,7 @@ public interface DataStore<T> {
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public WorldConfigStore pasteTo(LoadedMultiverseWorld world) {
|
||||
public WorldConfigStore<T> pasteTo(T world) {
|
||||
if (configMap == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package org.mvplugins.multiverse.core.world.helpers;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Option;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.utils.REPatterns;
|
||||
import org.mvplugins.multiverse.core.utils.compatibility.BukkitCompatibility;
|
||||
|
||||
/**
|
||||
* <p>Utility class in helping to check the status of a world name and it's associated world folder.</p>
|
||||
@@ -29,6 +31,18 @@ public final class WorldNameChecker {
|
||||
"plugins",
|
||||
"versions");
|
||||
|
||||
private static final List<WorldFolderSchema> WORLD_FOLDER_SCHEMA = List.of(
|
||||
// OLD
|
||||
WorldFolderSchema.file("level.dat"),
|
||||
WorldFolderSchema.folder("DIM1"),
|
||||
WorldFolderSchema.folder("DIM-1"),
|
||||
// NEW
|
||||
WorldFolderSchema.file("paper-world.yml"),
|
||||
WorldFolderSchema.folder("data"),
|
||||
WorldFolderSchema.folder("entities"),
|
||||
WorldFolderSchema.folder("poi"),
|
||||
WorldFolderSchema.folder("region"));
|
||||
|
||||
/**
|
||||
* Checks if a world name is valid.
|
||||
*
|
||||
@@ -105,7 +119,8 @@ public final class WorldNameChecker {
|
||||
if (worldName == null) {
|
||||
return FolderStatus.DOES_NOT_EXIST;
|
||||
}
|
||||
File worldFolder = new File(Bukkit.getWorldContainer(), worldName);
|
||||
File worldFolder = BukkitCompatibility.getWorldFoldersDirectory().resolve(worldName).toFile();
|
||||
Logging.finer("Checking valid folder for world '%s' at: '%s'", worldName, worldFolder.getPath());
|
||||
return checkFolder(worldFolder);
|
||||
}
|
||||
|
||||
@@ -120,7 +135,7 @@ public final class WorldNameChecker {
|
||||
if (worldFolder == null || !worldFolder.exists() || !worldFolder.isDirectory()) {
|
||||
return FolderStatus.DOES_NOT_EXIST;
|
||||
}
|
||||
if (!folderHasDat(worldFolder)) {
|
||||
if (!folderWorldSchemaCheck(worldFolder)) {
|
||||
return FolderStatus.NOT_A_WORLD;
|
||||
}
|
||||
return FolderStatus.VALID;
|
||||
@@ -133,9 +148,54 @@ public final class WorldNameChecker {
|
||||
* @param worldFolder The File that may be a world.
|
||||
* @return True if it looks like a world, else false.
|
||||
*/
|
||||
private boolean folderHasDat(@NotNull File worldFolder) {
|
||||
File[] files = worldFolder.listFiles((file, name) -> name.toLowerCase(Locale.ENGLISH).endsWith(".dat"));
|
||||
return files != null && files.length > 0;
|
||||
private boolean folderWorldSchemaCheck(@NotNull File worldFolder) {
|
||||
return WORLD_FOLDER_SCHEMA.stream()
|
||||
.filter(schema -> schema.check(worldFolder))
|
||||
.count() >= 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to check if a file or folder exist.
|
||||
*/
|
||||
private interface WorldFolderSchema {
|
||||
|
||||
static WorldFolderSchema file(String path) {
|
||||
return new WorldFile(path);
|
||||
}
|
||||
|
||||
static WorldFolderSchema folder(String path) {
|
||||
return new WorldFolder(path);
|
||||
}
|
||||
|
||||
boolean check(File worldFolder);
|
||||
|
||||
final class WorldFile implements WorldFolderSchema {
|
||||
private final String path;
|
||||
|
||||
private WorldFile(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(File worldFolder) {
|
||||
File thisFolder = worldFolder.toPath().resolve(path).toFile();
|
||||
return thisFolder.exists() && thisFolder.isFile();
|
||||
}
|
||||
}
|
||||
|
||||
final class WorldFolder implements WorldFolderSchema {
|
||||
private final String path;
|
||||
|
||||
private WorldFolder(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(File worldFolder) {
|
||||
File thisFolder = worldFolder.toPath().resolve(path).toFile();
|
||||
return thisFolder.exists() && thisFolder.isDirectory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.mvplugins.multiverse.core.world.options;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
|
||||
/**
|
||||
* Options for customizing the cloning of a world.
|
||||
@@ -9,17 +11,35 @@ import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
public final class CloneWorldOptions implements KeepWorldSettingsOptions {
|
||||
|
||||
/**
|
||||
* Creates a new {@link CloneWorldOptions} instance with the given world.
|
||||
* Creates a new {@link CloneWorldOptions} instance with the given loaded world.
|
||||
*
|
||||
* @param world The world to clone.
|
||||
* @param fromWorld The loaded world to clone.
|
||||
* @param newWorldName The name of the new world.
|
||||
* @return A new {@link CloneWorldOptions} instance.
|
||||
*
|
||||
* @deprecated Cloning can be done from unloaded worlds as well. Use {@link #fromTo(MultiverseWorld, String)} instead.
|
||||
*/
|
||||
public static CloneWorldOptions fromTo(LoadedMultiverseWorld world, String newWorldName) {
|
||||
return new CloneWorldOptions(world, newWorldName);
|
||||
@Deprecated(forRemoval = true, since = "5.6")
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
|
||||
public static @NotNull CloneWorldOptions fromTo(@NotNull LoadedMultiverseWorld fromWorld, @NotNull String newWorldName) {
|
||||
return new CloneWorldOptions(fromWorld, newWorldName);
|
||||
}
|
||||
|
||||
private final LoadedMultiverseWorld world;
|
||||
/**
|
||||
* Creates a new {@link CloneWorldOptions} instance with the given world.
|
||||
*
|
||||
* @param fromWorld The world to clone.
|
||||
* @param newWorldName The name of the new world.
|
||||
* @return A new {@link CloneWorldOptions} instance.
|
||||
*
|
||||
* @since 5.6
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.6")
|
||||
public static @NotNull CloneWorldOptions fromTo(@NotNull MultiverseWorld fromWorld, @NotNull String newWorldName) {
|
||||
return new CloneWorldOptions(fromWorld, newWorldName);
|
||||
}
|
||||
|
||||
private final MultiverseWorld fromWorld;
|
||||
private final String newWorldName;
|
||||
private boolean keepGameRule = true;
|
||||
private boolean keepWorldConfig = true;
|
||||
@@ -27,18 +47,34 @@ public final class CloneWorldOptions implements KeepWorldSettingsOptions {
|
||||
|
||||
private boolean keepWorldBorder = true;
|
||||
|
||||
CloneWorldOptions(LoadedMultiverseWorld world, String newWorldName) {
|
||||
this.world = world;
|
||||
CloneWorldOptions(MultiverseWorld fromWorld, String newWorldName) {
|
||||
this.fromWorld = fromWorld;
|
||||
this.newWorldName = newWorldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world to clone.
|
||||
* Gets the loaded world to clone.
|
||||
*
|
||||
* @return The world to clone.
|
||||
*
|
||||
* @deprecated Cloning can be done from unloaded worlds as well. Use {@link #fromWorld()} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "5.6")
|
||||
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
|
||||
public LoadedMultiverseWorld world() {
|
||||
return world;
|
||||
return fromWorld.asLoadedWorld().getOrNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the loaded world to clone.
|
||||
*
|
||||
* @return The world to clone.
|
||||
*
|
||||
* @since 5.6
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.6")
|
||||
public @NotNull MultiverseWorld fromWorld() {
|
||||
return fromWorld;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,7 +82,7 @@ public final class CloneWorldOptions implements KeepWorldSettingsOptions {
|
||||
*
|
||||
* @return The name of the new world.
|
||||
*/
|
||||
public String newWorldName() {
|
||||
public @NotNull String newWorldName() {
|
||||
return newWorldName;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.mvplugins.multiverse.core.world.reasons;
|
||||
import co.aikar.locales.MessageKey;
|
||||
import co.aikar.locales.MessageKeyProvider;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.utils.result.FailureReason;
|
||||
|
||||
@@ -30,6 +31,14 @@ public enum CloneFailureReason implements FailureReason {
|
||||
*/
|
||||
WORLD_EXIST_LOADED(MVCorei18n.CLONEWORLD_WORLDEXISTLOADED),
|
||||
|
||||
/**
|
||||
* The source world folder is invalid.
|
||||
*
|
||||
* @since 5.6
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.6")
|
||||
FROM_WORLD_FOLDER_INVALID(MVCorei18n.CLONEWORLD_FROMWORLDFOLDERINVALID),
|
||||
|
||||
/**
|
||||
* Failed to copy the world folder contents.
|
||||
*/
|
||||
|
||||
@@ -273,6 +273,7 @@ mv-core.cloneworld.invalidworldname=World '{world}' contains invalid characters!
|
||||
mv-core.cloneworld.worldexistfolder=World '{world}' exists in server folders! You need to delete it first before cloning.
|
||||
mv-core.cloneworld.worldexistunloaded=World '{world}' already exists and it's unloaded! You need to delete it first before cloning.
|
||||
mv-core.cloneworld.worldexistloaded=World '{world}' already exists! You need to delete it first before cloning.
|
||||
mv-core.cloneworld.fromworldfolderinvalid=Source world '{world}' folder contents does not seem to be a valid world! Make sure it contains the correct world structure of data and region folders.
|
||||
mv-core.cloneworld.copyfailed=Failed to copy world to '{world}': {error}\n&fSee console for more details.
|
||||
|
||||
mv-core.createworld.invalidworldname=World '{world}' contains invalid characters!
|
||||
@@ -288,7 +289,7 @@ mv-core.deleteworld.failedtodeletefolder=Failed to delete world folder '{world}'
|
||||
mv-core.importworld.invalidworldname=World '{world}' contains invalid characters!
|
||||
mv-core.importworld.worldexistunloaded=World '{world}' already exists, but it's not loaded!&f Type '&a/mv load {world}&f' if you wish to load it.
|
||||
mv-core.importworld.worldexistloaded=World '{world}' already exists!
|
||||
mv-core.importworld.worldfolderinvalid=World '{world}' folder contents does not seem to be a valid world!\n&cIf the server software does something different with world folders, or you are very certain the world is valid, use '&3--skip-folder-check&c' flag.
|
||||
mv-core.importworld.worldfolderinvalid=World '{world}' folder contents does not seem to be a valid world! Make sure it contains the correct world structure of data and region folders.\n&cIf the server software does something different with world folders, or you are very certain the world is valid, use '&3--skip-folder-check&c' flag.
|
||||
mv-core.importworld.bukkitenvironmentmismatch=Environment mismatch detected!&f The world '{world}' is already loaded with environment '{bukkitEnvironment}', but Multiverse is trying to import it with environment '{mvEnvironment}'.
|
||||
|
||||
mv-core.loadworld.worldalreadyloading=World '{world}' is already loading! Please wait...
|
||||
|
||||
@@ -39,6 +39,8 @@ public class MVServerMock extends ServerMock {
|
||||
world.getWorldFolder().mkdirs();
|
||||
createFile(new File(world.getWorldFolder(), "uid.dat"));
|
||||
createFile(new File(world.getWorldFolder(), "level.dat"));
|
||||
new File(world.getWorldFolder(), "region").mkdir();
|
||||
new File(world.getWorldFolder(), "data").mkdir();
|
||||
addWorld(world);
|
||||
return world;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,15 @@ import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.mockbukkit.mockbukkit.matcher.plugin.PluginManagerFiredEventClassMatcher.hasFiredEventInstance
|
||||
import org.mockbukkit.mockbukkit.matcher.plugin.PluginManagerFiredEventClassMatcher.hasNotFiredEventInstance
|
||||
import org.mvplugins.multiverse.core.TestWithMockBukkit
|
||||
import org.mvplugins.multiverse.core.event.world.*
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldClonedEvent
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldCreatedEvent
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldDeleteEvent
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldImportedEvent
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldLoadedEvent
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldPropertyChangedEvent
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldRegeneratedEvent
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldRemovedEvent
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldUnloadedEvent
|
||||
import org.mvplugins.multiverse.core.world.options.CloneWorldOptions
|
||||
import org.mvplugins.multiverse.core.world.options.CreateWorldOptions
|
||||
import org.mvplugins.multiverse.core.world.options.DeleteWorldOptions
|
||||
@@ -190,6 +198,8 @@ class WorldManagerTest : TestWithMockBukkit() {
|
||||
fun `Load world failed - world folder exists but not imported`() {
|
||||
File(Bukkit.getWorldContainer(), "worldfolder").mkdir()
|
||||
File(Bukkit.getWorldContainer(), "worldfolder/level.dat").createNewFile()
|
||||
File(Bukkit.getWorldContainer(), "worldfolder/data").mkdir()
|
||||
File(Bukkit.getWorldContainer(), "worldfolder/region").mkdir()
|
||||
assertEquals(
|
||||
LoadFailureReason.WORLD_EXIST_FOLDER,
|
||||
worldManager.loadWorld("worldfolder").failureReason
|
||||
@@ -270,8 +280,10 @@ class WorldManagerTest : TestWithMockBukkit() {
|
||||
fun `Get potential worlds`() {
|
||||
File(Bukkit.getWorldContainer(), "newworld1").mkdir()
|
||||
File(Bukkit.getWorldContainer(), "newworld1/level.dat").createNewFile()
|
||||
File(Bukkit.getWorldContainer(), "newworld1/data").mkdir()
|
||||
File(Bukkit.getWorldContainer(), "newworld2").mkdir()
|
||||
File(Bukkit.getWorldContainer(), "newworld2/level.dat").createNewFile()
|
||||
File(Bukkit.getWorldContainer(), "newworld2/data").mkdir()
|
||||
assertEquals(setOf("newworld1", "newworld2"), worldManager.getPotentialWorlds().toSet())
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,15 @@ class WorldNameCheckerTest : TestWithMockBukkit() {
|
||||
fun `Valid world folder`() {
|
||||
File(Bukkit.getWorldContainer(), "test").mkdir()
|
||||
File(Bukkit.getWorldContainer(), "test/level.dat").createNewFile()
|
||||
File(Bukkit.getWorldContainer(), "test/data").mkdir()
|
||||
assertEquals(WorldNameChecker.FolderStatus.VALID, worldNameChecker.checkFolder("test"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Valid world folder v26-1 format`() {
|
||||
File(Bukkit.getWorldContainer(), "test").mkdir()
|
||||
File(Bukkit.getWorldContainer(), "test/region").mkdir()
|
||||
File(Bukkit.getWorldContainer(), "test/data").mkdir()
|
||||
assertEquals(WorldNameChecker.FolderStatus.VALID, worldNameChecker.checkFolder("test"))
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user