Skip to content

Commit ee4cd18

Browse files
authored
Merge pull request #3410 from Multiverse/v5.5-2
V5.5-2
2 parents f446c94 + b6c309a commit ee4cd18

File tree

13 files changed

+221
-41
lines changed

13 files changed

+221
-41
lines changed

src/main/java/org/mvplugins/multiverse/core/MultiverseCore.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ public void onDisable() {
126126
MultiverseCoreApi.shutdown();
127127
shutdownDependencyInjection();
128128
PluginServiceLocatorFactory.get().shutdown();
129+
Logging.info("- Disabled");
129130
Logging.shutdown();
130131
}
131132

src/main/java/org/mvplugins/multiverse/core/command/MVCommandCompletions.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
import org.mvplugins.multiverse.core.world.generators.GeneratorPlugin;
5454
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
5555

56-
import static org.mvplugins.multiverse.core.utils.StringFormatter.addonToCommaSeperated;
56+
import static org.mvplugins.multiverse.core.utils.StringFormatter.addOnToCommaSeparated;
5757

5858
@Service
5959
public class MVCommandCompletions extends PaperCommandCompletions {
@@ -163,7 +163,7 @@ private Collection<String> completeWithPreconditions(
163163
}
164164
}
165165
if (context.hasConfig("multiple")) {
166-
return addonToCommaSeperated(context.getInput(), handler.getCompletions(context));
166+
return addOnToCommaSeparated(context.getInput(), handler.getCompletions(context));
167167
}
168168
return handler.getCompletions(context);
169169
}
@@ -334,7 +334,7 @@ private Collection<String> suggestPlayersArray(BukkitCommandCompletionContext co
334334
matchedPlayers.add(name);
335335
}
336336
}
337-
return addonToCommaSeperated(context.getInput(), matchedPlayers);
337+
return addOnToCommaSeparated(context.getInput(), matchedPlayers);
338338
}
339339

340340
private Collection<String> suggestSpawnCategoryPropsName(BukkitCommandCompletionContext context) {

src/main/java/org/mvplugins/multiverse/core/commands/CreateCommand.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919

2020
import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
2121
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
22-
import org.mvplugins.multiverse.core.command.MVCommandManager;
2322
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
2423
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
2524
import org.mvplugins.multiverse.core.command.flag.CommandValueFlag;
2625
import org.mvplugins.multiverse.core.command.flag.FlagBuilder;
2726
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
2827
import org.mvplugins.multiverse.core.locale.MVCorei18n;
2928
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
29+
import org.mvplugins.multiverse.core.utils.StringFormatter;
3030
import org.mvplugins.multiverse.core.utils.result.Attempt.Failure;
3131
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
3232
import org.mvplugins.multiverse.core.world.WorldManager;
@@ -53,7 +53,7 @@ class CreateCommand extends CoreCommand {
5353
@CommandPermission("multiverse.core.create")
5454
@CommandCompletion("@empty @environments @flags:groupName=" + Flags.NAME)
5555
@Syntax("<name> <environment> [--seed <seed> --generator <generator[:id]> --world-type <worldtype> --adjust-spawn "
56-
+ "--no-structures --biome <biome>]")
56+
+ "--no-structures --biome <biome> --properties <prop1=value1,prop2=value2,...>]")
5757
@Description("{@@mv-core.create.description}")
5858
void onCreateCommand(
5959
MVCommandIssuer issuer,
@@ -68,7 +68,7 @@ void onCreateCommand(
6868

6969
@Optional
7070
@Syntax("[--seed <seed> --generator <generator[:id]> --world-type <worldtype> --adjust-spawn "
71-
+ "--no-structures --biome <biome>]")
71+
+ "--no-structures --biome <biome> --properties <prop1=value1,prop2=value2,...>]")
7272
@Description("{@@mv-core.create.flags.description}")
7373
String[] flagArray) {
7474
ParsedCommandFlags parsedFlags = flags.parse(flagArray);
@@ -78,14 +78,15 @@ void onCreateCommand(
7878
issuer.sendInfo(MVCorei18n.CREATE_LOADING);
7979

8080
worldManager.createWorld(CreateWorldOptions.worldName(worldName)
81-
.biome(parsedFlags.flagValue(flags.biome, ""))
82-
.environment(environment)
83-
.seed(parsedFlags.flagValue(flags.seed))
84-
.worldType(parsedFlags.flagValue(flags.worldType, WorldType.NORMAL))
85-
.useSpawnAdjust(!parsedFlags.hasFlag(flags.noAdjustSpawn))
86-
.generator(parsedFlags.flagValue(flags.generator, ""))
87-
.generatorSettings(parsedFlags.flagValue(flags.generatorSettings, ""))
88-
.generateStructures(!parsedFlags.hasFlag(flags.noStructures)))
81+
.biome(parsedFlags.flagValue(flags.biome, ""))
82+
.environment(environment)
83+
.seed(parsedFlags.flagValue(flags.seed))
84+
.worldType(parsedFlags.flagValue(flags.worldType, WorldType.NORMAL))
85+
.useSpawnAdjust(!parsedFlags.hasFlag(flags.noAdjustSpawn))
86+
.generator(parsedFlags.flagValue(flags.generator, ""))
87+
.generatorSettings(parsedFlags.flagValue(flags.generatorSettings, ""))
88+
.generateStructures(!parsedFlags.hasFlag(flags.noStructures))
89+
.worldPropertyStrings(StringFormatter.parseCSVMap(parsedFlags.flagValue(flags.properties))))
8990
.onSuccess(newWorld -> messageSuccess(issuer, newWorld))
9091
.onFailure(failure -> messageFailure(issuer, failure));
9192
}
@@ -180,6 +181,10 @@ private Flags(
180181
.addAlias("-b")
181182
.completion(input -> biomeProviderFactory.suggestBiomeString(input))
182183
.build());
184+
185+
private final CommandValueFlag<String> properties = flag(CommandValueFlag.builder("--properties", String.class)
186+
.addAlias("-p")
187+
.build());
183188
}
184189

185190
@Service

src/main/java/org/mvplugins/multiverse/core/config/CoreConfig.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,16 @@ public boolean getEnforceFlight() {
186186
return configHandle.get(configNodes.enforceFlight);
187187
}
188188

189+
@ApiStatus.AvailableSince("5.5")
190+
public Try<Void> setGamemodeAndFlightEnforceDelay(int delayTicks) {
191+
return configHandle.set(configNodes.gamemodeAndFlightEnforceDelay, delayTicks);
192+
}
193+
194+
@ApiStatus.AvailableSince("5.5")
195+
public int getGamemodeAndFlightEnforceDelay() {
196+
return configHandle.get(configNodes.gamemodeAndFlightEnforceDelay);
197+
}
198+
189199
@ApiStatus.AvailableSince("5.3")
190200
public Try<Void> setApplyEntitySpawnRate(boolean applyEntitySpawnRate) {
191201
return configHandle.set(configNodes.applyEntitySpawnRate, applyEntitySpawnRate);
@@ -641,6 +651,16 @@ public EventPriority getEventPriorityPlayerTeleport() {
641651
return configHandle.get(configNodes.eventPriorityPlayerTeleport);
642652
}
643653

654+
@ApiStatus.AvailableSince("5.5")
655+
public Try<Void> setEventPriorityPlayerWorldChange(EventPriority eventPriorityPlayerWorldChange) {
656+
return configHandle.set(configNodes.eventPriorityPlayerWorldChange, eventPriorityPlayerWorldChange);
657+
}
658+
659+
@ApiStatus.AvailableSince("5.5")
660+
public EventPriority getEventPriorityPlayerWorldChange() {
661+
return configHandle.get(configNodes.eventPriorityPlayerWorldChange);
662+
}
663+
644664
public Try<Void> setBukkitYmlPath(String bukkitYmlPath) {
645665
return configHandle.set(configNodes.bukkitYmlPath, bukkitYmlPath);
646666
}

src/main/java/org/mvplugins/multiverse/core/config/CoreConfigNodes.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ private <N extends Node> N node(N node) {
135135
.name("enforce-flight")
136136
.build());
137137

138+
final ConfigNode<Integer> gamemodeAndFlightEnforceDelay = node(ConfigNode.builder("world.gamemode-and-flight-enforce-delay", Integer.class)
139+
.comment("")
140+
.comment("Sets the delay in ticks before Multiverse enforces gamemode and flight ability on world change.")
141+
.comment("Increase this value if you are experiencing issues with other plugins overriding gamemode or flight ability.")
142+
.comment("Or set to 0 to enforce immediately during world change event.")
143+
.defaultValue(1)
144+
.name("gamemode-and-flight-enforce-delay")
145+
.suggester((sender -> List.of("0", "1", "2", "5", "10")))
146+
.build());
147+
138148
final ConfigNode<Boolean> applyEntitySpawnRate = node(ConfigNode.builder("world.apply-entity-spawn-rate", Boolean.class)
139149
.comment("")
140150
.comment("Sets whether Multiverse will apply the world's entity `tick-rate` config in worlds.yml.")
@@ -545,6 +555,18 @@ private <N extends Node> N node(N node) {
545555
"full effect after a server restart."))
546556
.build());
547557

558+
final ConfigNode<EventPriority> eventPriorityPlayerWorldChange = node(ConfigNode.builder("event-priority.player-changed-world", EventPriority.class)
559+
.defaultValue(EventPriority.NORMAL)
560+
.name("event-priority-player-changed-world")
561+
.comment("")
562+
.comment("This config option defines the priority for the PlayerChangedWorldEvent.")
563+
.onLoadAndChange((oldValue, newValue) ->
564+
eventPriorityMapper.get().setPriority("mvcore-player-changed-world", newValue))
565+
.onChange((sender, oldValue, newValue) ->
566+
sender.sendMessage(ChatColor.YELLOW + "'event-priority.player-changed-world' config option will only take " +
567+
"full effect after a server restart."))
568+
.build());
569+
548570
private final ConfigHeaderNode miscHeader = node(ConfigHeaderNode.builder("misc")
549571
.comment("")
550572
.comment("")

src/main/java/org/mvplugins/multiverse/core/config/node/ListConfigNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,9 @@ private void setDefaults() {
120120
private void setDefaultSuggester() {
121121
if (itemSuggester instanceof SenderNodeSuggester senderItemSuggester) {
122122
this.suggester = (SenderNodeSuggester)(sender, input) ->
123-
StringFormatter.addonToCommaSeperated(input, senderItemSuggester.suggest(sender, input));
123+
StringFormatter.addOnToCommaSeparated(input, senderItemSuggester.suggest(sender, input));
124124
} else {
125-
this.suggester = input -> StringFormatter.addonToCommaSeperated(input, itemSuggester.suggest(input));
125+
this.suggester = input -> StringFormatter.addOnToCommaSeparated(input, itemSuggester.suggest(input));
126126
}
127127
}
128128

src/main/java/org/mvplugins/multiverse/core/listeners/MVPlayerListener.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77

88
package org.mvplugins.multiverse.core.listeners;
99

10-
import java.util.Map;
1110
import java.util.Objects;
12-
import java.util.concurrent.ConcurrentHashMap;
1311

1412
import com.dumptruckman.minecraft.util.Logging;
1513
import io.vavr.control.Option;
@@ -257,9 +255,9 @@ private void teleportToDestinationOnJoin(Player player, DestinationInstance<?, ?
257255
* @param event The Event that was fired.
258256
*/
259257
@EventMethod
260-
@DefaultEventPriority(EventPriority.MONITOR)
258+
@EventPriorityKey("mvcore-player-changed-world")
259+
@DefaultEventPriority(EventPriority.NORMAL)
261260
void playerChangedWorld(PlayerChangedWorldEvent event) {
262-
// Permissions now determine whether or not to handle a gamemode.
263261
this.handleGameModeAndFlight(event.getPlayer(), event.getPlayer().getWorld());
264262
}
265263

@@ -402,21 +400,31 @@ void playerPortal(PlayerPortalEvent event) {
402400
}
403401

404402
/**
405-
* Handles the gamemode for the specified {@link Player}.
403+
* Handles the gamemode for the specified {@link Player}. Delays the enforcement if configured to do so
404+
* to ensure multiverse has final say over other plugins changing gamemodes.
406405
*
407406
* @param player The {@link Player}.
408407
* @param world The {@link World} the player is supposed to be in.
409408
*/
410409
private void handleGameModeAndFlight(final Player player, World world) {
411-
// We perform this task one tick later to MAKE SURE that the player actually reaches the
412-
// destination world, otherwise we'd be changing the player mode if they havent moved anywhere.
413-
this.server.getScheduler().runTaskLater(this.plugin, () -> {
414-
if (!player.isOnline() || !player.getWorld().equals(world)) {
415-
return;
416-
}
417-
Logging.finer("Handling gamemode and flight for player %s in world '%s'", player.getName(), world.getName());
418-
enforcementHandler.handleFlightEnforcement(player);
419-
enforcementHandler.handleGameModeEnforcement(player);
420-
}, 1L);
410+
if (config.getGamemodeAndFlightEnforceDelay() <= 0) {
411+
doGameModeAndFlightEnforcement(player, world);
412+
return;
413+
}
414+
server.getScheduler().runTaskLater(
415+
this.plugin,
416+
() -> doGameModeAndFlightEnforcement(player, world),
417+
config.getGamemodeAndFlightEnforceDelay()
418+
);
419+
}
420+
421+
private void doGameModeAndFlightEnforcement(Player player, World world) {
422+
if (!player.isOnline() || !player.getWorld().equals(world)) {
423+
Logging.finer("Player %s is no longer online or not in the expected world '%s'", player.getName(), world.getName());
424+
return;
425+
}
426+
Logging.finer("Handling gamemode and flight for player %s in world '%s'", player.getName(), world.getName());
427+
enforcementHandler.handleFlightEnforcement(player);
428+
enforcementHandler.handleGameModeEnforcement(player);
421429
}
422430
}

src/main/java/org/mvplugins/multiverse/core/teleportation/BlockSafety.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ public boolean canSpawnAtLocationSafely(@NotNull Location location) {
132132
*/
133133
public boolean canSpawnAtBlockSafely(@NotNull Block block) {
134134
Logging.finest("Checking spawn safety for location: %s, %s, %s", block.getX(), block.getY(), block.getZ());
135+
if (!block.getWorld().getWorldBorder().isInside(block.getLocation())) {
136+
Logging.finest("Location is outside world border.");
137+
return false;
138+
}
135139
if (isUnsafeSpawnBody(block)) {
136140
// Player body will be stuck in solid
137141
Logging.finest("Unsafe location for player's body: " + block);

src/main/java/org/mvplugins/multiverse/core/utils/StringFormatter.java

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
import com.google.common.base.Strings;
44
import com.google.common.collect.Sets;
5+
import org.jetbrains.annotations.ApiStatus;
6+
import org.jetbrains.annotations.Contract;
57
import org.jetbrains.annotations.NotNull;
68
import org.jetbrains.annotations.Nullable;
9+
import org.jetbrains.annotations.Unmodifiable;
710

811
import java.util.ArrayList;
912
import java.util.Arrays;
1013
import java.util.Collection;
1114
import java.util.List;
15+
import java.util.Map;
1216
import java.util.Set;
1317
import java.util.stream.Collectors;
1418

@@ -30,15 +34,15 @@ private StringFormatter() {
3034
* @param list the list of strings to join. If the list is empty, an empty string is returned.
3135
* @return the concatenated string
3236
*/
33-
public static @NotNull String joinAnd(List<String> list) {
37+
public static @NotNull String joinAnd(@Nullable List<String> list) {
3438
return join(list, ", ", " and ");
3539
}
3640

37-
public static @NotNull String join(Collection list, String separator) {
41+
public static @NotNull String join(@Nullable Collection<?> list, @NotNull String separator) {
3842
if (list == null || list.isEmpty()) {
3943
return "";
4044
}
41-
return list.stream().map(String::valueOf).collect(Collectors.joining(separator)).toString();
45+
return list.stream().map(String::valueOf).collect(Collectors.joining(separator));
4246
}
4347

4448
/**
@@ -50,7 +54,7 @@ private StringFormatter() {
5054
* @param lastSeparator the separator to use before the last element. For example, " and ".
5155
* @return the concatenated string
5256
*/
53-
public static @NotNull String join(List<String> list, String separator, String lastSeparator) {
57+
public static @NotNull String join(@Nullable List<String> list, @NotNull String separator, @NotNull String lastSeparator) {
5458
if (list == null || list.isEmpty()) {
5559
return "";
5660
}
@@ -71,11 +75,30 @@ private StringFormatter() {
7175

7276
/**
7377
* Appends a list of suggestions to the end of the input string, separated by commas.
78+
*
7479
* @param input The current input
7580
* @param addons The autocomplete suggestions
7681
* @return A collection of suggestions with the next suggestion appended
82+
*
83+
* @deprecated Method name has a spelling error. Use {@link #addOnToCommaSeparated(String, Collection)} instead.
7784
*/
85+
@Deprecated(forRemoval = true, since = "5.5")
86+
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
7887
public static Collection<String> addonToCommaSeperated(@Nullable String input, @NotNull Collection<String> addons) {
88+
return addOnToCommaSeparated(input, addons);
89+
}
90+
91+
/**
92+
* Appends a list of suggestions to the end of the input string, separated by commas.
93+
*
94+
* @param input The current input
95+
* @param addons The autocomplete suggestions
96+
* @return A collection of suggestions with the next suggestion appended
97+
*
98+
* @since 5.5
99+
*/
100+
@ApiStatus.AvailableSince("5.5")
101+
public static Collection<String> addOnToCommaSeparated(@Nullable String input, @NotNull Collection<String> addons) {
79102
if (Strings.isNullOrEmpty(input)) {
80103
return addons;
81104
}
@@ -94,7 +117,7 @@ public static Collection<String> addonToCommaSeperated(@Nullable String input, @
94117
* @param args The args to parse
95118
* @return The parsed args
96119
*/
97-
public static Collection<String> parseQuotesInArgs(String[] args) {
120+
public static @NotNull Collection<String> parseQuotesInArgs(@NotNull String[] args) {
98121
List<String> result = new ArrayList<>(args.length);
99122
StringBuilder current = new StringBuilder();
100123
boolean inQuotes = false;
@@ -139,7 +162,28 @@ public static Collection<String> parseQuotesInArgs(String[] args) {
139162
* @param input The string to add quotes to
140163
* @return The quoted string
141164
*/
142-
public static String quoteMultiWordString(String input) {
143-
return input.contains(" ") ? "\"" + input + "\"" : input;
165+
@Contract("null -> null")
166+
public static @Nullable String quoteMultiWordString(@Nullable String input) {
167+
return input != null && input.contains(" ") ? "\"" + input + "\"" : input;
168+
}
169+
170+
/**
171+
* Parses a CSV string of key=value pairs into a map.
172+
* E.g. "key1=value1,key2=value2" -> {key1=value1, key2=value2}
173+
*
174+
* @param input The CSV string to parse
175+
* @return The parsed map
176+
*
177+
* @since 5.5
178+
*/
179+
@ApiStatus.AvailableSince("5.5")
180+
public static @Unmodifiable Map<String, String> parseCSVMap(@Nullable String input) {
181+
if (Strings.isNullOrEmpty(input)) {
182+
return Map.of();
183+
}
184+
return REPatterns.COMMA.splitAsStream(input)
185+
.map(s -> REPatterns.EQUALS.split(s, 2))
186+
.filter(parts -> parts.length == 2)
187+
.collect(Collectors.toUnmodifiableMap(parts -> parts[0], parts -> parts[1]));
144188
}
145189
}

0 commit comments

Comments
 (0)