Skip to content

Commit 29d3c0c

Browse files
authored
Merge pull request #3244 from Multiverse/5.1
5.1
2 parents 97cc7e5 + 4fd8350 commit 29d3c0c

File tree

59 files changed

+2140
-478
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2140
-478
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import jakarta.inject.Provider;
1616
import org.bukkit.configuration.file.FileConfiguration;
1717
import org.bukkit.configuration.serialization.ConfigurationSerialization;
18+
import org.jetbrains.annotations.ApiStatus;
1819
import org.jetbrains.annotations.NotNull;
1920
import org.jvnet.hk2.annotations.Service;
2021

@@ -238,7 +239,11 @@ private void logEnableMessage() {
238239
* Gets the MultiverseCoreApi
239240
*
240241
* @return The MultiverseCoreApi
242+
*
243+
* @deprecated Use {@link MultiverseCoreApi#get()} directly.
241244
*/
245+
@Deprecated(since = "5.1", forRemoval = true)
246+
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
242247
public MultiverseCoreApi getApi() {
243248
return MultiverseCoreApi.get();
244249
}

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.bukkit.Bukkit;
44
import org.bukkit.plugin.ServicePriority;
5+
import org.jetbrains.annotations.ApiStatus;
56
import org.jetbrains.annotations.NotNull;
67
import org.mvplugins.multiverse.core.anchor.AnchorManager;
78
import org.mvplugins.multiverse.core.config.CoreConfig;
@@ -15,32 +16,78 @@
1516
import org.mvplugins.multiverse.core.world.biomeprovider.BiomeProviderFactory;
1617
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
1718

19+
import java.util.ArrayList;
20+
import java.util.List;
1821
import java.util.Objects;
22+
import java.util.function.Consumer;
1923

2024
/**
2125
* Provides access to the MultiverseCore API.
2226
*/
2327
public class MultiverseCoreApi {
2428

2529
private static MultiverseCoreApi instance;
30+
private static final List<Consumer<MultiverseCoreApi>> whenLoadedCallbacks = new ArrayList<>();
2631

2732
static void init(@NotNull MultiverseCore multiverseCore) {
2833
if (instance != null) {
2934
throw new IllegalStateException("MultiverseCoreApi has already been initialized!");
3035
}
3136
instance = new MultiverseCoreApi(multiverseCore.getServiceLocator());
3237
Bukkit.getServicesManager().register(MultiverseCoreApi.class, instance, multiverseCore, ServicePriority.Normal);
38+
39+
whenLoadedCallbacks.forEach(c -> c.accept(instance));
40+
whenLoadedCallbacks.clear();
3341
}
3442

3543
static void shutdown() {
3644
Bukkit.getServicesManager().unregister(instance);
3745
instance = null;
3846
}
3947

48+
/**
49+
* Hook your plugin into the MultiverseCoreApi here to ensure you only start using the API after it has been initialized.
50+
* Use this if you know your plugin may load before Multiverse-Core is fully initialized.
51+
* <br/>
52+
* This handy method removes the need for you to check with plugin manager or listen to plugin enable event.
53+
* <br/>
54+
* Callback will be called immediately if the MultiverseCoreApi has already been initialized.
55+
*
56+
* @param consumer The callback to execute when the MultiverseCoreApi has been initialized.
57+
*
58+
* @since 5.1
59+
*/
60+
@ApiStatus.AvailableSince("5.1")
61+
public static void whenLoaded(@NotNull Consumer<MultiverseCoreApi> consumer) {
62+
if (instance != null) {
63+
consumer.accept(instance);
64+
} else {
65+
whenLoadedCallbacks.add(consumer);
66+
}
67+
}
68+
69+
/**
70+
* Checks if the MultiverseCoreApi has been initialized.
71+
*
72+
* @return True if the MultiverseCoreApi has been initialized, false otherwise
73+
*
74+
* @since 5.1
75+
*/
76+
@ApiStatus.AvailableSince("5.1")
77+
public static boolean isLoaded() {
78+
return instance != null;
79+
}
80+
4081
/**
4182
* Gets the MultiverseCoreApi. This will throw an exception if the Multiverse-Core has not been initialized.
83+
* <br/>
84+
* You can check if the MultiverseCoreApi has been initialized with {@link #isLoaded()} before using this method.
85+
* <br/>
86+
* Alternatively, you can use {@link #whenLoaded(Consumer)} to hook into the MultiverseCoreApi if your plugin may
87+
* load before Multiverse-Core is fully initialized.
4288
*
4389
* @return The MultiverseCoreApi
90+
* @throws IllegalStateException if the MultiverseCoreApi has not been initialized
4491
*/
4592
public static @NotNull MultiverseCoreApi get() {
4693
if (instance == null) {

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

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.mvplugins.multiverse.core;
22

3+
import com.google.common.collect.Lists;
34
import io.vavr.control.Option;
45
import jakarta.annotation.PostConstruct;
56
import jakarta.inject.Inject;
@@ -13,11 +14,16 @@
1314
import org.jvnet.hk2.annotations.Service;
1415

1516
import org.mvplugins.multiverse.core.economy.MVEconomist;
17+
import org.mvplugins.multiverse.core.utils.MinecraftTimeFormatter;
1618
import org.mvplugins.multiverse.core.utils.REPatterns;
1719
import org.mvplugins.multiverse.core.utils.StringFormatter;
1820
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
1921
import org.mvplugins.multiverse.core.world.WorldManager;
2022

23+
import java.util.ArrayList;
24+
import java.util.Arrays;
25+
import java.util.List;
26+
2127
@Service
2228
final class PlaceholderExpansionHook extends PlaceholderExpansion {
2329

@@ -68,32 +74,54 @@ public boolean persist() {
6874
@Override
6975
public @Nullable String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
7076
// Split string in to an Array with underscores
71-
String[] paramsArray = REPatterns.UNDERSCORE.split(params, 2);
77+
List<String> paramsArray = Lists.newArrayList(REPatterns.UNDERSCORE.split(params));
7278

7379
// No placeholder defined
74-
if (paramsArray.length < 1) {
75-
warning("No placeholder defined");
80+
if (paramsArray.isEmpty()) {
81+
warning("No placeholder key defined");
7682
return null;
7783
}
7884

79-
final var placeholder = paramsArray[0];
80-
Option<LoadedMultiverseWorld> targetWorld;
85+
final var placeholder = paramsArray.removeFirst();
86+
87+
String worldName = parseWorldName(offlinePlayer, paramsArray);
88+
if (worldName == null) return null;
89+
90+
return worldManager.getLoadedWorld(worldName)
91+
.onEmpty(() -> warning("Multiverse World not found: " + worldName))
92+
.map(world -> getWorldPlaceHolderValue(placeholder, paramsArray, world))
93+
.getOrNull();
94+
}
8195

82-
// If no world is defined, use the player's world
83-
if (paramsArray.length == 1) {
84-
if (!offlinePlayer.isOnline()) {
96+
private @Nullable String parseWorldName(OfflinePlayer offlinePlayer, List<String> paramsArray) {
97+
// No world defined, get from player
98+
if (paramsArray.isEmpty()) {
99+
if (offlinePlayer instanceof Player player) {
100+
return player.getWorld().getName();
101+
} else {
102+
warning("You must specify a world name for non-player placeholders");
85103
return null;
86104
}
87-
targetWorld = worldManager.getLoadedWorld(((Player)offlinePlayer).getWorld());
88-
} else {
89-
targetWorld = worldManager.getLoadedWorld(paramsArray[1]);
90105
}
91106

92-
// Fail if world is null
93-
return targetWorld.map(world -> getWorldPlaceHolderValue(placeholder, world)).getOrNull();
107+
// Try get from params
108+
String paramWorldName = paramsArray.getLast();
109+
if (worldManager.isLoadedWorld(paramWorldName)) {
110+
paramsArray.removeLast();
111+
return paramWorldName;
112+
}
113+
114+
// Param not a world, fallback to player
115+
if (offlinePlayer instanceof Player player) {
116+
return player.getWorld().getName();
117+
}
118+
warning("Multiverse World not found: " + paramWorldName);
119+
return null;
94120
}
95121

96-
private @Nullable String getWorldPlaceHolderValue(@NotNull String placeholder, @NotNull LoadedMultiverseWorld world) {
122+
private @Nullable String getWorldPlaceHolderValue(@NotNull String placeholder,
123+
@NotNull List<String> placeholderParams,
124+
@NotNull LoadedMultiverseWorld world) {
97125
// Switch to find what specific placeholder we want
98126
switch (placeholder.toLowerCase()) {
99127
case "alias" -> {
@@ -151,7 +179,22 @@ public boolean persist() {
151179
return String.valueOf(world.getSeed());
152180
}
153181
case "time" -> {
154-
return String.valueOf(world.getBukkitWorld().map(World::getTime).getOrElse(0L));
182+
String timeFormat = !placeholderParams.isEmpty() ? placeholderParams.getFirst() : "";
183+
long time = world.getBukkitWorld().map(World::getTime).getOrElse(0L);
184+
switch (timeFormat) {
185+
case "" -> {
186+
return String.valueOf(time);
187+
}
188+
case "12h" -> {
189+
return MinecraftTimeFormatter.format12h(time);
190+
}
191+
case "24h" -> {
192+
return MinecraftTimeFormatter.format24h(time);
193+
}
194+
default -> {
195+
return MinecraftTimeFormatter.formatTime(time, timeFormat);
196+
}
197+
}
155198
}
156199
case "type" -> {
157200
return world.getBukkitWorld().map(World::getWorldType).map(Enum::name).getOrElse("null");

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

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@
3333

3434
import org.mvplugins.multiverse.core.anchor.AnchorManager;
3535
import org.mvplugins.multiverse.core.anchor.MultiverseAnchor;
36+
import org.mvplugins.multiverse.core.command.context.issueraware.IssuerAwareValue;
37+
import org.mvplugins.multiverse.core.command.context.issueraware.MultiverseWorldValue;
38+
import org.mvplugins.multiverse.core.command.context.issueraware.PlayerArrayValue;
3639
import org.mvplugins.multiverse.core.config.CoreConfig;
3740
import org.mvplugins.multiverse.core.config.node.functions.DefaultSuggesterProvider;
3841
import org.mvplugins.multiverse.core.config.handle.PropertyModifyAction;
3942
import org.mvplugins.multiverse.core.destination.DestinationInstance;
43+
import org.mvplugins.multiverse.core.destination.DestinationSuggestionPacket;
4044
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
41-
import org.mvplugins.multiverse.core.destination.core.WorldDestination;
4245
import org.mvplugins.multiverse.core.permissions.CorePermissionsChecker;
4346
import org.mvplugins.multiverse.core.utils.REPatterns;
4447
import org.mvplugins.multiverse.core.utils.StringFormatter;
@@ -129,6 +132,22 @@ private Collection<String> completeWithPreconditions(
129132
if (context.hasConfig("playerOnly") && !context.getIssuer().isPlayer()) {
130133
return Collections.emptyList();
131134
}
135+
if (context.hasConfig("byIssuerForArg")) {
136+
Boolean byIssuerForArg = Try.of(() -> context.getContextValueByName(IssuerAwareValue.class, context.getConfig("byIssuerForArg")))
137+
.map(IssuerAwareValue::isByIssuer)
138+
.getOrElse(false);
139+
if (!byIssuerForArg) {
140+
return Collections.emptyList();
141+
}
142+
}
143+
if (context.hasConfig("notByIssuerForArg")) {
144+
Boolean byIssuerForArg = Try.of(() -> context.getContextValueByName(IssuerAwareValue.class, context.getConfig("notByIssuerForArg")))
145+
.map(IssuerAwareValue::isByIssuer)
146+
.getOrElse(false);
147+
if (byIssuerForArg) {
148+
return Collections.emptyList();
149+
}
150+
}
132151
if (context.hasConfig("resolveUntil")) {
133152
if (!Try.run(() -> context.getContextValueByName(Object.class, context.getConfig("resolveUntil"))).isSuccess()) {
134153
return Collections.emptyList();
@@ -195,7 +214,10 @@ private boolean checkPerms(CommandIssuer issuer, RegisteredCommand<?> command) {
195214
}
196215

197216
private Collection<String> suggestDestinations(BukkitCommandCompletionContext context) {
198-
return Try.of(() -> context.getContextValue(Player[].class))
217+
return Try.of(() -> context.getContextValue(PlayerArrayValue.class))
218+
.map(PlayerArrayValue::value)
219+
.recover(IllegalStateException.class, e -> context.getContextValue(Player[].class))
220+
.recover(IllegalStateException.class, e -> new Player[]{context.getContextValue(Player.class)})
199221
.map(players -> {
200222
if (players.length == 0) {
201223
// Most likely console did not specify a player
@@ -213,9 +235,7 @@ private Collection<String> suggestDestinationsWithPerms(CommandSender teleporter
213235
return destinationsProvider.suggestDestinations(teleporter, deststring).stream()
214236
.filter(packet -> corePermissionsChecker
215237
.checkDestinationPacketPermission(teleporter, Arrays.asList(players), packet))
216-
.map(packet -> packet.destination() instanceof WorldDestination
217-
? packet.destinationString()
218-
: packet.destination().getIdentifier() + ":" + packet.destinationString())
238+
.map(DestinationSuggestionPacket::parsableString)
219239
.toList();
220240
}
221241

@@ -248,7 +268,7 @@ private Collection<String> suggestGeneratorPlugins(BukkitCommandCompletionContex
248268
private Collection<String> suggestMVConfigValues(BukkitCommandCompletionContext context) {
249269
return Try.of(() -> context.getContextValue(String.class))
250270
.map(propertyName -> config.getStringPropertyHandle()
251-
.getSuggestedPropertyValue(propertyName, context.getInput(), PropertyModifyAction.SET))
271+
.getSuggestedPropertyValue(propertyName, context.getInput(), PropertyModifyAction.SET, context.getSender()))
252272
.getOrElse(Collections.emptyList());
253273
}
254274

@@ -283,18 +303,18 @@ private Collection<String> suggestMVWorlds(BukkitCommandCompletionContext contex
283303

284304
private Collection<String> suggestMVWorldPropsName(BukkitCommandCompletionContext context) {
285305
return Try.of(() -> {
286-
MultiverseWorld world = context.getContextValue(MultiverseWorld.class);
306+
MultiverseWorld world = context.getContextValue(MultiverseWorldValue.class).value();
287307
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
288308
return world.getStringPropertyHandle().getModifiablePropertyNames(action);
289309
}).getOrElse(Collections.emptyList());
290310
}
291311

292312
private Collection<String> suggestMVWorldPropsValue(BukkitCommandCompletionContext context) {
293313
return Try.of(() -> {
294-
MultiverseWorld world = context.getContextValue(MultiverseWorld.class);
314+
MultiverseWorld world = context.getContextValue(MultiverseWorldValue.class).value();
295315
PropertyModifyAction action = context.getContextValue(PropertyModifyAction.class);
296316
String propertyName = context.getContextValue(String.class);
297-
return world.getStringPropertyHandle().getSuggestedPropertyValue(propertyName, context.getInput(), action);
317+
return world.getStringPropertyHandle().getSuggestedPropertyValue(propertyName, context.getInput(), action, context.getSender());
298318
}).getOrElse(Collections.emptyList());
299319
}
300320

@@ -335,7 +355,7 @@ private Collection<String> suggestSpawnCategoryPropsValue(BukkitCommandCompletio
335355
return world.getEntitySpawnConfig()
336356
.getSpawnCategoryConfig(spawnCategory)
337357
.getStringPropertyHandle()
338-
.getSuggestedPropertyValue(propertyName, context.getInput(), action);
358+
.getSuggestedPropertyValue(propertyName, context.getInput(), action, context.getSender());
339359
}).getOrElse(Collections.emptyList());
340360
}
341361
}

0 commit comments

Comments
 (0)