Skip to content

Commit 28b1996

Browse files
authored
Merge pull request #701 from Multiverse/feat/action-handlers
Implement action handler to support command execution and bungeecord proxy
2 parents bcb78c7 + bd793e9 commit 28b1996

30 files changed

+1079
-272
lines changed

build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ repositories {
1515
name = 'benthecat'
1616
url = uri('https://repo.c0ding.party/multiverse-beta')
1717
}
18+
maven {
19+
name = "helpchatRepoReleases"
20+
url = uri("https://repo.helpch.at/releases/")
21+
}
1822
}
1923

2024
configure(apiDependencies) {
@@ -32,6 +36,9 @@ dependencies {
3236
exclude group: 'org.bukkit', module: 'bukkit'
3337
}
3438

39+
// PlaceholderAPI
40+
externalPlugin 'me.clip:placeholderapi:2.11.6'
41+
3542
// Utils
3643
shadowed('com.dumptruckman.minecraft:Logging:1.1.1') {
3744
exclude group: 'junit', module: 'junit'

src/main/java/org/mvplugins/multiverse/portals/MVPortal.java

Lines changed: 128 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,22 @@
99

1010
import java.util.Arrays;
1111
import java.util.Collection;
12+
import java.util.Date;
1213
import java.util.HashSet;
1314
import java.util.List;
15+
import java.util.Objects;
1416
import java.util.Set;
1517
import java.util.Stack;
1618
import java.util.regex.Pattern;
1719

1820
import com.dumptruckman.minecraft.util.Logging;
21+
import org.bukkit.Bukkit;
22+
import org.bukkit.command.CommandSender;
1923
import org.bukkit.configuration.ConfigurationSection;
24+
import org.bukkit.entity.Entity;
2025
import org.jetbrains.annotations.ApiStatus;
2126
import org.jetbrains.annotations.Nullable;
27+
import org.mvplugins.multiverse.core.command.MVCommandManager;
2228
import org.mvplugins.multiverse.core.config.handle.MemoryConfigurationHandle;
2329
import org.mvplugins.multiverse.core.config.handle.StringPropertyHandle;
2430
import org.mvplugins.multiverse.core.config.migration.ConfigMigrator;
@@ -27,9 +33,16 @@
2733
import org.mvplugins.multiverse.core.destination.DestinationInstance;
2834
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
2935
import org.mvplugins.multiverse.core.teleportation.BlockSafety;
36+
import org.mvplugins.multiverse.core.utils.result.Attempt;
37+
import org.mvplugins.multiverse.core.utils.text.ChatTextFormatter;
3038
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
3139
import org.mvplugins.multiverse.core.world.WorldManager;
40+
import org.mvplugins.multiverse.external.vavr.control.Option;
3241
import org.mvplugins.multiverse.external.vavr.control.Try;
42+
import org.mvplugins.multiverse.portals.action.ActionFailureReason;
43+
import org.mvplugins.multiverse.portals.action.ActionHandler;
44+
import org.mvplugins.multiverse.portals.action.ActionHandlerProvider;
45+
import org.mvplugins.multiverse.portals.action.ActionHandlerType;
3346
import org.mvplugins.multiverse.portals.config.PortalsConfig;
3447
import org.mvplugins.multiverse.portals.enums.PortalType;
3548
import org.bukkit.Location;
@@ -62,6 +75,8 @@ public static MVPortal loadMVPortalFromConfig(MultiversePortals instance, String
6275
private final WorldManager worldManager;
6376
private final DestinationsProvider destinationsProvider;
6477
private final BlockSafety blockSafety;
78+
private final ActionHandlerProvider actionHandlerProvider;
79+
private final MVCommandManager commandManager;
6580

6681
private final String name;
6782
private final MVPortalNodes configNodes;
@@ -94,16 +109,24 @@ private MVPortal(MultiversePortals plugin, String name) {
94109
this.worldManager = this.plugin.getServiceLocator().getService(WorldManager.class);
95110
this.destinationsProvider = this.plugin.getServiceLocator().getService(DestinationsProvider.class);
96111
this.blockSafety = this.plugin.getServiceLocator().getService(BlockSafety.class);
112+
this.actionHandlerProvider = this.plugin.getServiceLocator().getService(ActionHandlerProvider.class);
113+
this.commandManager = this.plugin.getServiceLocator().getService(MVCommandManager.class);
97114

98115
this.name = name;
99116

100117
var config = this.plugin.getPortalsConfig();
101118
this.configNodes = new MVPortalNodes(plugin, this);
102-
var portalSection = config.getConfigurationSection("portals." + this.name);
103-
if (portalSection == null) {
104-
portalSection = config.createSection("portals." + this.name);
105-
}
106-
this.configHandle = MemoryConfigurationHandle.builder(portalSection, configNodes.getNodes())
119+
var portalSection = Option.of(config.getConfigurationSection("portals." + this.name))
120+
.getOrElse(() -> config.createSection("portals." + this.name));
121+
this.configHandle = setUpConfigHandle(portalSection);
122+
this.stringPropertyHandle = new StringPropertyHandle(this.configHandle);
123+
configHandle.load();
124+
125+
setUpPermissions();
126+
}
127+
128+
private MemoryConfigurationHandle setUpConfigHandle(ConfigurationSection portalSection) {
129+
return MemoryConfigurationHandle.builder(portalSection, configNodes.getNodes())
107130
.migrator(ConfigMigrator.builder(configNodes.version)
108131
.addVersionMigrator(VersionMigrator.builder(1.0)
109132
.addAction(MoveMigratorAction.of("safeteleport", "safe-teleport"))
@@ -119,11 +142,14 @@ private MVPortal(MultiversePortals plugin, String name) {
119142
}
120143
})
121144
.build())
145+
.addVersionMigrator(VersionMigrator.builder(1.2)
146+
.addAction(MoveMigratorAction.of("destination", "action"))
147+
.build())
122148
.build())
123149
.build();
124-
this.stringPropertyHandle = new StringPropertyHandle(this.configHandle);
125-
configHandle.load();
150+
}
126151

152+
private void setUpPermissions() {
127153
this.permission = this.plugin.getServer().getPluginManager().getPermission("multiverse.portal.access." + this.name);
128154
if (this.permission == null) {
129155
this.permission = new Permission("multiverse.portal.access." + this.name, "Allows access to the " + this.name + " portal", PermissionDefault.OP);
@@ -142,6 +168,10 @@ private MVPortal(MultiversePortals plugin, String name) {
142168
}
143169
}
144170

171+
/**
172+
*
173+
* @return
174+
*/
145175
public String getName() {
146176
return this.name;
147177
}
@@ -271,24 +301,53 @@ public PortalLocation getPortalLocation() {
271301
return this.location;
272302
}
273303

274-
public boolean setDestination(String destinationString) {
275-
DestinationInstance<?, ?> newDestination = this.destinationsProvider.parseDestination(destinationString).getOrNull();
276-
return setDestination(newDestination);
304+
@ApiStatus.AvailableSince("5.2")
305+
public Try<Void> setActionType(ActionHandlerType<?, ?> actionType) {
306+
return configHandle.set(configNodes.actionType, actionType.getName());
277307
}
278308

279-
public boolean setDestination(DestinationInstance<?, ?> newDestination) {
280-
if (newDestination == null) {
281-
Logging.warning("Portal " + this.name + " has an invalid DESTINATION!");
282-
return false;
283-
}
284-
return this.configHandle.set(configNodes.destination, newDestination.toString()).isSuccess();
309+
@ApiStatus.AvailableSince("5.2")
310+
public Try<Void> setActionType(String actionType) {
311+
return configHandle.set(configNodes.actionType, actionType);
285312
}
286313

287-
public DestinationInstance<?, ?> getDestination() {
288-
return this.destinationsProvider.parseDestination(this.configHandle.get(configNodes.destination))
289-
.onFailure(f ->
290-
Logging.warning("Portal " + this.name + " has an invalid DESTINATION! " + f.getFailureMessage().formatted()))
291-
.getOrNull();
314+
@ApiStatus.AvailableSince("5.2")
315+
public String getActionType() {
316+
return this.configHandle.get(configNodes.actionType);
317+
}
318+
319+
@ApiStatus.AvailableSince("5.2")
320+
public Try<Void> setAction(String action) {
321+
return configHandle.set(configNodes.action, action);
322+
}
323+
324+
@ApiStatus.AvailableSince("5.2")
325+
public String getAction() {
326+
return configHandle.get(configNodes.action);
327+
}
328+
329+
@ApiStatus.AvailableSince("5.2")
330+
public Attempt<? extends ActionHandler<?, ?>, ActionFailureReason> getActionHandler() {
331+
return actionHandlerProvider.parseHandler(getActionType(), getAction());
332+
}
333+
334+
@ApiStatus.AvailableSince("5.2")
335+
public Attempt<? extends ActionHandler<?, ?>, ActionFailureReason> getActionHandler(CommandSender sender) {
336+
return actionHandlerProvider.parseHandler(sender, getActionType(), getAction());
337+
}
338+
339+
@ApiStatus.AvailableSince("5.2")
340+
public Attempt<Void, ActionFailureReason> runActionFor(Entity entity) {
341+
return getActionHandler(entity)
342+
.mapAttempt(actionHandler -> actionHandler.runAction(this, entity))
343+
.onSuccess(() -> {
344+
if (entity instanceof Player player) {
345+
plugin.getPortalSession(player).setTeleportTime(new Date());
346+
}
347+
})
348+
.onFailure(failure ->
349+
Logging.warning(ChatTextFormatter.removeColor("Invalid Portal Action: " +
350+
failure.getFailureMessage().formatted(commandManager.getCommandIssuer(Bukkit.getConsoleSender())))));
292351
}
293352

294353
/**
@@ -598,4 +657,52 @@ public boolean isExempt(Player player) {
598657
public PortalLocation getLocation() {
599658
return getPortalLocation();
600659
}
660+
661+
/**
662+
* @deprecated Portals now have new types of action. Hence, the portal's destination (now called action) may not
663+
* always be a multiverse destination. It can be a command or server name as well.
664+
* Please see {@link MVPortal#getActionHandler()} instead.
665+
*/
666+
@Deprecated(since = "5.2", forRemoval = true)
667+
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
668+
public boolean setDestination(String destinationString) {
669+
DestinationInstance<?, ?> newDestination = this.destinationsProvider.parseDestination(destinationString).getOrNull();
670+
return setDestination(newDestination);
671+
}
672+
673+
/**
674+
* @deprecated Portals now have new types of action. Hence, the portal's destination (now called action) may not
675+
* always be a multiverse destination. It can be a command or server name as well.
676+
* Please see {@link MVPortal#getActionHandler()} instead.
677+
*/
678+
@Deprecated(since = "5.2", forRemoval = true)
679+
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
680+
public boolean setDestination(DestinationInstance<?, ?> newDestination) {
681+
if (newDestination == null) {
682+
Logging.warning("Portal " + this.name + " has an invalid DESTINATION!");
683+
return false;
684+
}
685+
if (!Objects.equals(getActionType(), "multiverse-destination")) {
686+
Logging.warning("Portal " + this.name + " is not set to use multiverse destination!");
687+
return false;
688+
}
689+
return this.configHandle.set(configNodes.action, newDestination.toString()).isSuccess();
690+
}
691+
692+
/**
693+
* @deprecated Portals now have new types of action. Hence, the portal's destination (now called action) may not
694+
* always be a multiverse destination. It can be a command or server name as well.
695+
* Please see {@link MVPortal#getActionHandler()} instead.
696+
*/
697+
@Deprecated(since = "5.2", forRemoval = true)
698+
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
699+
public DestinationInstance<?, ?> getDestination() {
700+
return this.destinationsProvider.parseDestination(getAction())
701+
.onFailure(f -> {
702+
if (getAction().equals("multiverse-destination")) {
703+
Logging.warning("Portal " + this.name + " has an invalid DESTINATION! " + f.getFailureMessage().formatted());
704+
}
705+
})
706+
.getOrNull();
707+
}
601708
}

src/main/java/org/mvplugins/multiverse/portals/MVPortalNodes.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import org.mvplugins.multiverse.core.config.node.ConfigNode;
77
import org.mvplugins.multiverse.core.config.node.Node;
88
import org.mvplugins.multiverse.core.config.node.NodeGroup;
9-
import org.mvplugins.multiverse.core.destination.DestinationInstance;
109
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
1110
import org.mvplugins.multiverse.core.exceptions.MultiverseException;
1211
import org.mvplugins.multiverse.external.vavr.control.Try;
12+
import org.mvplugins.multiverse.portals.action.ActionHandler;
13+
import org.mvplugins.multiverse.portals.action.ActionHandlerProvider;
1314
import org.mvplugins.multiverse.portals.utils.MultiverseRegion;
1415

1516
import java.util.Collections;
@@ -21,12 +22,12 @@ final class MVPortalNodes {
2122

2223
private MultiversePortals plugin;
2324
private MVPortal portal;
24-
private DestinationsProvider destinationsProvider;
25+
private ActionHandlerProvider actionHandlerProvider;
2526

2627
MVPortalNodes(MultiversePortals plugin, MVPortal portal) {
2728
this.plugin = plugin;
2829
this.portal = portal;
29-
this.destinationsProvider = MultiverseCoreApi.get().getDestinationsProvider();
30+
this.actionHandlerProvider = plugin.getServiceLocator().getService(ActionHandlerProvider.class);
3031
}
3132

3233
NodeGroup getNodes() {
@@ -90,13 +91,23 @@ private <N extends Node> N node(N node) {
9091
.onSetValue((oldValue, newValue) -> portal.setPortalLocationInternal(PortalLocation.parseLocation(newValue)))
9192
.build());
9293

93-
final ConfigNode<String> destination = node(ConfigNode.builder("destination", String.class)
94+
final ConfigNode<String> actionType = node(ConfigNode.builder("action-type", String.class)
95+
.suggester(input -> actionHandlerProvider.getAllHandlerTypeNames())
96+
.defaultValue("multiverse-destination")
97+
.build());
98+
99+
final ConfigNode<String> action = node(ConfigNode.builder("action", String.class)
94100
.defaultValue("")
95-
.aliases("dest")
96-
.suggester((sender, input) -> destinationsProvider.suggestDestinationStrings(sender, input))
97-
.stringParser((sender, input, type) -> destinationsProvider.parseDestination(sender, input)
98-
.map(DestinationInstance::toString)
99-
.toTry())
101+
.aliases("destination", "dest")
102+
.suggester((sender, input) -> actionHandlerProvider.getHandlerType(portal.getActionType())
103+
.map(actionHandlerType -> actionHandlerType.suggestActions(sender, input))
104+
.getOrElse(Collections.emptyList()))
105+
.stringParser((sender, input, type) ->
106+
Try.of(() -> actionHandlerProvider.getHandlerType(portal.getActionType())
107+
.mapAttempt(actionHandlerType -> actionHandlerType.parseHandler(sender, input))
108+
.map(ActionHandler::serialise)
109+
.getOrThrow(failure ->
110+
new MultiverseException(failure.getFailureMessage()))))
100111
.build());
101112

102113
final ConfigNode<Boolean> checkDestinationSafety = node(ConfigNode.builder("check-destination-safety", Boolean.class)

src/main/java/org/mvplugins/multiverse/portals/MultiversePortals.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import java.util.logging.Level;
1717

1818
import com.dumptruckman.minecraft.util.Logging;
19+
import com.google.common.io.ByteArrayDataInput;
20+
import com.google.common.io.ByteStreams;
1921
import org.jetbrains.annotations.ApiStatus;
2022
import org.mvplugins.multiverse.core.config.CoreConfig;
2123
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
@@ -26,6 +28,8 @@
2628
import org.mvplugins.multiverse.external.jakarta.inject.Provider;
2729
import org.jvnet.hk2.annotations.Service;
2830
import org.mvplugins.multiverse.external.vavr.control.Try;
31+
import org.mvplugins.multiverse.portals.action.ActionHandlerProvider;
32+
import org.mvplugins.multiverse.portals.action.ActionHandlerType;
2933
import org.mvplugins.multiverse.portals.commands.PortalsCommand;
3034
import org.mvplugins.multiverse.portals.command.PortalsCommandCompletions;
3135
import org.mvplugins.multiverse.portals.command.PortalsCommandContexts;
@@ -70,6 +74,8 @@ public class MultiversePortals extends MultiverseModule {
7074
private Provider<PortalsConfig> portalsConfigProvider;
7175
@Inject
7276
private Provider<BstatsMetricsConfigurator> metricsConfiguratorProvider;
77+
@Inject
78+
private Provider<ActionHandlerProvider> actionHandlerProvider;
7379

7480
private FileConfiguration MVPPortalConfig;
7581
private WorldEditConnection worldEditConnection;
@@ -104,6 +110,7 @@ public void onEnable() {
104110
this.getServer().getPluginManager().disablePlugin(this);
105111
return;
106112
}
113+
this.setUpActionHandlers();
107114
this.loadPortals();
108115
this.setupMetrics();
109116

@@ -112,6 +119,9 @@ public void onEnable() {
112119
getServer().getPluginManager().registerEvents(new WorldEditPluginListener(), this);
113120
MultiversePortalsApi.init(this);
114121

122+
// for teleporting between servers
123+
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
124+
115125
Logging.log(true, Level.INFO, " Enabled - By %s", StringFormatter.joinAnd(getDescription().getAuthors()));
116126
}
117127

@@ -180,6 +190,12 @@ public void destroyPortalSession(Player p) {
180190
this.portalSessions.remove(p.getName());
181191
}
182192

193+
private void setUpActionHandlers() {
194+
serviceLocator.getAllServices(ActionHandlerType.class).forEach(handler -> {
195+
actionHandlerProvider.get().registerHandlerType(handler);
196+
});
197+
}
198+
183199
private void loadPortals() {
184200
this.MVPPortalConfig = YamlConfiguration.loadConfiguration(new File(getDataFolder(), "portals.yml"));
185201
if (!this.MVPPortalConfig.isConfigurationSection("portals")) {

src/main/java/org/mvplugins/multiverse/portals/PortalPlayerSession.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,17 +252,14 @@ public boolean showDebugInfo() {
252252
}
253253

254254
displayUtils.showStaticInfo(this.player, this.standingIn, "You are currently standing in ");
255-
displayUtils.showPortalPriceInfo(this.standingIn, this.player);
256255
return true;
257256
}
258257

259258
public boolean showDebugInfo(MVPortal portal) {
260259
if (portal.playerCanEnterPortal(this.player)) {
261260
displayUtils.showStaticInfo(this.player, portal, "Portal Info ");
262-
displayUtils.showPortalPriceInfo(portal, this.player);
263-
} else {
264-
Logging.info("Player " + this.player.getName() + " walked through" + portal.getName() + " with debug on.");
265261
}
262+
Logging.info("Player " + this.player.getName() + " walked through" + portal.getName() + " with debug on.");
266263
return true;
267264
}
268265

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.mvplugins.multiverse.portals.action;
2+
3+
import org.mvplugins.multiverse.core.utils.result.FailureReason;
4+
import org.mvplugins.multiverse.external.jetbrains.annotations.ApiStatus;
5+
6+
/**
7+
* Parent class for all reasons for a failure when trying to parse an action handler.
8+
*
9+
* @since 5.2
10+
*/
11+
@ApiStatus.AvailableSince("5.2")
12+
public interface ActionFailureReason extends FailureReason {
13+
ActionFailureReason INSTANCE = new ActionFailureReason() {};
14+
}

0 commit comments

Comments
 (0)