diff --git a/src/main/java/org/mvplugins/multiverse/netherportals/command/flags/BidirectionalFlag.java b/src/main/java/org/mvplugins/multiverse/netherportals/command/flags/BidirectionalFlag.java new file mode 100644 index 0000000..58e13c9 --- /dev/null +++ b/src/main/java/org/mvplugins/multiverse/netherportals/command/flags/BidirectionalFlag.java @@ -0,0 +1,25 @@ +package org.mvplugins.multiverse.netherportals.command.flags; + +import org.jetbrains.annotations.ApiStatus; +import org.jvnet.hk2.annotations.Service; +import org.mvplugins.multiverse.core.command.flag.CommandFlag; +import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager; +import org.mvplugins.multiverse.core.command.flag.FlagBuilder; +import org.mvplugins.multiverse.external.jakarta.inject.Inject; +import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull; + +@ApiStatus.Internal +@Service +public class BidirectionalFlag extends FlagBuilder { + + public static final String NAME = "bidirectional"; + + @Inject + private BidirectionalFlag(@NotNull CommandFlagsManager flagsManager) { + super(NAME, flagsManager); + } + + public final CommandFlag bidirectional = flag(CommandFlag.builder("--bidirectional") + .addAlias("-b") + .build()); +} diff --git a/src/main/java/org/mvplugins/multiverse/netherportals/commands/LinkCommand.java b/src/main/java/org/mvplugins/multiverse/netherportals/commands/LinkCommand.java index ecc8713..48c2f80 100644 --- a/src/main/java/org/mvplugins/multiverse/netherportals/commands/LinkCommand.java +++ b/src/main/java/org/mvplugins/multiverse/netherportals/commands/LinkCommand.java @@ -2,17 +2,20 @@ import org.mvplugins.multiverse.core.command.LegacyAliasCommand; import org.mvplugins.multiverse.core.command.MVCommandIssuer; +import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags; import org.mvplugins.multiverse.core.world.MultiverseWorld; 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; import org.mvplugins.multiverse.external.acf.commands.annotation.Description; import org.mvplugins.multiverse.external.acf.commands.annotation.Flags; +import org.mvplugins.multiverse.external.acf.commands.annotation.Optional; 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; import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; +import org.mvplugins.multiverse.netherportals.command.flags.BidirectionalFlag; import org.mvplugins.multiverse.netherportals.links.LinksManager; import org.mvplugins.multiverse.netherportals.links.WorldLinkType; import org.mvplugins.multiverse.netherportals.locale.MVNPi18n; @@ -24,15 +27,18 @@ class LinkCommand extends NetherPortalsCommand { private final LinksManager linksManager; + private final BidirectionalFlag flags; @Inject - LinkCommand(@NotNull LinksManager linksManager) { + LinkCommand(@NotNull LinksManager linksManager, @NotNull BidirectionalFlag flags) { this.linksManager = linksManager; + this.flags = flags; } @Subcommand("link") @CommandPermission("multiverse.netherportals.link") - @CommandCompletion("@worldlinktypes @mvworlds:scope=both @mvworlds:scope=both") + @CommandCompletion("@worldlinktypes @mvworlds:scope=both @mvworlds:scope=both " + + "@flags:groupName=" + BidirectionalFlag.NAME) @Syntax(" [fromWorld] ") @Description("{@@mv-netherportals.link.description}") public void onLinkCommand( @@ -49,9 +55,20 @@ public void onLinkCommand( @Syntax("") @Description("{@@mv-netherportals.link.toworld.description}") - @NotNull MultiverseWorld toWorld + @NotNull MultiverseWorld toWorld, + + @Optional + @Syntax("[--bidirectional]") + @Description("") + String[] flagArray ) { + ParsedCommandFlags parsedFlags = flags.parse(flagArray); + boolean isBidirectional = parsedFlags.hasFlag(flags.bidirectional); + this.linksManager.addWorldLink(fromWorld, toWorld, worldLinkType); + if (isBidirectional) { + this.linksManager.addWorldLink(toWorld, fromWorld, worldLinkType); + } this.linksManager.save() .onFailure(error -> issuer.sendError(MVNPi18n.LINK_FAILED, @@ -67,20 +84,30 @@ public void onLinkCommand( replace("{linkType}").with(worldLinkType), replace("{fromWorld}").with(fromWorld.getAliasOrName()), replace("{toWorld}").with(toWorld.getAliasOrName())); + if (isBidirectional) { + issuer.sendMessage(MVNPi18n.LINK_SUCCESS, + replace("{linkType}").with(worldLinkType), + replace("{fromWorld}").with(toWorld.getAliasOrName()), + replace("{toWorld}").with(fromWorld.getAliasOrName())); + } }); } @Service private final static class LegacyAlias extends LinkCommand implements LegacyAliasCommand { @Inject - LegacyAlias(LinksManager linksManager) { - super(linksManager); + LegacyAlias(LinksManager linksManager, BidirectionalFlag flags) { + super(linksManager, flags); } @Override @CommandAlias("mvnplink|mvnpl") - public void onLinkCommand(MVCommandIssuer issuer, WorldLinkType worldLinkType, MultiverseWorld fromWorld, MultiverseWorld toWorld) { - super.onLinkCommand(issuer, worldLinkType, fromWorld, toWorld); + public void onLinkCommand(MVCommandIssuer issuer, + WorldLinkType worldLinkType, + MultiverseWorld fromWorld, + MultiverseWorld toWorld, + String[] flagArray) { + super.onLinkCommand(issuer, worldLinkType, fromWorld, toWorld, flagArray); } } } diff --git a/src/main/java/org/mvplugins/multiverse/netherportals/commands/UnlinkCommand.java b/src/main/java/org/mvplugins/multiverse/netherportals/commands/UnlinkCommand.java index ecfb53b..ab9e7bd 100644 --- a/src/main/java/org/mvplugins/multiverse/netherportals/commands/UnlinkCommand.java +++ b/src/main/java/org/mvplugins/multiverse/netherportals/commands/UnlinkCommand.java @@ -2,6 +2,7 @@ import org.mvplugins.multiverse.core.command.LegacyAliasCommand; import org.mvplugins.multiverse.core.command.MVCommandIssuer; +import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags; import org.mvplugins.multiverse.core.config.CoreConfig; import org.mvplugins.multiverse.core.world.MultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; @@ -9,12 +10,15 @@ 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.Optional; 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; import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; +import org.mvplugins.multiverse.external.jetbrains.annotations.Nullable; import org.mvplugins.multiverse.external.vavr.control.Option; +import org.mvplugins.multiverse.netherportals.command.flags.BidirectionalFlag; import org.mvplugins.multiverse.netherportals.links.LinksManager; import org.mvplugins.multiverse.netherportals.links.WorldLinkType; import org.mvplugins.multiverse.netherportals.locale.MVNPi18n; @@ -28,19 +32,22 @@ class UnlinkCommand extends NetherPortalsCommand { private final LinksManager linksManager; private final CoreConfig coreConfig; private final WorldManager worldManager; + private final BidirectionalFlag flags; @Inject UnlinkCommand(@NotNull LinksManager linksManager, @NotNull CoreConfig coreConfig, - @NotNull WorldManager worldManager) { + @NotNull WorldManager worldManager, + @NotNull BidirectionalFlag flags) { this.linksManager = linksManager; this.coreConfig = coreConfig; this.worldManager = worldManager; + this.flags = flags; } @Subcommand("unlink") @CommandPermission("multiverse.netherportals.unlink") - @CommandCompletion("@worldlinktypes @worldswithlink") + @CommandCompletion("@worldlinktypes @worldswithlink @flags:groupName=" + BidirectionalFlag.NAME) @Syntax(" [fromWorld]") @Description("{@@mv-netherportals.unlink.description}") public void onUnlinkCommand( @@ -52,16 +59,52 @@ public void onUnlinkCommand( @Syntax("") @Description("{@@mv-netherportals.unlink.fromworld.description}") - @NotNull String fromWorldString + @NotNull String fromWorldString, + + @Optional + @Syntax("[--bidirectional]") + @Description("") + String[] flagArray ) { + ParsedCommandFlags parsedFlags = flags.parse(flagArray); + boolean isBidirectional = parsedFlags.hasFlag(flags.bidirectional); + String fromWorldName = resolveFromWorldString(fromWorldString) .map(MultiverseWorld::getName) .getOrElse(fromWorldString); // fallback as its possible world was already deleted! String toWorldName = this.linksManager.getWorldLink(fromWorldName, worldLinkType).getOrNull(); + doUnlink(issuer, worldLinkType, fromWorldName, toWorldName); + + if (isBidirectional && toWorldName != null) { + this.linksManager.getWorldLink(toWorldName, worldLinkType) + .onEmpty(() -> issuer.sendMessage(MVNPi18n.UNLINK_NOTLINKED, + Replace.WORLD.with(toWorldName), + replace("{linkType}").with(worldLinkType))) + .filter(linkedWorldName -> { + if (linkedWorldName.equals(fromWorldName)) { + return true; + } + issuer.sendMessage(MVNPi18n.UNLINK_BIDIRECTIONAL_MISMATCH, + replace("{linkType}").with(worldLinkType), + replace("{fromWorld}").with(fromWorldName), + replace("{toWorld}").with(toWorldName), + replace("{linkedWorld}").with(linkedWorldName)); + return false; + }) + .peek(ignore -> doUnlink(issuer, worldLinkType, toWorldName, fromWorldName)); + } + } + + private void doUnlink( + @NotNull MVCommandIssuer issuer, + @NotNull WorldLinkType worldLinkType, + @NotNull String fromWorldName, + @Nullable String toWorldName + ) { if (!this.linksManager.removeWorldLink(fromWorldName, worldLinkType)) { issuer.sendMessage(MVNPi18n.UNLINK_NOTLINKED, - Replace.WORLD.with(fromWorldString), + Replace.WORLD.with(fromWorldName), replace("{linkType}").with(worldLinkType)); return; } @@ -73,12 +116,12 @@ public void onUnlinkCommand( if (fromWorldName.equals(toWorldName)) { issuer.sendMessage(MVNPi18n.UNLINK_ENABLED, replace("{linkType}").with(worldLinkType), - Replace.WORLD.with(fromWorldString)); + Replace.WORLD.with(fromWorldName)); return; } issuer.sendMessage(MVNPi18n.UNLINK_SUCCESS, replace("{linkType}").with(worldLinkType), - replace("{fromWorld}").with(fromWorldString), + replace("{fromWorld}").with(fromWorldName), replace("{toWorld}").with(toWorldName)); }); } @@ -94,14 +137,18 @@ private final static class LegacyAlias extends UnlinkCommand implements LegacyAl @Inject LegacyAlias(@NotNull LinksManager linksManager, @NotNull CoreConfig coreConfig, - @NotNull WorldManager worldManager) { - super(linksManager, coreConfig, worldManager); + @NotNull WorldManager worldManager, + @NotNull BidirectionalFlag flags) { + super(linksManager, coreConfig, worldManager, flags); } @Override @CommandAlias("mvnpunlink|mvnpu") - public void onUnlinkCommand(MVCommandIssuer issuer, WorldLinkType worldLinkType, String fromWorldString) { - super.onUnlinkCommand(issuer, worldLinkType, fromWorldString); + public void onUnlinkCommand(MVCommandIssuer issuer, + WorldLinkType worldLinkType, + String fromWorldString, + String[] flagArray) { + super.onUnlinkCommand(issuer, worldLinkType, fromWorldString, flagArray); } } } diff --git a/src/main/java/org/mvplugins/multiverse/netherportals/locale/MVNPi18n.java b/src/main/java/org/mvplugins/multiverse/netherportals/locale/MVNPi18n.java index fd4cf5e..f620c5b 100644 --- a/src/main/java/org/mvplugins/multiverse/netherportals/locale/MVNPi18n.java +++ b/src/main/java/org/mvplugins/multiverse/netherportals/locale/MVNPi18n.java @@ -31,6 +31,7 @@ public enum MVNPi18n implements MessageKeyProvider { UNLINK_TYPE_DESCRIPTION, UNLINK_FROMWORLD_DESCRIPTION, UNLINK_NOTLINKED, + UNLINK_BIDIRECTIONAL_MISMATCH, UNLINK_FAILED, UNLINK_ENABLED, UNLINK_SUCCESS, diff --git a/src/main/resources/multiverse-netherportals_en.properties b/src/main/resources/multiverse-netherportals_en.properties index 237a768..a98f321 100644 --- a/src/main/resources/multiverse-netherportals_en.properties +++ b/src/main/resources/multiverse-netherportals_en.properties @@ -4,14 +4,15 @@ mv-netherportals.link.type.description=Portal type to link. mv-netherportals.link.fromworld.description=World containing the portals. mv-netherportals.link.toworld.description=World the portals should lead to. mv-netherportals.link.failed=&cThere was an error creating the portal link.\n&cError: {error} -mv-netherportals.link.disabled=&aSuccessfully &cdisabled &f{linkType} &aportals in world '&6{world}&f'. +mv-netherportals.link.disabled=&aSuccessfully &cdisabled &f{linkType} &aportals in world '&6{world}&a'. mv-netherportals.link.success=&aThe &f{linkType}&a portals in '&f{fromWorld}&a' are now linked to '&f{toWorld}&a'. # Unlink command mv-netherportals.unlink.description=Removes a Nether or End portal link from a world. mv-netherportals.unlink.type.description=Portal type to unlink. mv-netherportals.unlink.fromworld.description=World containing the portals. -mv-netherportals.unlink.notlinked=&cThe world '&f{world}&c' does not have a {linkType} portal link. +mv-netherportals.unlink.notlinked=&cThe world '&f{world}&c' does not have a {linkType} &cportal link. +mv-netherportals.unlink.bidirectional.mismatch=&cThe world '&f{toWorld}&c' {linkType} &cportal does not link back to '&f{fromWorld}&c', it links to '&f{linkedWorld}&c' instead. mv-netherportals.unlink.failed=&cThere was an error removing the portal link.\n&cError: {error} mv-netherportals.unlink.enabled=&aSuccessfully enabled &f{linkType}&a portals in world '&f{world}&a'. mv-netherportals.unlink.success=&aThe &f{linkType}&a portals in '&f{fromWorld}&a' are now unlinked from '&f{toWorld}&a'.