PlotSquared/Core/src/main/java/com/plotsquared/core/generator/HybridGen.java

435 lines
19 KiB
Java
Raw Normal View History

/*
* PlotSquared, a land and world management plugin for Minecraft.
* Copyright (C) IntellectualSites <https://intellectualsites.com>
* 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 <https://www.gnu.org/licenses/>.
*/
2020-04-15 21:26:54 +02:00
package com.plotsquared.core.generator;
2016-02-10 19:59:51 +01:00
2020-04-30 12:33:59 +02:00
import com.google.common.base.Preconditions;
2020-07-10 22:12:37 +02:00
import com.google.inject.Inject;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.PlotSquared;
2020-04-16 06:14:33 +02:00
import com.plotsquared.core.configuration.Settings;
2020-07-11 17:19:19 +02:00
import com.plotsquared.core.inject.factory.HybridPlotWorldFactory;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.location.Location;
import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.PlotId;
import com.plotsquared.core.queue.ScopedQueueCoordinator;
2020-04-30 12:33:59 +02:00
import com.plotsquared.core.util.MathMan;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.world.NullWorld;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
2018-08-10 17:01:10 +02:00
2020-07-10 19:25:05 +02:00
public class HybridGen extends IndependentPlotGenerator {
private static final CuboidRegion CHUNK = new CuboidRegion(BlockVector3.ZERO, BlockVector3.at(15, 396, 15));
2020-07-11 17:19:19 +02:00
private final HybridPlotWorldFactory hybridPlotWorldFactory;
2020-07-10 19:25:05 +02:00
@Inject
public HybridGen(final @NonNull HybridPlotWorldFactory hybridPlotWorldFactory) {
2020-07-11 17:19:19 +02:00
this.hybridPlotWorldFactory = hybridPlotWorldFactory;
2020-07-10 19:25:05 +02:00
}
2016-02-10 19:59:51 +01:00
@Override
public String getName() {
return PlotSquared.platform().pluginName();
2016-02-10 19:59:51 +01:00
}
2016-03-23 02:41:37 +01:00
private void placeSchem(
HybridPlotWorld world,
ScopedQueueCoordinator result,
short relativeX,
short relativeZ,
int x,
int z,
boolean isRoad,
boolean isPopulating
) {
2019-01-21 09:53:04 +01:00
int minY; // Math.min(world.PLOT_HEIGHT, world.ROAD_HEIGHT);
if ((isRoad && Settings.Schematics.PASTE_ROAD_ON_TOP) || (!isRoad && Settings.Schematics.PASTE_ON_TOP)) {
2019-04-05 16:54:02 +02:00
minY = world.SCHEM_Y;
2019-01-21 09:53:04 +01:00
} else {
minY = world.getMinBuildHeight();
2019-01-21 09:53:04 +01:00
}
BaseBlock[] blocks = world.G_SCH.get(MathMan.pair(relativeX, relativeZ));
2016-12-31 07:23:46 +01:00
if (blocks != null) {
for (int y = 0; y < blocks.length; y++) {
if (blocks[y] != null) {
if (!isPopulating || blocks[y].hasNbtData()) {
result.setBlock(x, minY + y, z, blocks[y]);
}
2016-12-31 07:23:46 +01:00
}
}
}
BiomeType biome = world.G_SCH_B.get(MathMan.pair(relativeX, relativeZ));
if (biome != null) {
result.setBiome(x, z, biome);
}
2016-12-31 07:23:46 +01:00
}
2020-04-30 12:33:59 +02:00
@Override
public void generateChunk(@NonNull ScopedQueueCoordinator result, @NonNull PlotArea settings) {
2020-02-24 14:00:45 +01:00
Preconditions.checkNotNull(result, "result cannot be null");
Preconditions.checkNotNull(settings, "settings cannot be null");
HybridPlotWorld hybridPlotWorld = (HybridPlotWorld) settings;
2016-02-10 19:59:51 +01:00
// Biome
result.fillBiome(hybridPlotWorld.getPlotBiome());
2016-02-10 19:59:51 +01:00
// Bedrock
if (hybridPlotWorld.PLOT_BEDROCK) {
2016-02-10 19:59:51 +01:00
for (short x = 0; x < 16; x++) {
for (short z = 0; z < 16; z++) {
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
result.setBlock(x, hybridPlotWorld.getMinGenHeight(), z, BlockTypes.BEDROCK.getDefaultState());
2016-02-10 19:59:51 +01:00
}
}
}
// Coords
2016-06-13 06:47:50 +02:00
Location min = result.getMin();
2022-01-20 21:01:38 +01:00
int bx = min.getX() - hybridPlotWorld.ROAD_OFFSET_X;
int bz = min.getZ() - hybridPlotWorld.ROAD_OFFSET_Z;
// The relative X-coordinate (within the plot) of the minimum X coordinate
// contained in the scoped queue
short relativeOffsetX;
2016-03-23 02:41:37 +01:00
if (bx < 0) {
relativeOffsetX = (short) (hybridPlotWorld.SIZE + (bx % hybridPlotWorld.SIZE));
2016-03-23 02:41:37 +01:00
} else {
relativeOffsetX = (short) (bx % hybridPlotWorld.SIZE);
2016-03-23 02:41:37 +01:00
}
// The relative Z-coordinate (within the plot) of the minimum Z coordinate
// contained in the scoped queue
short relativeOffsetZ;
2016-03-23 02:41:37 +01:00
if (bz < 0) {
relativeOffsetZ = (short) (hybridPlotWorld.SIZE + (bz % hybridPlotWorld.SIZE));
2016-03-23 02:41:37 +01:00
} else {
relativeOffsetZ = (short) (bz % hybridPlotWorld.SIZE);
2016-03-23 02:41:37 +01:00
}
// The X-coordinate of a given X coordinate, relative to the
// plot (Counting from the corner with the least positive
// coordinates)
short[] relativeX = new short[16];
boolean[] insideRoadX = new boolean[16];
boolean[] insideWallX = new boolean[16];
short offsetX = relativeOffsetX;
2016-02-10 19:59:51 +01:00
for (short i = 0; i < 16; i++) {
if (offsetX >= hybridPlotWorld.SIZE) {
offsetX -= hybridPlotWorld.SIZE;
2016-02-10 19:59:51 +01:00
}
relativeX[i] = offsetX;
if (hybridPlotWorld.ROAD_WIDTH != 0) {
insideRoadX[i] = offsetX < hybridPlotWorld.PATH_WIDTH_LOWER || offsetX > hybridPlotWorld.PATH_WIDTH_UPPER;
insideWallX[i] = offsetX == hybridPlotWorld.PATH_WIDTH_LOWER || offsetX == hybridPlotWorld.PATH_WIDTH_UPPER;
2016-02-10 19:59:51 +01:00
}
offsetX++;
2016-02-10 19:59:51 +01:00
}
// The Z-coordinate of a given Z coordinate, relative to the
// plot (Counting from the corner with the least positive
// coordinates)
short[] relativeZ = new short[16];
boolean[] insideRoadZ = new boolean[16];
boolean[] insideWallZ = new boolean[16];
short offsetZ = relativeOffsetZ;
2016-02-10 19:59:51 +01:00
for (short i = 0; i < 16; i++) {
if (offsetZ >= hybridPlotWorld.SIZE) {
offsetZ -= hybridPlotWorld.SIZE;
2016-02-10 19:59:51 +01:00
}
relativeZ[i] = offsetZ;
if (hybridPlotWorld.ROAD_WIDTH != 0) {
insideRoadZ[i] = offsetZ < hybridPlotWorld.PATH_WIDTH_LOWER || offsetZ > hybridPlotWorld.PATH_WIDTH_UPPER;
insideWallZ[i] = offsetZ == hybridPlotWorld.PATH_WIDTH_LOWER || offsetZ == hybridPlotWorld.PATH_WIDTH_UPPER;
2016-02-10 19:59:51 +01:00
}
offsetZ++;
2016-02-10 19:59:51 +01:00
}
// generation
int startY = hybridPlotWorld.getMinGenHeight() + (hybridPlotWorld.PLOT_BEDROCK ? 1 : 0);
2016-02-10 19:59:51 +01:00
for (short x = 0; x < 16; x++) {
if (insideRoadX[x]) {
2016-02-10 19:59:51 +01:00
for (short z = 0; z < 16; z++) {
// Road
for (int y = startY; y <= hybridPlotWorld.ROAD_HEIGHT; y++) {
result.setBlock(x, y, z, hybridPlotWorld.ROAD_BLOCK.toPattern());
2016-02-10 19:59:51 +01:00
}
if (hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) {
placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, true, false);
2016-02-10 19:59:51 +01:00
}
}
} else if (insideWallX[x]) {
2016-02-10 19:59:51 +01:00
for (short z = 0; z < 16; z++) {
if (insideRoadZ[z]) {
2016-02-10 19:59:51 +01:00
// road
for (int y = startY; y <= hybridPlotWorld.ROAD_HEIGHT; y++) {
result.setBlock(x, y, z, hybridPlotWorld.ROAD_BLOCK.toPattern());
2016-02-10 19:59:51 +01:00
}
if (hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) {
placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, true, false);
2016-02-10 19:59:51 +01:00
}
} else {
// wall
for (int y = startY; y <= hybridPlotWorld.WALL_HEIGHT; y++) {
result.setBlock(x, y, z, hybridPlotWorld.WALL_FILLING.toPattern());
2016-02-10 19:59:51 +01:00
}
if (!hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) {
if (hybridPlotWorld.PLACE_TOP_BLOCK) {
result.setBlock(x, hybridPlotWorld.WALL_HEIGHT + 1, z, hybridPlotWorld.WALL_BLOCK.toPattern());
}
2016-02-10 19:59:51 +01:00
} else {
placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, true, false);
2016-02-10 19:59:51 +01:00
}
}
}
} else {
for (short z = 0; z < 16; z++) {
if (insideRoadZ[z]) {
2016-02-10 19:59:51 +01:00
// road
for (int y = startY; y <= hybridPlotWorld.ROAD_HEIGHT; y++) {
result.setBlock(x, y, z, hybridPlotWorld.ROAD_BLOCK.toPattern());
2016-02-10 19:59:51 +01:00
}
if (hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) {
placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, true, false);
2016-02-10 19:59:51 +01:00
}
} else if (insideWallZ[z]) {
2016-02-10 19:59:51 +01:00
// wall
for (int y = startY; y <= hybridPlotWorld.WALL_HEIGHT; y++) {
result.setBlock(x, y, z, hybridPlotWorld.WALL_FILLING.toPattern());
2016-02-10 19:59:51 +01:00
}
if (!hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) {
if (hybridPlotWorld.PLACE_TOP_BLOCK) {
result.setBlock(x, hybridPlotWorld.WALL_HEIGHT + 1, z, hybridPlotWorld.WALL_BLOCK.toPattern());
}
2016-02-10 19:59:51 +01:00
} else {
placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, true, false);
2016-02-10 19:59:51 +01:00
}
} else {
// plot
for (int y = startY; y < hybridPlotWorld.PLOT_HEIGHT; y++) {
result.setBlock(x, y, z, hybridPlotWorld.MAIN_BLOCK.toPattern());
2016-02-10 19:59:51 +01:00
}
result.setBlock(x, hybridPlotWorld.PLOT_HEIGHT, z, hybridPlotWorld.TOP_BLOCK.toPattern());
if (hybridPlotWorld.PLOT_SCHEMATIC) {
placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, false, false);
2016-02-10 19:59:51 +01:00
}
}
}
}
}
}
2016-03-23 02:41:37 +01:00
@Override
public boolean populateChunk(final ScopedQueueCoordinator result, final PlotArea settings) {
HybridPlotWorld hybridPlotWorld = (HybridPlotWorld) settings;
if (!hybridPlotWorld.populationNeeded()) {
return false;
}
// Coords
Location min = result.getMin();
int bx = min.getX() - hybridPlotWorld.ROAD_OFFSET_X;
int bz = min.getZ() - hybridPlotWorld.ROAD_OFFSET_Z;
// The relative X-coordinate (within the plot) of the minimum X coordinate
// contained in the scoped queue
short relativeOffsetX;
if (bx < 0) {
relativeOffsetX = (short) (hybridPlotWorld.SIZE + (bx % hybridPlotWorld.SIZE));
} else {
relativeOffsetX = (short) (bx % hybridPlotWorld.SIZE);
}
// The relative Z-coordinate (within the plot) of the minimum Z coordinate
// contained in the scoped queue
short relativeOffsetZ;
if (bz < 0) {
relativeOffsetZ = (short) (hybridPlotWorld.SIZE + (bz % hybridPlotWorld.SIZE));
} else {
relativeOffsetZ = (short) (bz % hybridPlotWorld.SIZE);
}
boolean allRoad = true;
boolean overlap = false;
// The X-coordinate of a given X coordinate, relative to the
// plot (Counting from the corner with the least positive
// coordinates)
short[] relativeX = new short[16];
boolean[] insideRoadX = new boolean[16];
boolean[] insideWallX = new boolean[16];
short offsetX = relativeOffsetX;
for (short i = 0; i < 16; i++) {
if (offsetX >= hybridPlotWorld.SIZE) {
offsetX -= hybridPlotWorld.SIZE;
overlap = true;
}
relativeX[i] = offsetX;
if (hybridPlotWorld.ROAD_WIDTH != 0) {
boolean insideRoad = offsetX < hybridPlotWorld.PATH_WIDTH_LOWER || offsetX > hybridPlotWorld.PATH_WIDTH_UPPER;
boolean insideWall = offsetX == hybridPlotWorld.PATH_WIDTH_LOWER || offsetX == hybridPlotWorld.PATH_WIDTH_UPPER;
insideRoadX[i] = insideRoad;
insideWallX[i] = insideWall;
allRoad &= insideRoad && insideWall;
}
offsetX++;
}
// The Z-coordinate of a given Z coordinate, relative to the
// plot (Counting from the corner with the least positive
// coordinates)
short[] relativeZ = new short[16];
boolean[] insideRoadZ = new boolean[16];
boolean[] insideWallZ = new boolean[16];
short offsetZ = relativeOffsetZ;
for (short i = 0; i < 16; i++) {
if (offsetZ >= hybridPlotWorld.SIZE) {
offsetZ -= hybridPlotWorld.SIZE;
overlap = true;
}
relativeZ[i] = offsetZ;
if (hybridPlotWorld.ROAD_WIDTH != 0) {
boolean insideRoad = offsetZ < hybridPlotWorld.PATH_WIDTH_LOWER || offsetZ > hybridPlotWorld.PATH_WIDTH_UPPER;
boolean insideWall = offsetZ == hybridPlotWorld.PATH_WIDTH_LOWER || offsetZ == hybridPlotWorld.PATH_WIDTH_UPPER;
insideRoadZ[i] = insideRoad;
insideWallZ[i] = insideWall;
allRoad &= insideRoad && insideWall;
}
offsetZ++;
}
for (short x = 0; x < 16; x++) {
if (insideRoadX[x] || insideWallX[x]) {
if (hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) {
for (short z = 0; z < 16; z++) {
placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, true, true);
}
}
} else {
for (short z = 0; z < 16; z++) {
if (insideRoadZ[z] || insideWallZ[z]) {
if (hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) {
placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, true, true);
}
} else if (hybridPlotWorld.PLOT_SCHEMATIC) {
placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, false, true);
}
}
}
}
if (!allRoad && hybridPlotWorld.getPlotSchematicEntities() != null && !hybridPlotWorld
.getPlotSchematicEntities()
.isEmpty()) {
CuboidRegion region = CHUNK.clone();
try {
region.shift(hybridPlotWorld
.getPlotSchematicMinPoint()
.add(relativeOffsetX, 0, relativeOffsetZ)
.subtract(hybridPlotWorld.PATH_WIDTH_LOWER + 1, 0, hybridPlotWorld.PATH_WIDTH_LOWER + 1));
for (Entity entity : hybridPlotWorld.getPlotSchematicEntities()) {
if (region.contains(entity.getLocation().toVector().toBlockPoint())) {
Vector3 pos = (entity.getLocation().toVector()
.subtract(region.getMinimumPoint().withY(hybridPlotWorld.getPlotSchematicMinPoint().getY()).toVector3()))
.add(min.getBlockVector3().withY(hybridPlotWorld.SCHEM_Y).toVector3());
result.setEntity(new PopulatingEntity(
entity,
new com.sk89q.worldedit.util.Location(NullWorld.getInstance(), pos)
));
}
}
} catch (RegionOperationException e) {
throw new RuntimeException(e);
}
if (overlap) {
try {
region.shift(BlockVector3.at(-hybridPlotWorld.SIZE, 0, -hybridPlotWorld.SIZE));
for (Entity entity : hybridPlotWorld.getPlotSchematicEntities()) {
if (region.contains(entity.getLocation().toVector().toBlockPoint())) {
result.setEntity(entity);
}
}
} catch (RegionOperationException e) {
throw new RuntimeException(e);
}
}
}
return true;
}
@Override
public PlotArea getNewPlotArea(String world, String id, PlotId min, PlotId max) {
2020-07-11 17:19:19 +02:00
return this.hybridPlotWorldFactory.create(world, id, this, min, max);
2016-02-10 19:59:51 +01:00
}
2016-03-23 02:41:37 +01:00
@Override
public void initialize(PlotArea area) {
2016-02-10 19:59:51 +01:00
// All initialization is done in the PlotArea class
}
/**
* Wrapper to allow a WorldEdit {@link Entity} to effectively have a mutable location as the location in its NBT should be changed
* when set to the world.
*
2022-06-13 11:23:48 +02:00
* @since 6.9.0
*/
private static final class PopulatingEntity implements Entity {
private final Entity parent;
private com.sk89q.worldedit.util.Location location;
/**
2022-06-13 11:23:48 +02:00
* @since 6.9.0
*/
private PopulatingEntity(Entity parent, com.sk89q.worldedit.util.Location location) {
this.parent = parent;
this.location = location;
}
@Nullable
@Override
public BaseEntity getState() {
return parent.getState();
}
@Override
public boolean remove() {
return parent.remove();
}
@Override
public com.sk89q.worldedit.util.Location getLocation() {
return location;
}
@Override
public boolean setLocation(final com.sk89q.worldedit.util.Location location) {
this.location = location;
return true;
}
@Override
public Extent getExtent() {
return parent.getExtent();
}
@Nullable
@Override
public <T> T getFacet(final Class<? extends T> cls) {
return parent.getFacet(cls);
}
}
2016-02-10 19:59:51 +01:00
}