diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java index 64c1c9720..d55a5d54f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java @@ -49,12 +49,15 @@ import com.plotsquared.core.inject.annotations.DefaultGenerator; import com.plotsquared.core.inject.factory.ChunkCoordinatorBuilderFactory; import com.plotsquared.core.inject.factory.ChunkCoordinatorFactory; import com.plotsquared.core.inject.factory.HybridPlotWorldFactory; +import com.plotsquared.core.inject.factory.ProgressSubscriberFactory; import com.plotsquared.core.plot.world.DefaultPlotAreaManager; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotAreaManager; import com.plotsquared.core.queue.ChunkCoordinator; import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.queue.QueueProvider; +import com.plotsquared.core.queue.subscriber.DefaultProgressSubscriber; +import com.plotsquared.core.queue.subscriber.ProgressSubscriber; import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.InventoryUtil; @@ -105,6 +108,7 @@ public class BukkitModule extends AbstractModule { install(new FactoryModuleBuilder().build(HybridPlotWorldFactory.class)); install(new FactoryModuleBuilder().implement(ChunkCoordinator.class, BukkitChunkCoordinator.class).build(ChunkCoordinatorFactory.class)); install(new FactoryModuleBuilder().build(ChunkCoordinatorBuilderFactory.class)); + install(new FactoryModuleBuilder().implement(ProgressSubscriber.class, DefaultProgressSubscriber.class).build(ProgressSubscriberFactory.class)); } @Provides @Singleton @Nullable EconHandler provideEconHandler() { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java index 8d50f7a11..dde4312f0 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java @@ -29,6 +29,7 @@ import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import com.plotsquared.bukkit.BukkitPlatform; import com.plotsquared.core.queue.ChunkCoordinator; +import com.plotsquared.core.queue.subscriber.ProgressSubscriber; import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; import com.sk89q.worldedit.math.BlockVector2; @@ -82,7 +83,8 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { @Assisted @Nonnull final Collection requestedChunks, @Assisted @Nonnull final Runnable whenDone, @Assisted @Nonnull final Consumer throwableConsumer, - @Assisted final boolean unloadAfter) { + @Assisted final boolean unloadAfter, + @Assisted @Nonnull final Collection progressSubscribers) { this.requestedChunks = new LinkedBlockingQueue<>(requestedChunks); this.availableChunks = new LinkedBlockingQueue<>(); this.totalSize = requestedChunks.size(); @@ -95,6 +97,7 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { this.unloadAfter = unloadAfter; this.plugin = JavaPlugin.getPlugin(BukkitPlatform.class); this.bukkitWorld = Bukkit.getWorld(world.getName()); + this.progressSubscribers.addAll(progressSubscribers); } @Override public void start() { @@ -205,21 +208,8 @@ public final class BukkitChunkCoordinator extends ChunkCoordinator { * * @param subscriber Subscriber */ - public void subscribeToProgress(@Nonnull final BukkitChunkCoordinator.ProgressSubscriber subscriber) { + public void subscribeToProgress(@Nonnull final ProgressSubscriber subscriber) { this.progressSubscribers.add(subscriber); } - @FunctionalInterface - public interface ProgressSubscriber { - - /** - * Notify about a progress update in the coordinator - * - * @param coordinator Coordinator instance that triggered the notification - * @param progress Progress in the range [0, 1] - */ - void notifyProgress(@Nonnull final BukkitChunkCoordinator coordinator, final float progress); - - } - } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java index a0e5b028f..ad5f66c3f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java @@ -185,9 +185,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { })); } if (localChunk.getEntities().size() > 0) { - localChunk.getEntities().forEach((location, entity) -> { - getWorld().createEntity(location, entity); - }); + localChunk.getEntities().forEach((location, entity) -> getWorld().createEntity(location, entity)); } }; } @@ -198,7 +196,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { chunkCoordinator = chunkCoordinatorBuilderFactory.create(chunkCoordinatorFactory).inWorld(getWorld()).withChunks(getBlockChunks().keySet()).withChunks(read) .withInitialBatchSize(3).withMaxIterationTime(40).withThrowableConsumer(Throwable::printStackTrace).withFinalAction(getCompleteTask()) - .withConsumer(consumer).unloadAfter(isUnloadAfter()).build(); + .withConsumer(consumer).unloadAfter(isUnloadAfter()).withProgressSubscribers(getProgressSubscribers()).build(); return super.enqueue(); } diff --git a/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java b/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java index cda2e8e34..758b87328 100644 --- a/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java +++ b/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java @@ -26,6 +26,7 @@ package com.plotsquared.core.inject.factory; import com.plotsquared.core.queue.ChunkCoordinator; +import com.plotsquared.core.queue.subscriber.ProgressSubscriber; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.world.World; @@ -42,6 +43,7 @@ public interface ChunkCoordinatorFactory { @Nonnull final Collection requestedChunks, @Nonnull final Runnable whenDone, @Nonnull final Consumer throwableConsumer, - final boolean unloadAfter); + final boolean unloadAfter, + @Nonnull final Collection progressSubscribers); } diff --git a/Core/src/main/java/com/plotsquared/core/inject/factory/ProgressSubscriberFactory.java b/Core/src/main/java/com/plotsquared/core/inject/factory/ProgressSubscriberFactory.java new file mode 100644 index 000000000..e83f59357 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/inject/factory/ProgressSubscriberFactory.java @@ -0,0 +1,42 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.inject.factory; + +import com.google.inject.assistedinject.Assisted; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.queue.subscriber.ProgressSubscriber; +import com.plotsquared.core.util.task.TaskManager; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public interface ProgressSubscriberFactory { + + @Nonnull ProgressSubscriber create(@Nullable @Assisted("subscriber") PlotPlayer actor, + @Assisted("progressInterval") final long interval, + @Nonnull TaskManager taskManager); + +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java index aba4f7f08..f2d436962 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java @@ -25,6 +25,7 @@ */ package com.plotsquared.core.queue; +import com.plotsquared.core.queue.subscriber.ProgressSubscriber; import com.plotsquared.core.util.PatternUtil; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.entity.Entity; @@ -67,6 +68,7 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { private Consumer consumer = null; private boolean unloadAfter = true; private Runnable whenDone; + private List progressSubscribers = new ArrayList<>(); public BasicQueueCoordinator(@Nonnull World world) { super(world); @@ -252,6 +254,17 @@ public abstract class BasicQueueCoordinator extends QueueCoordinator { this.consumer = consumer; } + /** + * Get the list of progress subscribers currently added to the queue to be added to the Chunk Coordinator + */ + public final List getProgressSubscribers() { + return this.progressSubscribers; + } + + @Override public final void addProgressSubscriber(@Nonnull ProgressSubscriber progressSubscriber) { + this.progressSubscribers.add(progressSubscriber); + } + @Override public Runnable getCompleteTask() { return this.whenDone; } diff --git a/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java b/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java index 44c2f9a45..592e852c7 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java @@ -29,6 +29,7 @@ import com.google.common.base.Preconditions; import com.google.inject.Inject; import com.plotsquared.core.inject.factory.ChunkCoordinatorFactory; import com.plotsquared.core.location.Location; +import com.plotsquared.core.queue.subscriber.ProgressSubscriber; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.world.World; @@ -46,6 +47,7 @@ import java.util.function.Consumer; public class ChunkCoordinatorBuilder { private final List requestedChunks = new LinkedList<>(); + private final List progressSubscribers = new ArrayList<>(); private final ChunkCoordinatorFactory chunkCoordinatorFactory; private Consumer throwableConsumer = Throwable::printStackTrace; private World world; @@ -193,6 +195,16 @@ public class ChunkCoordinatorBuilder { return this; } + @Nonnull public ChunkCoordinatorBuilder withProgressSubscriber(ProgressSubscriber progressSubscriber) { + this.progressSubscribers.add(progressSubscriber); + return this; + } + + @Nonnull public ChunkCoordinatorBuilder withProgressSubscribers(Collection progressSubscribers) { + this.progressSubscribers.addAll(progressSubscribers); + return this; + } + /** * Create a new {@link ChunkCoordinator} instance based on the values in the Builder instance. * @@ -205,7 +217,7 @@ public class ChunkCoordinatorBuilder { Preconditions.checkNotNull(this.throwableConsumer, "No throwable consumer was supplied"); return chunkCoordinatorFactory .create(this.maxIterationTime, this.initialBatchSize, this.chunkConsumer, this.world, this.requestedChunks, this.whenDone, - this.throwableConsumer, this.unloadAfter); + this.throwableConsumer, this.unloadAfter, this.progressSubscribers); } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java index e12ec0e38..d40efce4b 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java @@ -28,6 +28,7 @@ package com.plotsquared.core.queue; import com.google.inject.Inject; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.location.Location; +import com.plotsquared.core.queue.subscriber.ProgressSubscriber; import com.plotsquared.core.util.PatternUtil; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.entity.Entity; @@ -353,6 +354,11 @@ public abstract class QueueCoordinator { */ public abstract void setChunkConsumer(@Nonnull Consumer consumer); + /** + * Add a {@link ProgressSubscriber} to the Queue to subscribe to the relevant Chunk Processor + */ + public abstract void addProgressSubscriber(@Nonnull ProgressSubscriber progressSubscriber); + /** * Fill a cuboid between two positions with a BlockState * diff --git a/Core/src/main/java/com/plotsquared/core/queue/subscriber/DefaultProgressSubscriber.java b/Core/src/main/java/com/plotsquared/core/queue/subscriber/DefaultProgressSubscriber.java new file mode 100644 index 000000000..710262a8f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/subscriber/DefaultProgressSubscriber.java @@ -0,0 +1,90 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) ${year} IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.plotsquared.core.queue.subscriber; + +import com.google.common.util.concurrent.AtomicDouble; +import com.plotsquared.core.configuration.caption.Caption; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.queue.ChunkCoordinator; +import com.plotsquared.core.util.task.PlotSquaredTask; +import com.plotsquared.core.util.task.TaskManager; +import com.plotsquared.core.util.task.TaskTime; +import net.kyori.adventure.text.minimessage.Template; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The default PlotSquared Progress Subscriber. Can be used for both console and player tasks. + * It is the {@link ProgressSubscriber} returned by {@link com.plotsquared.core.inject.factory.ProgressSubscriberFactory}. + * Runs a repeating synchronous task notifying the given actor about any updates, saving updates notified by the ChunkCoordinator. + */ +public class DefaultProgressSubscriber implements ProgressSubscriber { + + @Nonnull private final AtomicDouble progress = new AtomicDouble(0); + @Nonnull private final AtomicBoolean started = new AtomicBoolean(false); + @Nonnull private final TaskManager taskManager; + @Nonnull private final TaskTime interval; + @Nonnull private final PlotPlayer actor; + @Nonnull private final Caption caption; + private PlotSquaredTask task; + + public DefaultProgressSubscriber(@Nullable final PlotPlayer actor, + @Nonnull final TaskTime interval, + @Nonnull TaskManager taskManager, + @Nullable Caption caption) { + if (actor == null) { + throw new NullPointerException( + "Actor cannot be null when using DefaultProgressSubscriber! Make sure if attempting to use custom Subscribers it is correctly parsed to the queue!"); + } + if (caption == null) { + throw new NullPointerException( + "Caption cannot be null when using DefaultProgressSubscriber! Make sure if attempting to use custom Subscribers it is correctly parsed to the queue!"); + } + this.interval = interval; + this.taskManager = taskManager; + this.actor = actor; + this.caption = caption; + } + + @Override public void notifyProgress(@Nonnull ChunkCoordinator coordinator, float progress) { + this.progress.set((double) Math.round(progress * 100) / 100); + if (coordinator.isCancelled() || progress == 1) { + if (task != null) { + task.cancel(); + } + } else if (started.compareAndSet(false, true)) { + taskManager.taskLater(() -> task = taskManager.taskRepeat(() -> { + if (!started.get()) { + return; + } + actor.sendMessage(caption, Template.of("%s", this.progress.toString())); + }, interval), interval); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/subscriber/ProgressSubscriber.java b/Core/src/main/java/com/plotsquared/core/queue/subscriber/ProgressSubscriber.java new file mode 100644 index 000000000..0f3950017 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/subscriber/ProgressSubscriber.java @@ -0,0 +1,44 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) ${year} IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.plotsquared.core.queue.subscriber; + +import com.plotsquared.core.queue.ChunkCoordinator; + +import javax.annotation.Nonnull; + +@FunctionalInterface +public interface ProgressSubscriber { + + /** + * Notify about a progress update in the coordinator + * + * @param coordinator Coordinator instance that triggered the notification + * @param progress Progress in the range [0, 1] + */ + void notifyProgress(@Nonnull final ChunkCoordinator coordinator, final float progress); + +}