All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.plotsquared.core.plot.PlotModificationManager Maven / Gradle / Ivy

/*
 * PlotSquared, a land and world management plugin for Minecraft.
 * Copyright (C) IntellectualSites 
 * Copyright (C) IntellectualSites team and contributors
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package com.plotsquared.core.plot;

import com.google.inject.Inject;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.ConfigurationUtil;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.Caption;
import com.plotsquared.core.configuration.caption.LocaleHolder;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.database.DBFunc;
import com.plotsquared.core.events.PlotComponentSetEvent;
import com.plotsquared.core.events.PlotMergeEvent;
import com.plotsquared.core.events.PlotUnlinkEvent;
import com.plotsquared.core.events.Result;
import com.plotsquared.core.generator.ClassicPlotWorld;
import com.plotsquared.core.generator.SquarePlotWorld;
import com.plotsquared.core.inject.factory.ProgressSubscriberFactory;
import com.plotsquared.core.location.Direction;
import com.plotsquared.core.location.Location;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.flag.PlotFlag;
import com.plotsquared.core.queue.QueueCoordinator;
import com.plotsquared.core.util.task.TaskManager;
import com.plotsquared.core.util.task.TaskTime;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockTypes;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * Manager that handles {@link Plot} modifications
 */
public final class PlotModificationManager {

    private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + PlotModificationManager.class.getSimpleName());

    private final Plot plot;
    private final ProgressSubscriberFactory subscriberFactory;

    @Inject
    PlotModificationManager(final @NonNull Plot plot) {
        this.plot = plot;
        this.subscriberFactory = PlotSquared.platform().injector().getInstance(ProgressSubscriberFactory.class);
    }

    /**
     * Copy a plot to a location, both physically and the settings
     *
     * @param destination destination plot
     * @param actor       the actor associated with the copy
     * @return Future that completes with {@code true} if the copy was successful, else {@code false}
     */
    public CompletableFuture copy(final @NonNull Plot destination, @Nullable PlotPlayer actor) {
        final CompletableFuture future = new CompletableFuture<>();
        final PlotId offset = PlotId.of(
                destination.getId().getX() - this.plot.getId().getX(),
                destination.getId().getY() - this.plot.getId().getY()
        );
        final Location db = destination.getBottomAbs();
        final Location ob = this.plot.getBottomAbs();
        final int offsetX = db.getX() - ob.getX();
        final int offsetZ = db.getZ() - ob.getZ();
        if (!this.plot.hasOwner()) {
            TaskManager.runTaskLater(() -> future.complete(false), TaskTime.ticks(1L));
            return future;
        }
        final Set plots = this.plot.getConnectedPlots();
        for (final Plot plot : plots) {
            final Plot other = plot.getRelative(destination.getArea(), offset.getX(), offset.getY());
            if (other.hasOwner()) {
                TaskManager.runTaskLater(() -> future.complete(false), TaskTime.ticks(1L));
                return future;
            }
        }
        // world border
        destination.updateWorldBorder();
        // copy data
        for (final Plot plot : plots) {
            final Plot other = plot.getRelative(destination.getArea(), offset.getX(), offset.getY());
            other.getPlotModificationManager().create(plot.getOwner(), false);
            if (!plot.getFlagContainer().getFlagMap().isEmpty()) {
                final Collection> existingFlags = other.getFlags();
                other.getFlagContainer().clearLocal();
                other.getFlagContainer().addAll(plot.getFlagContainer().getFlagMap().values());
                // Update the database
                for (final PlotFlag flag : existingFlags) {
                    final PlotFlag newFlag = other.getFlagContainer().queryLocal(flag.getClass());
                    if (other.getFlagContainer().queryLocal(flag.getClass()) == null) {
                        DBFunc.removeFlag(other, flag);
                    } else {
                        DBFunc.setFlag(other, newFlag);
                    }
                }
            }
            if (plot.isMerged()) {
                other.setMerged(plot.getMerged());
            }
            if (plot.members != null && !plot.members.isEmpty()) {
                other.members = plot.members;
                for (UUID member : plot.members) {
                    DBFunc.setMember(other, member);
                }
            }
            if (plot.trusted != null && !plot.trusted.isEmpty()) {
                other.trusted = plot.trusted;
                for (UUID trusted : plot.trusted) {
                    DBFunc.setTrusted(other, trusted);
                }
            }
            if (plot.denied != null && !plot.denied.isEmpty()) {
                other.denied = plot.denied;
                for (UUID denied : plot.denied) {
                    DBFunc.setDenied(other, denied);
                }
            }
        }
        // copy terrain
        final ArrayDeque regions = new ArrayDeque<>(this.plot.getRegions());
        final Runnable run = new Runnable() {
            @Override
            public void run() {
                if (regions.isEmpty()) {
                    final QueueCoordinator queue = plot.getArea().getQueue();
                    for (final Plot current : plot.getConnectedPlots()) {
                        destination.getManager().claimPlot(current, queue);
                    }
                    if (queue.size() > 0) {
                        queue.enqueue();
                    }
                    destination.getPlotModificationManager().setSign();
                    future.complete(true);
                    return;
                }
                CuboidRegion region = regions.poll();
                Location[] corners = Plot.getCorners(plot.getWorldName(), region);
                Location pos1 = corners[0];
                Location pos2 = corners[1];
                Location newPos = pos1.add(offsetX, 0, offsetZ).withWorld(destination.getWorldName());
                PlotSquared.platform().regionManager().copyRegion(pos1, pos2, newPos, actor, this);
            }
        };
        run.run();
        return future;
    }

    /**
     * Clear the plot
     *
     * 

* Use {@link #deletePlot(PlotPlayer, Runnable)} to clear and delete a plot *

* * @param whenDone A runnable to execute when clearing finishes, or null * @see #clear(boolean, boolean, PlotPlayer, Runnable) */ public void clear(final @Nullable Runnable whenDone) { this.clear(false, false, null, whenDone); } /** * Clear the plot * *

* Use {@link #deletePlot(PlotPlayer, Runnable)} to clear and delete a plot *

* * @param checkRunning Whether or not already executing tasks should be checked * @param isDelete Whether or not the plot is being deleted * @param actor The actor clearing the plot * @param whenDone A runnable to execute when clearing finishes, or null */ public boolean clear( final boolean checkRunning, final boolean isDelete, final @Nullable PlotPlayer actor, final @Nullable Runnable whenDone ) { if (checkRunning && this.plot.getRunning() != 0) { return false; } final Set regions = this.plot.getRegions(); final Set plots = this.plot.getConnectedPlots(); final ArrayDeque queue = new ArrayDeque<>(plots); if (isDelete) { this.removeSign(); } final PlotManager manager = this.plot.getArea().getPlotManager(); Runnable run = new Runnable() { @Override public void run() { if (queue.isEmpty()) { Runnable run = () -> { for (CuboidRegion region : regions) { Location[] corners = Plot.getCorners(plot.getWorldName(), region); PlotSquared.platform().regionManager().clearAllEntities(corners[0], corners[1]); } TaskManager.runTask(whenDone); }; QueueCoordinator queue = plot.getArea().getQueue(); for (Plot current : plots) { if (isDelete || !current.hasOwner()) { manager.unClaimPlot(current, null, queue); } else { manager.claimPlot(current, queue); if (plot.getArea() instanceof ClassicPlotWorld cpw) { manager.setComponent(current.getId(), "wall", cpw.WALL_FILLING.toPattern(), actor, queue); } } } if (queue.size() > 0) { queue.setCompleteTask(run); queue.enqueue(); return; } run.run(); return; } Plot current = queue.poll(); current.clearCache(); if (plot.getArea().getTerrain() != PlotAreaTerrainType.NONE) { try { PlotSquared.platform().regionManager().regenerateRegion( current.getBottomAbs(), current.getTopAbs(), false, this ); } catch (UnsupportedOperationException exception) { exception.printStackTrace(); return; } return; } manager.clearPlot(current, this, actor, null); } }; PlotUnlinkEvent event = PlotSquared.get().getEventDispatcher() .callUnlink( this.plot.getArea(), this.plot, true, !isDelete, isDelete ? PlotUnlinkEvent.REASON.DELETE : PlotUnlinkEvent.REASON.CLEAR ); if (event.getEventResult() != Result.DENY) { if (this.unlinkPlot(event.isCreateRoad(), event.isCreateSign(), run)) { PlotSquared.get().getEventDispatcher().callPostUnlink(plot, event.getReason()); } } else { run.run(); } return true; } /** * Sets the biome for a plot asynchronously. * * @param biome The biome e.g. "forest" * @param whenDone The task to run when finished, or null */ public void setBiome(final @Nullable BiomeType biome, final @NonNull Runnable whenDone) { final ArrayDeque regions = new ArrayDeque<>(this.plot.getRegions()); final int extendBiome; if (this.plot.getArea() instanceof SquarePlotWorld) { extendBiome = (((SquarePlotWorld) this.plot.getArea()).ROAD_WIDTH > 0) ? 1 : 0; } else { extendBiome = 0; } Runnable run = new Runnable() { @Override public void run() { if (regions.isEmpty()) { TaskManager.runTask(whenDone); return; } CuboidRegion region = regions.poll(); PlotSquared.platform().regionManager().setBiome(region, extendBiome, biome, plot.getArea(), this); } }; run.run(); } /** * Unlink the plot and all connected plots. * * @param createRoad whether to recreate road * @param createSign whether to recreate signs * @return success/!cancelled */ public boolean unlinkPlot(final boolean createRoad, final boolean createSign) { return unlinkPlot(createRoad, createSign, null); } /** * Unlink the plot and all connected plots. * * @param createRoad whether to recreate road * @param createSign whether to recreate signs * @param whenDone Task to run when unlink is complete * @return success/!cancelled * @since 6.10.9 */ public boolean unlinkPlot(final boolean createRoad, final boolean createSign, final Runnable whenDone) { if (!this.plot.isMerged()) { if (whenDone != null) { whenDone.run(); } return false; } final Set plots = this.plot.getConnectedPlots(); ArrayList ids = new ArrayList<>(plots.size()); for (Plot current : plots) { current.setHome(null); current.clearCache(); ids.add(current.getId()); } this.plot.clearRatings(); QueueCoordinator queue = this.plot.getArea().getQueue(); if (createSign) { this.removeSign(); } PlotManager manager = this.plot.getArea().getPlotManager(); if (createRoad) { manager.startPlotUnlink(ids, queue); } if (this.plot.getArea().getTerrain() != PlotAreaTerrainType.ALL && createRoad) { for (Plot current : plots) { if (current.isMerged(Direction.EAST)) { manager.createRoadEast(current, queue); if (current.isMerged(Direction.SOUTH)) { manager.createRoadSouth(current, queue); if (current.isMerged(Direction.SOUTHEAST)) { manager.createRoadSouthEast(current, queue); } } } if (current.isMerged(Direction.SOUTH)) { manager.createRoadSouth(current, queue); } } } for (Plot current : plots) { boolean[] merged = new boolean[]{false, false, false, false}; current.setMerged(merged); } if (createSign) { queue.setCompleteTask(() -> TaskManager.runTaskAsync(() -> { List> tasks = plots.stream().map(current -> PlotSquared.platform().playerManager() .getUsernameCaption(current.getOwnerAbs()) .thenAccept(caption -> current .getPlotModificationManager() .setSign(caption.getComponent(LocaleHolder.console())))) .toList(); CompletableFuture.allOf(tasks.toArray(CompletableFuture[]::new)).whenComplete((unused, throwable) -> { if (whenDone != null) { TaskManager.runTask(whenDone); } }); })); } else if (whenDone != null) { queue.setCompleteTask(whenDone); } if (createRoad) { manager.finishPlotUnlink(ids, queue); } queue.enqueue(); return true; } /** * Sets the sign for a plot to a specific name * * @param name name */ public void setSign(final @NonNull String name) { if (!this.plot.isLoaded()) { return; } PlotManager manager = this.plot.getArea().getPlotManager(); if (this.plot.getArea().allowSigns()) { Location location = manager.getSignLoc(this.plot); String id = this.plot.getId().toString(); Caption[] lines = new Caption[]{TranslatableCaption.of("signs.owner_sign_line_1"), TranslatableCaption.of( "signs.owner_sign_line_2"), TranslatableCaption.of("signs.owner_sign_line_3"), TranslatableCaption.of("signs.owner_sign_line_4")}; PlotSquared.platform().worldUtil().setSign(location, lines, TagResolver.builder() .tag("id", Tag.inserting(Component.text(id))) .tag("owner", Tag.inserting(Component.text(name))) .build()); } } /** * Resend all chunks inside the plot to nearby players
* This should not need to be called */ public void refreshChunks() { final HashSet chunks = new HashSet<>(); for (final CuboidRegion region : this.plot.getRegions()) { for (int x = region.getMinimumPoint().getX() >> 4; x <= region.getMaximumPoint().getX() >> 4; x++) { for (int z = region.getMinimumPoint().getZ() >> 4; z <= region.getMaximumPoint().getZ() >> 4; z++) { if (chunks.add(BlockVector2.at(x, z))) { PlotSquared.platform().worldUtil().refreshChunk(x, z, this.plot.getWorldName()); } } } } } /** * Remove the plot sign if it is set. */ public void removeSign() { PlotManager manager = this.plot.getArea().getPlotManager(); if (!this.plot.getArea().allowSigns()) { return; } Location location = manager.getSignLoc(this.plot); QueueCoordinator queue = PlotSquared.platform().globalBlockQueue().getNewQueue(PlotSquared .platform() .worldUtil() .getWeWorld(this.plot.getWorldName())); queue.setBlock(location.getX(), location.getY(), location.getZ(), BlockTypes.AIR.getDefaultState()); queue.enqueue(); } /** * Sets the plot sign if plot signs are enabled. */ public void setSign() { if (!this.plot.hasOwner()) { this.setSign("unknown"); return; } PlotSquared.get().getImpromptuUUIDPipeline().getSingle( this.plot.getOwnerAbs(), (username, sign) -> this.setSign(username) ); } /** * Register a plot and create it in the database
* - The plot will not be created if the owner is null
* - Any setting from before plot creation will not be saved until the server is stopped properly. i.e. Set any values/options after plot * creation. * * @return {@code true} if plot was created successfully */ public boolean create() { return this.create(this.plot.getOwnerAbs(), true); } /** * Register a plot and create it in the database
* - The plot will not be created if the owner is null
* - Any setting from before plot creation will not be saved until the server is stopped properly. i.e. Set any values/options after plot * creation. * * @param uuid the uuid of the plot owner * @param notify notify * @return {@code true} if plot was created successfully, else {@code false} */ public boolean create(final @NonNull UUID uuid, final boolean notify) { this.plot.setOwnerAbs(uuid); Plot existing = this.plot.getArea().getOwnedPlotAbs(this.plot.getId()); if (existing != null) { throw new IllegalStateException("Plot already exists!"); } if (notify) { Integer meta = (Integer) this.plot.getArea().getMeta("worldBorder"); if (meta != null) { this.plot.updateWorldBorder(); } } this.plot.clearCache(); this.plot.getTrusted().clear(); this.plot.getMembers().clear(); this.plot.getDenied().clear(); this.plot.settings = new PlotSettings(); if (this.plot.getArea().addPlot(this.plot)) { DBFunc.createPlotAndSettings(this.plot, () -> { PlotArea plotworld = plot.getArea(); if (notify && plotworld.isAutoMerge()) { final PlotPlayer player = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); PlotMergeEvent event = PlotSquared.get().getEventDispatcher().callMerge( this.plot, Direction.ALL, Integer.MAX_VALUE, player ); if (event.getEventResult() == Result.DENY) { if (player != null) { player.sendMessage( TranslatableCaption.of("events.event_denied"), TagResolver.resolver("value", Tag.inserting(Component.text("Auto merge on claim"))) ); } return; } if (plot.getPlotModificationManager().autoMerge(event.getDir(), event.getMax(), uuid, player, true)) { PlotSquared.get().getEventDispatcher().callPostMerge(player, plot); } } }); return true; } LOGGER.info( "Failed to add plot {} to plot area {}", this.plot.getId().toCommaSeparatedString(), this.plot.getArea().toString() ); return false; } /** * Auto merge a plot in a specific direction. * * @param dir the direction to merge * @param max the max number of merges to do * @param uuid the UUID it is allowed to merge with * @param actor The actor executing the task * @param removeRoads whether to remove roads * @return {@code true} if a merge takes place, else {@code false} */ public boolean autoMerge( final @NonNull Direction dir, int max, final @NonNull UUID uuid, @Nullable PlotPlayer actor, final boolean removeRoads ) { //Ignore merging if there is no owner for the plot if (!this.plot.hasOwner()) { return false; } Set connected = this.plot.getConnectedPlots(); HashSet merged = connected.stream().map(Plot::getId).collect(Collectors.toCollection(HashSet::new)); ArrayDeque frontier = new ArrayDeque<>(connected); Plot current; boolean toReturn = false; HashSet visited = new HashSet<>(); QueueCoordinator queue = this.plot.getArea().getQueue(); while ((current = frontier.poll()) != null && max >= 0) { if (visited.contains(current)) { continue; } visited.add(current); Set plots; if ((dir == Direction.ALL || dir == Direction.NORTH) && !current.isMerged(Direction.NORTH)) { Plot other = current.getRelative(Direction.NORTH); if (other != null && other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) || (plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1)) { current.mergePlot(other, removeRoads, queue); merged.add(current.getId()); merged.add(other.getId()); toReturn = true; if (removeRoads) { ArrayList ids = new ArrayList<>(); ids.add(current.getId()); ids.add(other.getId()); this.plot.getManager().finishPlotMerge(ids, queue); } } } if (max >= 0 && (dir == Direction.ALL || dir == Direction.EAST) && !current.isMerged(Direction.EAST)) { Plot other = current.getRelative(Direction.EAST); if (other != null && other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) || (plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1)) { current.mergePlot(other, removeRoads, queue); merged.add(current.getId()); merged.add(other.getId()); toReturn = true; if (removeRoads) { ArrayList ids = new ArrayList<>(); ids.add(current.getId()); ids.add(other.getId()); this.plot.getManager().finishPlotMerge(ids, queue); } } } if (max >= 0 && (dir == Direction.ALL || dir == Direction.SOUTH) && !current.isMerged(Direction.SOUTH)) { Plot other = current.getRelative(Direction.SOUTH); if (other != null && other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) || (plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1)) { current.mergePlot(other, removeRoads, queue); merged.add(current.getId()); merged.add(other.getId()); toReturn = true; if (removeRoads) { ArrayList ids = new ArrayList<>(); ids.add(current.getId()); ids.add(other.getId()); this.plot.getManager().finishPlotMerge(ids, queue); } } } if (max >= 0 && (dir == Direction.ALL || dir == Direction.WEST) && !current.isMerged(Direction.WEST)) { Plot other = current.getRelative(Direction.WEST); if (other != null && other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) || (plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1)) { current.mergePlot(other, removeRoads, queue); merged.add(current.getId()); merged.add(other.getId()); toReturn = true; if (removeRoads) { ArrayList ids = new ArrayList<>(); ids.add(current.getId()); ids.add(other.getId()); this.plot.getManager().finishPlotMerge(ids, queue); } } } } if (actor != null && Settings.QUEUE.NOTIFY_PROGRESS) { queue.addProgressSubscriber(subscriberFactory.createWithActor(actor)); } if (queue.size() > 0) { queue.enqueue(); } visited.forEach(Plot::clearCache); return toReturn; } /** * Moves a plot physically, as well as the corresponding settings. * * @param destination Plot moved to * @param actor The actor executing the task * @param whenDone task when done * @param allowSwap whether to swap plots * @return {@code true} if the move was successful, else {@code false} */ public @NonNull CompletableFuture move( final @NonNull Plot destination, final @Nullable PlotPlayer actor, final @NonNull Runnable whenDone, final boolean allowSwap ) { final PlotId offset = PlotId.of( destination.getId().getX() - this.plot.getId().getX(), destination.getId().getY() - this.plot.getId().getY() ); Location db = destination.getBottomAbs(); Location ob = this.plot.getBottomAbs(); final int offsetX = db.getX() - ob.getX(); final int offsetZ = db.getZ() - ob.getZ(); if (!this.plot.hasOwner()) { TaskManager.runTaskLater(whenDone, TaskTime.ticks(1L)); return CompletableFuture.completedFuture(false); } AtomicBoolean occupied = new AtomicBoolean(false); Set plots = this.plot.getConnectedPlots(); for (Plot plot : plots) { Plot other = plot.getRelative(destination.getArea(), offset.getX(), offset.getY()); if (other.hasOwner()) { if (!allowSwap) { TaskManager.runTaskLater(whenDone, TaskTime.ticks(1L)); return CompletableFuture.completedFuture(false); } occupied.set(true); } else { plot.getPlotModificationManager().removeSign(); } } // world border destination.updateWorldBorder(); final ArrayDeque regions = new ArrayDeque<>(this.plot.getRegions()); // move / swap data final PlotArea originArea = this.plot.getArea(); final Iterator plotIterator = plots.iterator(); CompletableFuture future = null; if (plotIterator.hasNext()) { while (plotIterator.hasNext()) { final Plot plot = plotIterator.next(); final Plot other = plot.getRelative(destination.getArea(), offset.getX(), offset.getY()); final CompletableFuture swapResult = plot.swapData(other); if (future == null) { future = swapResult; } else { future = future.thenCombine(swapResult, (fn, th) -> fn); } } } else { future = CompletableFuture.completedFuture(true); } return future.thenApply(result -> { if (!result) { return false; } // copy terrain if (occupied.get()) { new Runnable() { @Override public void run() { if (regions.isEmpty()) { // Update signs destination.getPlotModificationManager().setSign(); setSign(); // Run final tasks TaskManager.runTask(whenDone); } else { CuboidRegion region = regions.poll(); Location[] corners = Plot.getCorners(plot.getWorldName(), region); Location pos1 = corners[0]; Location pos2 = corners[1]; Location pos3 = pos1.add(offsetX, 0, offsetZ).withWorld(destination.getWorldName()); PlotSquared.platform().regionManager().swap(pos1, pos2, pos3, actor, this); } } }.run(); } else { new Runnable() { @Override public void run() { if (regions.isEmpty()) { Plot plot = destination.getRelative(0, 0); Plot originPlot = originArea.getPlotAbs(PlotId.of( plot.getId().getX() - offset.getX(), plot.getId().getY() - offset.getY() )); final Runnable clearDone = () -> { QueueCoordinator queue = PlotModificationManager.this.plot.getArea().getQueue(); for (final Plot current : plot.getConnectedPlots()) { PlotModificationManager.this.plot.getManager().claimPlot(current, queue); } if (queue.size() > 0) { queue.enqueue(); } plot.getPlotModificationManager().setSign(); TaskManager.runTask(whenDone); }; if (originPlot != null) { originPlot.getPlotModificationManager().clear(false, true, actor, clearDone); } else { clearDone.run(); } return; } final Runnable task = this; CuboidRegion region = regions.poll(); Location[] corners = Plot.getCorners( PlotModificationManager.this.plot.getWorldName(), region ); final Location pos1 = corners[0]; final Location pos2 = corners[1]; Location newPos = pos1.add(offsetX, 0, offsetZ).withWorld(destination.getWorldName()); PlotSquared.platform().regionManager().copyRegion(pos1, pos2, newPos, actor, task); } }.run(); } return true; }); } /** * Unlink a plot and remove the roads * * @return {@code true} if plot was linked * @see #unlinkPlot(boolean, boolean) */ public boolean unlink() { return this.unlinkPlot(true, true); } /** * Swap the plot contents and settings with another location
* - The destination must correspond to a valid plot of equal dimensions * * @param destination The other plot to swap with * @param actor The actor executing the task * @param whenDone A task to run when finished, or null * @return Future that completes with {@code true} if the swap was successful, else {@code false} */ public @NonNull CompletableFuture swap( final @NonNull Plot destination, @Nullable PlotPlayer actor, final @NonNull Runnable whenDone ) { return this.move(destination, actor, whenDone, true); } /** * Moves the plot to an empty location
* - The location must be empty * * @param destination Where to move the plot * @param actor The actor executing the task * @param whenDone A task to run when done, or null * @return Future that completes with {@code true} if the move was successful, else {@code false} */ public @NonNull CompletableFuture move( final @NonNull Plot destination, @Nullable PlotPlayer actor, final @NonNull Runnable whenDone ) { return this.move(destination, actor, whenDone, false); } /** * Sets a component for a plot to the provided blocks
* - E.g. floor, wall, border etc.
* - The available components depend on the generator being used
* * @param component Component to set * @param blocks Pattern to use the generation * @param actor The actor executing the task * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, * otherwise writes to the queue but does not enqueue. * @return {@code true} if the component was set successfully, else {@code false} */ public boolean setComponent( final @NonNull String component, final @NonNull Pattern blocks, @Nullable PlotPlayer actor, final @Nullable QueueCoordinator queue ) { final PlotComponentSetEvent event = PlotSquared.get().getEventDispatcher().callComponentSet(this.plot, component, blocks); return this.plot.getManager().setComponent(this.plot.getId(), event.getComponent(), event.getPattern(), actor, queue); } /** * Delete a plot (use null for the runnable if you don't need to be notified on completion) * *

* Use {@link PlotModificationManager#clear(boolean, boolean, PlotPlayer, Runnable)} to simply clear a plot *

* * @param actor The actor executing the task * @param whenDone task to run when plot has been deleted. Nullable * @return {@code true} if the deletion was successful, {@code false} if not * @see PlotSquared#removePlot(Plot, boolean) */ public boolean deletePlot(@Nullable PlotPlayer actor, final Runnable whenDone) { if (!this.plot.hasOwner()) { return false; } final Set plots = this.plot.getConnectedPlots(); this.clear(false, true, actor, () -> { for (Plot current : plots) { current.unclaim(); } TaskManager.runTask(whenDone); }); return true; } /** * Sets components such as border, wall, floor. * (components are generator specific) * * @param component component to set * @param blocks string of block(s) to set component to * @param actor The player executing the task * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, * otherwise writes to the queue but does not enqueue. * @return {@code true} if the update was successful, {@code false} if not */ @Deprecated public boolean setComponent( String component, String blocks, @Nullable PlotPlayer actor, @Nullable QueueCoordinator queue ) { final BlockBucket parsed = ConfigurationUtil.BLOCK_BUCKET.parseString(blocks); if (parsed != null && parsed.isEmpty()) { return false; } return this.setComponent(component, parsed.toPattern(), actor, queue); } /** * Remove the south road section of a plot
* - Used when a plot is merged
* * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, * otherwise writes to the queue but does not enqueue. */ public void removeRoadSouth(final @Nullable QueueCoordinator queue) { if (this.plot.getArea().getType() != PlotAreaType.NORMAL && this.plot .getArea() .getTerrain() == PlotAreaTerrainType.ROAD) { Plot other = this.plot.getRelative(Direction.SOUTH); Location bot = other.getBottomAbs(); Location top = this.plot.getTopAbs(); Location pos1 = Location.at(this.plot.getWorldName(), bot.getX(), plot.getArea().getMinGenHeight(), top.getZ()); Location pos2 = Location.at(this.plot.getWorldName(), top.getX(), plot.getArea().getMaxGenHeight(), bot.getZ()); PlotSquared.platform().regionManager().regenerateRegion(pos1, pos2, true, null); } else if (this.plot.getArea().getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove this.plot.getManager().removeRoadSouth(this.plot, queue); } } /** * Remove the east road section of a plot
* - Used when a plot is merged
* * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, * otherwise writes to the queue but does not enqueue. */ public void removeRoadEast(@Nullable QueueCoordinator queue) { if (this.plot.getArea().getType() != PlotAreaType.NORMAL && this.plot .getArea() .getTerrain() == PlotAreaTerrainType.ROAD) { Plot other = this.plot.getRelative(Direction.EAST); Location bot = other.getBottomAbs(); Location top = this.plot.getTopAbs(); Location pos1 = Location.at(this.plot.getWorldName(), top.getX(), plot.getArea().getMinGenHeight(), bot.getZ()); Location pos2 = Location.at(this.plot.getWorldName(), bot.getX(), plot.getArea().getMaxGenHeight(), top.getZ()); PlotSquared.platform().regionManager().regenerateRegion(pos1, pos2, true, null); } else if (this.plot.getArea().getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove this.plot.getArea().getPlotManager().removeRoadEast(this.plot, queue); } } /** * Remove the SE road (only effects terrain) * * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, * otherwise writes to the queue but does not enqueue. */ public void removeRoadSouthEast(@Nullable QueueCoordinator queue) { if (this.plot.getArea().getType() != PlotAreaType.NORMAL && this.plot .getArea() .getTerrain() == PlotAreaTerrainType.ROAD) { Plot other = this.plot.getRelative(1, 1); Location pos1 = this.plot.getTopAbs().add(1, 0, 1); Location pos2 = other.getBottomAbs().subtract(1, 0, 1); PlotSquared.platform().regionManager().regenerateRegion(pos1, pos2, true, null); } else if (this.plot.getArea().getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove this.plot.getArea().getPlotManager().removeRoadSouthEast(this.plot, queue); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy