mirror of
https://github.com/Multiverse/Multiverse-Core.git
synced 2026-11-04 08:42:11 -05:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f19be1671 |
No files matched your search
@@ -71,7 +71,14 @@ jobs:
|
||||
message: |
|
||||
### ✅ `${{ inputs.plugin_name }}` test build ready
|
||||
|
||||
Last updated for: [${{ github.event.workflow_run.head_sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.event.workflow_run.head_sha }})
|
||||
**Download:** [${{ inputs.plugin_name }}-pr${{ steps.artifact.outputs.number }}.zip](${{ steps.artifact.outputs.url }})
|
||||
The build and tests passed. This PR build is ready to try.
|
||||
|
||||
View [CI build and checks](${{ github.event.workflow_run.html_url }}) for more details.
|
||||
**[⬇️ Download test build](${{ steps.artifact.outputs.url }})**
|
||||
Extract the downloaded ZIP to get the plugin JAR.
|
||||
|
||||
| Build details | |
|
||||
| --- | --- |
|
||||
| Commit | `${{ github.event.workflow_run.head_sha }}` |
|
||||
| Workflow | [Run #${{ github.event.workflow_run.run_number }}](${{ github.event.workflow_run.html_url }}) |
|
||||
|
||||
<sub>Sign in to GitHub to download. Artifacts expire after the repository's retention period. This comment updates after successful builds.</sub>
|
||||
@@ -46,6 +46,3 @@ debug.txt
|
||||
|
||||
# Gradle
|
||||
.gradle
|
||||
|
||||
# Kotlin generated files
|
||||
/.kotlin/
|
||||
@@ -26,7 +26,6 @@ public enum MVCorei18n implements MessageKeyProvider {
|
||||
CONFIG_STRING_PARSER_INVALIDDOUBLE,
|
||||
CONFIG_STRING_PARSER_INVALIDFLOAT,
|
||||
CONFIG_STRING_PARSER_INVALIDLONG,
|
||||
CONFIG_STRING_PARSER_INVALIDMATERIAL,
|
||||
|
||||
// core config
|
||||
CORE_CONFIG_CUSTOMPORTALSEARCHRADIUS_NONNEGATIVE,
|
||||
|
||||
+1
-2
@@ -264,8 +264,7 @@ public final class AsyncSafetyTeleporterAction {
|
||||
Logging.finer("Teleported async %s to %s", teleportee.getName(), location);
|
||||
return Attempt.success(null);
|
||||
}
|
||||
Logging.warning("Failed to async teleport %s to %s. This is usually caused by another " +
|
||||
"plugin canceling the teleport event and not a bug with Multiverse.", teleportee.getName(), location);
|
||||
Logging.warning("Failed to async teleport %s to %s", teleportee.getName(), location);
|
||||
return Attempt.failure(TeleportFailureReason.TELEPORT_FAILED);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.bukkit.WorldType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.teleportation.BlockSafety;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.world.entity.EntityPurger;
|
||||
@@ -22,6 +22,11 @@ import org.mvplugins.multiverse.core.world.location.SpawnLocation;
|
||||
|
||||
/**
|
||||
* Extension of {@link MultiverseWorld} that represents a world that is currently loaded with bukkit world object.
|
||||
* <p>
|
||||
* Do not store instances of this class for future use during runtime. Worlds can be unloaded, removed, reloaded,
|
||||
* or regenerated, making stored instances stale. Instead, store a {@link MultiverseWorldRef} obtained from
|
||||
* {@link #asRef()} and call {@link MultiverseWorldRef#getLoaded()} when a loaded world is needed. The reference
|
||||
* returns an empty Option when the world is unloaded or no longer managed by Multiverse.
|
||||
*/
|
||||
public final class LoadedMultiverseWorld extends MultiverseWorld {
|
||||
|
||||
@@ -34,16 +39,13 @@ public final class LoadedMultiverseWorld extends MultiverseWorld {
|
||||
LoadedMultiverseWorld(
|
||||
@NotNull World world,
|
||||
@NotNull WorldConfig worldConfig,
|
||||
@NotNull CoreConfig config,
|
||||
@NotNull BlockSafety blockSafety,
|
||||
@NotNull LocationManipulation locationManipulation,
|
||||
@NotNull EntityPurger entityPurger
|
||||
) {
|
||||
super(worldConfig, config);
|
||||
@NotNull MultiverseCore multiverseCore
|
||||
) {
|
||||
super(worldConfig, multiverseCore);
|
||||
this.worldUid = world.getUID();
|
||||
this.blockSafety = blockSafety;
|
||||
this.locationManipulation = locationManipulation;
|
||||
this.entityPurger = entityPurger;
|
||||
this.blockSafety = multiverseCore.getServiceLocator().getService(BlockSafety.class);
|
||||
this.locationManipulation = multiverseCore.getServiceLocator().getService(LocationManipulation.class);
|
||||
this.entityPurger = multiverseCore.getServiceLocator().getService(EntityPurger.class);
|
||||
|
||||
setupWorldConfig(world);
|
||||
setupSpawnLocation(world);
|
||||
@@ -55,7 +57,6 @@ public final class LoadedMultiverseWorld extends MultiverseWorld {
|
||||
worldConfig.load();
|
||||
worldConfig.setEnvironment(world.getEnvironment());
|
||||
worldConfig.setSeed(world.getSeed());
|
||||
worldConfig.setLegacyWorldName(world.getName());
|
||||
}
|
||||
|
||||
private void setupSpawnLocation(World world) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import org.jetbrains.annotations.UnmodifiableView;
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.config.handle.StringPropertyHandle;
|
||||
import org.mvplugins.multiverse.core.utils.text.ChatTextFormatter;
|
||||
@@ -29,6 +30,11 @@ import org.mvplugins.multiverse.core.world.entity.EntitySpawnConfig;
|
||||
|
||||
/**
|
||||
* Represents a world handled by Multiverse which has all the custom properties provided by Multiverse.
|
||||
* <p>
|
||||
* Do not store instances of this class for future use during runtime. Worlds can be unloaded, removed, reloaded,
|
||||
* or regenerated, making stored instances stale. Instead, store a {@link MultiverseWorldRef} obtained from
|
||||
* {@link #asRef()} and retrieve the current world instance when needed. The reference returns an empty Option
|
||||
* when the world is no longer available.
|
||||
*/
|
||||
public sealed class MultiverseWorld permits LoadedMultiverseWorld {
|
||||
/**
|
||||
@@ -37,11 +43,13 @@ public sealed class MultiverseWorld permits LoadedMultiverseWorld {
|
||||
WorldConfig worldConfig;
|
||||
|
||||
protected final CoreConfig config;
|
||||
private final WorldStore worldStore;
|
||||
private String colourlessAlias = "";
|
||||
|
||||
MultiverseWorld(WorldConfig worldConfig, CoreConfig config) {
|
||||
MultiverseWorld(@NotNull WorldConfig worldConfig, @NotNull MultiverseCore multiverseCore) {
|
||||
this.worldConfig = worldConfig;
|
||||
this.config = config;
|
||||
this.config = multiverseCore.getServiceLocator().getService(CoreConfig.class);
|
||||
this.worldStore = multiverseCore.getServiceLocator().getService(WorldStore.class);
|
||||
this.worldConfig.setMVWorld(this);
|
||||
updateColourlessAlias();
|
||||
}
|
||||
@@ -125,6 +133,22 @@ public sealed class MultiverseWorld permits LoadedMultiverseWorld {
|
||||
.map(world -> (LoadedMultiverseWorld) world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reference to this world's key for storing and retrieving the current world instance at runtime.
|
||||
* <p>
|
||||
* Store this reference when retaining a world across reloads or regeneration, which make stored
|
||||
* {@link MultiverseWorld} and {@link LoadedMultiverseWorld} instances stale. Use {@link MultiverseWorldRef#get()}
|
||||
* or {@link MultiverseWorldRef#getLoaded()} to retrieve the current instance when needed.
|
||||
*
|
||||
* @return A reference that looks up the current world instance using this world's key.
|
||||
*
|
||||
* @since 5.9
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.9")
|
||||
public MultiverseWorldRef asRef() {
|
||||
return new MultiverseWorldRef(getKey(), worldStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the properties handler of this world.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.mvplugins.multiverse.core.world;
|
||||
|
||||
import io.vavr.control.Option;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A reference to a world by its key that can be stored and used to retrieve the current world instance at runtime.
|
||||
* <p>
|
||||
* Stored {@link MultiverseWorld} and {@link LoadedMultiverseWorld} instances become stale when a world is reloaded
|
||||
* or regenerated. This reference looks up the world on each call to {@link #get()} or {@link #getLoaded()}, allowing
|
||||
* callers to keep the reference across those operations and retrieve the current instance when needed.
|
||||
* Store this reference rather than caching the world instances returned by its methods.
|
||||
* <p>
|
||||
* Obtain a reference using {@link MultiverseWorld#asRef()}. Resolving a reference does not load the world.
|
||||
*
|
||||
* @since 5.9
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.9")
|
||||
public class MultiverseWorldRef {
|
||||
|
||||
private final NamespacedKey worldKey;
|
||||
private final WorldStore worldStore;
|
||||
|
||||
MultiverseWorldRef(@NotNull NamespacedKey worldKey, @NotNull WorldStore worldStore) {
|
||||
this.worldKey = worldKey;
|
||||
this.worldStore = worldStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current world instance for this reference's key, whether loaded or unloaded.
|
||||
* The world is looked up on each call so the returned instance reflects reloads and regeneration.
|
||||
*
|
||||
* @return The current world instance wrapped in an Option, or None if the world is no longer managed by Multiverse.
|
||||
*
|
||||
* @since 5.9
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.9")
|
||||
public Option<MultiverseWorld> get() {
|
||||
return worldStore.getWorld(worldKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current loaded world instance for this reference's key without loading the world.
|
||||
* The world is looked up on each call so the returned instance reflects reloads and regeneration.
|
||||
*
|
||||
* @return The current loaded world instance wrapped in an Option, or None if the world is unloaded or no longer
|
||||
* managed by Multiverse.
|
||||
*
|
||||
* @since 5.9
|
||||
*/
|
||||
@ApiStatus.AvailableSince("5.9")
|
||||
public Option<LoadedMultiverseWorld> getLoaded() {
|
||||
return worldStore.getLoadedWorld(worldKey);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import java.util.Objects;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Option;
|
||||
import io.vavr.control.Try;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Difficulty;
|
||||
@@ -27,9 +26,6 @@ import org.mvplugins.multiverse.core.config.node.ConfigNode;
|
||||
import org.mvplugins.multiverse.core.config.node.ListConfigNode;
|
||||
import org.mvplugins.multiverse.core.config.node.NodeGroup;
|
||||
import org.mvplugins.multiverse.core.economy.MVEconomist;
|
||||
import org.mvplugins.multiverse.core.exceptions.MultiverseException;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.utils.MaterialConverter;
|
||||
import org.mvplugins.multiverse.core.utils.text.ChatTextFormatter;
|
||||
import org.mvplugins.multiverse.core.world.helpers.AliasNameConflictChecker;
|
||||
@@ -39,8 +35,6 @@ import org.mvplugins.multiverse.core.world.location.NullSpawnLocation;
|
||||
import org.mvplugins.multiverse.core.world.location.SpawnLocation;
|
||||
import org.mvplugins.multiverse.core.world.entity.EntitySpawnConfig;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
/**
|
||||
* Represents nodes in a world configuration.
|
||||
*/
|
||||
@@ -49,6 +43,7 @@ final class WorldConfigNodes {
|
||||
|
||||
private final NodeGroup nodes = new NodeGroup();
|
||||
private WorldManager worldManager;
|
||||
private WorldStore worldStore;
|
||||
private EnforcementHandler enforcementHandler;
|
||||
private CoreConfig config;
|
||||
private AliasNameConflictChecker aliasNameConflictChecker;
|
||||
@@ -58,6 +53,7 @@ final class WorldConfigNodes {
|
||||
|
||||
WorldConfigNodes(@NotNull MultiverseCore multiverseCore, @NotNull WorldKeyOrName keyOrName) {
|
||||
this.worldManager = multiverseCore.getServiceLocator().getService(WorldManager.class);
|
||||
this.worldStore = multiverseCore.getServiceLocator().getService(WorldStore.class);
|
||||
this.enforcementHandler = multiverseCore.getServiceLocator().getService(EnforcementHandler.class);
|
||||
this.config = multiverseCore.getServiceLocator().getService(CoreConfig.class);
|
||||
this.aliasNameConflictChecker = multiverseCore.getServiceLocator().getService(AliasNameConflictChecker.class);
|
||||
@@ -106,7 +102,7 @@ final class WorldConfigNodes {
|
||||
final ConfigNode<String> alias = node(ConfigNode.builder("alias", String.class)
|
||||
.defaultValue("")
|
||||
.onLoadAndChange((sender, oldValue, newValue) -> {
|
||||
worldManager.getWorldStore().changeAlias(
|
||||
worldStore.changeAlias(
|
||||
ChatTextFormatter.removeColor(oldValue),
|
||||
ChatTextFormatter.removeColor(newValue),
|
||||
keyOrName.usableKey()
|
||||
@@ -175,22 +171,11 @@ final class WorldConfigNodes {
|
||||
final ConfigNode<Material> entryFeeCurrency = node(ConfigNode.builder("entry-fee.currency", Material.class)
|
||||
.defaultValue(MVEconomist.VAULT_ECONOMY_MATERIAL)
|
||||
.name("entryfee-currency")
|
||||
.stringParser((value, clazz) -> {
|
||||
if (value != null && value.equalsIgnoreCase(MVEconomist.VAULT_ECONOMY_CODE)) {
|
||||
return Try.success(MVEconomist.VAULT_ECONOMY_MATERIAL);
|
||||
}
|
||||
return Try.of(() -> MaterialConverter.stringToMaterial(value))
|
||||
.filter(Objects::nonNull)
|
||||
.orElse(Try.failure(new MultiverseException(Message.of(
|
||||
MVCorei18n.CONFIG_STRING_PARSER_INVALIDMATERIAL,
|
||||
replace("{input}").with(value)))));
|
||||
})
|
||||
.serializer(new NodeSerializer<>() {
|
||||
@Override
|
||||
public Material deserialize(Object object, Class<Material> type) {
|
||||
return Option.of(object)
|
||||
.map(String::valueOf)
|
||||
.filter(s -> !s.isBlank())
|
||||
.map(materialStr -> {
|
||||
if (materialStr.equalsIgnoreCase(MVEconomist.VAULT_ECONOMY_CODE)) {
|
||||
return MVEconomist.VAULT_ECONOMY_MATERIAL;
|
||||
@@ -323,8 +308,6 @@ final class WorldConfigNodes {
|
||||
.hidden());
|
||||
|
||||
final ConfigNode<String> legacyWorldName = node(ConfigNode.builder("read-only.legacy-world-name", String.class)
|
||||
.onLoadAndChange((oldValue, newValue) -> worldManager.getWorldStore().changeLegacyWorldName(
|
||||
oldValue, newValue, keyOrName.usableKey()))
|
||||
.hidden());
|
||||
|
||||
final ConfigNode<Long> seed = node(ConfigNode.builder("read-only.seed", Long.class)
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
import org.mvplugins.multiverse.core.MultiverseCore;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldClonedEvent;
|
||||
import org.mvplugins.multiverse.core.event.world.MVWorldCreatedEvent;
|
||||
@@ -45,8 +46,6 @@ import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
|
||||
import org.mvplugins.multiverse.core.permissions.CorePermissions;
|
||||
import org.mvplugins.multiverse.core.teleportation.BlockSafety;
|
||||
import org.mvplugins.multiverse.core.teleportation.LocationManipulation;
|
||||
import org.mvplugins.multiverse.core.utils.ServerProperties;
|
||||
import org.mvplugins.multiverse.core.utils.compatibility.BukkitCompatibility;
|
||||
import org.mvplugins.multiverse.core.utils.compatibility.WorldCompatibility;
|
||||
@@ -56,7 +55,6 @@ import org.mvplugins.multiverse.core.utils.result.FailureReason;
|
||||
import org.mvplugins.multiverse.core.utils.FileUtils;
|
||||
import org.mvplugins.multiverse.core.utils.text.ChatTextFormatter;
|
||||
import org.mvplugins.multiverse.core.world.biomeprovider.BiomeProviderFactory;
|
||||
import org.mvplugins.multiverse.core.world.entity.EntityPurger;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
import org.mvplugins.multiverse.core.world.helpers.DataStore.GameRulesStore;
|
||||
import org.mvplugins.multiverse.core.world.helpers.DataTransfer;
|
||||
@@ -96,6 +94,7 @@ public final class WorldManager {
|
||||
"data/paper/metadata.dat" // New papermc format for 26.1+
|
||||
);
|
||||
|
||||
private final MultiverseCore multiverseCore;
|
||||
private final WorldStore worldStore;
|
||||
private final List<String> unloadTracker;
|
||||
private final List<String> loadTracker;
|
||||
@@ -104,44 +103,37 @@ public final class WorldManager {
|
||||
private final BiomeProviderFactory biomeProviderFactory;
|
||||
private final GeneratorProvider generatorProvider;
|
||||
private final FileUtils fileUtils;
|
||||
private final BlockSafety blockSafety;
|
||||
private final LocationManipulation locationManipulation;
|
||||
private final PluginManager pluginManager;
|
||||
private final CorePermissions corePermissions;
|
||||
private final ServerProperties serverProperties;
|
||||
private final CoreConfig config;
|
||||
private final EntityPurger entityPurger;
|
||||
private final Provider<PotentialWorldFinder> potentialWorldFinder;
|
||||
|
||||
@Inject
|
||||
WorldManager(
|
||||
@NotNull MultiverseCore multiverseCore,
|
||||
@NotNull WorldStore worldStore,
|
||||
@NotNull WorldsConfigManager worldsConfigManager,
|
||||
@NotNull WorldNameChecker worldNameChecker,
|
||||
@NotNull BiomeProviderFactory biomeProviderFactory,
|
||||
@NotNull GeneratorProvider generatorProvider,
|
||||
@NotNull FileUtils fileUtils,
|
||||
@NotNull BlockSafety blockSafety,
|
||||
@NotNull LocationManipulation locationManipulation,
|
||||
@NotNull PluginManager pluginManager,
|
||||
@NotNull CorePermissions corePermissions,
|
||||
@NotNull ServerProperties serverProperties,
|
||||
@NotNull CoreConfig config,
|
||||
@NotNull EntityPurger entityPurger,
|
||||
@NotNull Provider<PotentialWorldFinder> potentialWorldFinder) {
|
||||
this.multiverseCore = multiverseCore;
|
||||
this.worldStore = worldStore;
|
||||
this.worldsConfigManager = worldsConfigManager;
|
||||
this.worldNameChecker = worldNameChecker;
|
||||
this.biomeProviderFactory = biomeProviderFactory;
|
||||
this.generatorProvider = generatorProvider;
|
||||
this.fileUtils = fileUtils;
|
||||
this.blockSafety = blockSafety;
|
||||
this.locationManipulation = locationManipulation;
|
||||
this.pluginManager = pluginManager;
|
||||
this.corePermissions = corePermissions;
|
||||
this.serverProperties = serverProperties;
|
||||
this.config = config;
|
||||
this.entityPurger = entityPurger;
|
||||
this.potentialWorldFinder = potentialWorldFinder;
|
||||
|
||||
this.unloadTracker = new ArrayList<>();
|
||||
@@ -417,7 +409,7 @@ public final class WorldManager {
|
||||
}
|
||||
|
||||
private MultiverseWorld newMultiverseWorld(WorldConfig worldConfig) {
|
||||
MultiverseWorld mvWorld = new MultiverseWorld(worldConfig, config);
|
||||
MultiverseWorld mvWorld = new MultiverseWorld(worldConfig, multiverseCore);
|
||||
worldStore.putUnloadedWorld(mvWorld);
|
||||
corePermissions.addWorldPermissions(mvWorld);
|
||||
return mvWorld;
|
||||
@@ -456,10 +448,7 @@ public final class WorldManager {
|
||||
LoadedMultiverseWorld loadedWorld = new LoadedMultiverseWorld(
|
||||
world,
|
||||
worldConfig,
|
||||
config,
|
||||
blockSafety,
|
||||
locationManipulation,
|
||||
entityPurger
|
||||
multiverseCore
|
||||
);
|
||||
worldStore.putLoadedWorld(loadedWorld);
|
||||
saveWorldsConfig();
|
||||
@@ -592,10 +581,7 @@ public final class WorldManager {
|
||||
LoadedMultiverseWorld loadedWorld = new LoadedMultiverseWorld(
|
||||
bukkitWorld,
|
||||
worldConfig,
|
||||
config,
|
||||
blockSafety,
|
||||
locationManipulation,
|
||||
entityPurger
|
||||
multiverseCore
|
||||
);
|
||||
worldStore.putLoadedWorld(loadedWorld);
|
||||
saveWorldsConfig();
|
||||
@@ -1278,10 +1264,6 @@ public final class WorldManager {
|
||||
});
|
||||
}
|
||||
|
||||
WorldStore getWorldStore() {
|
||||
return worldStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple pair wrapper for convenience to pass both the world key or name and the options together between methods
|
||||
* when parsing world options.
|
||||
|
||||
@@ -120,29 +120,6 @@ final class WorldStore {
|
||||
unloadedList.add(unloadedMap.get(world.getKey().toString()));
|
||||
}
|
||||
|
||||
void changeLegacyWorldName(@Nullable String oldName, @Nullable String newName, @NotNull NamespacedKey worldKey) {
|
||||
if (Objects.equals(oldName, newName)) {
|
||||
return;
|
||||
}
|
||||
String key = worldKey.toString();
|
||||
updateLegacyWorldName(loadedMap, oldName, newName, key);
|
||||
updateLegacyWorldName(unloadedMap, oldName, newName, key);
|
||||
}
|
||||
|
||||
private <T extends MultiverseWorld> void updateLegacyWorldName(
|
||||
Map<String, T> map, @Nullable String oldName, @Nullable String newName, String key) {
|
||||
T world = map.get(key);
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
if (oldName != null && !key.equalsIgnoreCase(oldName)) {
|
||||
map.remove(oldName, world);
|
||||
}
|
||||
if (newName != null) {
|
||||
map.put(newName, world);
|
||||
}
|
||||
}
|
||||
|
||||
void changeAlias(@Nullable String oldAlias, @Nullable String newAlias, @NotNull NamespacedKey worldKey) {
|
||||
if (Objects.equals(oldAlias, newAlias)) {
|
||||
// nothing changed, ignore
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.SpawnCategory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.config.handle.MemoryConfigurationHandle;
|
||||
import org.mvplugins.multiverse.core.config.handle.StringPropertyHandle;
|
||||
@@ -17,19 +16,13 @@ import org.mvplugins.multiverse.core.config.node.ConfigNode;
|
||||
import org.mvplugins.multiverse.core.config.node.ListConfigNode;
|
||||
import org.mvplugins.multiverse.core.config.node.Node;
|
||||
import org.mvplugins.multiverse.core.config.node.NodeGroup;
|
||||
import org.mvplugins.multiverse.core.config.node.functions.NodeStringParser;
|
||||
import org.mvplugins.multiverse.core.config.node.serializer.NodeSerializer;
|
||||
import org.mvplugins.multiverse.core.exceptions.MultiverseException;
|
||||
import org.mvplugins.multiverse.core.locale.MVCorei18n;
|
||||
import org.mvplugins.multiverse.core.locale.message.Message;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
import org.mvplugins.multiverse.core.world.MultiverseWorld;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace;
|
||||
|
||||
public final class SpawnCategoryConfig {
|
||||
|
||||
private final CoreConfig config;
|
||||
@@ -184,7 +177,6 @@ public final class SpawnCategoryConfig {
|
||||
final ConfigNode<Integer> tickRate = node(ConfigNode.builder("tick-rate", Integer.class)
|
||||
.defaultValue(-2)
|
||||
.suggester(input -> List.of("@unset", "@bukkit", "10", "100", "400", "1000"))
|
||||
.stringParser(SpawnValueStringParser.INSTANCE)
|
||||
.serializer(SpawnValueSerializer.INSTANCE)
|
||||
.onLoadAndChange((oldValue, newValue) -> applyConfigToWorld())
|
||||
.onChange((sender, oldValue, newValue) -> {
|
||||
@@ -201,7 +193,6 @@ public final class SpawnCategoryConfig {
|
||||
final ConfigNode<Integer> spawnLimit = node(ConfigNode.builder("spawn-limit", Integer.class)
|
||||
.defaultValue(-2)
|
||||
.suggester(input -> List.of("@unset", "@bukkit", "10", "100", "400", "1000"))
|
||||
.stringParser(SpawnValueStringParser.INSTANCE)
|
||||
.serializer(SpawnValueSerializer.INSTANCE)
|
||||
.onLoadAndChange((oldValue, newValue) -> applyConfigToWorld())
|
||||
.onChange((sender, oldValue, newValue) -> {
|
||||
@@ -224,27 +215,6 @@ public final class SpawnCategoryConfig {
|
||||
.build());
|
||||
}
|
||||
|
||||
private static class SpawnValueStringParser implements NodeStringParser<Integer> {
|
||||
private static final SpawnValueStringParser INSTANCE = new SpawnValueStringParser();
|
||||
|
||||
@Override
|
||||
public @NotNull Try<Integer> parse(@Nullable String input, @NotNull Class<Integer> type) {
|
||||
String str = String.valueOf(input).trim();
|
||||
if (str.equalsIgnoreCase("@unset")) {
|
||||
return Try.success(-2);
|
||||
}
|
||||
if (str.equalsIgnoreCase("@bukkit")) {
|
||||
return Try.success(-1);
|
||||
}
|
||||
try {
|
||||
return Try.success(Integer.parseInt(str));
|
||||
} catch (NumberFormatException e) {
|
||||
return Try.failure(new MultiverseException(Message.of(MVCorei18n.CONFIG_STRING_PARSER_INVALIDINTEGER,
|
||||
replace("{input}").with(input))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SpawnValueSerializer implements NodeSerializer<Integer> {
|
||||
private static final SpawnValueSerializer INSTANCE = new SpawnValueSerializer();
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ mv-core.config.string.parser.invalidinteger=Unable to convert '{input}' to numbe
|
||||
mv-core.config.string.parser.invaliddouble=Unable to convert '{input}' to number. (double)
|
||||
mv-core.config.string.parser.invalidfloat=Unable to convert '{input}' to number. (float)
|
||||
mv-core.config.string.parser.invalidlong=Unable to convert '{input}' to number. (long)
|
||||
mv-core.config.string.parser.invalidmaterial='{input}' is not a valid material.
|
||||
|
||||
# core config
|
||||
mv-core.core.config.customportalsearchradius.nonnegative=The value must be greater than or equal to 0.
|
||||
|
||||
@@ -50,35 +50,45 @@ class WorldManagerTest : TestWithMockBukkit() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Legacy world name changes update loaded and unloaded lookups`() {
|
||||
val worldKey = world.key.toString()
|
||||
assertTrue(world.worldConfig.setLegacyWorldName("renamed_world").isSuccess)
|
||||
fun `World reference follows unload and reload`() {
|
||||
val ref = world2.asRef()
|
||||
assertSame(world2, ref.get().get())
|
||||
assertSame(world2, ref.getLoaded().get())
|
||||
|
||||
assertFalse(worldManager.getWorld("world").isDefined)
|
||||
assertSame(world, worldManager.getLoadedWorld("RENAMED_WORLD").get())
|
||||
assertSame(world, worldManager.getLoadedWorld(worldKey).get())
|
||||
assertTrue(worldManager.unloadWorld(UnloadWorldOptions.world(world2)).isSuccess)
|
||||
assertTrue(ref.getLoaded().isEmpty)
|
||||
val unloaded = ref.get().get()
|
||||
assertFalse(unloaded.isLoaded)
|
||||
assertSame(worldManager.getWorld(world2.name).get(), unloaded)
|
||||
|
||||
assertTrue(worldManager.unloadWorld(UnloadWorldOptions.world(world)).isSuccess)
|
||||
assertFalse(worldManager.getWorld("world").isDefined)
|
||||
assertFalse(worldManager.getLoadedWorld("renamed_world").isDefined)
|
||||
assertEquals(world.key, worldManager.getUnloadedWorld("RENAMED_WORLD").get().key)
|
||||
assertEquals(world.key, worldManager.getUnloadedWorld(worldKey).get().key)
|
||||
val unloadedRef = unloaded.asRef()
|
||||
assertTrue(worldManager.loadWorld(LoadWorldOptions.world(unloaded)).isSuccess)
|
||||
val reloaded = worldManager.getLoadedWorld(world2.name).get()
|
||||
assertNotSame(world2, reloaded)
|
||||
assertSame(reloaded, ref.get().get())
|
||||
assertSame(reloaded, ref.getLoaded().get())
|
||||
assertSame(reloaded, unloadedRef.getLoaded().get())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Setting up loaded world config refreshes legacy world name lookups`() {
|
||||
assertTrue(world.worldConfig.setLegacyWorldName("stale_name").isSuccess)
|
||||
assertTrue(world.worldConfig.save().isSuccess)
|
||||
fun `World reference follows regeneration`() {
|
||||
val ref = world2.asRef()
|
||||
assertTrue(worldManager.regenWorld(RegenWorldOptions.world(world2).seed(4321L)).isSuccess)
|
||||
|
||||
world.setWorldConfig(world.worldConfig)
|
||||
val regenerated = ref.getLoaded().get()
|
||||
assertNotSame(world2, regenerated)
|
||||
assertSame(worldManager.getLoadedWorld(world2.name).get(), regenerated)
|
||||
assertSame(regenerated, ref.get().get())
|
||||
assertEquals(4321L, regenerated.seed)
|
||||
}
|
||||
|
||||
assertEquals("world", world.name)
|
||||
assertSame(world, worldManager.getLoadedWorld("world").get())
|
||||
assertFalse(worldManager.getWorld("stale_name").isDefined)
|
||||
@Test
|
||||
fun `World reference is empty after removal`() {
|
||||
val ref = world2.asRef()
|
||||
assertTrue(worldManager.removeWorld(RemoveWorldOptions.world(world2)).isSuccess)
|
||||
|
||||
assertTrue(worldManager.unloadWorld(UnloadWorldOptions.world(world)).isSuccess)
|
||||
assertTrue(worldManager.getUnloadedWorld("world").isDefined)
|
||||
assertFalse(worldManager.getWorld("stale_name").isDefined)
|
||||
assertTrue(ref.get().isEmpty)
|
||||
assertTrue(ref.getLoaded().isEmpty)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user