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.location.Direction; 022import com.plotsquared.core.location.Location; 023import com.plotsquared.core.player.PlotPlayer; 024import com.plotsquared.core.plot.Plot; 025import com.plotsquared.core.plot.PlotArea; 026import com.plotsquared.core.plot.PlotId; 027import com.plotsquared.core.queue.QueueCoordinator; 028import com.plotsquared.core.util.HashUtil; 029import com.plotsquared.core.util.RegionManager; 030import com.sk89q.worldedit.regions.CuboidRegion; 031import org.apache.logging.log4j.LogManager; 032import org.apache.logging.log4j.Logger; 033import org.checkerframework.checker.nullness.qual.NonNull; 034import org.checkerframework.checker.nullness.qual.Nullable; 035 036import java.util.Iterator; 037import java.util.Set; 038 039/** 040 * A plot manager with a square grid layout, with square shaped plots. 041 */ 042public abstract class SquarePlotManager extends GridPlotManager { 043 044 private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SquarePlotManager.class.getSimpleName()); 045 046 private final SquarePlotWorld squarePlotWorld; 047 private final RegionManager regionManager; 048 049 public SquarePlotManager(final @NonNull SquarePlotWorld squarePlotWorld, final @NonNull RegionManager regionManager) { 050 super(squarePlotWorld); 051 this.squarePlotWorld = squarePlotWorld; 052 this.regionManager = regionManager; 053 } 054 055 @Override 056 public boolean clearPlot( 057 final @NonNull Plot plot, 058 final @Nullable Runnable whenDone, 059 @Nullable PlotPlayer<?> actor, 060 @Nullable QueueCoordinator queue 061 ) { 062 final Set<CuboidRegion> regions = plot.getRegions(); 063 Runnable run = new Runnable() { 064 @Override 065 public void run() { 066 if (regions.isEmpty()) { 067 if (whenDone != null) { 068 whenDone.run(); 069 } 070 return; 071 } 072 Iterator<CuboidRegion> iterator = regions.iterator(); 073 CuboidRegion region = iterator.next(); 074 iterator.remove(); 075 final Location pos1 = Location.at(plot.getWorldName(), region.getMinimumPoint()); 076 final Location pos2 = Location.at(plot.getWorldName(), region.getMaximumPoint()); 077 regionManager.regenerateRegion(pos1, pos2, false, this); 078 } 079 }; 080 run.run(); 081 return true; 082 } 083 084 @Override 085 public Location getPlotTopLocAbs(@NonNull PlotId plotId) { 086 int px = plotId.getX(); 087 int pz = plotId.getY(); 088 int x = (squarePlotWorld.ROAD_OFFSET_X + (px * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - (int) Math 089 .floor(squarePlotWorld.ROAD_WIDTH / 2) - 1; 090 int z = (squarePlotWorld.ROAD_OFFSET_Z + (pz * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - (int) Math 091 .floor(squarePlotWorld.ROAD_WIDTH / 2) - 1; 092 return Location.at(squarePlotWorld.getWorldName(), x, squarePlotWorld.getMaxGenHeight(), z); 093 } 094 095 @Override 096 public PlotId getPlotIdAbs(int x, int y, int z) { 097 if (squarePlotWorld.ROAD_OFFSET_X != 0) { 098 x -= squarePlotWorld.ROAD_OFFSET_X; 099 } 100 if (squarePlotWorld.ROAD_OFFSET_Z != 0) { 101 z -= squarePlotWorld.ROAD_OFFSET_Z; 102 } 103 int pathWidthLower; 104 int end; 105 if (squarePlotWorld.ROAD_WIDTH == 0) { 106 pathWidthLower = -1; 107 end = squarePlotWorld.PLOT_WIDTH; 108 } else { 109 if ((squarePlotWorld.ROAD_WIDTH % 2) == 0) { 110 pathWidthLower = (squarePlotWorld.ROAD_WIDTH / 2) - 1; 111 } else { 112 pathWidthLower = squarePlotWorld.ROAD_WIDTH / 2; 113 } 114 end = pathWidthLower + squarePlotWorld.PLOT_WIDTH; 115 } 116 int size = squarePlotWorld.PLOT_WIDTH + squarePlotWorld.ROAD_WIDTH; 117 int dx = Math.floorDiv(x, size) + 1; 118 int rx = Math.floorMod(x, size); 119 int dz = Math.floorDiv(z, size) + 1; 120 int rz = Math.floorMod(z, size); 121 if (rz <= pathWidthLower || rz > end || rx <= pathWidthLower || rx > end) { 122 return null; 123 } else { 124 return PlotId.of(dx, dz); 125 } 126 } 127 128 public PlotId getNearestPlotId(@NonNull PlotArea plotArea, int x, int y, int z) { 129 SquarePlotWorld dpw = (SquarePlotWorld) plotArea; 130 if (dpw.ROAD_OFFSET_X != 0) { 131 x -= dpw.ROAD_OFFSET_X; 132 } 133 if (dpw.ROAD_OFFSET_Z != 0) { 134 z -= dpw.ROAD_OFFSET_Z; 135 } 136 int size = dpw.PLOT_WIDTH + dpw.ROAD_WIDTH; 137 int idx; 138 if (x < 0) { 139 idx = x / size; 140 } else { 141 idx = (x / size) + 1; 142 } 143 int idz; 144 if (z < 0) { 145 idz = z / size; 146 } else { 147 idz = (z / size) + 1; 148 } 149 return PlotId.of(idx, idz); 150 } 151 152 @Override 153 public PlotId getPlotId(int x, int y, int z) { 154 try { 155 x -= squarePlotWorld.ROAD_OFFSET_X; 156 z -= squarePlotWorld.ROAD_OFFSET_Z; 157 int size = squarePlotWorld.PLOT_WIDTH + squarePlotWorld.ROAD_WIDTH; 158 int pathWidthLower; 159 int end; 160 if (squarePlotWorld.ROAD_WIDTH == 0) { 161 pathWidthLower = -1; 162 end = squarePlotWorld.PLOT_WIDTH; 163 } else { 164 if ((squarePlotWorld.ROAD_WIDTH % 2) == 0) { 165 pathWidthLower = (squarePlotWorld.ROAD_WIDTH / 2) - 1; 166 } else { 167 pathWidthLower = squarePlotWorld.ROAD_WIDTH / 2; 168 } 169 end = pathWidthLower + squarePlotWorld.PLOT_WIDTH; 170 } 171 int dx = Math.floorDiv(x, size) + 1; 172 int rx = Math.floorMod(x, size); 173 int dz = Math.floorDiv(z, size) + 1; 174 int rz = Math.floorMod(z, size); 175 PlotId id = PlotId.of(dx, dz); 176 boolean[] merged = new boolean[]{rz <= pathWidthLower, rx > end, rz > end, rx <= pathWidthLower}; 177 int hash = HashUtil.hash(merged); 178 // Not merged, and no need to check if it is 179 if (hash == 0) { 180 return id; 181 } 182 Plot plot = squarePlotWorld.getOwnedPlotAbs(id); 183 // Not merged, and standing on road 184 if (plot == null) { 185 return null; 186 } 187 switch (hash) { 188 case 8: 189 // north 190 return plot.isMerged(Direction.NORTH) ? id : null; 191 case 4: 192 // east 193 return plot.isMerged(Direction.EAST) ? id : null; 194 case 2: 195 // south 196 return plot.isMerged(Direction.SOUTH) ? id : null; 197 case 1: 198 // west 199 return plot.isMerged(Direction.WEST) ? id : null; 200 case 12: 201 // northeast 202 return plot.isMerged(Direction.NORTHEAST) ? id : null; 203 case 6: 204 // southeast 205 return plot.isMerged(Direction.SOUTHEAST) ? id : null; 206 case 3: 207 // southwest 208 return plot.isMerged(Direction.SOUTHWEST) ? id : null; 209 case 9: 210 // northwest 211 return plot.isMerged(Direction.NORTHWEST) ? id : null; 212 } 213 } catch (Exception ignored) { 214 LOGGER.error("Invalid plot / road width in settings.yml for world: {}", squarePlotWorld.getWorldName()); 215 } 216 return null; 217 } 218 219 /** 220 * Get the bottom plot loc (some basic math). 221 */ 222 @Override 223 public Location getPlotBottomLocAbs(@NonNull PlotId plotId) { 224 int px = plotId.getX(); 225 int pz = plotId.getY(); 226 int x = (squarePlotWorld.ROAD_OFFSET_X + (px * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - squarePlotWorld.PLOT_WIDTH 227 - (int) Math.floor(squarePlotWorld.ROAD_WIDTH / 2); 228 int z = (squarePlotWorld.ROAD_OFFSET_Z + (pz * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - squarePlotWorld.PLOT_WIDTH 229 - (int) Math.floor(squarePlotWorld.ROAD_WIDTH / 2); 230 return Location.at(squarePlotWorld.getWorldName(), x, squarePlotWorld.getMinGenHeight(), z); 231 } 232 233}