diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle
index bce858b36..d4c4d5994 100644
--- a/Bukkit/build.gradle
+++ b/Bukkit/build.gradle
@@ -126,6 +126,7 @@ shadowJar {
include(dependency('org.slf4j:slf4j-api'))
include(dependency('javax.inject:javax.inject:1'))
include(dependency('aopalliance:aopalliance:1.0'))
+ include(dependency('com.intellectualsites:Pipeline:1.4.0-SNAPSHOT'))
}
relocate('net.kyori.adventure', 'com.plotsquared.core.configuration.adventure')
diff --git a/Core/build.gradle b/Core/build.gradle
index 3189bd211..5b62806a6 100644
--- a/Core/build.gradle
+++ b/Core/build.gradle
@@ -23,6 +23,7 @@ dependencies {
compile group: 'aopalliance', name: 'aopalliance', version: '1.0'
// logging
implementation("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1")
+ implementation('com.intellectualsites:Pipeline:1.4.0-SNAPSHOT')
}
sourceCompatibility = 1.8
diff --git a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java
index 8cac8509a..17c8c84fd 100644
--- a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java
+++ b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java
@@ -28,6 +28,7 @@ package com.plotsquared.core;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
+import com.intellectualsites.services.ServicePipeline;
import com.plotsquared.core.backup.BackupManager;
import com.plotsquared.core.configuration.caption.LocaleHolder;
import com.plotsquared.core.generator.GeneratorWrapper;
@@ -269,4 +270,13 @@ public interface PlotPlatform
extends LocaleHolder {
return getInjector().getInstance(PermissionHandler.class);
}
+ /**
+ * Get the {@link ServicePipeline} implementation
+ *
+ * @return Service pipeline
+ */
+ @Nonnull default ServicePipeline getServicePipeline() {
+ return getInjector().getInstance(ServicePipeline.class);
+ }
+
}
diff --git a/Core/src/main/java/com/plotsquared/core/command/Auto.java b/Core/src/main/java/com/plotsquared/core/command/Auto.java
index 26ac1b3f9..467757d85 100644
--- a/Core/src/main/java/com/plotsquared/core/command/Auto.java
+++ b/Core/src/main/java/com/plotsquared/core/command/Auto.java
@@ -25,8 +25,9 @@
*/
package com.plotsquared.core.command;
-import com.google.common.collect.Lists;
+import com.google.common.reflect.TypeToken;
import com.google.inject.Inject;
+import com.intellectualsites.services.ServicePipeline;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
@@ -34,7 +35,6 @@ import com.plotsquared.core.database.DBFunc;
import com.plotsquared.core.events.PlayerAutoPlotEvent;
import com.plotsquared.core.events.PlotAutoMergeEvent;
import com.plotsquared.core.events.Result;
-import com.plotsquared.core.events.TeleportCause;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.permissions.PermissionHandler;
import com.plotsquared.core.player.MetaDataAccess;
@@ -42,9 +42,8 @@ import com.plotsquared.core.player.PlayerMetaDataKeys;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
-import com.plotsquared.core.plot.PlotAreaType;
-import com.plotsquared.core.plot.PlotId;
import com.plotsquared.core.plot.world.PlotAreaManager;
+import com.plotsquared.core.services.plots.AutoService;
import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.Expression;
@@ -56,8 +55,10 @@ import net.kyori.adventure.text.minimessage.Template;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
-import java.util.Set;
+import java.util.stream.Collectors;
@CommandDeclaration(command = "auto",
permission = "plots.auto",
@@ -70,13 +71,23 @@ public class Auto extends SubCommand {
private final PlotAreaManager plotAreaManager;
private final EventDispatcher eventDispatcher;
private final EconHandler econHandler;
+ private final ServicePipeline servicePipeline;
@Inject public Auto(@Nonnull final PlotAreaManager plotAreaManager,
@Nonnull final EventDispatcher eventDispatcher,
- @Nullable final EconHandler econHandler) {
+ @Nullable final EconHandler econHandler,
+ @Nonnull final ServicePipeline servicePipeline) {
this.plotAreaManager = plotAreaManager;
this.eventDispatcher = eventDispatcher;
this.econHandler = econHandler;
+ this.servicePipeline = servicePipeline;
+ this.servicePipeline.registerServiceType(TypeToken.of(AutoService.class), new AutoService.DefaultAutoService());
+ final AutoService.MultiPlotService multiPlotService = new AutoService.MultiPlotService();
+ this.servicePipeline.registerServiceImplementation(AutoService.class, multiPlotService,
+ Collections.singletonList(multiPlotService));
+ final AutoService.SinglePlotService singlePlotService = new AutoService.SinglePlotService();
+ this.servicePipeline.registerServiceImplementation(AutoService.class, singlePlotService,
+ Collections.singletonList(singlePlotService));
}
public static boolean checkAllowedPlots(PlotPlayer player, PlotArea plotarea,
@@ -122,62 +133,32 @@ public class Auto extends SubCommand {
return true;
}
- /**
- * Teleport the player home, or claim a new plot
- *
- * @param player player
- * @param area plot area
- * @param start start id
- * @param schematic schematic
- */
- public static void homeOrAuto(final PlotPlayer player, final PlotArea area, PlotId start,
- final String schematic) {
- Set plots = player.getPlots();
- if (!plots.isEmpty()) {
- plots.iterator().next().teleportPlayer(player, TeleportCause.COMMAND, result -> {
- });
- } else {
- autoClaimSafe(player, area, start, schematic);
- }
- }
-
- /**
- * Claim a new plot for a player
- *
- * @param player player
- * @param area plot area
- * @param start start id
- * @param schematic schematic
- */
- public static void autoClaimSafe(final PlotPlayer> player, final PlotArea area, PlotId start,
- final String schematic) {
+ private void claimSingle(@Nonnull final PlotPlayer> player, @Nonnull final Plot plot,
+ @Nonnull final PlotArea plotArea, @Nullable final String schematic) {
try (final MetaDataAccess metaDataAccess =
player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_AUTO)) {
metaDataAccess.set(true);
}
- autoClaimFromDatabase(player, area, start, new RunnableVal() {
+ plot.setOwnerAbs(player.getUUID());
+
+ final RunnableVal runnableVal = new RunnableVal() {
+ {
+ this.value = plot;
+ }
+
@Override public void run(final Plot plot) {
try {
- TaskManager.getPlatformImplementation().sync(new AutoClaimFinishTask(player, plot, area, schematic,
- PlotSquared.get().getEventDispatcher()));
+ TaskManager.getPlatformImplementation().sync(
+ new AutoClaimFinishTask(player, plot, plotArea, schematic,
+ PlotSquared.get().getEventDispatcher()));
} catch (final Exception e) {
e.printStackTrace();
}
}
- });
- }
+ };
+
+ DBFunc.createPlotSafe(plot, runnableVal, () -> claimSingle(player, plot, plotArea, schematic));
- public static void autoClaimFromDatabase(final PlotPlayer player, final PlotArea area,
- PlotId start, final RunnableVal whenDone) {
- final Plot plot = area.getNextFreePlot(player, start);
- if (plot == null) {
- whenDone.run(null);
- return;
- }
- whenDone.value = plot;
- plot.setOwnerAbs(player.getUUID());
- DBFunc.createPlotSafe(plot, whenDone,
- () -> autoClaimFromDatabase(player, area, plot.getId(), whenDone));
}
@Override public boolean onCommand(final PlotPlayer> player, String[] args) {
@@ -312,49 +293,33 @@ public class Auto extends SubCommand {
);
}
}
- // TODO handle type 2 (partial) the same as normal worlds!
- if (size_x == 1 && size_z == 1) {
- autoClaimSafe(player, plotarea, null, schematic);
- return true;
+
+ final List plots = this.servicePipeline
+ .pump(new AutoService.AutoQuery(player, null, size_x, size_z, plotarea))
+ .through(AutoService.class)
+ .getResult();
+
+ if (plots.isEmpty()) {
+ player.sendMessage(TranslatableCaption.of("errors.no_free_plots"));
+ return false;
+ } else if (plots.size() == 1) {
+ this.claimSingle(player, plots.get(0), plotarea, schematic);
} else {
- if (plotarea.getType() == PlotAreaType.PARTIAL) {
- player.sendMessage(TranslatableCaption.of("errors.no_free_plots"));
+ final Iterator plotIterator = plots.iterator();
+ while (plotIterator.hasNext()) {
+ plotIterator.next().claim(player, !plotIterator.hasNext(), null);
+ }
+ final PlotAutoMergeEvent mergeEvent = this.eventDispatcher.callAutoMerge(plots.get(0),
+ plots.stream().map(Plot::getId).collect(Collectors.toList()));
+ if (!force && mergeEvent.getEventResult() == Result.DENY) {
+ player.sendMessage(
+ TranslatableCaption.of("events.event_denied"),
+ Template.of("value", "Auto merge")
+ );
return false;
}
- while (true) {
- PlotId start = plotarea.getMeta("lastPlot", PlotId.of(0, 0)).getNextId();
- PlotId end = PlotId.of(start.getX() + size_x - 1, start.getY() + size_z - 1);
- if (plotarea.canClaim(player, start, end)) {
- plotarea.setMeta("lastPlot", start);
-
- for (final PlotId plotId : PlotId.PlotRangeIterator.range(start, end)) {
- final Plot plot = plotarea.getPlot(plotId);
- if (plot == null) {
- return false;
- }
- plot.claim(player, plotId.equals(end), null);
- }
-
- final List plotIds = Lists.newArrayList((Iterable extends PlotId>)
- PlotId.PlotRangeIterator.range(start, end));
- final PlotId pos1 = plotIds.get(0);
- final PlotAutoMergeEvent mergeEvent = this.eventDispatcher
- .callAutoMerge(plotarea.getPlotAbs(pos1), plotIds);
- if (!force && mergeEvent.getEventResult() == Result.DENY) {
- player.sendMessage(
- TranslatableCaption.of("events.event_denied"),
- Template.of("value", "Auto merge")
- );
- return false;
- }
- if (!plotarea.mergePlots(mergeEvent.getPlots(), true)) {
- return false;
- }
- break;
- }
- plotarea.setMeta("lastPlot", start);
- }
- return true;
+ return plotarea.mergePlots(mergeEvent.getPlots(), true);
}
+ return true;
}
}
diff --git a/Core/src/main/java/com/plotsquared/core/inject/modules/PlotSquaredModule.java b/Core/src/main/java/com/plotsquared/core/inject/modules/PlotSquaredModule.java
index 6900a57e5..82c5549c3 100644
--- a/Core/src/main/java/com/plotsquared/core/inject/modules/PlotSquaredModule.java
+++ b/Core/src/main/java/com/plotsquared/core/inject/modules/PlotSquaredModule.java
@@ -26,6 +26,7 @@
package com.plotsquared.core.inject.modules;
import com.google.inject.AbstractModule;
+import com.intellectualsites.services.ServicePipeline;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.file.YamlConfiguration;
import com.plotsquared.core.inject.annotations.BackgroundPipeline;
@@ -44,6 +45,7 @@ public class PlotSquaredModule extends AbstractModule {
@Override protected void configure() {
final PlotSquared plotSquared = PlotSquared.get();
+ bind(ServicePipeline.class).toInstance(ServicePipeline.builder().build());
bind(YamlConfiguration.class).annotatedWith(WorldConfig.class).toInstance(plotSquared.getWorldConfiguration());
bind(File.class).annotatedWith(WorldFile.class).toInstance(plotSquared.getWorldsFile());
bind(File.class).annotatedWith(ConfigFile.class).toInstance(plotSquared.getConfigFile());
diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java
index 36a0fe4d5..74246c907 100644
--- a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java
+++ b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java
@@ -83,6 +83,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -911,31 +912,38 @@ public abstract class PlotArea {
}
}
- public boolean canClaim(@Nullable final PlotPlayer player, @Nonnull final PlotId pos1,
+ @Nullable public List canClaim(@Nullable final PlotPlayer player, @Nonnull final PlotId pos1,
@Nonnull final PlotId pos2) {
if (pos1.getX() == pos2.getX() && pos1.getY() == pos2.getY()) {
if (getOwnedPlot(pos1) != null) {
- return false;
+ return null;
}
final Plot plot = getPlotAbs(pos1);
if (plot == null) {
- return false;
+ return null;
+ }
+ if (plot.canClaim(player)) {
+ return Collections.singletonList(plot);
+ } else {
+ return null;
}
- return plot.canClaim(player);
}
+ final List plots = new LinkedList<>();
for (int x = pos1.getX(); x <= pos2.getX(); x++) {
for (int y = pos1.getY(); y <= pos2.getY(); y++) {
final PlotId id = PlotId.of(x, y);
final Plot plot = getPlotAbs(id);
if (plot == null) {
- return false;
+ return null;
}
if (!plot.canClaim(player)) {
- return false;
+ return null;
+ } else {
+ plots.add(plot);
}
}
}
- return true;
+ return plots;
}
public boolean removePlot(@Nonnull final PlotId id) {
diff --git a/Core/src/main/java/com/plotsquared/core/services/plots/AutoService.java b/Core/src/main/java/com/plotsquared/core/services/plots/AutoService.java
new file mode 100644
index 000000000..0ebab9494
--- /dev/null
+++ b/Core/src/main/java/com/plotsquared/core/services/plots/AutoService.java
@@ -0,0 +1,163 @@
+package com.plotsquared.core.services.plots;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.intellectualsites.services.types.Service;
+import com.plotsquared.core.player.PlotPlayer;
+import com.plotsquared.core.plot.Plot;
+import com.plotsquared.core.plot.PlotArea;
+import com.plotsquared.core.plot.PlotAreaType;
+import com.plotsquared.core.plot.PlotId;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+
+public interface AutoService extends Service> {
+
+ Cache plotCandidateCache = CacheBuilder.newBuilder()
+ .expireAfterWrite(20, TimeUnit.SECONDS).build();
+ Object plotLock = new Object();
+
+ final class AutoQuery {
+
+ private final PlotPlayer> player;
+ private final PlotId startId;
+ private final int sizeX;
+ private final int sizeZ;
+ private final PlotArea plotArea;
+
+ /**
+ * Crate a new auto query
+ *
+ * @param player Player to claim for
+ * @param startId Plot ID to start searching from
+ * @param sizeX Number of plots along the X axis
+ * @param sizeZ Number of plots along the Z axis
+ * @param plotArea Plot area to search in
+ */
+ public AutoQuery(@Nonnull final PlotPlayer> player, @Nullable final PlotId startId,
+ final int sizeX, final int sizeZ, @Nonnull final PlotArea plotArea) {
+ this.player = player;
+ this.startId = startId;
+ this.sizeX = sizeX;
+ this.sizeZ = sizeZ;
+ this.plotArea = plotArea;
+ }
+
+ /**
+ * Get the player that the plots are meant for
+ *
+ * @return Player
+ */
+ @Nonnull public PlotPlayer> getPlayer() {
+ return this.player;
+ }
+
+ /**
+ * Get the plot ID to start searching from
+ *
+ * @return Start ID
+ */
+ @Nullable public PlotId getStartId() {
+ return this.startId;
+ }
+
+ /**
+ * Get the number of plots along the X axis
+ *
+ * @return Number of plots along the X axis
+ */
+ public int getSizeX() {
+ return this.sizeX;
+ }
+
+ /**
+ * Get the number of plots along the Z axis
+ *
+ * @return Number of plots along the Z axis
+ */
+ public int getSizeZ() {
+ return this.sizeZ;
+ }
+
+ /**
+ * Get the plot area to search in
+ *
+ * @return Plot area
+ */
+ @Nonnull public PlotArea getPlotArea() {
+ return this.plotArea;
+ }
+
+ }
+
+
+ final class DefaultAutoService implements AutoService {
+
+ @Override public List handle(@Nonnull final AutoQuery autoQuery) {
+ return Collections.emptyList();
+ }
+
+ }
+
+
+ final class SinglePlotService implements AutoService, Predicate {
+
+ @Nullable @Override public List handle(@Nonnull AutoQuery autoQuery) {
+ Plot plot;
+ do {
+ synchronized (plotLock) {
+ plot = autoQuery.getPlotArea().getNextFreePlot(autoQuery.getPlayer(), autoQuery.getStartId());
+ if (plot != null && plotCandidateCache.getIfPresent(plot.getId()) == null) {
+ plotCandidateCache.put(plot.getId(), plot);
+ return Collections.singletonList(plot);
+ }
+ }
+ } while (plot != null);
+ return null;
+ }
+
+ @Override public boolean test(@Nonnull final AutoQuery autoQuery) {
+ return autoQuery.sizeX == 1 && autoQuery.sizeZ == 1;
+ }
+
+ }
+
+
+ final class MultiPlotService implements AutoService, Predicate {
+
+ @Override public List handle(@Nonnull final AutoQuery autoQuery) {
+ /* TODO: Add timeout? */
+ outer: while (true) {
+ synchronized (plotLock) {
+ final PlotId start =
+ autoQuery.getPlotArea().getMeta("lastPlot", PlotId.of(0, 0)).getNextId();
+ final PlotId end = PlotId.of(start.getX() + autoQuery.getSizeX() - 1,
+ start.getY() + autoQuery.getSizeZ() - 1);
+ final List plots =
+ autoQuery.getPlotArea().canClaim(autoQuery.getPlayer(), start, end);
+ if (plots != null && !plots.isEmpty()) {
+ autoQuery.getPlotArea().setMeta("lastPlot", start);
+ for (final Plot plot : plots) {
+ if (plotCandidateCache.getIfPresent(plot.getId()) != null) {
+ continue outer;
+ }
+ plotCandidateCache.put(plot.getId(), plot);
+ }
+ return plots;
+ }
+ }
+ }
+ }
+
+ @Override public boolean test(@Nonnull final AutoQuery autoQuery) {
+ return autoQuery.getPlotArea().getType() != PlotAreaType.PARTIAL;
+ }
+
+ }
+
+}