001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.generator; 020 021import com.plotsquared.core.PlotSquared; 022import com.plotsquared.core.location.Location; 023import com.plotsquared.core.plot.PlotArea; 024import com.plotsquared.core.plot.PlotAreaTerrainType; 025import com.plotsquared.core.plot.PlotAreaType; 026import com.plotsquared.core.plot.PlotManager; 027import com.plotsquared.core.queue.AreaBoundDelegateQueueCoordinator; 028import com.plotsquared.core.queue.LocationOffsetDelegateQueueCoordinator; 029import com.plotsquared.core.queue.QueueCoordinator; 030import com.plotsquared.core.queue.ScopedQueueCoordinator; 031import com.plotsquared.core.util.RegionUtil; 032import com.sk89q.worldedit.regions.CuboidRegion; 033import com.sk89q.worldedit.world.block.BlockState; 034import com.sk89q.worldedit.world.block.BlockTypes; 035import org.checkerframework.checker.nullness.qual.NonNull; 036import org.checkerframework.checker.nullness.qual.Nullable; 037 038import java.util.Set; 039 040public class AugmentedUtils { 041 042 private static boolean enabled = true; 043 044 public static void bypass(boolean bypass, Runnable run) { 045 enabled = bypass; 046 run.run(); 047 enabled = true; 048 } 049 050 /** 051 * Generate an augmented world chunk at the given location. If a queue is given, the data will be written to it, else a new 052 * queue will be created and written to world. Returns true if generation occurred. 053 * 054 * @param world World name to generate data for. Must be a PlotSquared world containing one or more areas else nothing will 055 * happen. 056 * @param chunkX Chunk X position 057 * @param chunkZ Chunk Z position 058 * @param queue Queue to write to, if desired. 059 * @return true if generation occurred. 060 * @since 6.8.0 061 */ 062 public static boolean generateChunk( 063 final @NonNull String world, 064 final int chunkX, 065 final int chunkZ, 066 @Nullable QueueCoordinator queue 067 ) { 068 if (!enabled) { 069 return false; 070 } 071 // The coordinates of the block on the 072 // least positive corner of the chunk 073 final int blockX = chunkX << 4; 074 final int blockZ = chunkZ << 4; 075 // Create a region that contains the 076 // entire chunk 077 CuboidRegion region = RegionUtil.createRegion(blockX, blockX + 15, 0, 0, blockZ, blockZ + 15); 078 // Query for plot areas in the chunk 079 final Set<PlotArea> areas = PlotSquared.get().getPlotAreaManager().getPlotAreasSet(world, region); 080 if (areas.isEmpty()) { 081 return false; 082 } 083 boolean enqueue = false; 084 boolean generationResult = false; 085 for (final PlotArea area : areas) { 086 // A normal plot world may not contain any clusters 087 // and so there's no reason to continue searching 088 if (area.getType() == PlotAreaType.NORMAL) { 089 return false; 090 } 091 // This means that full vanilla generation is used 092 // so we do not interfere 093 if (area.getTerrain() == PlotAreaTerrainType.ALL || !area.contains(blockX, blockZ)) { 094 continue; 095 } 096 IndependentPlotGenerator generator = area.getGenerator(); 097 // Mask 098 if (queue == null) { 099 enqueue = true; 100 queue = PlotSquared.platform().globalBlockQueue().getNewQueue(PlotSquared 101 .platform() 102 .worldUtil() 103 .getWeWorld(world)); 104 } 105 QueueCoordinator primaryMask; 106 // coordinates 107 int relativeBottomX; 108 int relativeBottomZ; 109 int relativeTopX; 110 int relativeTopZ; 111 // Generation 112 if (area.getType() == PlotAreaType.PARTIAL) { 113 relativeBottomX = Math.max(0, area.getRegion().getMinimumPoint().getX() - blockX); 114 relativeBottomZ = Math.max(0, area.getRegion().getMinimumPoint().getZ() - blockZ); 115 relativeTopX = Math.min(15, area.getRegion().getMaximumPoint().getX() - blockX); 116 relativeTopZ = Math.min(15, area.getRegion().getMaximumPoint().getZ() - blockZ); 117 118 primaryMask = new AreaBoundDelegateQueueCoordinator(area, queue); 119 } else { 120 relativeBottomX = relativeBottomZ = 0; 121 relativeTopX = relativeTopZ = 15; 122 primaryMask = queue; 123 } 124 QueueCoordinator secondaryMask; 125 BlockState air = BlockTypes.AIR.getDefaultState(); 126 int startYOffset = !(area instanceof ClassicPlotWorld) || ((ClassicPlotWorld) area).PLOT_BEDROCK ? 1 : 0; 127 if (area.getTerrain() == PlotAreaTerrainType.ROAD) { 128 PlotManager manager = area.getPlotManager(); 129 final boolean[][] canPlace = new boolean[16][16]; 130 boolean has = false; 131 for (int x = relativeBottomX; x <= relativeTopX; x++) { 132 for (int z = relativeBottomZ; z <= relativeTopZ; z++) { 133 int worldX = x + blockX; 134 int worldZ = z + blockZ; 135 boolean can = manager.getPlotId(worldX, 0, worldZ) == null; 136 if (can) { 137 for (int y = area.getMinGenHeight() + startYOffset; y <= area.getMaxGenHeight(); y++) { 138 queue.setBlock(worldX, y, worldZ, air); 139 } 140 canPlace[x][z] = true; 141 has = true; 142 } 143 } 144 } 145 if (!has) { 146 continue; 147 } 148 generationResult = true; 149 secondaryMask = new LocationOffsetDelegateQueueCoordinator(canPlace, blockX, blockZ, primaryMask); 150 } else { 151 secondaryMask = primaryMask; 152 for (int x = relativeBottomX; x <= relativeTopX; x++) { 153 for (int z = relativeBottomZ; z <= relativeTopZ; z++) { 154 for (int y = area.getMinGenHeight() + startYOffset; y <= area.getMaxGenHeight(); y++) { 155 queue.setBlock(blockX + x, y, blockZ + z, air); 156 } 157 } 158 } 159 generationResult = true; 160 } 161 162 // This queue should not be enqueued as it is simply used to restrict block setting, and then delegate to the 163 // actual queue 164 ScopedQueueCoordinator scoped = 165 new ScopedQueueCoordinator( 166 secondaryMask, 167 Location.at(world, blockX, area.getMinGenHeight(), blockZ), 168 Location.at(world, blockX + 15, area.getMaxGenHeight(), blockZ + 15) 169 ); 170 generator.generateChunk(scoped, area); 171 generator.populateChunk(scoped, area); 172 } 173 if (enqueue) { 174 queue.enqueue(); 175 } 176 return generationResult; 177 } 178 179 /** 180 * @deprecated Use {@link AugmentedUtils#generateChunk(String, int, int, QueueCoordinator)} as chunkObject is not required 181 * in the above method 182 */ 183 @Deprecated(forRemoval = true, since = "6.8.0") 184 public static boolean generate( 185 @Nullable Object chunkObject, 186 final @NonNull String world, 187 final int chunkX, 188 final int chunkZ, 189 QueueCoordinator queue 190 ) { 191 return generateChunk(world, chunkX, chunkZ, queue); 192 } 193 194}