diff --git a/build.gradle b/build.gradle index 6b27d90d..a9d231a2 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,7 @@ dependencies { // Core // TODO update to correct version once we have it published - externalPlugin 'org.mvplugins.multiverse.core:multiverse-core:5.0.0-SNAPSHOT' + externalPlugin 'org.mvplugins.multiverse.core:multiverse-core:5.2.0-SNAPSHOT' // Config shadowed 'com.dumptruckman.minecraft:JsonConfiguration:1.2-SNAPSHOT' diff --git a/src/main/java/org/mvplugins/multiverse/inventories/PlaceholderExpansionHook.java b/src/main/java/org/mvplugins/multiverse/inventories/PlaceholderExpansionHook.java index 7d9b7d48..7b958356 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/PlaceholderExpansionHook.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/PlaceholderExpansionHook.java @@ -128,14 +128,14 @@ private String groupPlaceholders(OfflinePlayer offlinePlayer, List param private String getGroupPlaceholderValue(WorldGroup worldGroup, String placeholder) { return switch (placeholder) { case "name" -> worldGroup.getName(); - case "worlds" -> StringFormatter.join(worldGroup.getWorlds(), ", "); + case "worlds" -> StringFormatter.join(worldGroup.getApplicableWorlds(), ", "); case "shares" -> StringFormatter.join(worldGroup.getShares().toStringList(), ", "); - case "players" -> StringFormatter.join(worldGroup.getWorlds().stream() + case "players" -> StringFormatter.join(worldGroup.getApplicableWorlds().stream() .map(Bukkit::getWorld) .filter(Objects::nonNull) .flatMap(world -> world.getPlayers().stream().map(Player::getName)) .toList(), ", "); - case "playercount" -> worldGroup.getWorlds().stream() + case "playercount" -> worldGroup.getApplicableWorlds().stream() .map(Bukkit::getWorld) .filter(Objects::nonNull) .map(World::getPlayers) diff --git a/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandCompletion.java b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandCompletion.java index 7f18bd1f..6826891c 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandCompletion.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/command/MVInvCommandCompletion.java @@ -171,7 +171,7 @@ private Collection suggestWorldGroups(BukkitCommandCompletionContext con private Collection suggestWorldGroupWorlds(BukkitCommandCompletionContext context) { var worlds = Try.of(() -> context.getContextValue(WorldGroup.class)) - .map(WorldGroup::getWorlds) + .map(WorldGroup::getConfigWorlds) .getOrElse(Collections.emptySet()); return addonToCommaSeperated(context.getInput(), worlds); diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/AddWorldsCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/AddWorldsCommand.java index 3cf97d1e..194e1b43 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/commands/AddWorldsCommand.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/AddWorldsCommand.java @@ -2,13 +2,11 @@ import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.command.MVCommandIssuer; -import org.mvplugins.multiverse.core.command.MVCommandManager; -import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; -import org.mvplugins.multiverse.core.world.MultiverseWorld; -import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias; +import org.mvplugins.multiverse.core.utils.REPatterns; import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion; import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission; import org.mvplugins.multiverse.external.acf.commands.annotation.Description; +import org.mvplugins.multiverse.external.acf.commands.annotation.Single; import org.mvplugins.multiverse.external.acf.commands.annotation.Subcommand; import org.mvplugins.multiverse.external.acf.commands.annotation.Syntax; import org.mvplugins.multiverse.external.jakarta.inject.Inject; @@ -44,13 +42,16 @@ void onAddWorldCommand( @Description("Group you want to add the world to.") WorldGroup group, + @Single @Syntax("") @Description("World name to add.") - MultiverseWorld[] worlds + String worlds ) { - List worldNames = Arrays.stream(worlds).map(MultiverseWorld::getName).toList(); + List worldNames = Arrays.stream(REPatterns.COMMA.split(worlds)) + .map(String::toLowerCase) + .toList(); String worldNamesString = String.join(", ", worldNames); - if (!group.getWorlds().addAll(worldNames)) { + if (!group.getConfigWorlds().addAll(worldNames)) { issuer.sendError(MVInvi18n.ADDWORLD_WORLDALREADYEXISTS, replace("{group}").with(group.getName()), replace("{world}").with(worldNamesString)); diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/CreateGroupCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/CreateGroupCommand.java index 8717975c..bc9b49ea 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/commands/CreateGroupCommand.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/CreateGroupCommand.java @@ -2,9 +2,7 @@ import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.command.MVCommandIssuer; -import org.mvplugins.multiverse.core.command.MVCommandManager; -import org.mvplugins.multiverse.core.world.MultiverseWorld; -import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias; +import org.mvplugins.multiverse.core.utils.REPatterns; import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion; import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission; import org.mvplugins.multiverse.external.acf.commands.annotation.Conditions; @@ -19,7 +17,7 @@ import org.mvplugins.multiverse.inventories.share.Shares; import org.mvplugins.multiverse.inventories.util.MVInvi18n; -import java.util.Arrays; +import java.util.List; import static org.mvplugins.multiverse.core.locale.message.MessageReplacement.replace; @@ -47,7 +45,7 @@ void onCreateGroupCommand( @Optional @Syntax("[world[,extra]]") - MultiverseWorld[] worlds, + String worlds, @Optional @Syntax("[share,[extra]]") @@ -55,14 +53,14 @@ void onCreateGroupCommand( ) { WorldGroup worldGroup = worldGroupManager.newEmptyGroup(groupName); if (worlds != null) { - worldGroup.getWorlds().addAll(Arrays.stream(worlds).map(MultiverseWorld::getName).toList()); + worldGroup.addWorlds(List.of(REPatterns.COMMA.split(worlds)), false); } if (shares != null) { worldGroup.getShares().mergeShares(shares); } worldGroupManager.updateGroup(worldGroup); issuer.sendInfo(MVInvi18n.GROUP_CREATIONCOMPLETE, replace("{group}").with(groupName)); - issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(worldGroup.getWorlds())); + issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(worldGroup.getConfigWorlds())); issuer.sendInfo(MVInvi18n.INFO_GROUP_INFOSHARES, replace("{shares}").with(worldGroup.getShares())); } } diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/InfoCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/InfoCommand.java index 0ffc436c..287817c5 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/commands/InfoCommand.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/InfoCommand.java @@ -2,11 +2,11 @@ import org.mvplugins.multiverse.core.command.LegacyAliasCommand; import org.mvplugins.multiverse.core.command.MVCommandIssuer; +import org.mvplugins.multiverse.core.utils.StringFormatter; import org.mvplugins.multiverse.inventories.profile.key.ContainerType; import org.mvplugins.multiverse.inventories.profile.container.ProfileContainerStoreProvider; import org.mvplugins.multiverse.inventories.profile.group.WorldGroup; import org.bukkit.Bukkit; -import org.mvplugins.multiverse.core.command.MVCommandManager; import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias; import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion; import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission; @@ -82,7 +82,7 @@ void onInfoCommand( private void groupInfo(MVCommandIssuer issuer, WorldGroup worldGroup) { StringBuilder worldsString = new StringBuilder(); - Set worlds = worldGroup.getWorlds(); + Set worlds = worldGroup.getConfigWorlds(); if (worlds.isEmpty()) { worldsString.append("N/A"); } else { @@ -93,6 +93,8 @@ private void groupInfo(MVCommandIssuer issuer, WorldGroup worldGroup) { worldsString.append(world); } } + //todo: Better messaging formatting here + issuer.sendMessage("Applicable Worlds: " + StringFormatter.join(worldGroup.getApplicableWorlds(), ", ")); issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(worldsString)); issuer.sendInfo(MVInvi18n.INFO_GROUP_INFOSHARES, replace("{shares}").with(worldGroup.getShares())); } diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveWorldsCommand.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveWorldsCommand.java index 0840f9a1..e8566479 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveWorldsCommand.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/RemoveWorldsCommand.java @@ -2,10 +2,7 @@ import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.command.MVCommandIssuer; -import org.mvplugins.multiverse.core.command.MVCommandManager; -import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; -import org.mvplugins.multiverse.core.world.MultiverseWorld; -import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias; +import org.mvplugins.multiverse.core.utils.REPatterns; import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion; import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission; import org.mvplugins.multiverse.external.acf.commands.annotation.Description; @@ -51,14 +48,13 @@ void onRemoveWorldCommand( @Description("World name to remove.") String worldNames ) { - List worldNamesArr = Arrays.stream(worldNames.split(",")).toList(); + List worldNamesArr = Arrays.stream(REPatterns.COMMA.split(worldNames)).toList(); if (!group.removeWorlds(worldNamesArr)) { issuer.sendError(MVInvi18n.REMOVEWORLD_WORLDNOTINGROUP, replace("{group}").with(group.getName()), replace("{world}").with(worldNames)); return; } - worldGroupManager.updateGroup(group); issuer.sendInfo(MVInvi18n.REMOVEWORLD_WORLDREMOVED, replace("{group}").with(group.getName()), replace("{world}").with(worldNames)); diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupSharesPrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupSharesPrompt.java index 408778ec..5d8688a0 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupSharesPrompt.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupSharesPrompt.java @@ -61,7 +61,7 @@ public Prompt acceptInput(@NotNull final ConversationContext conversationContext issuer.sendInfo(MVInvi18n.GROUP_UPDATED); } issuer.sendInfo(MVInvi18n.INFO_GROUP, replace("{group}").with(group.getName())); - issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(group.getWorlds())); + issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(group.getConfigWorlds())); issuer.sendInfo(MVInvi18n.INFO_GROUP_INFOSHARES, replace("{shares}").with(group.getShares())); worldGroupManager.checkForConflicts(issuer); return nextPrompt; diff --git a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupWorldsPrompt.java b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupWorldsPrompt.java index 0ce588c0..34b8cd42 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupWorldsPrompt.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/commands/prompts/GroupWorldsPrompt.java @@ -31,7 +31,7 @@ public GroupWorldsPrompt(final MultiverseInventories plugin, final MVCommandIssu this.group = group; this.nextPrompt = nextPrompt; this.isCreating = creatingGroup; - this.worlds = new HashSet(group.getWorlds()); + this.worlds = new HashSet<>(group.getConfigWorlds()); } @NotNull @@ -64,7 +64,7 @@ public Prompt acceptInput(@NotNull final ConversationContext conversationContext worldGroupManager.updateGroup(group); issuer.sendInfo(MVInvi18n.GROUP_UPDATED); issuer.sendInfo(MVInvi18n.INFO_GROUP, replace("{group}").with(group.getName())); - issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(group.getWorlds())); + issuer.sendInfo(MVInvi18n.INFO_GROUP_INFO, replace("{worlds}").with(group.getConfigWorlds())); issuer.sendInfo(MVInvi18n.INFO_GROUP_INFOSHARES, replace("{shares}").with(group.getShares())); } return nextPrompt; diff --git a/src/main/java/org/mvplugins/multiverse/inventories/profile/bulkedit/PlayerProfilesAggregator.java b/src/main/java/org/mvplugins/multiverse/inventories/profile/bulkedit/PlayerProfilesAggregator.java index 6a2b856b..d543598c 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/profile/bulkedit/PlayerProfilesAggregator.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/profile/bulkedit/PlayerProfilesAggregator.java @@ -1,7 +1,6 @@ package org.mvplugins.multiverse.inventories.profile.bulkedit; import com.google.common.collect.Sets; -import org.jetbrains.annotations.ApiStatus; import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.external.jakarta.inject.Inject; import org.mvplugins.multiverse.inventories.profile.group.WorldGroup; @@ -80,7 +79,7 @@ private ContainerKey[] includeGroupsWorlds(ContainerKey[] containerKeys) { if (group == null) { continue; } - containerKeyList.addAll(group.getWorlds().stream() + containerKeyList.addAll(group.getApplicableWorlds().stream() .map(worldName -> ContainerKey.create(ContainerType.WORLD, worldName)) .toList()); } diff --git a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/AbstractWorldGroupManager.java b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/AbstractWorldGroupManager.java index fc477965..a501b42b 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/AbstractWorldGroupManager.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/AbstractWorldGroupManager.java @@ -1,9 +1,15 @@ package org.mvplugins.multiverse.inventories.profile.group; import com.dumptruckman.minecraft.util.Logging; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.event.world.WorldUnloadEvent; import org.jvnet.hk2.annotations.Contract; import org.mvplugins.multiverse.core.command.MVCommandIssuer; import org.mvplugins.multiverse.core.command.MVCommandManager; +import org.mvplugins.multiverse.core.event.world.MVWorldLoadedEvent; +import org.mvplugins.multiverse.core.event.world.MVWorldUnloadedEvent; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull; @@ -38,7 +44,7 @@ abstract sealed class AbstractWorldGroupManager implements WorldGroupManager per protected final ProfileContainerStoreProvider profileContainerStoreProvider; protected final WorldManager worldManager; - public AbstractWorldGroupManager( + AbstractWorldGroupManager( @NotNull MultiverseInventories plugin, @NotNull MVCommandManager commandManager, @NotNull InventoriesConfig config, @@ -49,6 +55,8 @@ public AbstractWorldGroupManager( this.inventoriesConfig = config; this.profileContainerStoreProvider = profileContainerStoreProvider; this.worldManager = worldManager; + + Bukkit.getPluginManager().registerEvents(new WorldChangeListener(), plugin); } /** @@ -94,7 +102,7 @@ public List getGroupsForWorld(String worldName) { @Override public boolean hasConfiguredGroup(String worldName) { return groupNamesMap.values().stream() - .anyMatch(worldGroup -> worldGroup.getWorlds().contains(worldName)); + .anyMatch(worldGroup -> worldGroup.containsWorld(worldName)); } /** @@ -109,6 +117,7 @@ protected Map getGroupNames() { @Override public void updateGroup(final WorldGroup worldGroup) { getGroupNames().put(worldGroup.getName().toLowerCase(), worldGroup); + worldGroup.recalculateApplicableWorlds(); worldGroup.recalculateApplicableShares(); } @@ -154,9 +163,8 @@ public void createDefaultGroup() { worldGroup.addWorld(defaultEnd); } updateGroup(worldGroup); - worldGroup.recalculateApplicableShares(); Logging.info("Created a default group for you containing all of your default worlds: " - + String.join(", ", worldGroup.getWorlds())); + + String.join(", ", worldGroup.getConfigWorlds())); } /** @@ -181,7 +189,7 @@ public List checkGroups() { List conflicts = new ArrayList<>(); Map previousConflicts = new HashMap<>(); for (WorldGroup checkingGroup : getGroupNames().values()) { - for (String worldName : checkingGroup.getWorlds()) { + for (String worldName : checkingGroup.getApplicableWorlds()) { for (WorldGroup worldGroup : getGroupsForWorld(worldName)) { if (checkingGroup.equals(worldGroup)) { continue; @@ -200,8 +208,8 @@ public List checkGroups() { Shares conflictingShares = worldGroup.getShares() .compare(checkingGroup.getShares()); if (!conflictingShares.isEmpty()) { - if (checkingGroup.getWorlds().containsAll(worldGroup.getWorlds()) - || worldGroup.getWorlds().containsAll(checkingGroup.getWorlds())) { + if (checkingGroup.getApplicableWorlds().containsAll(worldGroup.getApplicableWorlds()) + || worldGroup.getApplicableWorlds().containsAll(checkingGroup.getApplicableWorlds())) { continue; } conflicts.add(new GroupingConflict(checkingGroup, worldGroup, @@ -243,4 +251,31 @@ public void checkForConflicts(MVCommandIssuer issuer) { public void recalculateApplicableShares() { getGroupNames().values().forEach(WorldGroup::recalculateApplicableShares); } + + @Override + public void recalculateApplicableWorlds() { + groupNamesMap.values().forEach(WorldGroup::recalculateApplicableWorlds); + } + + private class WorldChangeListener implements Listener { + @EventHandler + void onMVWorldLoad(MVWorldLoadedEvent event) { + groupNamesMap.values().forEach(group -> group.addApplicableWorld(event.getWorld().getName())); + } + + @EventHandler + void onMVWorldUnload(MVWorldUnloadedEvent event) { + groupNamesMap.values().forEach(group -> group.removeApplicableWorld(event.getWorld().getName())); + } + + @EventHandler + void onWorldLoad(WorldLoadEvent event) { + groupNamesMap.values().forEach(group -> group.addApplicableWorld(event.getWorld().getName())); + } + + @EventHandler + void onWorldUnload(WorldUnloadEvent event) { + groupNamesMap.values().forEach(group -> group.removeApplicableWorld(event.getWorld().getName())); + } + } } diff --git a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/GroupingConflict.java b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/GroupingConflict.java index c42eba65..76992fc0 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/GroupingConflict.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/GroupingConflict.java @@ -46,8 +46,8 @@ public Shares getConflictingShares() { */ public List getConflictingWorlds() { List worlds = new ArrayList(); - for (String world : this.getFirstGroup().getWorlds()) { - if (this.getSecondGroup().getWorlds().contains(world)) { + for (String world : this.getFirstGroup().getApplicableWorlds()) { + if (this.getSecondGroup().getApplicableWorlds().contains(world)) { worlds.add(world); } } diff --git a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/WorldGroup.java b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/WorldGroup.java index d0829c4e..f254ae6f 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/WorldGroup.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/WorldGroup.java @@ -1,6 +1,9 @@ package org.mvplugins.multiverse.inventories.profile.group; import com.dumptruckman.minecraft.util.Logging; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.ApiStatus; +import org.mvplugins.multiverse.core.utils.matcher.MatcherGroup; import org.mvplugins.multiverse.inventories.config.InventoriesConfig; import org.mvplugins.multiverse.inventories.profile.key.ContainerType; import org.mvplugins.multiverse.inventories.profile.container.ProfileContainer; @@ -12,8 +15,9 @@ import org.bukkit.event.EventPriority; import java.util.Collection; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; +import java.util.stream.Collectors; public final class WorldGroup { @@ -21,14 +25,17 @@ public final class WorldGroup { private final ProfileContainerStoreProvider profileContainerStoreProvider; private final InventoriesConfig inventoriesConfig; private final String name; - private final HashSet worlds = new HashSet<>(); + private final Set configWorlds = new LinkedHashSet<>(); private final Shares shares = Sharables.noneOf(); private final Shares disabledShares = Sharables.noneOf(); - - private Shares applicableShares = Sharables.noneOf(); private String spawnWorld = null; private EventPriority spawnPriority = EventPriority.NORMAL; + // calculated values + private MatcherGroup matcherGroup = new MatcherGroup(); + private Set applicableWorlds = new LinkedHashSet<>(); + private Shares applicableShares = Sharables.noneOf(); + WorldGroup( final WorldGroupManager worldGroupManager, final ProfileContainerStoreProvider profileContainerStoreProvider, @@ -65,7 +72,7 @@ public void addWorld(String worldName) { * @param updateConfig True to update this group in the config. */ public void addWorld(String worldName, boolean updateConfig) { - this.getWorlds().add(worldName.toLowerCase()); + this.configWorlds.add(worldName.toLowerCase()); if (updateConfig) { worldGroupManager.updateGroup(this); } @@ -96,7 +103,7 @@ public void addWorlds(Collection worlds) { * @param updateConfig True to update this group in the config. */ public void addWorlds(Collection worlds, boolean updateConfig) { - worlds.forEach(worldName -> this.addWorld(worldName, false)); + configWorlds.addAll(worlds.stream().map(String::toLowerCase).toList()); if (updateConfig) { worldGroupManager.updateGroup(this); } @@ -118,7 +125,7 @@ public void removeWorld(String worldName) { * @param updateConfig True to update this group in the config. */ public void removeWorld(String worldName, boolean updateConfig) { - this.getWorlds().remove(worldName.toLowerCase()); + this.configWorlds.remove(worldName.toLowerCase()); if (updateConfig) { worldGroupManager.updateGroup(this); } @@ -140,7 +147,23 @@ public void removeWorld(World world) { * @return True if any of the worlds were removed. */ public boolean removeWorlds(Collection removeWorlds) { - return this.getWorlds().removeAll(removeWorlds); + return removeWorlds(removeWorlds, true); + } + + /** + * Removes multiple worlds from this World Group and optionally updates the group in the Config. + * + * @param removeWorlds A collection of world names to remove. + * @return True if any of the worlds were removed. + */ + public boolean removeWorlds(Collection removeWorlds, boolean updateConfig) { + if (this.configWorlds.removeAll(removeWorlds.stream().map(String::toLowerCase).collect(Collectors.toSet()))) { + if (updateConfig) { + worldGroupManager.updateGroup(this); + } + return true; + } + return false; } /** @@ -156,19 +179,77 @@ public void removeAllWorlds() { * @param updateConfig True to update this group in the config. */ public void removeAllWorlds(boolean updateConfig) { - this.worlds.clear(); + this.configWorlds.clear(); if (updateConfig) { worldGroupManager.updateGroup(this); } } + /** + * @param worldName Name of world to check for. + * @return True if specified world is part of this group. + */ + public boolean containsWorld(String worldName) { + return this.applicableWorlds.contains(worldName.toLowerCase()); + } + + /** + * Retrieves the set of worlds that were configured in the group config. + * + * @return The set of worlds that were configured in the group config. + * + * @since 5.2 + */ + @ApiStatus.AvailableSince("5.2") + public Set getConfigWorlds() { + return this.configWorlds; + } + + /** + * Retrieves all the worlds applicable in this World Group, after parsing wildcard and regex matches. + * Modifying this set will not change the worlds saved in the groups config. + * + * @return The worlds of this World Group. + */ + public Set getApplicableWorlds() { + return this.applicableWorlds; + } + /** * Retrieves all of the worlds in this World Group. + *
+ * In 5.2, this method returns the same as {@link #getApplicableWorlds()}. + * To get the worlds string in groups config, use {@link #getConfigWorlds()} instead. * * @return The worlds of this World Group. + * + * @deprecated Use {@link #getApplicableWorlds()} instead. */ + @Deprecated(forRemoval = true, since = "5.2") public Set getWorlds() { - return this.worlds; + return this.applicableWorlds; + } + + /** + * Recalculates the applicable worlds for this World Group based on the configured worlds. + */ + @ApiStatus.AvailableSince("5.2") + public void recalculateApplicableWorlds() { + this.matcherGroup = new MatcherGroup(configWorlds); + this.applicableWorlds = Bukkit.getWorlds().stream().map(World::getName) + .map(String::toLowerCase) + .filter(matcherGroup::matches) + .collect(Collectors.toSet()); + } + + void addApplicableWorld(String worldName) { + if (this.matcherGroup.matches(worldName.toLowerCase())) { + this.applicableWorlds.add(worldName.toLowerCase()); + } + } + + void removeApplicableWorld(String worldName) { + this.applicableWorlds.remove(worldName.toLowerCase()); } /** @@ -210,14 +291,6 @@ public void recalculateApplicableShares() { Logging.finest("Applicable shares for " + this.getName() + ": " + this.applicableShares); } - /** - * @param worldName Name of world to check for. - * @return True if specified world is part of this group. - */ - public boolean containsWorld(String worldName) { - return this.getWorlds().contains(worldName.toLowerCase()); - } - /** * @return The name of the world that will be used as the spawn for this group. * Or null if no world was specified as the group spawn world. @@ -270,7 +343,7 @@ public ProfileContainer getGroupProfileContainer() { public String toString() { StringBuilder builder = new StringBuilder(); builder.append(this.getName()).append(": {Worlds: ["); - String[] worldsString = this.getWorlds().toArray(new String[0]); + String[] worldsString = this.getConfigWorlds().toArray(new String[0]); for (int i = 0; i < worldsString.length; i++) { if (i != 0) { builder.append(", "); diff --git a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/WorldGroupManager.java b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/WorldGroupManager.java index 0f488fb4..aedbb16d 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/WorldGroupManager.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/WorldGroupManager.java @@ -1,5 +1,6 @@ package org.mvplugins.multiverse.inventories.profile.group; +import org.jetbrains.annotations.ApiStatus; import org.jvnet.hk2.annotations.Contract; import org.mvplugins.multiverse.core.command.MVCommandIssuer; import org.mvplugins.multiverse.external.vavr.control.Try; @@ -112,6 +113,19 @@ public sealed interface WorldGroupManager permits AbstractWorldGroupManager { /** * Recalculates the applicable shares for all groups removing disabled optional shares. + *
+ * You should not need to call this method unless there is an edge case of the shares not recalculating automatically. */ void recalculateApplicableShares(); + + /** + * Recalculates the applicable worlds for all groups. This will be automatically called when a world is added or removed, + * and when the group is saved. + *
+ * You should not need to call this method unless there is an edge case of the worlds not recalculating automatically. + * + * @since 5.2 + */ + @ApiStatus.AvailableSince("5.2") + void recalculateApplicableWorlds(); } diff --git a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/YamlWorldGroupManager.java b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/YamlWorldGroupManager.java index f0833a07..e775da92 100644 --- a/src/main/java/org/mvplugins/multiverse/inventories/profile/group/YamlWorldGroupManager.java +++ b/src/main/java/org/mvplugins/multiverse/inventories/profile/group/YamlWorldGroupManager.java @@ -22,7 +22,6 @@ import org.bukkit.event.EventPriority; import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -215,6 +214,7 @@ private WorldGroup deserializeGroup(final String name, final Map Logging.warning("Spawn settings for group formatted incorrectly"); } } + profile.recalculateApplicableWorlds(); profile.recalculateApplicableShares(); return profile; } @@ -226,7 +226,7 @@ private void updateWorldGroup(WorldGroup worldGroup) { private Map serializeWorldGroupProfile(WorldGroup profile) { Map results = new LinkedHashMap<>(); - results.put("worlds", Lists.newArrayList(profile.getWorlds())); + results.put("worlds", Lists.newArrayList(profile.getConfigWorlds())); List sharesList = profile.getShares().toStringList(); if (!sharesList.isEmpty()) { results.put("shares", sharesList); diff --git a/src/test/java/org/mvplugins/multiverse/inventories/profile/WorldGroupManagerTest.kt b/src/test/java/org/mvplugins/multiverse/inventories/profile/WorldGroupManagerTest.kt index 0348423e..312f75a1 100644 --- a/src/test/java/org/mvplugins/multiverse/inventories/profile/WorldGroupManagerTest.kt +++ b/src/test/java/org/mvplugins/multiverse/inventories/profile/WorldGroupManagerTest.kt @@ -1,5 +1,7 @@ package org.mvplugins.multiverse.inventories.profile +import com.dumptruckman.minecraft.util.Logging +import org.bukkit.Bukkit import org.mvplugins.multiverse.core.world.WorldManager import org.mvplugins.multiverse.core.world.options.CreateWorldOptions import org.mvplugins.multiverse.inventories.TestWithMockBukkit @@ -26,6 +28,7 @@ class WorldGroupManagerTest : TestWithMockBukkit() { } assertTrue(worldManager.createWorld(CreateWorldOptions.worldName("world")).isSuccess) assertTrue(worldManager.createWorld(CreateWorldOptions.worldName("world_nether")).isSuccess) + assertTrue(worldManager.createWorld(CreateWorldOptions.worldName("world_the_end")).isSuccess) } @Test @@ -34,7 +37,7 @@ class WorldGroupManagerTest : TestWithMockBukkit() { assertTrue(worldGroupManager.load().isSuccess) worldGroupManager.createDefaultGroup() assertEquals("default", worldGroupManager.defaultGroup.name) - assertEquals(setOf("world", "world_nether"), worldGroupManager.defaultGroup.worlds) + assertEquals(setOf("world", "world_nether", "world_the_end"), worldGroupManager.defaultGroup.configWorlds) assertConfigEquals("/group/default_group.yml", "groups.yml") } @@ -47,4 +50,28 @@ class WorldGroupManagerTest : TestWithMockBukkit() { worldGroupManager.updateGroup(group) assertConfigEquals("/group/test_group.yml", "groups.yml") } + + @Test + fun `Create a new group with wildcard`() { + val group = worldGroupManager.newEmptyGroup("test") + group.addWorld("world") + group.addWorld("world_*") + worldGroupManager.updateGroup(group) + assertEquals(setOf("world", "world_nether", "world_the_end"), group.applicableWorlds) + } + + @Test + fun `Create a new group with regex`() { + val group = worldGroupManager.newEmptyGroup("test") + group.addWorld("r=^world[\\w]*") + worldGroupManager.updateGroup(group) + assertEquals(setOf("world", "world_nether", "world_the_end"), group.applicableWorlds) + } + + @Test + fun `Create a new group without worlds`() { + val group = worldGroupManager.newEmptyGroup("test") + worldGroupManager.updateGroup(group) + assertEquals(emptySet(), group.applicableWorlds) + } } diff --git a/src/test/resources/group/default_group.yml b/src/test/resources/group/default_group.yml index 5aaab393..bd9f1329 100644 --- a/src/test/resources/group/default_group.yml +++ b/src/test/resources/group/default_group.yml @@ -3,5 +3,6 @@ groups: worlds: - world - world_nether + - world_the_end shares: - all diff --git a/src/test/resources/group/test_group.yml b/src/test/resources/group/test_group.yml index cfc105c2..b3b86154 100644 --- a/src/test/resources/group/test_group.yml +++ b/src/test/resources/group/test_group.yml @@ -1,8 +1,8 @@ groups: test: worlds: - - test2 - test1 + - test2 shares: - inventory_contents - armor_contents