Skip to content
Draft

V5.7 #3450

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
192ee26
Refactor compatibility utilities to use Try for method and class retr…
benwoo1110 May 1, 2026
8a1bbeb
Refactor long chained if-else to use Attempt#failIf
benwoo1110 May 1, 2026
c9db931
Merge pull request #3446 from Multiverse/refactor/try-reflect
benwoo1110 May 1, 2026
372b600
Merge pull request #3447 from Multiverse/refactor/fail-if
benwoo1110 May 1, 2026
9643cce
Migrate world config to store worlds using namespace key
benwoo1110 May 2, 2026
272e118
Create, import and clone worlds with namespaced key
benwoo1110 May 2, 2026
65db598
Merge pull request #3449 from Multiverse/feat/namespace-key
benwoo1110 May 3, 2026
a6cbe44
Add world key to output in `/mv info` command
benwoo1110 May 3, 2026
3052489
Move getCoordinateScale to WorldCompatibility
benwoo1110 May 3, 2026
ee40eb5
Prevent instantiation of utility classes by adding private constructors
benwoo1110 May 3, 2026
ac86b69
Merge pull request #3451 from Multiverse/feat/info-key
benwoo1110 May 3, 2026
8060514
Merge pull request #3453 from Multiverse/refactor/coord-scale
benwoo1110 May 3, 2026
58402b0
Merge pull request #3452 from Multiverse/fix/instantiation
benwoo1110 May 3, 2026
c291df2
Add support for looking up worlds with namespace key string
benwoo1110 May 3, 2026
f470df6
Fix isIteratingOverLevels field not found
benwoo1110 May 3, 2026
9ed5837
Merge pull request #3455 from Multiverse/fix/isIteratingOverLevels
benwoo1110 May 3, 2026
9460f0b
Merge pull request #3454 from Multiverse/feat/key-lookup
benwoo1110 May 3, 2026
944acd8
Add support for potential worlds finding with new 26.1 dimensions format
benwoo1110 May 3, 2026
3e62084
Fix command typo in spawn adjustment logging message
benwoo1110 May 3, 2026
35133ee
Add support for creating world with bonus chest and force spawn
benwoo1110 May 4, 2026
dfeb72e
Bump mockbukkit to fix skipped tests
benwoo1110 May 4, 2026
ed92349
Merge pull request #3457 from Multiverse/fix/command-typo
benwoo1110 May 4, 2026
867462b
Merge pull request #3460 from Multiverse/chore/bump-mockbukkit
benwoo1110 May 4, 2026
7937d88
Add preCreatureSpawn event handler to optimize spawn checks
benwoo1110 May 4, 2026
0b18c8d
Merge pull request #3456 from Multiverse/feat/potential-worlds
benwoo1110 May 4, 2026
a7d0672
Merge pull request #3458 from Multiverse/feat/pre-creature-spawn
benwoo1110 May 4, 2026
fd8d026
Merge pull request #3459 from Multiverse/feat/bonus-chest-force-spawn
benwoo1110 May 4, 2026
5451e55
Add support for custom destination with `--remove-player` flag
benwoo1110 May 4, 2026
bc07b24
Merge pull request #3461 from Multiverse/feat/remove-player-dest
benwoo1110 May 5, 2026
5e7637b
Add support for setting world border time with ticks
benwoo1110 May 5, 2026
603ab5b
Improve getCoordinateScale method checking
benwoo1110 May 5, 2026
5ad47da
Add tests for TickDuration parsing and conversion methods
benwoo1110 May 5, 2026
cab6358
Merge pull request #3463 from Multiverse/refactor/get-coordinate-scale
benwoo1110 May 5, 2026
a59ec16
Merge pull request #3462 from Multiverse/feat/worldborder-ticks
benwoo1110 May 5, 2026
357532d
Add missing world properties to InfoCommand output and remove unused …
benwoo1110 May 5, 2026
d65cde7
Store generator settings used to ensure it persist during regen
benwoo1110 May 5, 2026
bf05abc
Fix unable to remove world config with legacy name as key
benwoo1110 May 6, 2026
2e6dc23
Merge pull request #3464 from Multiverse/fix/remove-world-name
benwoo1110 May 6, 2026
6d88c6c
Add generator-settings property to test files
benwoo1110 May 6, 2026
392d66a
Merge pull request #3465 from Multiverse/feat/generator-settings
benwoo1110 May 6, 2026
c486f03
Notify users about the removal of the keep spawn in memory feature in…
benwoo1110 May 6, 2026
534f274
Merge pull request #3466 from Multiverse/fix/warn-keep-spawn
benwoo1110 May 6, 2026
e29b851
Make MultiverseCoreApi class final to prevent subclassing
benwoo1110 May 6, 2026
0fdc74a
Retain bonus chest setting on regen world
benwoo1110 May 6, 2026
a54a3b6
Merge pull request #3467 from Multiverse/refactor/final-api-class
benwoo1110 May 6, 2026
504f17e
Bump mockbukkit to version that supports bonus chest
benwoo1110 May 6, 2026
e82bc00
Merge pull request #3468 from Multiverse/fix/regen-bonus-chest
benwoo1110 May 6, 2026
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
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ repositories {
configure(apiDependencies) {
serverApiVersion = '1.21.11-R0.1-SNAPSHOT'
mockBukkitServerApiVersion = '1.21'
mockBukkitVersion = '4.100.0'
mockBukkitVersion = '4.110.0'
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
/**
* Provides access to the MultiverseCore API.
*/
public class MultiverseCoreApi {
public final class MultiverseCoreApi {

private static MultiverseCoreApi instance;
private static final List<Consumer<MultiverseCoreApi>> whenLoadedCallbacks = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.mvplugins.multiverse.core.world.WorldManager;
import org.mvplugins.multiverse.core.world.generators.GeneratorPlugin;
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
import org.mvplugins.multiverse.core.world.helpers.PotentialWorldFinder;

import static org.mvplugins.multiverse.core.utils.StringFormatter.addOnToCommaSeparated;

Expand All @@ -65,6 +66,7 @@ public class MVCommandCompletions extends PaperCommandCompletions {
private final CorePermissionsChecker corePermissionsChecker;
private final AnchorManager anchorManager;
private final GeneratorProvider generatorProvider;
private final PotentialWorldFinder potentialWorldFinder;

@Inject
MVCommandCompletions(
Expand All @@ -74,7 +76,8 @@ public class MVCommandCompletions extends PaperCommandCompletions {
@NotNull CoreConfig config,
@NotNull CorePermissionsChecker corePermissionsChecker,
@NotNull AnchorManager anchorManager,
@NotNull GeneratorProvider generatorProvider
@NotNull GeneratorProvider generatorProvider,
@NotNull PotentialWorldFinder potentialWorldFinder
) {
super(mvCommandManager);
this.commandManager = mvCommandManager;
Expand All @@ -84,6 +87,7 @@ public class MVCommandCompletions extends PaperCommandCompletions {
this.corePermissionsChecker = corePermissionsChecker;
this.anchorManager = anchorManager;
this.generatorProvider = generatorProvider;
this.potentialWorldFinder = potentialWorldFinder;

registerAsyncCompletion("anchornames", this::suggestAnchorNames);
registerAsyncCompletion("commands", this::suggestCommands);
Expand Down Expand Up @@ -297,7 +301,7 @@ private Collection<String> suggestMVWorlds(BukkitCommandCompletionContext contex
.toList();
}
case "potential" -> {
return worldManager.getPotentialWorlds();
return potentialWorldFinder.findPotentialWorlds();
}
}
Logging.severe("Invalid MVWorld scope: " + scope);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.mvplugins.multiverse.core.locale.message.Message;
import org.mvplugins.multiverse.core.utils.PlayerFinder;
import org.mvplugins.multiverse.core.utils.REPatterns;
import org.mvplugins.multiverse.core.utils.tick.TickDuration;
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
import org.mvplugins.multiverse.core.world.MultiverseWorld;
import org.mvplugins.multiverse.core.world.WorldManager;
Expand Down Expand Up @@ -93,6 +94,7 @@ public class MVCommandContexts extends PaperCommandContexts {
registerIssuerAwareContext(PlayerArrayValue.class, playerArrayContextBuilder().generateContext(PlayerArrayValue::new));
registerIssuerAwareContext(PlayerLocation.class, this::parsePlayerLocation);
registerContext(SpawnCategory[].class, this::parseSpawnCategories);
registerContext(TickDuration.class, this::parseTickDuration);
}

private MVCommandIssuer parseMVCommandIssuer(BukkitCommandExecutionContext context) {
Expand Down Expand Up @@ -393,4 +395,13 @@ private SpawnCategory[] parseSpawnCategories(BukkitCommandExecutionContext conte
}
return categories.toArray(new SpawnCategory[0]);
}

private TickDuration parseTickDuration(BukkitCommandExecutionContext context) {
String arg = context.popFirstArg();
return TickDuration.parseString(arg)
.getOrElseThrow(failure ->
new InvalidCommandArgument("Invalid time duration format: \"" +arg + "\". Use a number " +
"followed by an optional suffix (s for seconds, d for game days) or just a number " +
"for ticks. Examples: 100, 5s, 2d"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import java.util.List;
import java.util.Locale;
import java.util.function.Function;
import java.util.function.Supplier;

import co.aikar.commands.InvalidCommandArgument;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -40,34 +42,34 @@ public class CommandValueFlag<T> extends CommandFlag {

private final Class<T> type;
private final boolean optional;
private final T defaultValue;
private final Supplier<? extends T> defaultValueSupplier;
private final Function<String, T> context;
private final Function<String, Collection<String>> completion;

/**
* Creates a new flag.
*
* @param key The key for the new flag.
* @param aliases The aliases that also refer to this flag.
* @param type The type of the value.
* @param optional Allow for flag without value.
* @param defaultValue The default value if optional is true and user does not specify a value.
* @param context Function to parse string into value type.
* @param completion Function to get completion for this flag.
* @param key The key for the new flag.
* @param aliases The aliases that also refer to this flag.
* @param type The type of the value.
* @param optional Allow for flag without value.
* @param defaultValueSupplier The default value if optional is true and user does not specify a value.
* @param context Function to parse string into value type.
* @param completion Function to get completion for this flag.
*/
protected CommandValueFlag(
@NotNull String key,
@NotNull List<String> aliases,
@NotNull Class<T> type,
boolean optional,
@Nullable T defaultValue,
@Nullable Supplier<? extends T> defaultValueSupplier,
@Nullable Function<String, T> context,
@Nullable Function<String, Collection<String>> completion
) {
super(key, aliases);
this.type = type;
this.optional = optional;
this.defaultValue = defaultValue;
this.defaultValueSupplier = defaultValueSupplier;
this.context = context;
this.completion = completion;
}
Expand Down Expand Up @@ -96,7 +98,7 @@ public boolean isOptional() {
* @return The default value.
*/
public @Nullable T getDefaultValue() {
return defaultValue;
return defaultValueSupplier == null ? null : defaultValueSupplier.get();
}

/**
Expand Down Expand Up @@ -126,7 +128,7 @@ public boolean isOptional() {
public static class Builder<T, S extends Builder<T, S>> extends CommandFlag.Builder<S> {
protected final Class<T> type;
protected boolean optional = false;
protected T defaultValue = null;
protected Supplier<? extends T> defaultValueSupplier = null;
protected Function<String, T> context = null;
protected Function<String, Collection<String>> completion = null;

Expand Down Expand Up @@ -158,7 +160,21 @@ public Builder(@NotNull String key, @NotNull Class<T> type) {
* @return The builder.
*/
public @NotNull S defaultValue(@NotNull T defaultValue) {
this.defaultValue = defaultValue;
return defaultValue(() -> defaultValue);
}

/**
* Set the default value supplier. Used if optional is true and user does not specify a value.
* Supplier is only called when command is executed with the flag is present in input.
*
* @param defaultValueSupplier The default value supplier
* @return The builder
*
* @since 5.7
*/
@ApiStatus.AvailableSince("5.7")
public @NotNull S defaultValue(@NotNull Supplier<? extends T> defaultValueSupplier) {
this.defaultValueSupplier = defaultValueSupplier;
return (S) this;
}

Expand Down Expand Up @@ -194,7 +210,7 @@ public Builder(@NotNull String key, @NotNull Class<T> type) {
if (context == null && !String.class.equals(type)) {
throw new IllegalStateException("Context is required for non-string value flags");
}
return new CommandValueFlag<>(key, aliases, type, optional, defaultValue, context, completion);
return new CommandValueFlag<>(key, aliases, type, optional, defaultValueSupplier, context, completion);
}
}

Expand All @@ -207,7 +223,7 @@ public Builder(@NotNull String key, @NotNull Class<T> type) {
public static class EnumBuilder<T extends Enum<T>, S extends EnumBuilder<T, S>> extends CommandFlag.Builder<S> {
protected final Class<T> type;
protected boolean optional = false;
protected T defaultValue = null;
protected Supplier<? extends T> defaultValueSupplier = null;
protected Function<String, T> context = null;
protected Function<String, Collection<String>> completion = null;

Expand Down Expand Up @@ -253,7 +269,21 @@ private void setEnumCompletion() {
* @return The builder.
*/
public @NotNull S defaultValue(@NotNull T defaultValue) {
this.defaultValue = defaultValue;
return defaultValue(() -> defaultValue);
}

/**
* Set the default value to supply. Used if optional is true and user does not specify a value.
* Supplier is only called when command is executed with the flag is present in input.
*
* @param defaultValueSupplier The default value supplier.
* @return The builder.
*
* @since 5.7
*/
@ApiStatus.AvailableSince("5.7")
public @NotNull S defaultValue(@NotNull Supplier<? extends T> defaultValueSupplier) {
this.defaultValueSupplier = defaultValueSupplier;
return (S) this;
}

Expand All @@ -264,7 +294,7 @@ private void setEnumCompletion() {
*/
@Override
public @NotNull CommandValueFlag<T> build() {
return new CommandValueFlag<>(key, aliases, type, optional, defaultValue, context, completion);
return new CommandValueFlag<>(key, aliases, type, optional, defaultValueSupplier, context, completion);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.mvplugins.multiverse.core.command.flags;

import co.aikar.commands.InvalidCommandArgument;
import jakarta.inject.Inject;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
import org.mvplugins.multiverse.core.destination.DestinationInstance;
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
import org.mvplugins.multiverse.core.destination.core.WorldDestination;
import org.mvplugins.multiverse.core.exceptions.command.MVInvalidCommandArgument;
import org.mvplugins.multiverse.core.world.WorldManager;

@ApiStatus.AvailableSince("5.7")
@Service
public class RemovePlayerDestinationFlags extends FlagBuilder {

public static final String NAME = "removeplayer";

private WorldManager worldManager;
private DestinationsProvider destinationsProvider;
private WorldDestination worldDestination;

protected RemovePlayerDestinationFlags(
@NotNull String name,
@NotNull CommandFlagsManager flagsManager,
@NotNull WorldManager worldManager,
@NotNull DestinationsProvider destinationsProvider,
@NotNull WorldDestination worldDestination
) {
super(name, flagsManager);
this.worldManager = worldManager;
this.destinationsProvider = destinationsProvider;
this.worldDestination = worldDestination;
}

@Inject
private RemovePlayerDestinationFlags(
@NotNull CommandFlagsManager flagsManager,
@NotNull WorldManager worldManager,
@NotNull DestinationsProvider destinationsProvider,
@NotNull WorldDestination worldDestination
) {
super(NAME, flagsManager);
this.destinationsProvider = destinationsProvider;
this.worldManager = worldManager;
this.worldDestination = worldDestination;
}

public final CommandValueFlag<DestinationInstance> removePlayers = flag(CommandValueFlag.builder("--remove-players", DestinationInstance.class)

Check warning on line 54 in src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerDestinationFlags.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=Multiverse_Multiverse-Core&issues=AZ33I5-cpD15EvfQRU0w&open=AZ33I5-cpD15EvfQRU0w&pullRequest=3450
.addAlias("-r")
.defaultValue(() -> worldManager.getDefaultWorld()
.map(defaultWorld -> worldDestination.fromWorld(defaultWorld))
.getOrElseThrow(() -> new InvalidCommandArgument("No default world found, so the --remove-players flag requires a destination argument."))) //TODO: locale

Check warning on line 58 in src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerDestinationFlags.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=Multiverse_Multiverse-Core&issues=AZ33I5-cpD15EvfQRU0x&open=AZ33I5-cpD15EvfQRU0x&pullRequest=3450
.completion(input -> destinationsProvider.suggestDestinationStrings(Bukkit.getConsoleSender(), input))
.context(input -> destinationsProvider.parseDestination(input)
.getOrThrow(failure ->
MVInvalidCommandArgument.of(failure.getFailureMessage())))
.optional()
.build());
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package org.mvplugins.multiverse.core.command.flags;

import jakarta.inject.Inject;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;

/**
* @deprecated The --remove-players flag is being removed in favor of a more flexible system that allows for specifying
* a destination for players to be teleported to when a world is unloaded. See {@link RemovePlayerDestinationFlags}.
*/
@Deprecated(forRemoval = true, since = "5.7")
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
@Service
public class RemovePlayerFlags extends FlagBuilder {

Check warning on line 18 in src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerFlags.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not forget to remove this deprecated code someday.

See more on https://sonarcloud.io/project/issues?id=Multiverse_Multiverse-Core&issues=AZ33I5-8pD15EvfQRU0y&open=AZ33I5-8pD15EvfQRU0y&pullRequest=3450

public static final String NAME = "removeplayer";

Expand Down
Loading
Loading