From 3ede0447b024b34f62150091707d6a5627d0768f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Thu, 21 May 2020 20:06:04 +0200 Subject: [PATCH 01/13] Fix up the plot area nightmare --- Core/build.gradle | 2 + .../com/plotsquared/core/plot/PlotWorld.java | 105 +++++++ .../plot/world/DefaultPlotAreaManager.java | 269 +++++------------- .../core/plot/world/PlotAreaManager.java | 3 +- .../core/plot/world/ScatteredPlotWorld.java | 110 +++++++ .../core/plot/world/StandardPlotWorld.java | 65 +++++ .../com/plotsquared/core/util/RegionUtil.java | 10 + 7 files changed, 372 insertions(+), 192 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/plot/PlotWorld.java create mode 100644 Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java create mode 100644 Core/src/main/java/com/plotsquared/core/plot/world/StandardPlotWorld.java diff --git a/Core/build.gradle b/Core/build.gradle index ee6edfda2..8581a39a4 100644 --- a/Core/build.gradle +++ b/Core/build.gradle @@ -16,6 +16,7 @@ dependencies { testAnnotationProcessor("org.projectlombok:lombok:1.18.8") implementation("org.jetbrains.kotlin:kotlin-stdlib:1.3.72") implementation("org.jetbrains:annotations:19.0.0") + implementation 'com.github.davidmoten:rtree:0.8.7' } sourceCompatibility = 1.8 @@ -73,6 +74,7 @@ shadowJar { include(dependency("net.kyori:text-serializer-gson:3.0.2")) include(dependency("net.kyori:text-serializer-legacy:3.0.2")) include(dependency("net.kyori:text-serializer-plain:3.0.2")) + include(dependency("com.github.davidmoten:rtree:0.8.7")) } relocate('net.kyori.text', 'com.plotsquared.formatting.text') relocate("org.json", "com.plotsquared.json") { diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotWorld.java b/Core/src/main/java/com/plotsquared/core/plot/PlotWorld.java new file mode 100644 index 000000000..ed7b854c2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotWorld.java @@ -0,0 +1,105 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.plot; + +import com.plotsquared.core.location.Location; +import com.sk89q.worldedit.regions.CuboidRegion; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * A world that contains plots + */ +@EqualsAndHashCode +public abstract class PlotWorld { + + private final String world; + + /** + * Create a new plot world with a given world name + * + * @param world World name + */ + protected PlotWorld(@NotNull final String world) { + this.world = world; + } + + /** + * Get the plot area that contains the given location, or null + * if the location is not a part of a plot area. + * + * @param location Location + * @return Containing plot area, or null + */ + @Nullable public abstract PlotArea getArea(@NotNull final Location location); + + /** + * Get all plot areas in the world + * + * @return All plot areas in the world + */ + @NotNull public abstract Collection getAreas(); + + /** + * Get all plot areas in a specified region + * + * @param region Region + * @return All areas in the region + */ + @NotNull public abstract Collection getAreasInRegion( + @NotNull final CuboidRegion region); + + /** + * Register a new area in the world + * + * @param area Plot area + */ + public void addArea(@NotNull final PlotArea area) { + throw new UnsupportedOperationException("This world type does not allow adding new areas"); + } + + /** + * Remove an area from the world + * + * @param area Plot area + */ + public void removeArea(@NotNull final PlotArea area) { + throw new UnsupportedOperationException("This world type does not allow removing areas"); + } + + /** + * Get the world name + * + * @return World name + */ + public String getWorld() { + return this.world; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java b/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java index 833bf3d4f..f86b5b8b6 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java @@ -25,143 +25,96 @@ */ package com.plotsquared.core.plot.world; -import com.plotsquared.core.collection.QuadMap; import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotAreaType; +import com.plotsquared.core.plot.PlotWorld; import com.plotsquared.core.util.StringMan; import com.sk89q.worldedit.regions.CuboidRegion; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; import java.util.Set; public class DefaultPlotAreaManager implements PlotAreaManager { final PlotArea[] noPlotAreas = new PlotArea[0]; - // All plot areas mapped by world - private final HashMap plotAreaMap = new HashMap<>(); - // All plot areas mapped by position - private final HashMap> plotAreaGrid = new HashMap<>(); - private final HashSet plotAreaHashCheck = new HashSet<>(); - // All plot areas - private PlotArea[] plotAreas = new PlotArea[0]; + + private final Map plotWorlds = new HashMap<>(); // Optimization if there are no hash collisions private boolean plotAreaHasCollision = false; - private String[] worlds = new String[0]; @Override public PlotArea[] getAllPlotAreas() { - return plotAreas; - } - - @Override public PlotArea getApplicablePlotArea(Location location) { - switch (this.plotAreas.length) { - case 0: - return null; - case 1: - return this.plotAreas[0].getWorldHash() == location.getWorld().hashCode() - && this.plotAreas[0].contains(location) && (!this.plotAreaHasCollision - || location.getWorld().equals(this.plotAreas[0].getWorldName())) ? - this.plotAreas[0] : - null; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - String world = location.getWorld(); - int hash = world.hashCode(); - for (PlotArea area : this.plotAreas) { - if (hash == area.getWorldHash()) { - if (area.contains(location.getX(), location.getZ()) && ( - !this.plotAreaHasCollision || world.equals(area.getWorldName()))) { - return area; - } - } - } - return null; - default: - PlotArea[] areas = this.plotAreaMap.get(location.getWorld()); - if (areas == null) { - return null; - } - int z; - int x; - switch (areas.length) { - case 1: - return areas[0]; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - x = location.getX(); - z = location.getZ(); - for (PlotArea area : areas) { - if (area.contains(x, z)) { - return area; - } - } - return null; - default: - QuadMap search = this.plotAreaGrid.get(location.getWorld()); - return search.get(location.getX(), location.getZ()); - } + final Set area = new HashSet<>(); + for (final PlotWorld world : plotWorlds.values()) { + area.addAll(world.getAreas()); } + return area.toArray(new PlotArea[0]); } - @Override public void addPlotArea(PlotArea plotArea) { - HashSet localAreas = - new HashSet<>(Arrays.asList(getPlotAreas(plotArea.getWorldName(), null))); - HashSet globalAreas = new HashSet<>(Arrays.asList(plotAreas)); - localAreas.add(plotArea); - globalAreas.add(plotArea); - this.plotAreas = globalAreas.toArray(new PlotArea[0]); - this.plotAreaMap.put(plotArea.getWorldName(), localAreas.toArray(new PlotArea[0])); - QuadMap map = this.plotAreaGrid.get(plotArea.getWorldName()); - if (map == null) { - map = new QuadMap(Integer.MAX_VALUE, 0, 0) { - @Override public CuboidRegion getRegion(PlotArea value) { - return value.getRegion(); - } - }; - this.plotAreaGrid.put(plotArea.getWorldName(), map); + @Override @Nullable public PlotArea getApplicablePlotArea(final Location location) { + if (location == null) { + return null; } - map.add(plotArea); + final PlotWorld world = this.plotWorlds.get(location.getWorld()); + if (world == null) { + return null; + } + return world.getArea(location); } - @Override public void removePlotArea(PlotArea area) { - ArrayList globalAreas = new ArrayList<>(Arrays.asList(plotAreas)); - globalAreas.remove(area); - this.plotAreas = globalAreas.toArray(new PlotArea[0]); - if (globalAreas.isEmpty()) { - this.plotAreaMap.remove(area.getWorldName()); - this.plotAreaGrid.remove(area.getWorldName()); + @Override public void addPlotArea(final PlotArea plotArea) { + PlotWorld world = this.plotWorlds.get(plotArea.getWorldName()); + if (world != null) { + if (world instanceof StandardPlotWorld && world.getAreas().isEmpty()) { + this.plotWorlds.remove(plotArea.getWorldName()); + } else { + world.addArea(plotArea); + return; + } + } + if (plotArea.getType() != PlotAreaType.PARTIAL) { + world = new StandardPlotWorld(plotArea.getWorldName(), plotArea); } else { - this.plotAreaMap.put(area.getWorldName(), globalAreas.toArray(new PlotArea[0])); - this.plotAreaGrid.get(area.getWorldName()).remove(area); + world = new ScatteredPlotWorld(plotArea.getWorldName()); + world.addArea(plotArea); + } + this.plotWorlds.put(plotArea.getWorldName(), world); + } + + @Override public void removePlotArea(final PlotArea area) { + final PlotWorld world = this.plotWorlds.get(area.getWorldName()); + if (world == null) { + return; + } + if (world instanceof StandardPlotWorld) { + this.plotWorlds.remove(world.getWorld()); + } else { + world.removeArea(area); + if (world.getAreas().isEmpty()) { + this.plotWorlds.remove(world.getWorld()); + } } } - @Override public PlotArea getPlotArea(String world, String id) { - PlotArea[] areas = this.plotAreaMap.get(world); - if (areas == null) { + @Override public PlotArea getPlotArea(final String world, final String id) { + final PlotWorld plotWorld = this.plotWorlds.get(world); + if (plotWorld == null) { return null; } - if (areas.length == 1) { - return areas[0]; - } else if (id == null) { + final List areas = new ArrayList<>(plotWorld.getAreas()); + if (areas.size() == 1) { + return areas.get(0); + } + if (id == null) { return null; } - for (PlotArea area : areas) { + for (final PlotArea area : areas) { if (StringMan.isEqual(id, area.getId())) { return area; } @@ -169,103 +122,37 @@ public class DefaultPlotAreaManager implements PlotAreaManager { return null; } - @Override public PlotArea getPlotArea(@NotNull Location location) { - switch (this.plotAreas.length) { - case 0: - return null; - case 1: - PlotArea pa = this.plotAreas[0]; - if (pa.contains(location)) { - return pa; - } else { - return null; - } - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - String world = location.getWorld(); - int hash = world.hashCode(); - for (PlotArea area : this.plotAreas) { - if (hash == area.getWorldHash()) { - if (area.contains(location.getX(), location.getZ()) && ( - !this.plotAreaHasCollision || world.equals(area.getWorldName()))) { - return area; - } - } - } - return null; - default: - PlotArea[] areas = this.plotAreaMap.get(location.getWorld()); - if (areas == null) { - return null; - } - int x; - int z; - switch (areas.length) { - case 0: - PlotArea a = areas[0]; - return a.contains(location.getX(), location.getZ()) ? a : null; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - x = location.getX(); - z = location.getZ(); - for (PlotArea area : areas) { - if (area.contains(x, z)) { - return area; - } - } - return null; - default: - QuadMap search = this.plotAreaGrid.get(location.getWorld()); - return search.get(location.getX(), location.getZ()); - } - } + @Override public PlotArea getPlotArea(@NotNull final Location location) { + return this.getApplicablePlotArea(location); } - @Override public PlotArea[] getPlotAreas(String world, CuboidRegion region) { - if (region == null) { - PlotArea[] areas = this.plotAreaMap.get(world); - if (areas == null) { - return noPlotAreas; - } - return areas; - } - QuadMap areas = this.plotAreaGrid.get(world); - if (areas == null) { + @Override public PlotArea[] getPlotAreas(final String world, final CuboidRegion region) { + final PlotWorld plotWorld = this.plotWorlds.get(world); + if (plotWorld == null) { return noPlotAreas; - } else { - Set found = areas.get(region); - return found.toArray(new PlotArea[0]); } + if (region == null) { + return plotWorld.getAreas().toArray(new PlotArea[0]); + } + return plotWorld.getAreasInRegion(region).toArray(new PlotArea[0]); } - @Override public void addWorld(String worldName) { - if (!this.plotAreaHasCollision && !this.plotAreaHashCheck.add(worldName.hashCode())) { - this.plotAreaHasCollision = true; + @Override public void addWorld(final String worldName) { + PlotWorld world = this.plotWorlds.get(worldName); + if (world != null) { + return; } - Set tmp = new LinkedHashSet<>(); - Collections.addAll(tmp, worlds); - tmp.add(worldName); - worlds = tmp.toArray(new String[0]); + // Create a new empty world. When a new area is added + // the world will be re-recreated with the correct type + world = new StandardPlotWorld(worldName, null); + this.plotWorlds.put(worldName, world); } - @Override public void removeWorld(String worldName) { - Set tmp = new LinkedHashSet<>(); - Collections.addAll(tmp, worlds); - tmp.remove(worldName); - worlds = tmp.toArray(new String[0]); + @Override public void removeWorld(final String worldName) { + this.plotWorlds.remove(worldName); } @Override public String[] getAllWorlds() { - return worlds; + return this.plotWorlds.keySet().toArray(new String[0]); } } diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/PlotAreaManager.java b/Core/src/main/java/com/plotsquared/core/plot/world/PlotAreaManager.java index b6d23b3d4..34033cb2b 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/world/PlotAreaManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/world/PlotAreaManager.java @@ -29,6 +29,7 @@ import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.PlotArea; import com.sk89q.worldedit.regions.CuboidRegion; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface PlotAreaManager { @@ -44,7 +45,7 @@ public interface PlotAreaManager { * @param location The location * @return An applicable area, or null */ - PlotArea getApplicablePlotArea(Location location); + @Nullable PlotArea getApplicablePlotArea(Location location); /** * Get the plot area, if there is any, for the given diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java b/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java new file mode 100644 index 000000000..78cb0b7b2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java @@ -0,0 +1,110 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.plot.world; + +import com.github.davidmoten.rtree.Entry; +import com.github.davidmoten.rtree.RTree; +import com.github.davidmoten.rtree.geometry.Geometries; +import com.github.davidmoten.rtree.geometry.Geometry; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotWorld; +import com.plotsquared.core.util.RegionUtil; +import com.sk89q.worldedit.regions.CuboidRegion; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import rx.Observable; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * Plot world that contains several plot areas (clusters) + */ +public class ScatteredPlotWorld extends PlotWorld { + + private final List areas = new LinkedList<>(); + private final Object treeLock = new Object(); + private RTree areaTree; + + /** + * Create a new plot world with a given world name + * + * @param world World name + */ + public ScatteredPlotWorld(@NotNull final String world) { + super(world); + } + + @Override @Nullable public PlotArea getArea(@NotNull final Location location) { + synchronized (this.treeLock) { + final Observable> area = + areaTree.search(Geometries.point(location.getX(), location.getZ())); + if (area.isEmpty().toBlocking().first()) { + return null; + } + return area.toBlocking().first().value(); + } + } + + @Override @NotNull public Collection getAreas() { + return Collections.unmodifiableCollection(this.areas); + } + + @Override public void addArea(@NotNull final PlotArea area) { + this.areas.add(area); + this.buildTree(); + } + + @Override public void removeArea(@NotNull final PlotArea area) { + this.areas.remove(area); + this.buildTree(); + } + + @Override @NotNull public Collection getAreasInRegion(@NotNull final CuboidRegion region) { + synchronized (this.treeLock) { + final List areas = new LinkedList<>(); + this.areaTree.search(RegionUtil.toRectangle(region)).toBlocking().forEach(entry -> areas.add(entry.value())); + return areas; + } + } + + /** + * Rebuild the area tree + */ + private void buildTree() { + synchronized (this.treeLock) { + this.areaTree = RTree.create(); + for (final PlotArea area : areas) { + this.areaTree = this.areaTree.add(area, + RegionUtil.toRectangle(area.getRegion())); + } + } + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/StandardPlotWorld.java b/Core/src/main/java/com/plotsquared/core/plot/world/StandardPlotWorld.java new file mode 100644 index 000000000..162cf0e9f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/plot/world/StandardPlotWorld.java @@ -0,0 +1,65 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.plot.world; + +import com.plotsquared.core.location.Location; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotWorld; +import com.sk89q.worldedit.regions.CuboidRegion; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; + +/** + * Ordinary plot world with a single plot area + */ +public class StandardPlotWorld extends PlotWorld { + + private final PlotArea area; + + public StandardPlotWorld(@NotNull final String world, @Nullable final PlotArea area) { + super(world); + this.area = area; + } + + @Override @Nullable public PlotArea getArea(@NotNull final Location location) { + return this.area; + } + + @Override @NotNull public Collection getAreas() { + if (this.area == null) { + return Collections.emptyList(); + } + return Collections.singletonList(this.area); + } + + @Override @NotNull public Collection getAreasInRegion(@NotNull final CuboidRegion region) { + return this.getAreas(); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java b/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java index fe4d83a96..59b14651a 100644 --- a/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java @@ -25,9 +25,13 @@ */ package com.plotsquared.core.util; +import com.github.davidmoten.rtree.geometry.Geometries; +import com.github.davidmoten.rtree.geometry.Rectangle; import com.plotsquared.core.plot.Plot; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; +import org.jetbrains.annotations.NotNull; public class RegionUtil { public static CuboidRegion createRegion(int pos1x, int pos2x, int pos1z, int pos2z) { @@ -54,6 +58,12 @@ public class RegionUtil { .getY() && y <= max.getY(); } + @NotNull public static Rectangle toRectangle(@NotNull final CuboidRegion region) { + final BlockVector2 min = region.getMinimumPoint().toBlockVector2(); + final BlockVector2 max = region.getMaximumPoint().toBlockVector2(); + return Geometries.rectangle(min.getX(), min.getZ(), max.getX(), max.getZ()); + } + // Because WE (not fawe) lack this for CuboidRegion public static boolean intersects(CuboidRegion region, CuboidRegion other) { BlockVector3 regionMin = region.getMinimumPoint(); From 1c6075df2bed1308e1c2a01fa720c1f7be02a992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Thu, 21 May 2020 20:06:37 +0200 Subject: [PATCH 02/13] Get rid of unused field --- .../plotsquared/core/plot/world/DefaultPlotAreaManager.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java b/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java index f86b5b8b6..9ce0b1623 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java @@ -44,10 +44,7 @@ import java.util.Set; public class DefaultPlotAreaManager implements PlotAreaManager { final PlotArea[] noPlotAreas = new PlotArea[0]; - private final Map plotWorlds = new HashMap<>(); - // Optimization if there are no hash collisions - private boolean plotAreaHasCollision = false; @Override public PlotArea[] getAllPlotAreas() { final Set area = new HashSet<>(); From 38a7c771bee6d2aef959e80535c9c67e7272a45d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Thu, 21 May 2020 20:23:36 +0200 Subject: [PATCH 03/13] Don't access tree until it has been created --- .../com/plotsquared/core/plot/world/ScatteredPlotWorld.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java b/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java index 78cb0b7b2..9f245a5ba 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java +++ b/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java @@ -62,6 +62,9 @@ public class ScatteredPlotWorld extends PlotWorld { } @Override @Nullable public PlotArea getArea(@NotNull final Location location) { + if (this.areas.isEmpty()) { + return null; + } synchronized (this.treeLock) { final Observable> area = areaTree.search(Geometries.point(location.getX(), location.getZ())); @@ -87,6 +90,9 @@ public class ScatteredPlotWorld extends PlotWorld { } @Override @NotNull public Collection getAreasInRegion(@NotNull final CuboidRegion region) { + if (this.areas.isEmpty()) { + return Collections.emptyList(); + } synchronized (this.treeLock) { final List areas = new LinkedList<>(); this.areaTree.search(RegionUtil.toRectangle(region)).toBlocking().forEach(entry -> areas.add(entry.value())); From 9752e5f62b41942cced1158901044a49e2bb831b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Fri, 22 May 2020 02:48:32 +0200 Subject: [PATCH 04/13] Start working on single plot areas --- Core/pom.xml | 6 + .../com/plotsquared/core/command/Area.java | 106 ++++++++++++++++++ .../core/configuration/Captions.java | 10 ++ .../core/generator/HybridPlotWorld.java | 12 +- 4 files changed, 132 insertions(+), 2 deletions(-) diff --git a/Core/pom.xml b/Core/pom.xml index 280cd8b1a..4e53e831a 100644 --- a/Core/pom.xml +++ b/Core/pom.xml @@ -92,6 +92,12 @@ 1.3.72 runtime + + com.github.davidmoten + rtree + 0.8.7 + runtime + junit junit diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index f5d494868..fcb4993c7 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -33,6 +33,7 @@ import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.generator.AugmentedUtils; import com.plotsquared.core.generator.HybridPlotWorld; import com.plotsquared.core.location.Location; +import com.plotsquared.core.player.ConsolePlayer; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotAreaTerrainType; @@ -50,9 +51,18 @@ import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal3; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Objects; @@ -74,6 +84,102 @@ public class Area extends SubCommand { return false; } switch (args[0].toLowerCase()) { + case "single": + if (player instanceof ConsolePlayer) { + MainUtil.sendMessage(player, Captions.IS_CONSOLE); + return false; + } + if (!Permissions.hasPermission(player, Captions.PERMISSION_AREA_CREATE)) { + MainUtil.sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_AREA_CREATE); + return false; + } + if (args.length < 2) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_NEEDS_NAME); + return false; + } + if (PlotSquared.get().getPlotArea(player.getLocation().getWorld(), args[1]) != null) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_NAME_TAKEN); + return false; + } + final LocalSession localSession = WorldEdit.getInstance().getSessionManager().getIfPresent(player.toActor()); + if (localSession == null) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_MISSING_SELECTION); + return false; + } + Region selectedRegion = null; + try { + selectedRegion = localSession.getSelection(((Player) player.toActor()).getWorld()); + } catch (final Exception ignored) {} + if (selectedRegion == null) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_MISSING_SELECTION); + return false; + } + if (selectedRegion.getWidth() != selectedRegion.getLength()) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_NOT_SQUARE); + return false; + } + if (PlotSquared.get().getPlotAreaManager().getPlotAreas( + Objects.requireNonNull(selectedRegion.getWorld()).getName(), CuboidRegion.makeCuboid(selectedRegion)).length != 0) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_OVERLAPPING); + } + // There's only one plot in the area... + final PlotId plotId = new PlotId(1, 1); + final HybridPlotWorld hybridPlotWorld = new HybridPlotWorld(player.getLocation().getWorld(), args[1], + Objects.requireNonNull(PlotSquared.imp()).getDefaultGenerator(), plotId, plotId); + // Plot size is the same as the region width + hybridPlotWorld.SIZE = (short) selectedRegion.getWidth(); + // We use a schematic generator + hybridPlotWorld.setTerrain(PlotAreaTerrainType.ALL); + // It is always a partial plot world + hybridPlotWorld.setType(PlotAreaType.PARTIAL); + // We save the schematic :D + final File parentFile = MainUtil.getFile(PlotSquared.imp().getDirectory(), "schematics" + File.separator + + "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld.getWorldName() + File.separator + + hybridPlotWorld.getId()); + if (!parentFile.exists() && !parentFile.mkdirs()) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_COULD_NOT_MAKE_DIRECTORIES); + return false; + } + final File file = new File(parentFile, "plot.schem"); + try (final ClipboardWriter clipboardWriter = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(file))) { + final BlockArrayClipboard clipboard = new BlockArrayClipboard(selectedRegion); + clipboardWriter.write(clipboard); + } catch (final Exception e) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_FAILED_TO_SAVE); + e.printStackTrace(); + return false; + } + // Now the schematic is saved, which is wonderful! + final SetupObject singleSetup = new SetupObject(); + singleSetup.world = hybridPlotWorld.getWorldName(); + singleSetup.id = hybridPlotWorld.getId(); + singleSetup.terrain = hybridPlotWorld.getTerrain(); + singleSetup.type = hybridPlotWorld.getType(); + singleSetup.plotManager = PlotSquared.imp().getPluginName(); + singleSetup.setupGenerator = PlotSquared.imp().getPluginName(); + singleSetup.step = hybridPlotWorld.getSettingNodes(); + singleSetup.max = plotId; + singleSetup.min = plotId; + Runnable singleRun = () -> { + final String world = SetupUtils.manager.setupWorld(singleSetup); + if (WorldUtil.IMP.isWorld(world)) { + PlotSquared.get().loadWorld(world, null); + Captions.SETUP_FINISHED.send(player); + player.teleport(WorldUtil.IMP.getSpawn(world), + TeleportCause.COMMAND); + } else { + MainUtil.sendMessage(player, + "An error occurred while creating the world: " + hybridPlotWorld + .getWorldName()); + } + }; + if (hasConfirmation(player)) { + CmdConfirm.addPending(player, + getCommandString() + " create pos2 (Creates world)", singleRun); + } else { + singleRun.run(); + } + return true; case "c": case "setup": case "create": diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java index 6238ec066..4e1fc9482 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java @@ -783,6 +783,16 @@ public enum Captions implements Caption { GENERIC_INVALID_CHOICE("invalid choice", "Generic"), // + // + SINGLE_AREA_MISSING_SELECTION("$2Error! You need to select a square region", "Single"), + SINGLE_AREA_NOT_SQUARE("$2Error! Your selection needs to be a square", "Single"), + SINGLE_AREA_OVERLAPPING("$2Error! Your selection overlaps with an existing plot area", "Single"), + SINGLE_AREA_NEEDS_NAME("$2Error! Please specify a plot name: /plot area single ", "Single"), + SINGLE_AREA_NAME_TAKEN("$2Error! The plot name is already taken", "Single"), + SINGLE_AREA_FAILED_TO_SAVE("$2Error! Failed to save the area schematic", "Single"), + SINGLE_AREA_COULD_NOT_MAKE_DIRECTORIES("$2Error! Failed to create the schematic directory", "Single"), + // + /** * Legacy Configuration Conversion */ diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java index da7f46a47..e8bb47f66 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java @@ -195,8 +195,16 @@ public class HybridPlotWorld extends ClassicPlotWorld { public void setupSchematics() throws SchematicHandler.UnsupportedFormatException { this.G_SCH = new HashMap<>(); this.G_SCH_B = new HashMap<>(); - File root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), - "schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName()); + + // Try to determine root. This means that plot areas can have separate schematic + // directories + File root; + if (!(root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" + + this.getWorldName() + "/" + this.getId())).exists()) { + root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), + "schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName()); + } + File schematic1File = new File(root, "sideroad.schem"); if (!schematic1File.exists()) schematic1File = new File(root, "sideroad.schematic"); From 7c080770f03e84438613719abe65d255b80cd184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Fri, 22 May 2020 02:51:40 +0200 Subject: [PATCH 05/13] Shade r-tree into the bukkit module --- Bukkit/build.gradle | 1 + Core/pom.xml | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle index 9fa1f8cf1..4e69d6a41 100644 --- a/Bukkit/build.gradle +++ b/Bukkit/build.gradle @@ -87,6 +87,7 @@ shadowJar { include(dependency("io.papermc:paperlib:1.0.2")) include(dependency("net.kyori:text-adapter-bukkit:3.0.3")) include(dependency("org.bstats:bstats-bukkit:1.7")) + include(dependency("com.github.davidmoten:rtree:0.8.7")) } relocate('net.kyori.text', 'com.plotsquared.formatting.text') relocate("io.papermc.lib", "com.plotsquared.bukkit.paperlib") diff --git a/Core/pom.xml b/Core/pom.xml index 280cd8b1a..4e53e831a 100644 --- a/Core/pom.xml +++ b/Core/pom.xml @@ -92,6 +92,12 @@ 1.3.72 runtime + + com.github.davidmoten + rtree + 0.8.7 + runtime + junit junit From a3179bf11478fb483a8ff5c6e62da6f3c1f590a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Fri, 22 May 2020 02:54:10 +0200 Subject: [PATCH 06/13] Shade rx into the bukkot module --- Bukkit/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle index 4e69d6a41..1e1f8bb02 100644 --- a/Bukkit/build.gradle +++ b/Bukkit/build.gradle @@ -88,6 +88,7 @@ shadowJar { include(dependency("net.kyori:text-adapter-bukkit:3.0.3")) include(dependency("org.bstats:bstats-bukkit:1.7")) include(dependency("com.github.davidmoten:rtree:0.8.7")) + include(dependency("io.reactivex:rxjava:1.3.8")) } relocate('net.kyori.text', 'com.plotsquared.formatting.text') relocate("io.papermc.lib", "com.plotsquared.bukkit.paperlib") From d4bd08415a4c0c4f0ffaa5d3b243bc460e89c7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Fri, 22 May 2020 02:56:23 +0200 Subject: [PATCH 07/13] Shade guava-mini into the bukkot module --- Bukkit/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle index 1e1f8bb02..5a1c91e20 100644 --- a/Bukkit/build.gradle +++ b/Bukkit/build.gradle @@ -89,6 +89,7 @@ shadowJar { include(dependency("org.bstats:bstats-bukkit:1.7")) include(dependency("com.github.davidmoten:rtree:0.8.7")) include(dependency("io.reactivex:rxjava:1.3.8")) + include(dependency("com.github.davidmoten:guava-mini:0.1.1")) } relocate('net.kyori.text', 'com.plotsquared.formatting.text') relocate("io.papermc.lib", "com.plotsquared.bukkit.paperlib") From b61dfd6f973b49e9f639c2938e90e39ade80d65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Fri, 22 May 2020 03:20:11 +0200 Subject: [PATCH 08/13] Single plot area progress --- .../com/plotsquared/core/command/Area.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index fcb4993c7..e2c1e828e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -58,6 +58,7 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; @@ -97,7 +98,8 @@ public class Area extends SubCommand { MainUtil.sendMessage(player, Captions.SINGLE_AREA_NEEDS_NAME); return false; } - if (PlotSquared.get().getPlotArea(player.getLocation().getWorld(), args[1]) != null) { + final PlotArea existingArea = PlotSquared.get().getPlotArea(player.getLocation().getWorld(), args[1]); + if (existingArea != null && existingArea.getId().equalsIgnoreCase(args[1])) { MainUtil.sendMessage(player, Captions.SINGLE_AREA_NAME_TAKEN); return false; } @@ -127,12 +129,15 @@ public class Area extends SubCommand { final HybridPlotWorld hybridPlotWorld = new HybridPlotWorld(player.getLocation().getWorld(), args[1], Objects.requireNonNull(PlotSquared.imp()).getDefaultGenerator(), plotId, plotId); // Plot size is the same as the region width - hybridPlotWorld.SIZE = (short) selectedRegion.getWidth(); + hybridPlotWorld.PLOT_WIDTH = hybridPlotWorld.SIZE = (short) selectedRegion.getWidth(); // We use a schematic generator hybridPlotWorld.setTerrain(PlotAreaTerrainType.ALL); // It is always a partial plot world hybridPlotWorld.setType(PlotAreaType.PARTIAL); // We save the schematic :D + hybridPlotWorld.PLOT_SCHEMATIC = true; + // Set the road width to 0 + hybridPlotWorld.ROAD_WIDTH = hybridPlotWorld.ROAD_OFFSET_X = hybridPlotWorld.ROAD_OFFSET_Z = 0; final File parentFile = MainUtil.getFile(PlotSquared.imp().getDirectory(), "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld.getWorldName() + File.separator + hybridPlotWorld.getId()); @@ -149,6 +154,9 @@ public class Area extends SubCommand { e.printStackTrace(); return false; } + // Calculate the offset + final BlockVector3 singlePos1 = selectedRegion.getMinimumPoint(); + // Now the schematic is saved, which is wonderful! final SetupObject singleSetup = new SetupObject(); singleSetup.world = hybridPlotWorld.getWorldName(); @@ -161,6 +169,19 @@ public class Area extends SubCommand { singleSetup.max = plotId; singleSetup.min = plotId; Runnable singleRun = () -> { + final String path = + "worlds." + hybridPlotWorld.getWorldName() + ".areas." + hybridPlotWorld.getId() + '-' + + singleSetup.min + '-' + singleSetup.max; + final int offsetX = singlePos1.getX(); + final int offsetZ = singlePos1.getZ(); + if (offsetX != 0) { + PlotSquared.get().worlds + .set(path + ".road.offset.x", offsetX); + } + if (offsetZ != 0) { + PlotSquared.get().worlds + .set(path + ".road.offset.z", offsetZ); + } final String world = SetupUtils.manager.setupWorld(singleSetup); if (WorldUtil.IMP.isWorld(world)) { PlotSquared.get().loadWorld(world, null); From 32a55127f1029c2da0aed0e68a7701d8e9d861e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sat, 23 May 2020 14:32:02 +0200 Subject: [PATCH 09/13] Fix partial area regeneration when using PlotSquared generation. Also fix issues with region height and road width. --- .../bukkit/util/BukkitRegionManager.java | 2 +- .../com/plotsquared/core/PlotSquared.java | 22 ++++++++++++++++++- .../com/plotsquared/core/command/Area.java | 4 +++- .../plotsquared/core/util/ChunkManager.java | 2 +- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java index 16c63d093..158f90928 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java @@ -348,7 +348,7 @@ public class BukkitRegionManager extends RegionManager { CuboidRegion currentPlotClear = RegionUtil .createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ()); map.saveEntitiesOut(chunkObj, currentPlotClear); - AugmentedUtils.bypass(ignoreAugment, () -> ChunkManager.manager + AugmentedUtils.bypass(ignoreAugment, () -> ChunkManager .setChunkInPlotArea(null, new RunnableVal() { @Override public void run(ScopedLocalBlockQueue value) { Location min = value.getMin(); diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 4cb0731d5..535406a96 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -53,6 +53,7 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.BlockBucket; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotAreaTerrainType; import com.plotsquared.core.plot.PlotAreaType; import com.plotsquared.core.plot.PlotCluster; import com.plotsquared.core.plot.PlotFilter; @@ -90,6 +91,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import lombok.Getter; import lombok.NonNull; import lombok.Setter; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; @@ -270,7 +272,8 @@ public class PlotSquared { // create setup util class SetupUtils.manager = this.IMP.initSetupUtils(); // Set block - GlobalBlockQueue.IMP = new GlobalBlockQueue(IMP.initBlockQueue(), 1, Settings.QUEUE.TARGET_TIME); + GlobalBlockQueue.IMP = + new GlobalBlockQueue(IMP.initBlockQueue(), 1, Settings.QUEUE.TARGET_TIME); GlobalBlockQueue.IMP.runTask(); // Set chunk ChunkManager.manager = this.IMP.initChunkManager(); @@ -2014,6 +2017,23 @@ public class PlotSquared { return Collections.unmodifiableSet(set); } + /** + * Check if the chunk uses vanilla/non-PlotSquared generation + * + * @param world World name + * @param chunkCoordinates Chunk coordinates + * @return True if the chunk uses non-standard generation, false if not + */ + public boolean isNonStandardGeneration(@NotNull final String world, + @NotNull final BlockVector2 chunkCoordinates) { + final Location location = new Location(world, chunkCoordinates.getBlockX() << 4, 64, chunkCoordinates.getBlockZ() << 4); + final PlotArea area = plotAreaManager.getApplicablePlotArea(location); + if (area == null) { + return true; + } + return area.getTerrain() != PlotAreaTerrainType.NONE; + } + public boolean isAugmented(@NonNull final String world) { final PlotArea[] areas = plotAreaManager.getPlotAreas(world, null); return areas != null && (areas.length > 1 || areas[0].getType() != PlotAreaType.NORMAL); diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index e2c1e828e..05d97faca 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -131,13 +131,15 @@ public class Area extends SubCommand { // Plot size is the same as the region width hybridPlotWorld.PLOT_WIDTH = hybridPlotWorld.SIZE = (short) selectedRegion.getWidth(); // We use a schematic generator - hybridPlotWorld.setTerrain(PlotAreaTerrainType.ALL); + hybridPlotWorld.setTerrain(PlotAreaTerrainType.NONE); // It is always a partial plot world hybridPlotWorld.setType(PlotAreaType.PARTIAL); // We save the schematic :D hybridPlotWorld.PLOT_SCHEMATIC = true; // Set the road width to 0 hybridPlotWorld.ROAD_WIDTH = hybridPlotWorld.ROAD_OFFSET_X = hybridPlotWorld.ROAD_OFFSET_Z = 0; + // Set the plot height to the selection height + hybridPlotWorld.PLOT_HEIGHT = hybridPlotWorld.ROAD_HEIGHT = hybridPlotWorld.WALL_HEIGHT = selectedRegion.getHeight(); final File parentFile = MainUtil.getFile(PlotSquared.imp().getDirectory(), "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld.getWorldName() + File.separator + hybridPlotWorld.getId()); diff --git a/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java b/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java index 7bbea34d1..3e052737a 100644 --- a/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java @@ -52,7 +52,7 @@ public abstract class ChunkManager { public static void setChunkInPlotArea(RunnableVal force, RunnableVal add, String world, BlockVector2 loc) { LocalBlockQueue queue = GlobalBlockQueue.IMP.getNewQueue(world, false); - if (PlotSquared.get().isAugmented(world)) { + if (PlotSquared.get().isAugmented(world) && PlotSquared.get().isNonStandardGeneration(world, loc)) { int blockX = loc.getX() << 4; int blockZ = loc.getZ() << 4; ScopedLocalBlockQueue scoped = From 47c74cfa6d7650675f631e5882313909b4e2709e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sat, 23 May 2020 14:39:28 +0200 Subject: [PATCH 10/13] Set correct region height --- Core/src/main/java/com/plotsquared/core/command/Area.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index 05d97faca..f8846fbf7 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -139,7 +139,7 @@ public class Area extends SubCommand { // Set the road width to 0 hybridPlotWorld.ROAD_WIDTH = hybridPlotWorld.ROAD_OFFSET_X = hybridPlotWorld.ROAD_OFFSET_Z = 0; // Set the plot height to the selection height - hybridPlotWorld.PLOT_HEIGHT = hybridPlotWorld.ROAD_HEIGHT = hybridPlotWorld.WALL_HEIGHT = selectedRegion.getHeight(); + hybridPlotWorld.PLOT_HEIGHT = hybridPlotWorld.ROAD_HEIGHT = hybridPlotWorld.WALL_HEIGHT = selectedRegion.getMaximumPoint().getBlockY(); final File parentFile = MainUtil.getFile(PlotSquared.imp().getDirectory(), "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld.getWorldName() + File.separator + hybridPlotWorld.getId()); From 8c37cc53407f8526f4a7c9793a9321f4a8e5c8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sat, 23 May 2020 15:02:31 +0200 Subject: [PATCH 11/13] Fix minor issues --- .../com/plotsquared/core/command/Area.java | 22 +++++++------ .../core/generator/HybridPlotWorld.java | 31 +------------------ .../com/plotsquared/core/plot/PlotArea.java | 2 +- 3 files changed, 15 insertions(+), 40 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index f8846fbf7..15705da27 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -46,6 +46,7 @@ import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.RegionUtil; +import com.plotsquared.core.util.SchematicHandler; import com.plotsquared.core.util.SetupUtils; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.WorldUtil; @@ -140,6 +141,8 @@ public class Area extends SubCommand { hybridPlotWorld.ROAD_WIDTH = hybridPlotWorld.ROAD_OFFSET_X = hybridPlotWorld.ROAD_OFFSET_Z = 0; // Set the plot height to the selection height hybridPlotWorld.PLOT_HEIGHT = hybridPlotWorld.ROAD_HEIGHT = hybridPlotWorld.WALL_HEIGHT = selectedRegion.getMaximumPoint().getBlockY(); + // No sign plz + hybridPlotWorld.setAllowSigns(false); final File parentFile = MainUtil.getFile(PlotSquared.imp().getDirectory(), "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld.getWorldName() + File.separator + hybridPlotWorld.getId()); @@ -156,6 +159,14 @@ public class Area extends SubCommand { e.printStackTrace(); return false; } + + // Setup schematic + try { + hybridPlotWorld.setupSchematics(); + } catch (final SchematicHandler.UnsupportedFormatException e) { + e.printStackTrace(); + } + // Calculate the offset final BlockVector3 singlePos1 = selectedRegion.getMinimumPoint(); @@ -187,21 +198,14 @@ public class Area extends SubCommand { final String world = SetupUtils.manager.setupWorld(singleSetup); if (WorldUtil.IMP.isWorld(world)) { PlotSquared.get().loadWorld(world, null); - Captions.SETUP_FINISHED.send(player); - player.teleport(WorldUtil.IMP.getSpawn(world), - TeleportCause.COMMAND); + MainUtil.sendMessage(player, Captions.SINGLE_AREA_CREATED); } else { MainUtil.sendMessage(player, "An error occurred while creating the world: " + hybridPlotWorld .getWorldName()); } }; - if (hasConfirmation(player)) { - CmdConfirm.addPending(player, - getCommandString() + " create pos2 (Creates world)", singleRun); - } else { - singleRun.run(); - } + singleRun.run(); return true; case "c": case "setup": diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java index e8bb47f66..c2c1323c5 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java @@ -280,37 +280,8 @@ public class HybridPlotWorld extends ClassicPlotWorld { (short) (z + shift + oddshift + centerShiftZ), biome); } } -/* HashMap items = schematic3.getTiles(); - if (!items.isEmpty()) { - this.G_SCH_STATE = new HashMap<>(); - outer: - for (Map.Entry entry : items.entrySet()) { - BlockLoc loc = entry.getKey(); - short x = (short) (loc.x + shift + oddshift + centerShiftX); - short z = (short) (loc.z + shift + oddshift + centerShiftZ); - short y = (short) (loc.y + this.PLOT_HEIGHT); - int pair = MathMan.pair(x, z); - HashMap existing = this.G_SCH_STATE.get(pair); - if (existing == null) { - existing = new HashMap<>(); - this.G_SCH_STATE.put(pair, existing); - } - existing.put((int) y, entry.getValue()); - CompoundTag tag = entry.getValue(); - Map map = ReflectionUtils.getMap(tag.getValue()); - for (int i = 1; i <= 4; i++) { - String ln = tag.getString("Line" + i); - if (ln == null || ln.length() > 11) - continue outer; - } - SIGN_LOCATION = - new Location(worldname, loc.x + centerShiftX, this.PLOT_HEIGHT + loc.y, - loc.z + centerShiftZ); - ALLOW_SIGNS = true; - continue outer; - } - }*/ + PlotSquared.debug(Captions.PREFIX + "&3 - plot schematic: &7true"); } if (schematic1 == null || schematic2 == null || this.ROAD_WIDTH == 0) { PlotSquared.debug(Captions.PREFIX + "&3 - schematic: &7false"); diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java index 45749d9e1..fc2c12453 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java @@ -1023,7 +1023,7 @@ public abstract class PlotArea { * @return true if plot signs are allow, false otherwise. */ public boolean allowSigns() { - return allowSigns; + return allowSigns && (this.plots.size() > 1) /* Do not generate signs for single plots */; } /** From 4dd2613f2f6d88947044a71b471ec30282adbbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sat, 23 May 2020 15:02:53 +0200 Subject: [PATCH 12/13] Add missing caption --- .../main/java/com/plotsquared/core/configuration/Captions.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java index 4e1fc9482..1e411d38c 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java @@ -791,6 +791,7 @@ public enum Captions implements Caption { SINGLE_AREA_NAME_TAKEN("$2Error! The plot name is already taken", "Single"), SINGLE_AREA_FAILED_TO_SAVE("$2Error! Failed to save the area schematic", "Single"), SINGLE_AREA_COULD_NOT_MAKE_DIRECTORIES("$2Error! Failed to create the schematic directory", "Single"), + SINGLE_AREA_CREATED("$1The area was created successfully!", "Single"), // /** From 113da81f29f1397d970f6eb2f2ce22d935375fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sat, 23 May 2020 16:15:48 +0200 Subject: [PATCH 13/13] Actually save the schematic --- .../com/plotsquared/core/command/Area.java | 27 ++++++++++++++----- .../core/generator/HybridPlotWorld.java | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index 15705da27..932bbf0ab 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -52,12 +52,15 @@ import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal3; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; 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.regions.CuboidRegion; @@ -109,22 +112,29 @@ public class Area extends SubCommand { MainUtil.sendMessage(player, Captions.SINGLE_AREA_MISSING_SELECTION); return false; } - Region selectedRegion = null; + Region playerSelectedRegion = null; try { - selectedRegion = localSession.getSelection(((Player) player.toActor()).getWorld()); + playerSelectedRegion = localSession.getSelection(((Player) player.toActor()).getWorld()); } catch (final Exception ignored) {} - if (selectedRegion == null) { + if (playerSelectedRegion == null) { MainUtil.sendMessage(player, Captions.SINGLE_AREA_MISSING_SELECTION); return false; } - if (selectedRegion.getWidth() != selectedRegion.getLength()) { + if (playerSelectedRegion.getWidth() != playerSelectedRegion.getLength()) { MainUtil.sendMessage(player, Captions.SINGLE_AREA_NOT_SQUARE); return false; } if (PlotSquared.get().getPlotAreaManager().getPlotAreas( - Objects.requireNonNull(selectedRegion.getWorld()).getName(), CuboidRegion.makeCuboid(selectedRegion)).length != 0) { + Objects.requireNonNull(playerSelectedRegion.getWorld()).getName(), CuboidRegion.makeCuboid(playerSelectedRegion)).length != 0) { MainUtil.sendMessage(player, Captions.SINGLE_AREA_OVERLAPPING); } + // Alter the region + final BlockVector3 playerSelectionMin = playerSelectedRegion.getMinimumPoint(); + final BlockVector3 playerSelectionMax = playerSelectedRegion.getMaximumPoint(); + // Create a new selection that spans the entire vertical range of the world + final CuboidRegion selectedRegion = new CuboidRegion(playerSelectedRegion.getWorld(), + BlockVector3.at(playerSelectionMin.getX(), 0, playerSelectionMin.getZ()), + BlockVector3.at(playerSelectionMax.getX(), 255, playerSelectionMax.getZ())); // There's only one plot in the area... final PlotId plotId = new PlotId(1, 1); final HybridPlotWorld hybridPlotWorld = new HybridPlotWorld(player.getLocation().getWorld(), args[1], @@ -140,7 +150,7 @@ public class Area extends SubCommand { // Set the road width to 0 hybridPlotWorld.ROAD_WIDTH = hybridPlotWorld.ROAD_OFFSET_X = hybridPlotWorld.ROAD_OFFSET_Z = 0; // Set the plot height to the selection height - hybridPlotWorld.PLOT_HEIGHT = hybridPlotWorld.ROAD_HEIGHT = hybridPlotWorld.WALL_HEIGHT = selectedRegion.getMaximumPoint().getBlockY(); + hybridPlotWorld.PLOT_HEIGHT = hybridPlotWorld.ROAD_HEIGHT = hybridPlotWorld.WALL_HEIGHT = playerSelectionMin.getBlockY(); // No sign plz hybridPlotWorld.setAllowSigns(false); final File parentFile = MainUtil.getFile(PlotSquared.imp().getDirectory(), "schematics" + File.separator + @@ -153,6 +163,11 @@ public class Area extends SubCommand { final File file = new File(parentFile, "plot.schem"); try (final ClipboardWriter clipboardWriter = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(file))) { final BlockArrayClipboard clipboard = new BlockArrayClipboard(selectedRegion); + final EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(selectedRegion.getWorld(), -1); + final ForwardExtentCopy forwardExtentCopy = new ForwardExtentCopy(editSession, selectedRegion, clipboard, selectedRegion.getMinimumPoint()); + forwardExtentCopy.setCopyingBiomes(true); + forwardExtentCopy.setCopyingEntities(true); + Operations.complete(forwardExtentCopy); clipboardWriter.write(clipboard); } catch (final Exception e) { MainUtil.sendMessage(player, Captions.SINGLE_AREA_FAILED_TO_SAVE); diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java index c2c1323c5..49a5c0da4 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java @@ -281,7 +281,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { } } - PlotSquared.debug(Captions.PREFIX + "&3 - plot schematic: &7true"); + PlotSquared.debug(Captions.PREFIX + "&3 - plot schematic: &7" + schematic3File.getPath()); } if (schematic1 == null || schematic2 == null || this.ROAD_WIDTH == 0) { PlotSquared.debug(Captions.PREFIX + "&3 - schematic: &7false");