diff --git a/build.gradle.kts b/build.gradle.kts
index 6013616a..261d76f1 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -46,6 +46,7 @@ dependencies {
implementation(libs.com.alpsbte.alpslib.alpslib.utils)
implementation(libs.org.mariadb.jdbc.mariadb.java.client)
implementation(libs.com.zaxxer.hikaricp)
+ implementation(libs.com.github.querz.nbt)
compileOnly(libs.io.papermc.paper.paper.api)
implementation(platform(libs.com.intellectualsites.bom.bom.newest))
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core")
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 0af5093b..7b8d7fb4 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -18,6 +18,7 @@ io-papermc-paper-paper-api = "1.21.8-R0.1-SNAPSHOT"
li-cinnazeyy-langlibs-api = "1.5.1"
org-mariadb-jdbc-mariadb-java-client = "2.7.4"
com-intellectualsites-bom-bom-newest = "1.55" # Ref: https://github.com/IntellectualSites/bom
+com-github-querz-nbt-newest = "6.1"
[libraries]
com-alpsbte-alpslib-alpslib-hologram = { module = "com.alpsbte.alpslib:alpslib-hologram", version.ref = "com-alpsbte-alpslib-alpslib-hologram" }
@@ -27,6 +28,7 @@ com-alpsbte-canvas = { module = "com.alpsbte:canvas", version.ref = "com-alpsbte
com-arcaniax-headdatabase-api = { module = "com.arcaniax:HeadDatabase-API", version.ref = "com-arcaniax-headdatabase-api" }
com-github-decentsoftware-eu-decentholograms = { module = "com.github.decentsoftware-eu:decentholograms", version.ref = "com-github-decentsoftware-eu-decentholograms" }
com-github-fierioziy-particlenativeapi-particlenativeapi-plugin = { module = "com.github.fierioziy.particlenativeapi:ParticleNativeAPI-plugin", version.ref = "com-github-fierioziy-particlenativeapi-particlenativeapi-plugin" }
+com-github-querz-nbt = { module = "com.github.Querz:NBT", version.ref = "com-github-querz-nbt-newest" }
multiverse-core = { module = "org.mvplugins.multiverse.core:multiverse-core", version.ref = "multiverse-core" }
com-sk89q-worldguard-worldguard-bukkit = { module = "com.sk89q.worldguard:worldguard-bukkit", version.ref = "com-sk89q-worldguard-worldguard-bukkit" }
com-zaxxer-hikaricp = { module = "com.zaxxer:HikariCP", version.ref = "com-zaxxer-hikaricp" }
@@ -35,4 +37,4 @@ de-oliver-fancynpcs = { module = "de.oliver:FancyNpcs", version.ref = "de-oliver
io-papermc-paper-paper-api = { module = "io.papermc.paper:paper-api", version.ref = "io-papermc-paper-paper-api" }
li-cinnazeyy-langlibs-api = { module = "li.cinnazeyy:LangLibs-API", version.ref = "li-cinnazeyy-langlibs-api" }
org-mariadb-jdbc-mariadb-java-client = { module = "org.mariadb.jdbc:mariadb-java-client", version.ref = "org-mariadb-jdbc-mariadb-java-client" }
-com-intellectualsites-bom-bom-newest = { module = "com.intellectualsites.bom:bom-newest", version.ref = "com-intellectualsites-bom-bom-newest" }
\ No newline at end of file
+com-intellectualsites-bom-bom-newest = { module = "com.intellectualsites.bom:bom-newest", version.ref = "com-intellectualsites-bom-bom-newest" }
diff --git a/pom.xml b/pom.xml
index bbcc0a99..cb6a44ee 100644
--- a/pom.xml
+++ b/pom.xml
@@ -169,6 +169,11 @@
2.17.0
provided
+
+ com.github.Querz
+ NBT
+ 6.1
+
diff --git a/src/main/java/com/alpsbte/plotsystem/PlotSystem.java b/src/main/java/com/alpsbte/plotsystem/PlotSystem.java
index 201a5912..7f2f77a3 100644
--- a/src/main/java/com/alpsbte/plotsystem/PlotSystem.java
+++ b/src/main/java/com/alpsbte/plotsystem/PlotSystem.java
@@ -12,6 +12,8 @@
import com.alpsbte.plotsystem.core.holograms.HologramRegister;
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.Plot;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
+import com.alpsbte.plotsystem.core.system.plot.generator.world.SkeletonWorldGenerator;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
import com.alpsbte.plotsystem.core.system.tutorial.AbstractTutorial;
import com.alpsbte.plotsystem.core.system.tutorial.BeginnerTutorial;
@@ -28,6 +30,7 @@
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
import org.ipvp.canvas.MenuFunctionListener;
import org.jetbrains.annotations.NotNull;
@@ -117,16 +120,25 @@ public void onEnable() {
DecentHologramDisplay.registerPlugin(this);
HologramRegister.init();
- PlotUtils.checkPlotsForLastActivity();
Utils.ChatUtils.checkForChatInputExpiry();
PlotUtils.Effects.startTimer();
+ // Start task that checks for and abandons inactive plots every hour
+ Bukkit.getScheduler().runTaskTimerAsynchronously(PlotSystem.getPlugin(), PlotHandler::abandonInactivePlots, 0L, 20 * 60 * 60L);
+
// Register tutorials
if (getConfig().getBoolean(ConfigPaths.TUTORIAL_ENABLE)) {
AbstractTutorial.registerTutorials(Collections.singletonList(BeginnerTutorial.class));
Bukkit.getScheduler().runTaskTimerAsynchronously(FancyNpcsPlugin.get().getPlugin(), new TutorialNPCTurnTracker(), 0, 1L);
}
+ // Generate Skeleton World
+ if (Bukkit.getWorld("Skeleton") == null) {
+ getComponentLogger().info("No skeleton world found!");
+ getComponentLogger().info("Generating skeleton world...");
+ new SkeletonWorldGenerator();
+ }
+
pluginEnabled = true;
getComponentLogger().info(text("Enabled Plot-System plugin.", DARK_GREEN));
getComponentLogger().info(text("------------------------------------------------------", GOLD));
@@ -196,4 +208,9 @@ public void initDatabase() throws IOException, SQLException, ClassNotFoundExcept
s.execute(initScript);
}
}
+
+ @Override
+ public ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, String id) {
+ return new SkeletonWorldGenerator.EmptyChunkGenerator();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_DeletePlot.java b/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_DeletePlot.java
index 72d6539b..45f12f17 100644
--- a/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_DeletePlot.java
+++ b/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_DeletePlot.java
@@ -5,6 +5,7 @@
import com.alpsbte.plotsystem.commands.BaseCommand;
import com.alpsbte.plotsystem.core.database.DataProvider;
import com.alpsbte.plotsystem.core.system.plot.Plot;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
import com.alpsbte.plotsystem.utils.Utils;
import org.bukkit.Bukkit;
@@ -38,10 +39,12 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @N
sender.sendMessage(Utils.ChatUtils.getInfoFormat("Deleting plot..."));
Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
- if (PlotUtils.Actions.deletePlot(plot)) {
- sender.sendMessage(Utils.ChatUtils.getInfoFormat("Successfully deleted plot with the ID §6#" + plotID + "§a!"));
- if (getPlayer(sender) != null) getPlayer(sender).playSound(getPlayer(sender).getLocation(), Utils.SoundUtils.DONE_SOUND, 1f, 1f);
- } else sender.sendMessage(Utils.ChatUtils.getAlertFormat("An unexpected error has occurred!"));
+ if (!PlotHandler.deletePlot(plot)) {
+ sender.sendMessage(Utils.ChatUtils.getAlertFormat("An unexpected error has occurred!"));
+ return;
+ }
+ sender.sendMessage(Utils.ChatUtils.getInfoFormat("Successfully deleted plot with the ID §6#" + plotID + "§a!"));
+ if (getPlayer(sender) != null) getPlayer(sender).playSound(getPlayer(sender).getLocation(), Utils.SoundUtils.DONE_SOUND, 1f, 1f);
});
});
return true;
diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Abandon.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Abandon.java
index 7dd10f9a..c06a6b09 100644
--- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Abandon.java
+++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Abandon.java
@@ -8,6 +8,7 @@
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
import com.alpsbte.plotsystem.core.system.plot.Plot;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
import com.alpsbte.plotsystem.utils.Utils;
import com.alpsbte.plotsystem.utils.enums.Status;
@@ -67,10 +68,9 @@ public void onCommand(CommandSender sender, String[] args) {
}
Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
- if (PlotUtils.Actions.abandonPlot(plot)) {
- sender.sendMessage(Utils.ChatUtils.getInfoFormat(langUtil.get(sender, LangPaths.Message.Info.ABANDONED_PLOT, plot.getId() + "")));
- player.playSound(player.getLocation(), Utils.SoundUtils.ABANDON_PLOT_SOUND, 1, 1);
- }
+ if (!PlotHandler.abandonPlot(plot)) return;
+ sender.sendMessage(Utils.ChatUtils.getInfoFormat(langUtil.get(sender, LangPaths.Message.Info.ABANDONED_PLOT, plot.getId() + "")));
+ player.playSound(player.getLocation(), Utils.SoundUtils.ABANDON_PLOT_SOUND, 1, 1);
});
});
}
diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Submit.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Submit.java
index dd24a910..605e54e0 100644
--- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Submit.java
+++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Submit.java
@@ -8,6 +8,7 @@
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
import com.alpsbte.plotsystem.core.system.plot.Plot;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
import com.alpsbte.plotsystem.utils.Utils;
import com.alpsbte.plotsystem.utils.enums.Status;
@@ -75,7 +76,7 @@ public void onCommand(CommandSender sender, String[] args) {
Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
- PlotUtils.Actions.submitPlot(plot);
+ PlotHandler.submitPlot(plot);
if (plotMembers.isEmpty()) {
// Plot was made alone
langUtil.broadcast(LangPaths.Message.Info.FINISHED_PLOT, String.valueOf(plot.getId()), plot.getPlotOwner().getName());
diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Teleport.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Teleport.java
index b4c9033b..741f751c 100644
--- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Teleport.java
+++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Teleport.java
@@ -9,7 +9,7 @@
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
import com.alpsbte.plotsystem.core.system.plot.Plot;
-import com.alpsbte.plotsystem.core.system.plot.generator.DefaultPlotGenerator;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
import com.alpsbte.plotsystem.utils.Utils;
import com.alpsbte.plotsystem.utils.enums.Status;
import com.alpsbte.plotsystem.utils.io.LangPaths;
@@ -63,7 +63,7 @@ public void onCommand(CommandSender sender, String[] args) {
return;
}
- Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> new DefaultPlotGenerator(plot, builder));
+ PlotHandler.assignAndGeneratePlot(builder, plot);
return;
}
diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_UndoSubmit.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_UndoSubmit.java
index a9b89bb9..a14013fc 100644
--- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_UndoSubmit.java
+++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_UndoSubmit.java
@@ -8,6 +8,7 @@
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
import com.alpsbte.plotsystem.core.system.plot.Plot;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
import com.alpsbte.plotsystem.utils.Utils;
import com.alpsbte.plotsystem.utils.enums.Status;
@@ -69,7 +70,7 @@ public void onCommand(CommandSender sender, String[] args) {
}
Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
- PlotUtils.Actions.undoSubmit(plot);
+ PlotHandler.undoSubmit(plot);
sender.sendMessage(Utils.ChatUtils.getInfoFormat(langUtil.get(sender, LangPaths.Message.Info.UNDID_SUBMISSION, plot.getId() + "")));
player.playSound(player.getLocation(), Utils.SoundUtils.FINISH_PLOT_SOUND, 1, 1);
diff --git a/src/main/java/com/alpsbte/plotsystem/core/EventListener.java b/src/main/java/com/alpsbte/plotsystem/core/EventListener.java
index 0d38d00c..a4949e63 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/EventListener.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/EventListener.java
@@ -7,8 +7,8 @@
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.CityProject;
import com.alpsbte.plotsystem.core.system.plot.Plot;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
import com.alpsbte.plotsystem.core.system.plot.TutorialPlot;
-import com.alpsbte.plotsystem.core.system.plot.generator.DefaultPlotGenerator;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld;
import com.alpsbte.plotsystem.core.system.review.ReviewNotification;
@@ -123,7 +123,7 @@ public void onPlayerInteractAtEntity(@NotNull PlayerInteractAtEntityEvent event)
public void onPlayerQuitEvent(@NotNull PlayerQuitEvent event) {
final World w = event.getPlayer().getWorld();
- DefaultPlotGenerator.playerPlotGenerationHistory.remove(event.getPlayer().getUniqueId());
+ PlotHandler.removePlayerFromGenerationHistory(event.getPlayer().getUniqueId());
ChatInput.awaitChatInput.remove(event.getPlayer().getUniqueId());
PlotUtils.Cache.clearCache(event.getPlayer().getUniqueId());
@@ -170,7 +170,7 @@ public void onInventoryClickEvent(@NotNull InventoryClickEvent event) {
}
@EventHandler
- public void onlPlayerItemDropEvent(@NotNull PlayerDropItemEvent event) {
+ public void onPlayerItemDropEvent(@NotNull PlayerDropItemEvent event) {
if (event.getItemDrop().getItemStack().equals(CompanionMenu.getMenuItem(event.getPlayer())) ||
event.getItemDrop().getItemStack().equals(ReviewMenu.getMenuItem(event.getPlayer()))) {
event.setCancelled(true);
diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CityProjectMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CityProjectMenu.java
index e9ab62ab..36e4894f 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CityProjectMenu.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CityProjectMenu.java
@@ -8,7 +8,7 @@
import com.alpsbte.plotsystem.core.system.CityProject;
import com.alpsbte.plotsystem.core.system.Country;
import com.alpsbte.plotsystem.core.system.plot.Plot;
-import com.alpsbte.plotsystem.core.system.plot.generator.DefaultPlotGenerator;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
import com.alpsbte.plotsystem.utils.Utils;
import com.alpsbte.plotsystem.utils.enums.PlotDifficulty;
import com.alpsbte.plotsystem.utils.enums.Status;
@@ -16,6 +16,9 @@
import com.alpsbte.plotsystem.utils.io.LangPaths;
import com.alpsbte.plotsystem.utils.io.LangUtil;
import com.alpsbte.plotsystem.utils.items.MenuItems;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.ipvp.canvas.mask.BinaryMask;
import org.ipvp.canvas.mask.Mask;
@@ -24,6 +27,7 @@
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CityProjectMenu extends AbstractPaginatedMenu {
@@ -96,6 +100,28 @@ protected void setItemClickEventsAsync() {
CompanionMenu.clickEventTutorialItem(getMenu());
}
+ public void handleCityProjectClick(Player player, CityProject city) {
+ Builder builder = Builder.byUUID(player.getUniqueId());
+
+ PlotDifficulty plotDifficultyForCity;
+ try {
+ plotDifficultyForCity = selectedPlotDifficulty != null ? selectedPlotDifficulty : Plot.getPlotDifficultyForBuilder(city, builder).get();
+ } catch (ExecutionException | InterruptedException ex) {
+ sqlError(player, ex);
+ return;
+ }
+
+ List unclaimedPlots = DataProvider.PLOT.getPlots(city, plotDifficultyForCity, Status.unclaimed);
+ if (unclaimedPlots.isEmpty()) {
+ player.sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(player, LangPaths.Message.Error.NO_PLOTS_LEFT)));
+ Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> player.playSound(player.getLocation(), Utils.SoundUtils.ERROR_SOUND, 1, 1));
+ return;
+ }
+
+ Plot plot = unclaimedPlots.get(Utils.getRandom().nextInt(unclaimedPlots.size()));
+ PlotHandler.assignAndGeneratePlot(builder, plot);
+ }
+
public static boolean generateRandomPlot(Player player, @NotNull List items, PlotDifficulty selectedPlotDifficulty) {
PlotDifficulty difficulty = selectedPlotDifficulty;
if (items.isEmpty()) {
@@ -108,14 +134,13 @@ public static boolean generateRandomPlot(Player player, @NotNull List source) {
clickPlayer.playSound(clickPlayer.getLocation(), Utils.SoundUtils.ERROR_SOUND, 1, 1);
return;
}
-
clickPlayer.closeInventory();
- Builder builder = Builder.byUUID(clickPlayer.getUniqueId());
-
- try {
- PlotDifficulty plotDifficultyForCity = selectedPlotDifficulty != null ? selectedPlotDifficulty : Plot.getPlotDifficultyForBuilder(city, builder).get();
- List unclaimedPlots = DataProvider.PLOT.getPlots(city, plotDifficultyForCity, Status.unclaimed);
- if (unclaimedPlots.isEmpty()) {
- clickPlayer.sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(clickPlayer, LangPaths.Message.Error.NO_PLOTS_LEFT)));
- clickPlayer.playSound(clickPlayer.getLocation(), Utils.SoundUtils.ERROR_SOUND, 1, 1);
- return;
- }
-
- if (selectedPlotDifficulty != null && PlotSystem.getPlugin().getConfig().getBoolean(ConfigPaths.ENABLE_SCORE_REQUIREMENT) && !DataProvider.DIFFICULTY.builderMeetsRequirements(builder, selectedPlotDifficulty)) {
- clickPlayer.sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(clickPlayer, LangPaths.Message.Error.PLAYER_NEEDS_HIGHER_SCORE)));
- clickPlayer.playSound(clickPlayer.getLocation(), Utils.SoundUtils.ERROR_SOUND, 1, 1);
- return;
- }
-
- new DefaultPlotGenerator(city, plotDifficultyForCity, builder);
- } catch (ExecutionException | InterruptedException ex) {
- sqlError(clickPlayer, ex);
- }
+
+ CompletableFuture.runAsync(() -> handleCityProjectClick(clickPlayer, city));
});
slot++;
}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/review/ReviewPlotTogglesMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/review/ReviewPlotTogglesMenu.java
index 91e949de..b8f886f1 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/menus/review/ReviewPlotTogglesMenu.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/menus/review/ReviewPlotTogglesMenu.java
@@ -7,7 +7,7 @@
import com.alpsbte.plotsystem.core.menus.AbstractMenu;
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.Plot;
-import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
import com.alpsbte.plotsystem.core.system.review.PlotReview;
import com.alpsbte.plotsystem.core.system.review.ReviewRating;
import com.alpsbte.plotsystem.core.system.review.ToggleCriteria;
@@ -34,6 +34,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ExecutionException;
import static net.kyori.adventure.text.Component.text;
@@ -131,7 +132,7 @@ private void submitReview() {
if(!acceptPlot(review.getScore(), review.getSplitScore())) return;
} else {
reviewerConfirmationMessage = Utils.ChatUtils.getInfoFormat(LangUtil.getInstance().get(getMenuPlayer(), LangPaths.Message.Info.PLOT_REJECTED, Integer.toString(plot.getId()), getParticipantsString()));
- PlotUtils.Actions.undoSubmit(plot);
+ PlotHandler.undoSubmit(plot);
}
Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
@@ -172,11 +173,11 @@ private boolean acceptPlot(int score, int splitScore) {
getMenuPlayer().sendMessage(Utils.ChatUtils.getInfoFormat(LangUtil.getInstance().get(getMenuPlayer(), LangPaths.Message.Info.SAVING_PLOT)));
Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
try {
- if (!PlotUtils.savePlotAsSchematic(plot)) {
+ if (!PlotHandler.savePlotAsSchematic(plot)) {
getMenuPlayer().sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(getMenuPlayer(), LangPaths.Message.Error.ERROR_OCCURRED)));
PlotSystem.getPlugin().getComponentLogger().warn(text("Could not save finished plot schematic (ID: " + plot.getId() + ")!"));
}
- } catch (IOException | WorldEditException ex) {
+ } catch (IOException | WorldEditException | ExecutionException | InterruptedException ex) {
PlotSystem.getPlugin().getComponentLogger().error(text("Could not save finished plot schematic (ID: " + plot.getId() + ")!"), ex);
}
});
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/Plot.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/Plot.java
index eaee4697..62766942 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/Plot.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/Plot.java
@@ -6,7 +6,6 @@
import com.alpsbte.plotsystem.core.system.CityProject;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotType;
import com.alpsbte.plotsystem.core.system.plot.world.CityPlotWorld;
-import com.alpsbte.plotsystem.core.system.plot.world.OnePlotWorld;
import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld;
import com.alpsbte.plotsystem.core.system.review.PlotReview;
import com.alpsbte.plotsystem.utils.enums.PlotDifficulty;
@@ -127,14 +126,8 @@ public boolean setPlotType(PlotType type) {
@SuppressWarnings("unchecked")
@Override
- public T getWorld() {
- if (getVersion() <= 2 || getPlotType().hasOnePlotPerWorld()) {
- if (onePlotWorld == null) onePlotWorld = new OnePlotWorld(this);
- return (T) onePlotWorld;
- } else {
- if (cityPlotWorld == null) cityPlotWorld = new CityPlotWorld(this);
- return (T) cityPlotWorld;
- }
+ public PlotWorld getWorld() {
+ return PlotWorld.getByType(getPlotType(), this);
}
@Override
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotHandler.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotHandler.java
new file mode 100644
index 00000000..c0230592
--- /dev/null
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotHandler.java
@@ -0,0 +1,299 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2021-2025, Alps BTE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.alpsbte.plotsystem.core.system.plot;
+
+import com.alpsbte.plotsystem.PlotSystem;
+import com.alpsbte.plotsystem.core.database.DataProvider;
+import com.alpsbte.plotsystem.core.system.Builder;
+import com.alpsbte.plotsystem.core.system.CityProject;
+import com.alpsbte.plotsystem.core.system.plot.generator.loader.AbstractPlotLoader;
+import com.alpsbte.plotsystem.core.system.plot.generator.loader.DefaultPlotLoader;
+import com.alpsbte.plotsystem.core.system.plot.utils.PlotType;
+import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
+import com.alpsbte.plotsystem.core.system.plot.world.CityPlotWorld;
+import com.alpsbte.plotsystem.core.system.plot.world.OnePlotWorld;
+import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld;
+import com.alpsbte.plotsystem.utils.Utils;
+import com.alpsbte.plotsystem.utils.enums.PlotDifficulty;
+import com.alpsbte.plotsystem.utils.enums.Slot;
+import com.alpsbte.plotsystem.utils.enums.Status;
+import com.alpsbte.plotsystem.utils.io.ConfigPaths;
+import com.alpsbte.plotsystem.utils.io.ConfigUtil;
+import com.alpsbte.plotsystem.utils.io.LangPaths;
+import com.alpsbte.plotsystem.utils.io.LangUtil;
+import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.bukkit.BukkitWorld;
+import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
+import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
+import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
+import com.sk89q.worldedit.function.operation.Operations;
+import com.sk89q.worldedit.math.BlockVector2;
+import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.math.Vector3;
+import com.sk89q.worldedit.math.transform.AffineTransform;
+import com.sk89q.worldedit.regions.CuboidRegion;
+import com.sk89q.worldedit.regions.Polygonal2DRegion;
+import org.bukkit.Bukkit;
+import org.bukkit.SoundCategory;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static net.kyori.adventure.text.Component.text;
+
+public class PlotHandler {
+ private PlotHandler() {}
+
+ private static final Map playerPlotGenerationHistory = new HashMap<>();
+
+ public static boolean assignPlot(Builder builder, Plot plot) {
+ Player player = builder.getPlayer();
+
+ // Score Requirement met?
+ if (PlotSystem.getPlugin().getConfig().getBoolean(ConfigPaths.ENABLE_SCORE_REQUIREMENT) && !DataProvider.DIFFICULTY.builderMeetsRequirements(builder, plot.getDifficulty())) {
+ player.sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(player, LangPaths.Message.Error.PLAYER_NEEDS_HIGHER_SCORE)));
+ player.playSound(player.getLocation(), Utils.SoundUtils.ERROR_SOUND, SoundCategory.MASTER, 1, 1, 0);
+ return false;
+ }
+
+ // Slot available?
+ Slot freeSlot = builder.getFreeSlot();
+ if (freeSlot == null) {
+ player.sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(player, LangPaths.Message.Error.ALL_SLOTS_OCCUPIED)));
+ player.playSound(player.getLocation(), Utils.SoundUtils.ERROR_SOUND, SoundCategory.MASTER, 1, 1, 0);
+ return false;
+ }
+
+ // Assign
+ if (!builder.setSlot(builder.getFreeSlot(), plot.getId())) return false;
+ if (!plot.setStatus(Status.unfinished)) return false;
+ return plot.setPlotOwner(builder);
+ }
+
+ public static boolean assignAndGeneratePlot(Builder builder, Plot plot) {
+ PlotType type = builder.getPlotType();
+ if (type.equals(PlotType.CITY_INSPIRATION_MODE) && ConfigUtil.getInstance().configs[0].getBoolean(ConfigPaths.DISABLE_CITY_INSPIRATION_MODE))
+ type = PlotType.LOCAL_INSPIRATION_MODE;
+
+ boolean successful = assignPlot(builder, plot);
+ if (successful) generatePlot(builder, plot, type);
+
+ return successful;
+ }
+
+ public static boolean assignAndGenerateRandomPlot(Builder builder, CityProject city, PlotDifficulty difficulty) {
+ Plot randomPlot = DataProvider.PLOT.getPlots(city, difficulty, Status.unclaimed)
+ .get(Utils.getRandom().nextInt(DataProvider.PLOT.getPlots(city, difficulty, Status.unclaimed).size()));
+ return assignAndGeneratePlot(builder, randomPlot);
+ }
+
+ public static void generatePlot(Builder builder, Plot plot, PlotType type) {
+ Player player = builder.getPlayer();
+
+ // Cooldown
+ if (playerPlotGenerationHistory.containsKey(builder.getUUID())) {
+ if (!playerPlotGenerationHistory.get(builder.getUUID()).isBefore(LocalDateTime.now().minusSeconds(10))) {
+ player.sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(player, LangPaths.Message.Error.PLEASE_WAIT)));
+ player.playSound(player.getLocation(), Utils.SoundUtils.ERROR_SOUND, SoundCategory.MASTER, 1, 1, 0);
+ return;
+ }
+ playerPlotGenerationHistory.remove(builder.getUUID());
+ }
+ playerPlotGenerationHistory.put(builder.getUUID(), LocalDateTime.now());
+
+ player.sendMessage(Utils.ChatUtils.getInfoFormat(LangUtil.getInstance().get(player, LangPaths.Message.Info.CREATING_PLOT)));
+ player.playSound(player.getLocation(), Utils.SoundUtils.CREATE_PLOT_SOUND, SoundCategory.MASTER, 1, 1, 0);
+
+ new DefaultPlotLoader(plot, builder, type, PlotWorld.getByType(type, plot));
+ }
+
+ @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+ public static boolean abandonPlot(AbstractPlot plot) {
+ boolean successfullyAbandoned = plot.getWorld().onAbandon();
+ if (!successfullyAbandoned) {
+ PlotSystem.getPlugin().getComponentLogger().error(text("Failed to abandon plot with the ID " + plot.getId() + "!"));
+ return false;
+ }
+
+ CompletableFuture.runAsync(() -> {
+ if (plot.getPlotType() == PlotType.TUTORIAL) return;
+ Plot dPlot = (Plot) plot;
+ boolean successful;
+ successful = DataProvider.REVIEW.removeAllReviewsOfPlot(dPlot.getId());
+
+ for (Builder builder : dPlot.getPlotMembers()) {
+ if (!successful) break;
+ successful = dPlot.removePlotMember(builder);
+ }
+
+ if (successful && plot.getPlotOwner() != null) {
+ PlotUtils.Cache.clearCache(plot.getPlotOwner().getUUID());
+ successful = plot.getPlotOwner().setSlot(plot.getPlotOwner().getSlot(dPlot), -1);
+ }
+
+ if (successful) {
+ successful = dPlot.setPlotOwner(null)
+ && dPlot.setLastActivity(true)
+ && dPlot.setStatus(Status.unclaimed)
+ && dPlot.setPlotType(PlotType.LOCAL_INSPIRATION_MODE);
+ }
+
+ successful = successful && DataProvider.PLOT.setCompletedSchematic(plot.getId(), null);
+ if (!successful) PlotSystem.getPlugin().getComponentLogger().error(text("Failed to abandon plot with the ID " + plot.getId() + "!"));
+ });
+ return true;
+ }
+
+ public static boolean deletePlot(Plot plot) {
+ if (!abandonPlot(plot)) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Failed to delete plot with the ID " + plot.getId() + "!"));
+ return false;
+ }
+ CompletableFuture.runAsync(() -> {
+ if (DataProvider.PLOT.deletePlot(plot.getId())) return;
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Failed to delete plot with the ID " + plot.getId() + " from the database!"));
+ });
+ return true;
+ }
+
+ public static void abandonInactivePlots() {
+ FileConfiguration config = PlotSystem.getPlugin().getConfig();
+ long inactivityIntervalDays = config.getLong(ConfigPaths.INACTIVITY_INTERVAL);
+ long rejectedInactivityIntervalDays = (config.getLong(ConfigPaths.REJECTED_INACTIVITY_INTERVAL) != -1) ? config.getLong(ConfigPaths.REJECTED_INACTIVITY_INTERVAL) : inactivityIntervalDays;
+ if (inactivityIntervalDays == -2 && rejectedInactivityIntervalDays == -2) return;
+
+ for (Plot plot : DataProvider.PLOT.getPlots(Status.unfinished)) {
+ LocalDate lastActivity = plot.getLastActivity();
+ long interval = plot.isRejected() ? rejectedInactivityIntervalDays : inactivityIntervalDays;
+ if (interval == -2 || lastActivity == null || lastActivity.plusDays(interval).isAfter(LocalDate.now())) continue;
+
+ Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
+ if (!abandonPlot(plot)) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("An error occurred while abandoning plot #" + plot.getId() + " due to inactivity!"));
+ return;
+ }
+ PlotSystem.getPlugin().getComponentLogger().info(text("Abandoned plot #" + plot.getId() + " due to inactivity!"));
+ });
+ }
+ }
+
+ public static void submitPlot(@NotNull Plot plot) {
+ plot.setStatus(Status.unreviewed);
+
+ if (plot.getWorld().isWorldLoaded()) {
+ for (Player player : plot.getWorld() instanceof OnePlotWorld ? plot.getWorld().getBukkitWorld().getPlayers() : ((CityPlotWorld) plot.getWorld()).getPlayersOnPlot(plot)) {
+ player.teleport(Utils.getSpawnLocation());
+ }
+ }
+
+ plot.getPermissions().removeBuilderPerms(plot.getPlotOwner().getUUID()).save();
+ if (!plot.getPlotMembers().isEmpty()) {
+ for (Builder builder : plot.getPlotMembers()) {
+ plot.getPermissions().removeBuilderPerms(builder.getUUID());
+ }
+ }
+ }
+
+ public static void undoSubmit(@NotNull Plot plot) {
+ plot.setStatus(Status.unfinished);
+
+ plot.getPermissions().addBuilderPerms(plot.getPlotOwner().getUUID()).save();
+ if (!plot.getPlotMembers().isEmpty()) {
+ for (Builder builder : plot.getPlotMembers()) {
+ plot.getPermissions().addBuilderPerms(builder.getUUID());
+ }
+ }
+ }
+
+ public static void removePlayerFromGenerationHistory(UUID playerUuid) {
+ playerPlotGenerationHistory.remove(playerUuid);
+ }
+
+ public static boolean savePlotAsSchematic(@NotNull Plot plot) throws IOException, WorldEditException, ExecutionException, InterruptedException {
+ if (plot.getVersion() < 4) {
+ PlotSystem.getPlugin().getComponentLogger().error(text("Saving schematics of legacy plots is no longer allowed!"));
+ return false;
+ }
+
+ Clipboard clipboard;
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(plot.getInitialSchematicBytes());
+ try (ClipboardReader reader = AbstractPlot.CLIPBOARD_FORMAT.getReader(inputStream)) {
+ clipboard = reader.read();
+ }
+ if (clipboard == null) return false;
+
+ CuboidRegion cuboidRegion = PlotUtils.getPlotAsRegion(plot);
+ if (cuboidRegion == null) return false;
+
+ BlockVector3 plotCenter = plot.getCenter();
+
+ // Get plot outline
+ List plotOutlines = plot.getOutline();
+
+ // Load finished plot region as cuboid region
+ if (!plot.getWorld().loadWorld()) return false;
+ com.sk89q.worldedit.world.World world = new BukkitWorld(plot.getWorld().getBukkitWorld());
+ Polygonal2DRegion region = new Polygonal2DRegion(world, plotOutlines, cuboidRegion.getMinimumPoint().y(), cuboidRegion.getMaximumPoint().y());
+
+ // Copy and write finished plot clipboard to schematic
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ try (Clipboard cb = new BlockArrayClipboard(region)) {
+ cb.setOrigin(BlockVector3.at(plotCenter.x(), cuboidRegion.getMinimumY(), (double) plotCenter.z()));
+
+ ForwardExtentCopy forwardExtentCopy = new ForwardExtentCopy(Objects.requireNonNull(region.getWorld()), region, cb, region.getMinimumPoint());
+ Operations.complete(forwardExtentCopy);
+
+ try (ClipboardWriter writer = AbstractPlot.CLIPBOARD_FORMAT.getWriter(outputStream)) {
+ double initialY = clipboard.getRegion().getMinimumY();
+ double offset = initialY - cuboidRegion.getMinimumY();
+ writer.write(cb.transform(new AffineTransform().translate(Vector3.at(0, offset, 0))));
+ }
+ }
+
+ // Set Completed Schematic
+ boolean successful = DataProvider.PLOT.setCompletedSchematic(plot.getId(), outputStream.toByteArray());
+ if (!successful) return false;
+
+ // If plot was created in a void world, copy the result to the city world
+ if (plot.getPlotType() != PlotType.CITY_INSPIRATION_MODE) {
+ Utils.runSync(() -> {
+ AbstractPlotLoader.pasteSchematic(null, outputStream.toByteArray(), new CityPlotWorld(plot), false);
+ return null;
+ }).get();
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/DefaultPlotGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/DefaultPlotGenerator.java
deleted file mode 100644
index 0a0455e8..00000000
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/DefaultPlotGenerator.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package com.alpsbte.plotsystem.core.system.plot.generator;
-
-import com.alpsbte.plotsystem.PlotSystem;
-import com.alpsbte.plotsystem.core.database.DataProvider;
-import com.alpsbte.plotsystem.core.system.Builder;
-import com.alpsbte.plotsystem.core.system.CityProject;
-import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
-import com.alpsbte.plotsystem.core.system.plot.Plot;
-import com.alpsbte.plotsystem.core.system.plot.utils.PlotType;
-import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
-import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld;
-import com.alpsbte.plotsystem.utils.Utils;
-import com.alpsbte.plotsystem.utils.enums.PlotDifficulty;
-import com.alpsbte.plotsystem.utils.enums.Status;
-import com.alpsbte.plotsystem.utils.io.LangPaths;
-import com.alpsbte.plotsystem.utils.io.LangUtil;
-import com.sk89q.worldedit.WorldEditException;
-import com.sk89q.worldedit.bukkit.BukkitAdapter;
-import com.sk89q.worldedit.function.mask.BlockTypeMask;
-import com.sk89q.worldedit.function.mask.Mask;
-import com.sk89q.worldedit.world.block.BlockTypes;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.IOException;
-import java.time.LocalDateTime;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-import static net.kyori.adventure.text.Component.text;
-
-public class DefaultPlotGenerator extends AbstractPlotGenerator {
- public static final Map playerPlotGenerationHistory = new HashMap<>();
-
- public DefaultPlotGenerator(CityProject city, PlotDifficulty plotDifficulty, Builder builder) {
- this(DataProvider.PLOT.getPlots(city, plotDifficulty, Status.unclaimed).get(Utils.getRandom().nextInt(DataProvider.PLOT.getPlots(city, plotDifficulty, Status.unclaimed).size())), builder);
- }
-
- public DefaultPlotGenerator(@NotNull AbstractPlot plot, @NotNull Builder builder) {
- super(plot, builder);
- }
-
- public DefaultPlotGenerator(@NotNull AbstractPlot plot, @NotNull Builder builder, PlotType plotType) {
- super(plot, builder, plotType);
- }
-
- @Override
- protected boolean init() {
- if (getBuilder().getFreeSlot() != null) {
- if (DefaultPlotGenerator.playerPlotGenerationHistory.containsKey(getBuilder().getUUID())) {
- if (DefaultPlotGenerator.playerPlotGenerationHistory.get(getBuilder().getUUID()).isBefore(LocalDateTime.now().minusSeconds(10))) {
- DefaultPlotGenerator.playerPlotGenerationHistory.remove(getBuilder().getUUID());
- } else {
- getBuilder().getPlayer().sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(getBuilder().getPlayer(), LangPaths.Message.Error.PLEASE_WAIT)));
- getBuilder().getPlayer().playSound(getBuilder().getPlayer().getLocation(), Utils.SoundUtils.ERROR_SOUND, 1, 1);
- return false;
- }
- }
-
- DefaultPlotGenerator.playerPlotGenerationHistory.put(getBuilder().getUUID(), LocalDateTime.now());
- getBuilder().getPlayer().sendMessage(Utils.ChatUtils.getInfoFormat(LangUtil.getInstance().get(getBuilder().getPlayer(), LangPaths.Message.Info.CREATING_PLOT)));
- getBuilder().getPlayer().playSound(getBuilder().getPlayer().getLocation(), Utils.SoundUtils.CREATE_PLOT_SOUND, 1, 1);
- return true;
- } else {
- getBuilder().getPlayer().sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(getBuilder().getPlayer(), LangPaths.Message.Error.ALL_SLOTS_OCCUPIED)));
- getBuilder().getPlayer().playSound(getBuilder().getPlayer().getLocation(), Utils.SoundUtils.ERROR_SOUND, 1, 1);
- }
- return false;
- }
-
- @Override
- protected void generateOutlines() throws IOException, WorldEditException {
- if (plot instanceof Plot) {
- byte[] completedSchematic = ((Plot) plot).getCompletedSchematic();
- if (completedSchematic != null) {
- PlotSystem.getPlugin().getComponentLogger().info("Found completed schematic, pasting only that.");
- Mask airMask = new BlockTypeMask(BukkitAdapter.adapt(world.getBukkitWorld()), BlockTypes.AIR);
- pasteSchematic(airMask, completedSchematic, world, false);
- } else super.generateOutlines();
- } else super.generateOutlines();
-
- // If the player is playing in his own world, then additionally generate the plot in the city world
- if (PlotWorld.isOnePlotWorld(world.getWorldName()) && plotVersion >= 3 && plot.getStatus() != Status.completed) {
- // Generate city plot world if it doesn't exist
- new AbstractPlotGenerator(plot, getBuilder(), PlotType.CITY_INSPIRATION_MODE) {
- @Override
- protected boolean init() {
- return true;
- }
-
- @Override
- protected void createPlotProtection() {}
-
- @Override
- protected void onComplete(boolean failed, boolean unloadWorld) {
- super.onComplete(true, true);
- }
-
- @Override
- protected void onException(Throwable ex) {
- PlotSystem.getPlugin().getComponentLogger().warn(text("Could not generate plot in city world " + world.getWorldName() + "!"), ex);
- }
- };
- }
- }
-
- @Override
- protected void onComplete(boolean failed, boolean unloadWorld) {
- super.onComplete(failed, false);
- if (failed) return;
-
- if (!getBuilder().setSlot(getBuilder().getFreeSlot(), plot.getId())) return;
- if (!plot.setStatus(Status.unfinished)) return;
- if (!((Plot) plot).setPlotType(plotType)) return;
- if (!plot.setPlotOwner(getBuilder())) return;
-
- PlotUtils.Cache.clearCache(getBuilder().getUUID());
- plot.getWorld().teleportPlayer(getBuilder().getPlayer());
- LangUtil.getInstance().broadcast(LangPaths.Message.Info.CREATED_NEW_PLOT, getBuilder().getName());
- }
-}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/PlotWorldGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/PlotWorldGenerator.java
deleted file mode 100644
index 6dbd2041..00000000
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/PlotWorldGenerator.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.alpsbte.plotsystem.core.system.plot.generator;
-
-import com.alpsbte.plotsystem.PlotSystem;
-import com.alpsbte.plotsystem.utils.DependencyManager;
-import com.sk89q.worldedit.bukkit.BukkitAdapter;
-import com.sk89q.worldguard.WorldGuard;
-import com.sk89q.worldguard.protection.flags.Flags;
-import com.sk89q.worldguard.protection.flags.RegionGroup;
-import com.sk89q.worldguard.protection.flags.StateFlag;
-import com.sk89q.worldguard.protection.managers.RegionManager;
-import com.sk89q.worldguard.protection.managers.storage.StorageException;
-import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
-import com.sk89q.worldguard.protection.regions.RegionContainer;
-import org.bukkit.Bukkit;
-import org.bukkit.Difficulty;
-import org.bukkit.GameMode;
-import org.bukkit.GameRule;
-import org.bukkit.World;
-import org.bukkit.WorldCreator;
-import org.bukkit.WorldType;
-import org.bukkit.entity.SpawnCategory;
-import org.bukkit.generator.ChunkGenerator;
-import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
-import org.mvplugins.multiverse.core.world.WorldManager;
-import org.mvplugins.multiverse.core.world.options.ImportWorldOptions;
-import org.mvplugins.multiverse.external.vavr.control.Option;
-
-import javax.annotation.Nonnull;
-import java.util.Objects;
-import java.util.Random;
-
-import static net.kyori.adventure.text.Component.text;
-
-public class PlotWorldGenerator {
- private final WorldManager worldManager = DependencyManager.getMultiverseCore().getWorldManager();
- private WorldCreator worldCreator;
-
- private final String worldName;
- private static final World.Environment environment = World.Environment.NORMAL;
- private static final WorldType worldType = WorldType.FLAT;
- private static final String generatorSettings = "{\"features\": false,\"layers\": [{\"block\": \"air\", \"height\": 1}],\"biome\":\"plains\"}";
-
- public PlotWorldGenerator(String worldName) throws Exception {
- this.worldName = worldName;
- generateWorld();
- createMultiverseWorld();
- configureWorld();
- createGlobalProtection();
- }
-
- protected void generateWorld() {
- worldCreator = new WorldCreator(worldName);
- worldCreator.environment(environment);
- worldCreator.type(worldType);
- worldCreator.generator(new EmptyChunkGenerator());
- worldCreator.generatorSettings(generatorSettings);
- worldCreator.createWorld();
- }
-
- protected void createMultiverseWorld() throws Exception {
- // Check if world creator is configured and add new world to multiverse world manager
- if (worldCreator != null) {
- if (!worldManager.isLoadedWorld(worldName)) {
- worldManager.importWorld(ImportWorldOptions.worldName(worldName)
- .environment(environment)
- .generator("VoidGen:{\"caves\":false,\"decoration\":false,\"mobs\":false,\"structures\":false}")
- .useSpawnAdjust(false)
- );
- }
- } else {
- throw new Exception("World Creator is not configured");
- }
- }
-
- protected void configureWorld() {
- World bukkitWorld = Bukkit.getWorld(worldName);
- Option mvWorld = worldManager.getLoadedWorld(worldName);
-
- if (mvWorld.isEmpty()) {
- PlotSystem.getPlugin().getComponentLogger().warn(text("Multiverse world" + worldName + " is not loaded! Skipping world configuration..."));
- return;
- }
-
- // Set world time to midday
- assert bukkitWorld != null;
- bukkitWorld.setTime(6000);
-
- // Set Bukkit world game rules
- bukkitWorld.setGameRule(GameRule.RANDOM_TICK_SPEED, 0);
- bukkitWorld.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
- bukkitWorld.setGameRule(GameRule.DO_FIRE_TICK, false);
- bukkitWorld.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
- bukkitWorld.setGameRule(GameRule.KEEP_INVENTORY, true);
- bukkitWorld.setGameRule(GameRule.DO_MOB_SPAWNING, false);
- bukkitWorld.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false);
- bukkitWorld.setGameRule(GameRule.DO_TILE_DROPS, false);
- bukkitWorld.setGameRule(GameRule.DO_MOB_LOOT, false);
-
- // Configure multiverse world
- mvWorld.get().setAllowFlight(true);
- mvWorld.get().setGameMode(GameMode.CREATIVE);
- mvWorld.get().setAllowWeather(false);
- mvWorld.get().setDifficulty(Difficulty.PEACEFUL);
- mvWorld.get().getEntitySpawnConfig().getSpawnCategoryConfig(SpawnCategory.ANIMAL).setSpawn(false);
- mvWorld.get().getEntitySpawnConfig().getSpawnCategoryConfig(SpawnCategory.MONSTER).setSpawn(false);
- mvWorld.get().setAutoLoad(false);
- mvWorld.get().setKeepSpawnInMemory(false);
- worldManager.saveWorldsConfig();
- }
-
- protected void createGlobalProtection() throws StorageException {
- RegionContainer regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer();
- RegionManager regionManager = regionContainer.get(BukkitAdapter.adapt(Objects.requireNonNull(Bukkit.getWorld(worldName))));
-
- if (regionManager != null) {
- // Create a protected region for the plot world
- String regionName = "__global__";
- GlobalProtectedRegion globalRegion = new GlobalProtectedRegion(regionName);
- globalRegion.setFlag(Flags.ENTRY, StateFlag.State.DENY);
- globalRegion.setFlag(Flags.ENTRY.getRegionGroupFlag(), RegionGroup.ALL);
- globalRegion.setFlag(Flags.PASSTHROUGH, StateFlag.State.DENY);
- globalRegion.setFlag(Flags.PASSTHROUGH.getRegionGroupFlag(), RegionGroup.ALL);
- globalRegion.setFlag(Flags.TNT, StateFlag.State.DENY);
- globalRegion.setFlag(Flags.TNT.getRegionGroupFlag(), RegionGroup.ALL);
- if (DependencyManager.isWorldGuardExtraFlagsEnabled())
- globalRegion.setFlag(new StateFlag("worldedit", true, RegionGroup.ALL), StateFlag.State.DENY);
-
- if (regionManager.hasRegion(regionName)) regionManager.removeRegion(regionName);
- regionManager.addRegion(globalRegion);
- regionManager.saveChanges();
- } else PlotSystem.getPlugin().getComponentLogger().warn(text("Region Manager is null!"));
- }
-
- public static class EmptyChunkGenerator extends ChunkGenerator {
- @Override
- @Nonnull
- public ChunkData generateChunkData(@Nonnull World world, @Nonnull Random random, int x, int z, @Nonnull BiomeGrid biome) {
- return createChunkData(world);
- }
- }
-
-}
-
-
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/AbstractPlotGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/loader/AbstractPlotLoader.java
similarity index 56%
rename from src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/AbstractPlotGenerator.java
rename to src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/loader/AbstractPlotLoader.java
index 6b168e97..7b5946f8 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/AbstractPlotGenerator.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/loader/AbstractPlotLoader.java
@@ -1,13 +1,36 @@
-package com.alpsbte.plotsystem.core.system.plot.generator;
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2021-2025, Alps BTE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.alpsbte.plotsystem.core.system.plot.generator.loader;
import com.alpsbte.plotsystem.PlotSystem;
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
-import com.alpsbte.plotsystem.core.system.plot.Plot;
+import com.alpsbte.plotsystem.core.system.plot.PlotHandler;
+import com.alpsbte.plotsystem.core.system.plot.generator.world.PlotWorldGenerator;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotType;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
-import com.alpsbte.plotsystem.core.system.plot.world.CityPlotWorld;
-import com.alpsbte.plotsystem.core.system.plot.world.OnePlotWorld;
import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld;
import com.alpsbte.plotsystem.utils.DependencyManager;
import com.alpsbte.plotsystem.utils.Utils;
@@ -40,7 +63,6 @@
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
-import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
@@ -56,107 +78,75 @@
import static net.kyori.adventure.text.Component.text;
-public abstract class AbstractPlotGenerator {
+public abstract class AbstractPlotLoader {
protected final AbstractPlot plot;
- private final Builder builder;
- protected final PlotWorld world;
- protected final double plotVersion;
protected final PlotType plotType;
+ protected final PlotWorld plotWorld;
- /**
- * Generates a new plot in the plot world
- *
- * @param plot - plot which should be generated
- * @param builder - builder of the plot
- */
- protected AbstractPlotGenerator(@NotNull AbstractPlot plot, @NotNull Builder builder) {
- this(plot, builder, builder.getPlotType());
- }
+ protected final Builder builder;
- /**
- * Generates a new plot in the given world
- *
- * @param plot - plot which should be generated
- * @param builder - builder of the plot
- * @param plotType - type of the plot
- */
- protected AbstractPlotGenerator(@NotNull AbstractPlot plot, @NotNull Builder builder, @NotNull PlotType plotType) {
- this(plot, builder, plotType, plot.getVersion() <= 2 || plotType.hasOnePlotPerWorld() ? new OnePlotWorld(plot) : new CityPlotWorld((Plot) plot));
- }
+ protected byte[] schematicBytes = null;
- /**
- * Generates a new plot in the given world
- *
- * @param plot - plot which should be generated
- * @param builder - builder of the plot
- * @param world - world of the plot
- */
- private AbstractPlotGenerator(@NotNull AbstractPlot plot, @NotNull Builder builder, @NotNull PlotType plotType, @NotNull PlotWorld world) {
+ protected AbstractPlotLoader(@NotNull AbstractPlot plot, Builder builder, PlotType plotType, PlotWorld plotWorld) {
this.plot = plot;
- this.builder = builder;
- this.world = world;
- this.plotVersion = plot.getVersion();
this.plotType = plotType;
+ this.plotWorld = plotWorld;
+ this.builder = builder;
- if (init()) {
- Exception exception = null;
- try {
- if (plotType.hasOnePlotPerWorld() || !world.isWorldGenerated()) {
- new PlotWorldGenerator(world.getWorldName());
- } else if (!world.isWorldLoaded() && !world.loadWorld()) throw new Exception("Could not load world");
- generateOutlines();
- createPlotProtection();
- } catch (Exception ex) {
- exception = ex;
- }
- this.onComplete(exception != null, false);
-
- if (exception != null) {
- PlotUtils.Actions.abandonPlot(plot);
- onException(exception);
- }
+ PlotSystem.getPlugin().getComponentLogger().info("Loading plot #{}...", plot.getId());
+ PlotSystem.getPlugin().getComponentLogger().info("Plot Type: {}", plot.getPlotType().name());
+
+ boolean successful = true;
+ try {
+ generateWorld();
+ loadWorld();
+ fetchSchematicData();
+ createPlotProtection();
+ generateStructure();
+ } catch (Exception e) {
+ successful = false;
+ onException(e);
}
+
+ if (successful) onCompletion();
}
+ protected void generateWorld() throws Exception {
+ boolean generateWorld = plotType.hasOnePlotPerWorld() || !Utils.supplySync(plotWorld::isWorldGenerated).get();
+ if (!generateWorld) return;
- /**
- * Executed before plot generation
- *
- * @return true if initialization was successful
- */
- protected abstract boolean init();
+ new PlotWorldGenerator(plotWorld.getWorldName());
+ }
+ protected void loadWorld() throws Exception {
+ Utils.runSync(() -> {
+ if (plotWorld.isWorldLoaded()) return null;
- /**
- * Generates plot schematic and outlines
- */
- protected void generateOutlines() throws IOException {
- if (plotVersion >= 3 && plotType.hasEnvironment()) {
- pasteSchematic(null, plot.getInitialSchematicBytes(), world, false);
- } else {
- Mask airMask = new BlockTypeMask(BukkitAdapter.adapt(world.getBukkitWorld()), BlockTypes.AIR);
- pasteSchematic(airMask, PlotUtils.getOutlinesSchematicBytes(plot, world.getBukkitWorld()), world, true);
- }
+ boolean successful = plotWorld.loadWorld();
+ if (!successful) throw new Exception("Could not load world!");
+ return null;
+ }).get();
}
+ protected void fetchSchematicData() {
+ this.schematicBytes = plot.getInitialSchematicBytes();
+ }
- /**
- * Creates plot protection
- */
- protected void createPlotProtection() throws StorageException {
- RegionContainer regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer();
- RegionManager regionManager = regionContainer.get(BukkitAdapter.adapt(world.getBukkitWorld()));
+ protected void createPlotProtection() throws Exception {
+ Utils.runSync(() -> {
+ RegionContainer regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer();
+ RegionManager regionManager = regionContainer.get(BukkitAdapter.adapt(plotWorld.getBukkitWorld()));
+ if (regionManager == null) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Region Manager is null!"));
+ return null;
+ }
- if (regionManager != null) {
// Create build region for plot from the outline of the plot
- ProtectedRegion protectedBuildRegion = new ProtectedPolygonalRegion(world.getRegionName(), plot.getOutline(), PlotWorld.MIN_WORLD_HEIGHT, PlotWorld.MAX_WORLD_HEIGHT);
+ ProtectedRegion protectedBuildRegion = new ProtectedPolygonalRegion(plotWorld.getRegionName(), plot.getOutline(), PlotWorld.MIN_WORLD_HEIGHT, PlotWorld.MAX_WORLD_HEIGHT);
protectedBuildRegion.setPriority(100);
// Create protected plot region for plot
- World weWorld = new BukkitWorld(world.getBukkitWorld());
- CylinderRegion cylinderRegion = new CylinderRegion(weWorld, plot.getCenter(), Vector2.at(PlotWorld.PLOT_SIZE, PlotWorld.PLOT_SIZE), PlotWorld.MIN_WORLD_HEIGHT, PlotWorld.MAX_WORLD_HEIGHT);
- ProtectedRegion protectedRegion = new ProtectedPolygonalRegion(world.getRegionName() + "-1", cylinderRegion.polygonize(-1), PlotWorld.MIN_WORLD_HEIGHT, PlotWorld.MAX_WORLD_HEIGHT);
- protectedRegion.setPriority(50);
+ ProtectedRegion protectedRegion = getProtectedRegion();
// Add plot owner
DefaultDomain owner = protectedBuildRegion.getOwners();
@@ -170,12 +160,21 @@ protected void createPlotProtection() throws StorageException {
setRegionPermissions(protectedRegion);
// Add regions and save changes
- if (regionManager.hasRegion(world.getRegionName())) regionManager.removeRegion(world.getRegionName());
- if (regionManager.hasRegion(world.getRegionName() + "-1")) regionManager.removeRegion(world.getRegionName() + "-1");
+ if (regionManager.hasRegion(plotWorld.getRegionName())) regionManager.removeRegion(plotWorld.getRegionName());
+ if (regionManager.hasRegion(plotWorld.getRegionName() + "-1")) regionManager.removeRegion(plotWorld.getRegionName() + "-1");
regionManager.addRegion(protectedBuildRegion);
regionManager.addRegion(protectedRegion);
regionManager.saveChanges();
- } else PlotSystem.getPlugin().getComponentLogger().warn(text("Region Manager is null!"));
+ return null;
+ }).get();
+ }
+
+ private @NotNull ProtectedRegion getProtectedRegion() {
+ World weWorld = new BukkitWorld(plotWorld.getBukkitWorld());
+ CylinderRegion cylinderRegion = new CylinderRegion(weWorld, plot.getCenter(), Vector2.at(PlotWorld.PLOT_SIZE, PlotWorld.PLOT_SIZE), PlotWorld.MIN_WORLD_HEIGHT, PlotWorld.MAX_WORLD_HEIGHT);
+ ProtectedRegion protectedRegion = new ProtectedPolygonalRegion(plotWorld.getRegionName() + "-1", cylinderRegion.polygonize(-1), PlotWorld.MIN_WORLD_HEIGHT, PlotWorld.MAX_WORLD_HEIGHT);
+ protectedRegion.setPriority(50);
+ return protectedRegion;
}
/**
@@ -216,56 +215,20 @@ protected List getBlockedCommands(@NotNull FileConfiguration config) {
return blockedCommands;
}
- /**
- * Gets invoked when generation is completed
- *
- * @param failed - true if generation has failed
- * @param unloadWorld - try to unload world after generation
- */
- protected void onComplete(boolean failed, boolean unloadWorld) {
- // Unload plot world if it is not needed anymore
- if (unloadWorld) world.unloadWorld(false);
- }
-
-
- /**
- * Gets invoked when an exception has occurred
- *
- * @param ex - caused exception
- */
- protected void onException(Throwable ex) {
- PlotSystem.getPlugin().getComponentLogger().error(text("An error occurred while generating plot!"), ex);
- builder.getPlayer().sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(builder.getPlayer(), LangPaths.Message.Error.ERROR_OCCURRED)));
- builder.getPlayer().playSound(builder.getPlayer().getLocation(), Utils.SoundUtils.ERROR_SOUND, 1, 1);
- }
-
-
- /**
- * @return - plot object
- */
- public AbstractPlot getPlot() {
- return plot;
- }
-
-
- /**
- * @return - builder object
- */
- public Builder getBuilder() {
- return builder;
+ protected void generateStructure() throws Exception {
+ Utils.runSync(() -> {
+ if (plotType.hasEnvironment()) {
+ pasteSchematic(null, this.schematicBytes, this.plotWorld, false);
+ } else {
+ Mask airMask = new BlockTypeMask(BukkitAdapter.adapt(this.plotWorld.getBukkitWorld()), BlockTypes.AIR);
+ pasteSchematic(airMask, PlotUtils.getOutlinesSchematicBytes(plot, this.schematicBytes, this.plotWorld.getBukkitWorld()), this.plotWorld, true);
+ }
+ return null;
+ }).get();
}
-
- /**
- * Pastes the schematic to the plot center in the given world
- *
- * @param pasteMask - sets a mask for the paste operation, can be null
- * @param schematicFile - plot/environment schematic file
- * @param world - world to paste in
- * @param clearArea - clears the plot area with air before pasting
- */
public static void pasteSchematic(@Nullable Mask pasteMask, byte[] schematicFile, @NotNull PlotWorld world, boolean clearArea) throws IOException {
- // load world
+ // load world if not loaded already
if (!world.loadWorld()) return;
World weWorld = new BukkitWorld(world.getBukkitWorld());
@@ -295,4 +258,14 @@ public static void pasteSchematic(@Nullable Mask pasteMask, byte[] schematicFile
Operations.complete(clipboardHolder);
}
}
+
+ protected void onException(Exception e) {
+ PlotHandler.abandonPlot(this.plot);
+
+ PlotSystem.getPlugin().getComponentLogger().error(text("An error occurred while generating plot!"), e);
+ builder.getPlayer().sendMessage(Utils.ChatUtils.getAlertFormat(LangUtil.getInstance().get(builder.getPlayer(), LangPaths.Message.Error.ERROR_OCCURRED)));
+ builder.getPlayer().playSound(builder.getPlayer().getLocation(), Utils.SoundUtils.ERROR_SOUND, 1, 1);
+ }
+
+ protected abstract void onCompletion();
}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/loader/DefaultPlotLoader.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/loader/DefaultPlotLoader.java
new file mode 100644
index 00000000..feafcc26
--- /dev/null
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/loader/DefaultPlotLoader.java
@@ -0,0 +1,95 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2021-2025, Alps BTE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.alpsbte.plotsystem.core.system.plot.generator.loader;
+
+import com.alpsbte.plotsystem.PlotSystem;
+import com.alpsbte.plotsystem.core.system.Builder;
+import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
+import com.alpsbte.plotsystem.core.system.plot.Plot;
+import com.alpsbte.plotsystem.core.system.plot.utils.PlotType;
+import com.alpsbte.plotsystem.core.system.plot.world.CityPlotWorld;
+import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld;
+import com.alpsbte.plotsystem.utils.Utils;
+import com.alpsbte.plotsystem.utils.enums.Status;
+import com.alpsbte.plotsystem.utils.io.LangPaths;
+import com.alpsbte.plotsystem.utils.io.LangUtil;
+import com.sk89q.worldedit.bukkit.BukkitAdapter;
+import com.sk89q.worldedit.function.mask.BlockTypeMask;
+import com.sk89q.worldedit.function.mask.Mask;
+import com.sk89q.worldedit.world.block.BlockTypes;
+import org.bukkit.Bukkit;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+
+public class DefaultPlotLoader extends AbstractPlotLoader {
+ public DefaultPlotLoader(@NotNull AbstractPlot plot, Builder builder, PlotType plotType, PlotWorld plotWorld) {
+ super(plot, builder, plotType, plotWorld);
+ }
+
+ public DefaultPlotLoader(@NotNull AbstractPlot plot, Builder builder) {
+ this(plot, builder, builder.getPlotType());
+ }
+
+ public DefaultPlotLoader(@NotNull AbstractPlot plot, Builder builder, PlotType plotType) {
+ this(plot, builder, plotType, PlotWorld.getByType(plotType, (Plot) plot));
+ }
+
+ @Override
+ protected void generateStructure() throws Exception {
+ if (!(plot instanceof Plot p)) {
+ super.generateStructure();
+ return;
+ }
+
+ byte[] completedSchematic = p.getCompletedSchematic();
+ if (completedSchematic != null) {
+ Utils.runSync(() -> {
+ Mask airMask = new BlockTypeMask(BukkitAdapter.adapt(plotWorld.getBukkitWorld()), BlockTypes.AIR);
+ pasteSchematic(airMask, completedSchematic, plotWorld, true);
+ return null;
+ }).get();
+ } else super.generateStructure();
+ copyToCityWorld();
+ }
+
+ @Override
+ protected void onCompletion() {
+ Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
+ plot.getWorld().teleportPlayer(builder.getPlayer());
+ LangUtil.getInstance().broadcast(LangPaths.Message.Info.CREATED_NEW_PLOT, builder.getName());
+ });
+ }
+
+ protected void copyToCityWorld() throws IOException {
+ assert plot instanceof Plot;
+ if (plot.getStatus() == Status.completed) return;
+ if (!PlotWorld.isOnePlotWorld(plotWorld.getWorldName())) return;
+
+ // If the player is playing in his own world, then additionally generate the plot in the city world
+ CityPlotWorld cityPlotWorld = new CityPlotWorld((Plot) plot);
+ AbstractPlotLoader.pasteSchematic(null, this.schematicBytes, cityPlotWorld, false);
+ }
+}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/TutorialPlotGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/loader/TutorialPlotLoader.java
similarity index 71%
rename from src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/TutorialPlotGenerator.java
rename to src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/loader/TutorialPlotLoader.java
index b5662f25..77eb2bee 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/TutorialPlotGenerator.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/loader/TutorialPlotLoader.java
@@ -1,12 +1,12 @@
-package com.alpsbte.plotsystem.core.system.plot.generator;
+package com.alpsbte.plotsystem.core.system.plot.generator.loader;
import com.alpsbte.plotsystem.PlotSystem;
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
import com.alpsbte.plotsystem.core.system.plot.TutorialPlot;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotType;
+import com.alpsbte.plotsystem.core.system.plot.world.OnePlotWorld;
import com.alpsbte.plotsystem.utils.DependencyManager;
-import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.Flags;
@@ -16,27 +16,22 @@
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.jetbrains.annotations.NotNull;
-import java.io.IOException;
import java.util.Objects;
import static net.kyori.adventure.text.Component.text;
-public class TutorialPlotGenerator extends AbstractPlotGenerator {
+public class TutorialPlotLoader extends AbstractPlotLoader {
private boolean buildingEnabled = false;
private boolean worldEditEnabled = false;
- public TutorialPlotGenerator(@NotNull AbstractPlot plot, @NotNull Builder builder) {
- super(plot, builder, PlotType.TUTORIAL);
+ public TutorialPlotLoader(@NotNull AbstractPlot plot, Builder builder) {
+ super(plot, builder, PlotType.TUTORIAL, new OnePlotWorld(plot));
}
- @Override
- protected boolean init() {
- return true;
- }
-
- public void generateOutlines(int schematicId) throws IOException, WorldEditException {
+ public void generateOutlines(int schematicId) throws Exception {
((TutorialPlot) plot).setTutorialSchematic(schematicId);
- generateOutlines();
+ fetchSchematicData();
+ generateStructure();
}
@Override
@@ -48,24 +43,19 @@ protected void setBuildRegionPermissions(@NotNull ProtectedRegion region) {
region.setFlag(new StateFlag("worldedit", false, RegionGroup.OWNERS), isWorldEditEnabled() ? StateFlag.State.ALLOW : StateFlag.State.DENY);
try {
- Objects.requireNonNull(WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(world.getBukkitWorld()))).save();
+ Objects.requireNonNull(WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(plotWorld.getBukkitWorld()))).save();
} catch (StorageException ex) {
PlotSystem.getPlugin().getComponentLogger().error(text("An error occurred while saving plot tutorial region!"), ex);
}
}
- @Override
- protected void onComplete(boolean failed, boolean unloadWorld) {
- super.onComplete(failed, false);
- }
-
public boolean isBuildingEnabled() {
return buildingEnabled;
}
public void setBuildingEnabled(boolean buildingEnabled) {
this.buildingEnabled = buildingEnabled;
- setBuildRegionPermissions(world.getProtectedBuildRegion());
+ setBuildRegionPermissions(plotWorld.getProtectedBuildRegion());
}
public boolean isWorldEditEnabled() {
@@ -74,6 +64,9 @@ public boolean isWorldEditEnabled() {
public void setWorldEditEnabled(boolean worldEditEnabled) {
this.worldEditEnabled = worldEditEnabled;
- setBuildRegionPermissions(world.getProtectedBuildRegion());
+ setBuildRegionPermissions(plotWorld.getProtectedBuildRegion());
}
+
+ @Override
+ protected void onCompletion() {}
}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/world/PlotWorldGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/world/PlotWorldGenerator.java
new file mode 100644
index 00000000..024253f3
--- /dev/null
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/world/PlotWorldGenerator.java
@@ -0,0 +1,161 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2021-2025, Alps BTE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.alpsbte.plotsystem.core.system.plot.generator.world;
+
+import com.alpsbte.plotsystem.PlotSystem;
+import com.alpsbte.plotsystem.utils.DependencyManager;
+import com.alpsbte.plotsystem.utils.Utils;
+import com.sk89q.worldedit.bukkit.BukkitAdapter;
+import com.sk89q.worldguard.WorldGuard;
+import com.sk89q.worldguard.protection.flags.Flags;
+import com.sk89q.worldguard.protection.flags.RegionGroup;
+import com.sk89q.worldguard.protection.flags.StateFlag;
+import com.sk89q.worldguard.protection.managers.RegionManager;
+import com.sk89q.worldguard.protection.managers.storage.StorageException;
+import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
+import com.sk89q.worldguard.protection.regions.RegionContainer;
+import net.querz.nbt.io.NBTUtil;
+import net.querz.nbt.io.NamedTag;
+import net.querz.nbt.tag.CompoundTag;
+import org.apache.commons.io.FileUtils;
+import org.bukkit.*;
+import org.bukkit.entity.SpawnCategory;
+import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
+import org.mvplugins.multiverse.core.world.WorldManager;
+import org.mvplugins.multiverse.core.world.options.ImportWorldOptions;
+import org.mvplugins.multiverse.external.vavr.control.Option;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
+
+import static net.kyori.adventure.text.Component.text;
+
+public class PlotWorldGenerator {
+ private final WorldManager worldManager = DependencyManager.getMultiverseCore().getWorldManager();
+ private final String worldName;
+ private static final World.Environment environment = World.Environment.NORMAL;
+ private static final WorldType worldType = WorldType.FLAT;
+
+ public PlotWorldGenerator(String worldName) throws Exception {
+ long startTime = System.nanoTime();
+ this.worldName = worldName;
+
+ // Async Part
+ generateWorld();
+
+ // Sync Part
+ long mainThreadStart = System.nanoTime();
+ Utils.runSync(() -> {
+ createMultiverseWorld();
+ configureWorld();
+ createGlobalProtection();
+ return null;
+ }).get();
+
+ PlotSystem.getPlugin().getComponentLogger().info("(PWG) Total time to generate world: {}ms", (System.nanoTime() - startTime) / 1_000_000);
+ PlotSystem.getPlugin().getComponentLogger().info("(PWG) Total time on main thread: {}ms", (System.nanoTime() - mainThreadStart) / 1_000_000);
+ }
+
+ protected void generateWorld() throws IOException {
+ // copy skeleton world with correct world name
+ Path skeletonPath = Bukkit.getWorldContainer().toPath().resolve("Skeleton");
+ Path worldPath = Bukkit.getWorldContainer().toPath().resolve(worldName);
+ FileUtils.copyDirectory(skeletonPath.toFile(), worldPath.toFile());
+
+ // delete uid.dat
+ Files.delete(worldPath.resolve("uid.dat"));
+
+ // rename world name in level.dat
+ Path levelDat = worldPath.resolve("level.dat");
+ NamedTag level = NBTUtil.read(levelDat.toFile());
+ CompoundTag tag = (CompoundTag) level.getTag();
+ tag.remove("LevelName");
+ tag.putString("LevelName", worldName);
+ level.setTag(tag);
+ NBTUtil.write(level, levelDat.toFile());
+
+ // rename world in paper-world.yml
+ Path paperWorld = worldPath.resolve("paper-world.yml");
+ String paperWorldContents = Files.readString(paperWorld);
+ String updatedContents = paperWorldContents
+ .replaceAll(SkeletonWorldGenerator.WORLD_NAME, worldName)
+ .replaceAll(SkeletonWorldGenerator.WORLD_NAME.toLowerCase(), worldName.toLowerCase());
+ Files.writeString(paperWorld, updatedContents);
+ }
+
+ protected void createMultiverseWorld() {
+ if (!worldManager.isLoadedWorld(worldName)) {
+ worldManager.importWorld(ImportWorldOptions.worldName(worldName)
+ .environment(environment)
+ .generator("VoidGen:{\"caves\":false,\"decoration\":false,\"mobs\":false,\"structures\":false}")
+ .useSpawnAdjust(false)
+ );
+ }
+ }
+
+ protected void configureWorld() {
+ World world = Bukkit.getWorld(worldName);
+ assert world != null;
+ Option mvWorld = worldManager.getLoadedWorld(worldName);
+
+ // Configure multiverse world
+ mvWorld.get().setAllowFlight(true);
+ mvWorld.get().setGameMode(GameMode.CREATIVE);
+ mvWorld.get().setAllowWeather(false);
+ mvWorld.get().setDifficulty(Difficulty.PEACEFUL);
+ mvWorld.get().getEntitySpawnConfig().getSpawnCategoryConfig(SpawnCategory.ANIMAL).setSpawn(false);
+ mvWorld.get().getEntitySpawnConfig().getSpawnCategoryConfig(SpawnCategory.MONSTER).setSpawn(false);
+ mvWorld.get().setAutoLoad(false);
+ mvWorld.get().setKeepSpawnInMemory(false);
+ worldManager.saveWorldsConfig();
+ }
+
+ protected void createGlobalProtection() throws StorageException {
+ RegionContainer regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer();
+ RegionManager regionManager = regionContainer.get(BukkitAdapter.adapt(Objects.requireNonNull(Bukkit.getWorld(worldName))));
+
+ if (regionManager != null) {
+ // Create a protected region for the plot world
+ String regionName = "__global__";
+ GlobalProtectedRegion globalRegion = new GlobalProtectedRegion(regionName);
+ globalRegion.setFlag(Flags.ENTRY, StateFlag.State.DENY);
+ globalRegion.setFlag(Flags.ENTRY.getRegionGroupFlag(), RegionGroup.ALL);
+ globalRegion.setFlag(Flags.PASSTHROUGH, StateFlag.State.DENY);
+ globalRegion.setFlag(Flags.PASSTHROUGH.getRegionGroupFlag(), RegionGroup.ALL);
+ globalRegion.setFlag(Flags.TNT, StateFlag.State.DENY);
+ globalRegion.setFlag(Flags.TNT.getRegionGroupFlag(), RegionGroup.ALL);
+ if (DependencyManager.isWorldGuardExtraFlagsEnabled())
+ globalRegion.setFlag(new StateFlag("worldedit", true, RegionGroup.ALL), StateFlag.State.DENY);
+
+ if (regionManager.hasRegion(regionName)) regionManager.removeRegion(regionName);
+ regionManager.addRegion(globalRegion);
+ regionManager.saveChanges();
+ } else PlotSystem.getPlugin().getComponentLogger().warn(text("Region Manager is null!"));
+ }
+}
+
+
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/world/SkeletonWorldGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/world/SkeletonWorldGenerator.java
new file mode 100644
index 00000000..acf97e31
--- /dev/null
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/world/SkeletonWorldGenerator.java
@@ -0,0 +1,85 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2021-2025, Alps BTE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.alpsbte.plotsystem.core.system.plot.generator.world;
+
+import net.kyori.adventure.util.TriState;
+import org.bukkit.GameRule;
+import org.bukkit.World;
+import org.bukkit.WorldCreator;
+import org.bukkit.WorldType;
+import org.bukkit.generator.ChunkGenerator;
+
+public class SkeletonWorldGenerator {
+ public static final String WORLD_NAME = "Skeleton";
+ private static final World.Environment ENVIRONMENT = World.Environment.NORMAL;
+ private static final WorldType WORLD_TYPE = WorldType.FLAT;
+ private static final String GENERATOR_SETTINGS = "{\"features\": false,\"layers\": [{\"block\": \"air\", \"height\": 1}],\"biome\":\"plains\"}";
+
+ private World world;
+
+ public SkeletonWorldGenerator() {
+ generateWorld();
+ configureWorld();
+ saveWorld();
+ }
+
+ protected void generateWorld() {
+ WorldCreator worldCreator = new WorldCreator(WORLD_NAME)
+ .environment(ENVIRONMENT)
+ .type(WORLD_TYPE)
+ .generator(new SkeletonWorldGenerator.EmptyChunkGenerator())
+ .generatorSettings(GENERATOR_SETTINGS)
+ .keepSpawnLoaded(TriState.FALSE);
+ this.world = worldCreator.createWorld();
+ }
+
+ protected void configureWorld() {
+ World bukkitWorld = this.world;
+ assert bukkitWorld != null;
+
+ // Set game rules
+ bukkitWorld.setGameRule(GameRule.RANDOM_TICK_SPEED, 0);
+ bukkitWorld.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
+ bukkitWorld.setGameRule(GameRule.DO_FIRE_TICK, false);
+ bukkitWorld.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
+ bukkitWorld.setGameRule(GameRule.KEEP_INVENTORY, true);
+ bukkitWorld.setGameRule(GameRule.DO_MOB_SPAWNING, false);
+ bukkitWorld.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false);
+ bukkitWorld.setGameRule(GameRule.DO_TILE_DROPS, false);
+ bukkitWorld.setGameRule(GameRule.SPAWN_CHUNK_RADIUS, 0);
+
+ // Set time to noon
+ bukkitWorld.setTime(6000);
+ }
+
+ protected void saveWorld() {
+ assert this.world != null;
+ this.world.save();
+ }
+
+ public static class EmptyChunkGenerator extends ChunkGenerator {
+ // It should just do nothing
+ }
+}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/utils/PlotUtils.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/utils/PlotUtils.java
index d0d2b5b0..b06a1d87 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/utils/PlotUtils.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/utils/PlotUtils.java
@@ -6,10 +6,6 @@
import com.alpsbte.plotsystem.core.system.CityProject;
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
import com.alpsbte.plotsystem.core.system.plot.Plot;
-import com.alpsbte.plotsystem.core.system.plot.TutorialPlot;
-import com.alpsbte.plotsystem.core.system.plot.generator.AbstractPlotGenerator;
-import com.alpsbte.plotsystem.core.system.plot.world.CityPlotWorld;
-import com.alpsbte.plotsystem.core.system.plot.world.OnePlotWorld;
import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld;
import com.alpsbte.plotsystem.core.system.review.PlotReview;
import com.alpsbte.plotsystem.core.system.review.ReviewNotification;
@@ -23,9 +19,7 @@
import com.github.fierioziy.particlenativeapi.api.ParticleNativeAPI;
import com.github.fierioziy.particlenativeapi.api.Particles_1_13;
import com.github.fierioziy.particlenativeapi.plugin.ParticleNativePlugin;
-import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
-import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
@@ -35,20 +29,15 @@
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
-import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Polygonal2DRegion;
-import com.sk89q.worldguard.WorldGuard;
-import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
-import com.sk89q.worldguard.protection.regions.RegionContainer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.World;
-import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
@@ -62,13 +51,10 @@
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.text.DecimalFormat;
-import java.time.LocalDate;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@@ -168,9 +154,10 @@ public static AbstractPlot getCurrentPlot(@NotNull Builder builder, Status... st
}
public static boolean isPlayerOnPlot(@NotNull AbstractPlot plot, Player player) {
- if (plot.getWorld().isWorldLoaded() && plot.getWorld().getBukkitWorld().getPlayers().contains(player)) {
+ PlotWorld world = plot.getWorld();
+ if (world.isWorldLoaded() && world.getBukkitWorld().getPlayers().contains(player)) {
Location playerLoc = player.getLocation();
- ProtectedRegion protectedRegion = plot.getWorld().getProtectedRegion();
+ ProtectedRegion protectedRegion = world.getProtectedRegion();
return protectedRegion == null || protectedRegion.contains(Vector3.toBlockPoint(playerLoc.getX(), playerLoc.getY(), playerLoc.getZ()));
}
return false;
@@ -195,9 +182,9 @@ public static boolean isPlotWorld(@NotNull World world) {
return DependencyManager.getMultiverseCore().getWorldManager().isLoadedWorld(world) && (PlotWorld.isOnePlotWorld(world.getName()) || PlotWorld.isCityPlotWorld(world.getName()));
}
- public static byte @Nullable [] getOutlinesSchematicBytes(@NotNull AbstractPlot plot, World world) throws IOException {
+ public static byte @Nullable [] getOutlinesSchematicBytes(@NotNull AbstractPlot plot, byte[] initialSchematic, World world) throws IOException {
Clipboard clipboard;
- ByteArrayInputStream inputStream = new ByteArrayInputStream(plot.getInitialSchematicBytes());
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(initialSchematic);
try (ClipboardReader reader = AbstractPlot.CLIPBOARD_FORMAT.getReader(inputStream)) {
clipboard = reader.read();
}
@@ -231,58 +218,6 @@ public static boolean isPlotWorld(@NotNull World world) {
return Paths.get(PlotSystem.getPlugin().getDataFolder().getAbsolutePath(), "schematics") + File.separator;
}
- public static boolean savePlotAsSchematic(@NotNull Plot plot) throws IOException, WorldEditException {
- if (plot.getVersion() < 4) {
- PlotSystem.getPlugin().getComponentLogger().error(text("Saving schematics of legacy plots is no longer allowed!"));
- return false;
- }
-
- Clipboard clipboard;
- ByteArrayInputStream inputStream = new ByteArrayInputStream(plot.getInitialSchematicBytes());
- try (ClipboardReader reader = AbstractPlot.CLIPBOARD_FORMAT.getReader(inputStream)) {
- clipboard = reader.read();
- }
- if (clipboard == null) return false;
-
- CuboidRegion cuboidRegion = getPlotAsRegion(plot);
- if (cuboidRegion == null) return false;
-
- BlockVector3 plotCenter = plot.getCenter();
-
- // Get plot outline
- List plotOutlines = plot.getOutline();
-
- // Load finished plot region as cuboid region
- if (!plot.getWorld().loadWorld()) return false;
- com.sk89q.worldedit.world.World world = new BukkitWorld(plot.getWorld().getBukkitWorld());
- Polygonal2DRegion region = new Polygonal2DRegion(world, plotOutlines, cuboidRegion.getMinimumPoint().y(), cuboidRegion.getMaximumPoint().y());
-
- // Copy and write finished plot clipboard to schematic
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- try (Clipboard cb = new BlockArrayClipboard(region)) {
- cb.setOrigin(BlockVector3.at(plotCenter.x(), cuboidRegion.getMinimumY(), (double) plotCenter.z()));
-
- ForwardExtentCopy forwardExtentCopy = new ForwardExtentCopy(Objects.requireNonNull(region.getWorld()), region, cb, region.getMinimumPoint());
- Operations.complete(forwardExtentCopy);
-
- try (ClipboardWriter writer = AbstractPlot.CLIPBOARD_FORMAT.getWriter(outputStream)) {
- double initialY = clipboard.getRegion().getMinimumY();
- double offset = initialY - cuboidRegion.getMinimumY();
- writer.write(cb.transform(new AffineTransform().translate(Vector3.at(0, offset, 0))));
- }
- }
-
- // Set Completed Schematic
- boolean successful = DataProvider.PLOT.setCompletedSchematic(plot.getId(), outputStream.toByteArray());
- if (!successful) return false;
-
- // If plot was created in a void world, copy the result to the city world
- if (plot.getPlotType() != PlotType.CITY_INSPIRATION_MODE) {
- AbstractPlotGenerator.pasteSchematic(null, outputStream.toByteArray(), new CityPlotWorld(plot), false);
- }
- return true;
- }
-
public static @Nullable CompletableFuture convertTerraToPlotXZ(@NotNull AbstractPlot plot, double[] terraCoords) throws IOException {
// Load plot outlines schematic as clipboard
Clipboard clipboard;
@@ -309,39 +244,17 @@ public static boolean savePlotAsSchematic(@NotNull Plot plot) throws IOException
};
// Return coordinates if they are in the schematic plot region
- ProtectedRegion protectedPlotRegion = plot.getWorld().getProtectedRegion() != null
- ? plot.getWorld().getProtectedRegion()
- : plot.getWorld().getProtectedBuildRegion();
- if (protectedPlotRegion.contains(BlockVector3.at((int) plotCoords[0], plot.getWorld().getPlotHeightCentered(), (int) plotCoords[1]))) {
+ PlotWorld world = plot.getWorld();
+ ProtectedRegion protectedPlotRegion = world.getProtectedRegion() != null
+ ? world.getProtectedRegion()
+ : world.getProtectedBuildRegion();
+ if (protectedPlotRegion.contains(BlockVector3.at((int) plotCoords[0], world.getPlotHeightCentered(), (int) plotCoords[1]))) {
return CompletableFuture.completedFuture(plotCoords);
}
return null;
}
- public static void checkPlotsForLastActivity() {
- Bukkit.getScheduler().runTaskTimerAsynchronously(PlotSystem.getPlugin(), () -> {
- List plots = DataProvider.PLOT.getPlots(Status.unfinished);
- FileConfiguration config = PlotSystem.getPlugin().getConfig();
- long inactivityIntervalDays = config.getLong(ConfigPaths.INACTIVITY_INTERVAL);
- long rejectedInactivityIntervalDays = (config.getLong(ConfigPaths.REJECTED_INACTIVITY_INTERVAL) != -1) ? config.getLong(ConfigPaths.REJECTED_INACTIVITY_INTERVAL) : inactivityIntervalDays;
- if (inactivityIntervalDays == -2 && rejectedInactivityIntervalDays == -2) return;
- for (Plot plot : plots) {
- LocalDate lastActivity = plot.getLastActivity();
- long interval = plot.isRejected() ? rejectedInactivityIntervalDays : inactivityIntervalDays;
- if (interval == -2 || lastActivity == null || lastActivity.plusDays(interval).isAfter(LocalDate.now())) continue;
-
- Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
- if (Actions.abandonPlot(plot)) {
- PlotSystem.getPlugin().getComponentLogger().info(text("Abandoned plot #" + plot.getId() + " due to inactivity!"));
- } else {
- PlotSystem.getPlugin().getComponentLogger().warn(text("An error occurred while abandoning plot #" + plot.getId() + " due to inactivity!"));
- }
- });
- }
- }, 0L, 20 * 60 * 60L); // Check every hour
- }
-
public static void informPlayerAboutUnfinishedPlots(@NotNull Player player, Builder builder) {
try {
List plots = Cache.getCachedInProgressPlots(builder);
@@ -361,119 +274,6 @@ public static void startUnfinishedPlotReminderTimer(Player player) {
20L * 60 * interval));
}
- public static final class Actions {
- private Actions() {}
-
- public static void submitPlot(@NotNull Plot plot) {
- plot.setStatus(Status.unreviewed);
-
- if (plot.getWorld().isWorldLoaded()) {
- for (Player player : plot.getWorld() instanceof OnePlotWorld ? plot.getWorld().getBukkitWorld().getPlayers() : ((CityPlotWorld) plot.getWorld()).getPlayersOnPlot()) {
- player.teleport(Utils.getSpawnLocation());
- }
- }
-
- plot.getPermissions().removeBuilderPerms(plot.getPlotOwner().getUUID()).save();
- if (!plot.getPlotMembers().isEmpty()) {
- for (Builder builder : plot.getPlotMembers()) {
- plot.getPermissions().removeBuilderPerms(builder.getUUID());
- }
- }
- }
-
- public static void undoSubmit(@NotNull Plot plot) {
- plot.setStatus(Status.unfinished);
-
- plot.getPermissions().addBuilderPerms(plot.getPlotOwner().getUUID()).save();
- if (!plot.getPlotMembers().isEmpty()) {
- for (Builder builder : plot.getPlotMembers()) {
- plot.getPermissions().addBuilderPerms(builder.getUUID());
- }
- }
- }
-
- public static boolean abandonPlot(@NotNull AbstractPlot plot) {
- try {
- if (plot.getWorld() instanceof OnePlotWorld) {
- if (plot.getWorld().isWorldGenerated()) {
- if (plot.getWorld().isWorldLoaded()) {
- for (Player player : plot.getWorld().getBukkitWorld().getPlayers()) {
- player.teleport(Utils.getSpawnLocation());
- }
- }
- if (!plot.getWorld().deleteWorld()) PlotSystem.getPlugin().getComponentLogger().warn(text("Could not delete plot world " + plot.getWorld().getWorldName() + "!"));
- }
- } else if (!(plot instanceof TutorialPlot)) {
- RegionContainer regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer();
-
- if (plot.getWorld().loadWorld()) {
- CityPlotWorld world = plot.getWorld();
- List playersToTeleport = new ArrayList<>(world.getPlayersOnPlot());
-
- RegionManager regionManager = regionContainer.get(BukkitAdapter.adapt(world.getBukkitWorld()));
- if (regionManager != null) {
- for (Builder builder : ((Plot) plot).getPlotMembers()) {
- ((Plot) plot).removePlotMember(builder);
- }
-
- if (regionManager.hasRegion(world.getRegionName())) regionManager.removeRegion(world.getRegionName());
- if (regionManager.hasRegion(world.getRegionName() + "-1")) regionManager.removeRegion(world.getRegionName() + "-1");
-
- AbstractPlotGenerator.pasteSchematic(null, getOutlinesSchematicBytes(plot, world.getBukkitWorld()), world, true);
- } else PlotSystem.getPlugin().getComponentLogger().warn(text("Region Manager is null!"));
-
- playersToTeleport.forEach(p -> p.teleport(Utils.getSpawnLocation()));
- if (plot.getWorld().isWorldLoaded()) plot.getWorld().unloadWorld(false);
- }
- }
- } catch (IOException | WorldEditException ex) {
- PlotSystem.getPlugin().getComponentLogger().error(text("Failed to abandon plot with the ID " + plot.getId() + "!"), ex);
- return false;
- }
-
- CompletableFuture.runAsync(() -> {
- if (plot.getPlotType() == PlotType.TUTORIAL) return;
- Plot dPlot = (Plot) plot;
- boolean successful;
- successful = DataProvider.REVIEW.removeAllReviewsOfPlot(dPlot.getId());
-
- for (Builder builder : dPlot.getPlotMembers()) {
- if (!successful) break;
- successful = dPlot.removePlotMember(builder);
- }
-
- if (successful && plot.getPlotOwner() != null) {
- Cache.clearCache(plot.getPlotOwner().getUUID());
- successful = plot.getPlotOwner().setSlot(plot.getPlotOwner().getSlot(dPlot), -1);
- }
-
- if (successful) {
- successful = dPlot.setPlotOwner(null)
- && dPlot.setLastActivity(true)
- && dPlot.setStatus(Status.unclaimed)
- && dPlot.setPlotType(PlotType.LOCAL_INSPIRATION_MODE);
- }
-
- successful = successful && DataProvider.PLOT.setCompletedSchematic(plot.getId(), null);
-
- if (!successful) PlotSystem.getPlugin().getComponentLogger().error(text("Failed to abandon plot with the ID " + plot.getId() + "!"));
- });
- return true;
- }
-
- public static boolean deletePlot(Plot plot) {
- if (abandonPlot(plot)) {
- CompletableFuture.runAsync(() -> {
- if (DataProvider.PLOT.deletePlot(plot.getId())) return;
- PlotSystem.getPlugin().getComponentLogger().warn(text("Failed to abandon plot with the ID " + plot.getId() + "!"));
- });
- return true;
- }
- PlotSystem.getPlugin().getComponentLogger().warn(text("Failed to abandon plot with the ID " + plot.getId() + "!"));
- return false;
- }
- }
-
public static final class Cache {
private Cache() {}
@@ -555,19 +355,19 @@ public static void showOutlines() {
List points = plot.getBlockOutline();
- for (BlockVector2 point : points)
- if (point.distanceSq(playerPos2D) < 50 * 50) {
- if (!particleAPIEnabled) {
- player.spawnParticle(Particle.FLAME, point.x(), player.getLocation().getY() + 1, point.z(), 1, 0.0, 0.0, 0.0, 0);
- } else {
- Location loc = new Location(player.getWorld(), point.x(), player.getLocation().getY() + 1, point.z());
- // create a particle packet
- Object packet = particles.FLAME().packet(true, loc);
-
- // send this packet to player
- particles.sendPacket(player, packet);
- }
+ for (BlockVector2 point : points) {
+ if (point.distanceSq(playerPos2D) >= 50 * 50) continue;
+ if (!particleAPIEnabled) {
+ player.spawnParticle(Particle.FLAME, point.x(), player.getLocation().getY() + 1, point.z(), 1, 0.0, 0.0, 0.0, 0);
+ continue;
}
+ Location loc = new Location(player.getWorld(), point.x(), player.getLocation().getY() + 1, point.z());
+ // create a particle packet
+ Object packet = particles.FLAME().packet(true, loc);
+
+ // send this packet to player
+ particles.sendPacket(player, packet);
+ }
}
}
}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/CityPlotWorld.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/CityPlotWorld.java
index d37dcccc..d4124697 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/CityPlotWorld.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/CityPlotWorld.java
@@ -1,14 +1,21 @@
package com.alpsbte.plotsystem.core.system.plot.world;
+import com.alpsbte.plotsystem.PlotSystem;
+import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
import com.alpsbte.plotsystem.core.system.plot.Plot;
+import com.alpsbte.plotsystem.core.system.plot.generator.loader.AbstractPlotLoader;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
import com.alpsbte.plotsystem.utils.Utils;
import com.alpsbte.plotsystem.utils.io.LangPaths;
import com.alpsbte.plotsystem.utils.io.LangUtil;
import com.google.common.annotations.Beta;
+import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
+import com.sk89q.worldguard.WorldGuard;
+import com.sk89q.worldguard.protection.managers.RegionManager;
+import com.sk89q.worldguard.protection.regions.RegionContainer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@@ -17,6 +24,8 @@
import java.util.ArrayList;
import java.util.List;
+import static net.kyori.adventure.text.Component.text;
+
public class CityPlotWorld extends PlotWorld {
public CityPlotWorld(@NotNull Plot plot) {
super("C-" + plot.getCityProject().getId(), plot);
@@ -24,37 +33,35 @@ public CityPlotWorld(@NotNull Plot plot) {
@Override
public boolean teleportPlayer(@NotNull Player player) {
- if (super.teleportPlayer(player)) {
- player.playSound(player.getLocation(), Utils.SoundUtils.TELEPORT_SOUND, 1, 1);
- player.setAllowFlight(true);
- player.setFlying(true);
+ if (!super.teleportPlayer(player)) return false;
- if (getPlot() != null) {
- player.sendMessage(Utils.ChatUtils.getInfoFormat(LangUtil.getInstance().get(player, LangPaths.Message.Info.TELEPORTING_PLOT, String.valueOf(getPlot().getId()))));
+ player.playSound(player.getLocation(), Utils.SoundUtils.TELEPORT_SOUND, 1, 1);
+ player.setAllowFlight(true);
+ player.setFlying(true);
- Utils.updatePlayerInventorySlots(player);
- PlotUtils.ChatFormatting.sendLinkMessages(getPlot(), player);
+ if (plot == null) return true;
- if (getPlot().getPlotOwner().getUUID().equals(player.getUniqueId())) {
- getPlot().setLastActivity(false);
- }
- }
+ player.sendMessage(Utils.ChatUtils.getInfoFormat(LangUtil.getInstance().get(player, LangPaths.Message.Info.TELEPORTING_PLOT, String.valueOf(plot.getId()))));
- return true;
- }
- return false;
+ Utils.updatePlayerInventorySlots(player);
+ PlotUtils.ChatFormatting.sendLinkMessages(plot, player);
+
+ if (!plot.getPlotOwner().getUUID().equals(player.getUniqueId())) return true;
+ plot.setLastActivity(false);
+
+ return true;
}
@Override
public String getRegionName() {
- return super.getRegionName() + "-" + getPlot().getId();
+ return super.getRegionName() + "-" + plot.getId();
}
@Beta
@Override
public int getPlotHeight() throws IOException {
- return getPlot().getVersion() >= 3 ? MIN_WORLD_HEIGHT + getWorldHeight() : getPlotHeightCentered();
+ return plot.getVersion() >= 3 ? MIN_WORLD_HEIGHT + getWorldHeight() : getPlotHeightCentered();
}
@Beta
@@ -72,12 +79,13 @@ public int getPlotHeightCentered() throws IOException {
@Beta
public int getWorldHeight() throws IOException {
Clipboard clipboard;
- ByteArrayInputStream inputStream = new ByteArrayInputStream(getPlot().getInitialSchematicBytes());
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(plot.getInitialSchematicBytes());
try (ClipboardReader reader = AbstractPlot.CLIPBOARD_FORMAT.getReader(inputStream)) {
clipboard = reader.read();
}
- if (clipboard != null) {
- int plotHeight = clipboard.getMinimumPoint().y();
+ if (clipboard == null) throw new IOException("A Plot's Outline schematic fails to load, cannot get clipboard.");
+
+ int plotHeight = clipboard.getMinimumPoint().y();
// Minimum building height for a plot (this should be configurable depending on minecraft build limit)
// This is in the case that a plot is created at y level 300 where the max build limit is 318,
@@ -88,13 +96,11 @@ public int getWorldHeight() throws IOException {
// Additional ground layer the plot use to save as schematic need to be included for plot's y-level
int groundLayer = 64;
- // Plots created outside of vanilla build limit or the build-able height is too small
- if (plotHeight + groundLayer < MIN_WORLD_HEIGHT + groundLayer
- || plotHeight + groundLayer + minBuildingHeight > MAX_WORLD_HEIGHT + groundLayer)
- return 0; // throw new IOException("Plot height is out of range.");
- return plotHeight;
- }
- throw new IOException("A Plot's Outline schematic fails to load, cannot get clipboard.");
+ // Plots created outside of vanilla build limit or the build-able height is too small
+ if (plotHeight + groundLayer < MIN_WORLD_HEIGHT + groundLayer
+ || plotHeight + groundLayer + minBuildingHeight > MAX_WORLD_HEIGHT + groundLayer)
+ return 0; // throw new IOException("Plot height is out of range.");
+ return plotHeight;
}
/**
@@ -102,14 +108,48 @@ public int getWorldHeight() throws IOException {
*
* @return a list of players located on the plot
*/
- public List getPlayersOnPlot() {
+ public List getPlayersOnPlot(AbstractPlot plot) {
List players = new ArrayList<>();
- if (getPlot() != null && getPlot().getWorld().isWorldLoaded() && !getPlot().getWorld().getBukkitWorld().getPlayers().isEmpty()) {
- for (Player player : getPlot().getWorld().getBukkitWorld().getPlayers()) {
- if (PlotUtils.isPlayerOnPlot(getPlot(), player)) players.add(player);
- }
- return players;
+ if (plot == null || !plot.getWorld().isWorldLoaded() || plot.getWorld().getBukkitWorld().getPlayers().isEmpty()) return players;
+
+ for (Player player : plot.getWorld().getBukkitWorld().getPlayers()) {
+ if (PlotUtils.isPlayerOnPlot(plot, player)) players.add(player);
}
return players;
}
+
+ @Override
+ public boolean onAbandon() {
+ RegionContainer regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer();
+ if (!loadWorld()) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Could not load world!"));
+ return false;
+ }
+
+ RegionManager regionManager = regionContainer.get(BukkitAdapter.adapt(getBukkitWorld()));
+ if (regionManager == null) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Region Manager is null!"));
+ return false;
+ }
+
+ for (Builder builder : ((Plot) plot).getPlotMembers()) {
+ ((Plot) plot).removePlotMember(builder);
+ }
+
+ if (regionManager.hasRegion(getRegionName())) regionManager.removeRegion(getRegionName());
+ if (regionManager.hasRegion(getRegionName() + "-1")) regionManager.removeRegion(getRegionName() + "-1");
+
+ // paste initial schematic to reset plot
+ try {
+ AbstractPlotLoader.pasteSchematic(null, PlotUtils.getOutlinesSchematicBytes(plot, plot.getInitialSchematicBytes(), getBukkitWorld()), this, true);
+ } catch (IOException e) {
+ PlotSystem.getPlugin().getComponentLogger().error(text("Could not paste schematic!"), e);
+ }
+
+ List playersToTeleport = new ArrayList<>(getPlayersOnPlot(plot));
+ playersToTeleport.forEach(p -> p.teleport(Utils.getSpawnLocation()));
+
+ if (isWorldLoaded()) unloadWorld(false);
+ return super.onAbandon();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IWorld.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IWorld.java
index bf5cf74a..ea6a1a0e 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IWorld.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IWorld.java
@@ -1,6 +1,7 @@
package com.alpsbte.plotsystem.core.system.plot.world;
-import com.alpsbte.plotsystem.core.system.plot.generator.AbstractPlotGenerator;
+import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
+import com.alpsbte.plotsystem.core.system.plot.generator.loader.AbstractPlotLoader;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.bukkit.Location;
@@ -10,6 +11,9 @@
import java.io.IOException;
+/**
+ * Represents the world of a given plot. There can be multiple instances of this interface per actual bukkit world.
+ */
public interface IWorld {
/**
* Generates the plot world with the required configurations and schematic
@@ -17,7 +21,7 @@ public interface IWorld {
* @param generator generator type as class
* @return true if world was generated successfully
*/
- boolean generateWorld(@NotNull Class generator);
+ boolean generateWorld(@NotNull Class generator);
/**
* Regenerates the current plot with an optional new generator type
@@ -25,7 +29,7 @@ public interface IWorld {
* @param generator generator type as class
* @return true if world was regenerated successfully
*/
- boolean regenWorld(@NotNull Class generator);
+ boolean regenWorld(@NotNull Class generator);
/**
* Deletes the world file and entry in the config file
@@ -123,4 +127,18 @@ public interface IWorld {
* @return true if world is generated
*/
boolean isWorldGenerated();
+
+ /**
+ * Returns the plot associated with this world object
+ *
+ * @return the plot associated with this world object
+ */
+ AbstractPlot getPlot();
+
+ /**
+ * Executes all World specific side effects needed to abandon a plot
+ *
+ * @return true if successfully executed
+ */
+ boolean onAbandon();
}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/OnePlotWorld.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/OnePlotWorld.java
index 2f439bec..4eb4dfbb 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/OnePlotWorld.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/OnePlotWorld.java
@@ -1,3 +1,27 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2023, Alps BTE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
package com.alpsbte.plotsystem.core.system.plot.world;
import com.alpsbte.plotsystem.PlotSystem;
@@ -5,9 +29,9 @@
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
import com.alpsbte.plotsystem.core.system.plot.Plot;
import com.alpsbte.plotsystem.core.system.plot.TutorialPlot;
-import com.alpsbte.plotsystem.core.system.plot.generator.AbstractPlotGenerator;
-import com.alpsbte.plotsystem.core.system.plot.generator.DefaultPlotGenerator;
-import com.alpsbte.plotsystem.core.system.plot.generator.TutorialPlotGenerator;
+import com.alpsbte.plotsystem.core.system.plot.generator.loader.AbstractPlotLoader;
+import com.alpsbte.plotsystem.core.system.plot.generator.loader.DefaultPlotLoader;
+import com.alpsbte.plotsystem.core.system.plot.generator.loader.TutorialPlotLoader;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotType;
import com.alpsbte.plotsystem.core.system.plot.utils.PlotUtils;
import com.alpsbte.plotsystem.utils.Utils;
@@ -22,47 +46,38 @@
public class OnePlotWorld extends PlotWorld {
private final Builder plotOwner;
+ private final AbstractPlot plot;
public OnePlotWorld(@NotNull AbstractPlot plot) {
super((plot instanceof TutorialPlot ? "T-" : "P-") + plot.getId(), plot);
+ this.plot = plot;
this.plotOwner = plot.getPlotOwner();
}
@Override
- public boolean generateWorld(@NotNull Class generator) {
+ public boolean generateWorld(@NotNull Class generator) {
if (isWorldGenerated()) return false;
- if (generator.isAssignableFrom(DefaultPlotGenerator.class)) {
- new DefaultPlotGenerator(getPlot(), plotOwner);
- } else if (generator.isAssignableFrom(TutorialPlotGenerator.class)) {
- new TutorialPlotGenerator(getPlot(), plotOwner);
+ if (generator.isAssignableFrom(DefaultPlotLoader.class)) {
+ new DefaultPlotLoader(plot, plotOwner);
+ } else if (generator.isAssignableFrom(TutorialPlotLoader.class)) {
+ new TutorialPlotLoader(plot, plotOwner);
} else return false;
return true;
}
@Override
public boolean loadWorld() {
- if (getPlot() == null || isWorldGenerated()) return super.loadWorld();
+ if (plot == null || isWorldGenerated()) return super.loadWorld();
// Generate plot if it doesn't exist
- if (getPlot().getPlotType() == PlotType.TUTORIAL || ((Plot) getPlot()).getCompletedSchematic() == null)
- generateWorld(TutorialPlotGenerator.class);
-
- new DefaultPlotGenerator(getPlot(), plotOwner, getPlot().getPlotType()) {
- @Override
- protected boolean init() {
- return true;
- }
-
- @Override
- protected void onComplete(boolean failed, boolean unloadWorld) {
- getPlot().getPermissions().clearAllPerms();
- super.onComplete(true, false);
- }
- };
+ if (plot.getPlotType() == PlotType.TUTORIAL || ((Plot) plot).getCompletedSchematic() == null)
+ generateWorld(TutorialPlotLoader.class);
+
+ new DefaultPlotLoader(plot, plotOwner, plot.getPlotType(), this);
if (!isWorldGenerated() || !isWorldLoaded()) {
- PlotSystem.getPlugin().getComponentLogger().warn(text("Could not regenerate world " + getWorldName() + " for plot " + getPlot().getId() + "!"));
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Could not regenerate world " + getWorldName() + " for plot " + plot.getId() + "!"));
return false;
}
return true;
@@ -71,13 +86,10 @@ protected void onComplete(boolean failed, boolean unloadWorld) {
@Override
public boolean unloadWorld(boolean movePlayers) {
boolean isTutorialPlot;
- isTutorialPlot = getPlot().getPlotType() == PlotType.TUTORIAL;
+ isTutorialPlot = plot.getPlotType() == PlotType.TUTORIAL;
- if (getPlot() != null) {
- if (isTutorialPlot) return deleteWorld();
- else return super.unloadWorld(movePlayers);
- }
- return false;
+ if (isTutorialPlot) return deleteWorld();
+ else return super.unloadWorld(movePlayers);
}
@Override
@@ -88,15 +100,15 @@ public boolean teleportPlayer(@NotNull Player player) {
player.setAllowFlight(true);
player.setFlying(true);
- if (getPlot() == null) return true;
- if (getPlot().getPlotType() != PlotType.TUTORIAL) {
- player.sendMessage(Utils.ChatUtils.getInfoFormat(LangUtil.getInstance().get(player, LangPaths.Message.Info.TELEPORTING_PLOT, String.valueOf(getPlot().getId()))));
- PlotUtils.ChatFormatting.sendLinkMessages(getPlot(), player);
+ if (plot == null) return true;
+ if (plot.getPlotType() != PlotType.TUTORIAL) {
+ player.sendMessage(Utils.ChatUtils.getInfoFormat(LangUtil.getInstance().get(player, LangPaths.Message.Info.TELEPORTING_PLOT, String.valueOf(plot.getId()))));
+ PlotUtils.ChatFormatting.sendLinkMessages(plot, player);
}
Utils.updatePlayerInventorySlots(player);
- if (!getPlot().getPlotOwner().getUUID().equals(player.getUniqueId())) return true;
- getPlot().setLastActivity(false);
+ if (!plot.getPlotOwner().getUUID().equals(player.getUniqueId())) return true;
+ plot.setLastActivity(false);
return true;
}
@@ -110,4 +122,17 @@ public int getPlotHeight() {
public int getPlotHeightCentered() throws IOException {
return MIN_WORLD_HEIGHT + super.getPlotHeightCentered();
}
+
+ @Override
+ public boolean onAbandon() {
+ if (!isWorldGenerated()) return super.onAbandon();
+ if (isWorldLoaded()) {
+ for (Player player : getBukkitWorld().getPlayers()) player.teleport(Utils.getSpawnLocation());
+ }
+ if (!deleteWorld()) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Could not delete plot world " + getWorldName() + "!"));
+ return false;
+ }
+ return super.onAbandon();
+ }
}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/PlotWorld.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/PlotWorld.java
index 87375756..5eb2c7cd 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/PlotWorld.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/PlotWorld.java
@@ -1,13 +1,40 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2021-2025, Alps BTE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
package com.alpsbte.plotsystem.core.system.plot.world;
import com.alpsbte.alpslib.utils.AlpsUtils;
import com.alpsbte.plotsystem.PlotSystem;
import com.alpsbte.plotsystem.core.database.DataProvider;
import com.alpsbte.plotsystem.core.system.plot.AbstractPlot;
+import com.alpsbte.plotsystem.core.system.plot.Plot;
import com.alpsbte.plotsystem.core.system.plot.TutorialPlot;
-import com.alpsbte.plotsystem.core.system.plot.generator.AbstractPlotGenerator;
+import com.alpsbte.plotsystem.core.system.plot.generator.loader.AbstractPlotLoader;
+import com.alpsbte.plotsystem.core.system.plot.utils.PlotType;
import com.alpsbte.plotsystem.utils.DependencyManager;
import com.alpsbte.plotsystem.utils.Utils;
+import com.alpsbte.plotsystem.utils.io.ConfigPaths;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
@@ -40,7 +67,7 @@ public class PlotWorld implements IWorld {
private final MultiverseCoreApi mvCore = DependencyManager.getMultiverseCore();
private final String worldName;
- private final AbstractPlot plot;
+ protected final AbstractPlot plot;
public PlotWorld(@NotNull String worldName, @Nullable AbstractPlot plot) {
this.worldName = worldName;
@@ -48,61 +75,61 @@ public PlotWorld(@NotNull String worldName, @Nullable AbstractPlot plot) {
}
@Override
- public boolean generateWorld(@NotNull Class generator) {
+ public boolean generateWorld(@NotNull Class generator) {
throw new UnsupportedOperationException("No world generator set for world " + getWorldName());
}
@Override
- public boolean regenWorld(@NotNull Class generator) {
+ public boolean regenWorld(@NotNull Class generator) {
return deleteWorld() && generateWorld(generator);
}
@Override
public boolean deleteWorld() {
- if (isWorldGenerated() && loadWorld()) {
- if (Boolean.TRUE.equals(mvCore.getWorldManager().getWorld(getWorldName())
- .map(world -> mvCore.getWorldManager().deleteWorld(DeleteWorldOptions.world(world)).isSuccess())
- .getOrElse(false)) && mvCore.getWorldManager().saveWorldsConfig().isSuccess()) {
- try {
- File multiverseInventoriesConfig = new File(DependencyManager.getMultiverseInventoriesConfigPath(getWorldName()));
- File worldGuardConfig = new File(DependencyManager.getWorldGuardConfigPath(getWorldName()));
- if (multiverseInventoriesConfig.exists()) FileUtils.deleteDirectory(multiverseInventoriesConfig);
- if (worldGuardConfig.exists()) FileUtils.deleteDirectory(worldGuardConfig);
- } catch (IOException ex) {
- PlotSystem.getPlugin().getComponentLogger().warn(text("Could not delete config files for world " + getWorldName() + "!"));
- return false;
- }
- return true;
- } else PlotSystem.getPlugin().getComponentLogger().warn(text("Could not delete world " + getWorldName() + "!"));
+ if (!isWorldGenerated() || !loadWorld()) return false;
+ if (!Boolean.TRUE.equals(mvCore.getWorldManager().getWorld(getWorldName())
+ .map(world -> mvCore.getWorldManager().deleteWorld(DeleteWorldOptions.world(world)).isSuccess())
+ .getOrElse(false)) || !mvCore.getWorldManager().saveWorldsConfig().isSuccess()) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Could not delete world " + getWorldName() + "!"));
+ return false;
}
- return false;
+ try {
+ File multiverseInventoriesConfig = new File(DependencyManager.getMultiverseInventoriesConfigPath(getWorldName()));
+ File worldGuardConfig = new File(DependencyManager.getWorldGuardConfigPath(getWorldName()));
+ if (multiverseInventoriesConfig.exists()) FileUtils.deleteDirectory(multiverseInventoriesConfig);
+ if (worldGuardConfig.exists()) FileUtils.deleteDirectory(worldGuardConfig);
+ } catch (IOException ex) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Could not delete config files for world " + getWorldName() + "!"));
+ return false;
+ }
+ return true;
}
@Override
public boolean loadWorld() {
- if (isWorldGenerated()) {
- if (isWorldLoaded()) {
- return true;
- } else return mvCore.getWorldManager().loadWorld(getWorldName()).isSuccess() || isWorldLoaded();
- } else PlotSystem.getPlugin().getComponentLogger().warn(text("Could not load world " + worldName + " because it is not generated!"));
- return false;
+ if (!isWorldGenerated()) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Could not load world " + worldName + " because it is not generated!"));
+ return false;
+ }
+
+ return isWorldLoaded() || mvCore.getWorldManager().loadWorld(getWorldName()).isSuccess();
}
@Override
public boolean unloadWorld(boolean movePlayers) {
- if (isWorldGenerated()) {
- if (isWorldLoaded()) {
- if (movePlayers && !getBukkitWorld().getPlayers().isEmpty()) {
- for (Player player : getBukkitWorld().getPlayers()) {
- player.teleport(Utils.getSpawnLocation());
- }
- }
-
- return Bukkit.unloadWorld(getBukkitWorld(), true);
+ if (!isWorldGenerated()) {
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Could not unload world " + worldName + " because it is not generated!"));
+ return false;
+ }
+ if (!isWorldLoaded()) return true;
+
+ if (movePlayers && !getBukkitWorld().getPlayers().isEmpty()) {
+ for (Player player : getBukkitWorld().getPlayers()) {
+ player.teleport(Utils.getSpawnLocation());
}
- return true;
- } else PlotSystem.getPlugin().getComponentLogger().warn(text("Could not unload world " + worldName + " because it is not generated!"));
- return false;
+ }
+
+ return Bukkit.unloadWorld(getBukkitWorld(), true);
}
@Override
@@ -110,25 +137,21 @@ public boolean teleportPlayer(@NotNull Player player) {
if (loadWorld() && plot != null) {
player.teleport(getSpawnPoint(plot instanceof TutorialPlot ? null : plot.getCenter()));
return true;
- } else PlotSystem.getPlugin().getComponentLogger().warn(text("Could not teleport player " + player.getName() + " to world " + worldName + "!"));
+ }
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Could not teleport player " + player.getName() + " to world " + worldName + "!"));
return false;
}
@Override
public Location getSpawnPoint(BlockVector3 plotVector) {
- if (isWorldGenerated() && loadWorld()) {
- Location spawnLocation;
- if (plotVector == null) {
- spawnLocation = getBukkitWorld().getSpawnLocation();
- } else {
- spawnLocation = new Location(getBukkitWorld(), plotVector.x(), plotVector.y(), plotVector.z());
- }
+ if (!isWorldGenerated() || !loadWorld()) return null;
+ Location spawnLocation = plotVector == null
+ ? getBukkitWorld().getSpawnLocation()
+ : new Location(getBukkitWorld(), plotVector.x(), plotVector.y(), plotVector.z());
- // Set spawn point 1 block above the highest block at the spawn location
- spawnLocation.setY(getBukkitWorld().getHighestBlockYAt((int) spawnLocation.getX(), (int) spawnLocation.getZ()) + 1d);
- return spawnLocation;
- }
- return null;
+ // Set spawn point 1 block above the highest block at the spawn location
+ spawnLocation.setY(getBukkitWorld().getHighestBlockYAt((int) spawnLocation.getX(), (int) spawnLocation.getZ()) + 1d);
+ return spawnLocation;
}
@Override
@@ -138,17 +161,15 @@ public int getPlotHeight() throws IOException {
@Override
public int getPlotHeightCentered() throws IOException {
- if (plot != null) {
- Clipboard clipboard;
- ByteArrayInputStream inputStream = new ByteArrayInputStream(plot.getInitialSchematicBytes());
- try (ClipboardReader reader = AbstractPlot.CLIPBOARD_FORMAT.getReader(inputStream)) {
- clipboard = reader.read();
- }
- if (clipboard != null) {
- return (int) clipboard.getRegion().getCenter().y() - clipboard.getMinimumPoint().y();
- }
+ if (plot == null) return 0;
+
+ Clipboard clipboard;
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(plot.getInitialSchematicBytes());
+ try (ClipboardReader reader = AbstractPlot.CLIPBOARD_FORMAT.getReader(inputStream)) {
+ clipboard = reader.read();
}
- return 0;
+ if (clipboard == null) return 0;
+ return (int) clipboard.getRegion().getCenter().y() - clipboard.getMinimumPoint().y();
}
@Override
@@ -186,21 +207,26 @@ public boolean isWorldGenerated() {
return mvCore.getWorldManager().getWorld(worldName).isDefined();
}
- private @Nullable ProtectedRegion getRegion(String regionName) {
- RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
- if (loadWorld()) {
- RegionManager regionManager = container.get(BukkitAdapter.adapt(getBukkitWorld()));
- if (regionManager != null) {
- return regionManager.getRegion(regionName);
- } else PlotSystem.getPlugin().getComponentLogger().warn(text("Region manager is null!"));
- }
- return null;
- }
-
+ @Override
public AbstractPlot getPlot() {
return plot;
}
+ @Override
+ public boolean onAbandon() {
+ return true;
+ }
+
+ private @Nullable ProtectedRegion getRegion(String regionName) {
+ if (!loadWorld()) return null;
+
+ RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
+ RegionManager regionManager = container.get(BukkitAdapter.adapt(getBukkitWorld()));
+ if (regionManager != null) return regionManager.getRegion(regionName);
+
+ PlotSystem.getPlugin().getComponentLogger().warn(text("Region manager is null!"));
+ return null;
+ }
/**
* @param worldName - the name of the world
@@ -226,12 +252,19 @@ public static boolean isCityPlotWorld(@NotNull String worldName) {
* @return - plot world
*/
public static @Nullable PlotWorld getPlotWorldByName(String worldName) {
- if (isOnePlotWorld(worldName) || isCityPlotWorld(worldName)) {
- Integer id = AlpsUtils.tryParseInt(worldName.substring(2));
- if (id == null) return new PlotWorld(worldName, null);
- AbstractPlot plot = worldName.toLowerCase().startsWith("t-") ? DataProvider.TUTORIAL_PLOT.getById(id).orElse(null) : DataProvider.PLOT.getPlotById(id);
- return plot == null ? null : plot.getWorld();
- }
- return null;
+ // TODO: rework
+ if (!isOnePlotWorld(worldName) && !isCityPlotWorld(worldName)) return null;
+
+ Integer id = AlpsUtils.tryParseInt(worldName.substring(2));
+ if (id == null) return new PlotWorld(worldName, null);
+
+ AbstractPlot plot = worldName.toLowerCase().startsWith("t-") ? DataProvider.TUTORIAL_PLOT.getById(id).orElse(null) : DataProvider.PLOT.getPlotById(id);
+ return plot == null ? null : plot.getWorld();
+ }
+
+ public static PlotWorld getByType(PlotType type, Plot plot) {
+ // TODO: rework
+ boolean disableCIM = PlotSystem.getPlugin().getConfig().getBoolean(ConfigPaths.DISABLE_CITY_INSPIRATION_MODE);
+ return disableCIM || type.hasOnePlotPerWorld() ? new OnePlotWorld(plot) : new CityPlotWorld(plot);
}
}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/AbstractPlotTutorial.java b/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/AbstractPlotTutorial.java
index c6b6fcab..9bb7d777 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/AbstractPlotTutorial.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/AbstractPlotTutorial.java
@@ -6,7 +6,7 @@
import com.alpsbte.plotsystem.core.database.providers.TutorialPlotProvider;
import com.alpsbte.plotsystem.core.system.Builder;
import com.alpsbte.plotsystem.core.system.plot.TutorialPlot;
-import com.alpsbte.plotsystem.core.system.plot.generator.TutorialPlotGenerator;
+import com.alpsbte.plotsystem.core.system.plot.generator.loader.TutorialPlotLoader;
import com.alpsbte.plotsystem.core.system.tutorial.stage.AbstractPlotStage;
import com.alpsbte.plotsystem.core.system.tutorial.stage.AbstractStage;
import com.alpsbte.plotsystem.core.system.tutorial.utils.TutorialNPC;
@@ -22,7 +22,6 @@
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
-import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Optional;
import java.util.UUID;
@@ -40,7 +39,7 @@
public abstract class AbstractPlotTutorial extends AbstractTutorial implements PlotTutorial {
protected TutorialPlot tutorialPlot;
- private TutorialPlotGenerator plotGenerator;
+ private TutorialPlotLoader plotGenerator;
private boolean isPasteSchematic;
protected AbstractPlotTutorial(Player player, int tutorialId, int stageId) {
@@ -91,7 +90,7 @@ public void setStage(int stageId) {
}
@Override
- public void onPlotSchematicPaste(UUID playerUUID, int schematicId) throws IOException {
+ public void onPlotSchematicPaste(UUID playerUUID, int schematicId) throws Exception {
if (!getPlayerUUID().toString().equals(playerUUID.toString())) return;
if (plotGenerator != null && tutorialPlot.getWorld().isWorldGenerated() && tutorialPlot.getWorld().isWorldLoaded()) {
plotGenerator.generateOutlines(schematicId);
@@ -119,7 +118,7 @@ protected void prepareStage(PrepareStageAction action) {
if (isPasteSchematic) {
try {
onPlotSchematicPaste(getPlayerUUID(), ((AbstractPlotStage) currentStage).getInitSchematicId());
- } catch (IOException ex) {
+ } catch (Exception ex) {
onException(ex);
return;
}
@@ -151,11 +150,11 @@ public void saveTutorial(int stageId) {
@Override
public void onSwitchWorld(UUID playerUUID, int tutorialWorldIndex) {
if (!getPlayerUUID().toString().equals(playerUUID.toString())) return;
- if (tutorialWorldIndex == 1 && (plotGenerator == null || !plotGenerator.getPlot().getWorld().isWorldGenerated())) {
- plotGenerator = new TutorialPlotGenerator(tutorialPlot, Builder.byUUID(playerUUID));
+ if (tutorialWorldIndex == 1 && (plotGenerator == null || !tutorialPlot.getWorld().isWorldGenerated())) {
+ plotGenerator = new TutorialPlotLoader(tutorialPlot, Builder.byUUID(playerUUID));
try {
onPlotSchematicPaste(playerUUID, ((AbstractPlotStage) currentStage).getInitSchematicId());
- } catch (IOException ex) {
+ } catch (Exception ex) {
onException(ex);
return;
}
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/PlotTutorial.java b/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/PlotTutorial.java
index 261e52fc..43f281c4 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/PlotTutorial.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/PlotTutorial.java
@@ -1,6 +1,5 @@
package com.alpsbte.plotsystem.core.system.tutorial;
-import java.io.IOException;
import java.util.UUID;
public interface PlotTutorial extends Tutorial {
@@ -11,7 +10,7 @@ public interface PlotTutorial extends Tutorial {
* @param playerUUID uuid of the player
* @param schematicId The schematic id
*/
- void onPlotSchematicPaste(UUID playerUUID, int schematicId) throws IOException;
+ void onPlotSchematicPaste(UUID playerUUID, int schematicId) throws Exception;
/**
* This method is called when the building and WorldEdit permissions on the plot need to be changed.
diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/stage/tasks/PlotSchematicPasteTask.java b/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/stage/tasks/PlotSchematicPasteTask.java
index bc7e7e10..e1975aaa 100644
--- a/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/stage/tasks/PlotSchematicPasteTask.java
+++ b/src/main/java/com/alpsbte/plotsystem/core/system/tutorial/stage/tasks/PlotSchematicPasteTask.java
@@ -4,8 +4,6 @@
import com.alpsbte.plotsystem.core.system.tutorial.PlotTutorial;
import org.bukkit.entity.Player;
-import java.io.IOException;
-
public class PlotSchematicPasteTask extends AbstractTask {
private final int schematicId;
@@ -20,7 +18,7 @@ public void performTask() {
if (tutorial != null) {
try {
tutorial.onPlotSchematicPaste(player.getUniqueId(), schematicId);
- } catch (IOException ex) {
+ } catch (Exception ex) {
tutorial.onException(ex);
return;
}
diff --git a/src/main/java/com/alpsbte/plotsystem/utils/Utils.java b/src/main/java/com/alpsbte/plotsystem/utils/Utils.java
index d2f9dbaf..9cbd1d47 100644
--- a/src/main/java/com/alpsbte/plotsystem/utils/Utils.java
+++ b/src/main/java/com/alpsbte/plotsystem/utils/Utils.java
@@ -40,6 +40,9 @@
import java.util.Objects;
import java.util.Random;
import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
import static com.alpsbte.plotsystem.core.system.tutorial.utils.TutorialUtils.TEXT_HIGHLIGHT_END;
import static com.alpsbte.plotsystem.core.system.tutorial.utils.TutorialUtils.TEXT_HIGHLIGHT_START;
@@ -103,6 +106,34 @@ public static ItemStack getConfiguredItem(@NotNull String material, Object custo
return builder.build();
}
+ public static CompletableFuture runSync(Callable task) {
+ CompletableFuture future = new CompletableFuture<>();
+ Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> {
+ try {
+ var result = task.call();
+ future.complete(result);
+ } catch (Exception e) {
+ future.completeExceptionally(e);
+ }
+ });
+
+ return future;
+ }
+
+ public static CompletableFuture supplySync(Callable task) {
+ CompletableFuture future = new CompletableFuture<>();
+ Executor executor = Bukkit.getScheduler().getMainThreadExecutor(PlotSystem.getPlugin());
+ executor.execute(() -> {
+ try {
+ var result = task.call();
+ future.complete(result);
+ } catch (Exception e) {
+ future.completeExceptionally(e);
+ }
+ });
+ return future;
+ }
+
public static class SoundUtils {
private SoundUtils() {}