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.queue;
020
021import com.intellectualsites.annotations.DoNotUse;
022import com.plotsquared.core.location.Location;
023import com.sk89q.jnbt.CompoundTag;
024import com.sk89q.worldedit.function.pattern.Pattern;
025import com.sk89q.worldedit.math.BlockVector3;
026import com.sk89q.worldedit.world.biome.BiomeType;
027import com.sk89q.worldedit.world.block.BaseBlock;
028import com.sk89q.worldedit.world.block.BlockState;
029import org.checkerframework.checker.nullness.qual.NonNull;
030import org.checkerframework.checker.nullness.qual.Nullable;
031
032/**
033 * {@link QueueCoordinator} that caches all blocks set to it in a given array of form BlockState[][][]. An offset can be
034 * applied to blocks set to it, and the scope limited. This should have blocks set to it one chunk at a time, based on the
035 * result of {@link BlockArrayCacheScopedQueueCoordinator#getMin()} and {@link BlockArrayCacheScopedQueueCoordinator#getMax()}.
036 * The min and max points of this queue are offset according to the minimum point given in the constructor, and the offsets set
037 * in {@link BlockArrayCacheScopedQueueCoordinator#setOffsetX(int)} and
038 * {@link BlockArrayCacheScopedQueueCoordinator#setOffsetZ(int)}
039 */
040@DoNotUse
041public class BlockArrayCacheScopedQueueCoordinator extends ScopedQueueCoordinator {
042
043    private final BlockState[][][] blockStates;
044    private final int height;
045    private final int width;
046    private final int length;
047    private final int minY;
048    private final int maxY;
049    private final int scopeMinX;
050    private final int scopeMinZ;
051    private final int scopeMaxX;
052    private final int scopeMaxZ;
053    private int offsetX = 0;
054    private int offsetZ = 0;
055    /**
056     * Construct a new instance
057     *
058     * @param min Inclusive location of the minimum point to limit the scope to.
059     * @param max Inclusive location of the maximum point to limit the scope to.
060     * @since 6.8.0
061     */
062    public BlockArrayCacheScopedQueueCoordinator(Location min, Location max) {
063        super(null, min, max);
064        this.width = max.getX() - min.getX() + 1;
065        this.length = max.getZ() - min.getZ() + 1;
066        this.minY = min.getY();
067        this.maxY = max.getY();
068        this.height = maxY - minY + 1;
069
070        this.scopeMinX = min.getX() & 15;
071        this.scopeMinZ = min.getZ() & 15;
072        this.scopeMaxX = scopeMinX + width;
073        this.scopeMaxZ = scopeMinZ + length;
074        this.blockStates = new BlockState[height][width][length];
075    }
076
077    public BlockState[][][] getBlockStates() {
078        return blockStates;
079    }
080
081    @Override
082    public boolean setBlock(int x, final int y, int z, final @NonNull BlockState id) {
083        x += offsetX;
084        z += offsetZ;
085        if (x >= scopeMinX && x < scopeMaxX && y >= minY && y <= maxY && z >= scopeMinZ && z < scopeMaxZ) {
086            blockStates[y - minY][x - scopeMinX][z - scopeMinZ] = id;
087        }
088        return false;
089    }
090
091    @Override
092    public boolean setBlock(final int x, final int y, final int z, @NonNull final Pattern pattern) {
093        int rx = x + offsetX;
094        int rz = z + offsetZ;
095        if (rx >= scopeMinX && rx < scopeMaxX && y >= minY && y <= maxY && rz >= scopeMinZ && rz < scopeMaxZ) {
096            BlockState state = pattern
097                    .applyBlock(super.getMin().getBlockVector3().add(BlockVector3.at(x, y, z)))
098                    .toImmutableState();
099            blockStates[y - minY][rx - scopeMinX][rz - scopeMinZ] = state;
100        }
101        return false;
102    }
103
104    @Override
105    public @NonNull Location getMin() {
106        return super.getMin().add(offsetX - scopeMinX, 0, offsetZ - scopeMinZ);
107    }
108
109    @Override
110    public @NonNull Location getMax() {
111        return getMin().add(15, 0, 15).withY(maxY);
112    }
113
114    @Override
115    public boolean setBlock(int x, int y, int z, final @NonNull BaseBlock id) {
116        x += offsetX;
117        z += offsetZ;
118        if (x >= scopeMinX && x < scopeMaxX && y >= minY && y <= maxY && z >= scopeMinZ && z < scopeMaxZ) {
119            blockStates[y - minY][x - scopeMinX][z - scopeMinZ] = id.toImmutableState();
120        }
121        return false;
122    }
123
124    @Override
125    public @Nullable BlockState getBlock(final int x, final int y, final int z) {
126        if (x >= 0 && x < width && y >= minY && y <= maxY && z >= 0 && z < length) {
127            return blockStates[y - minY][x][z];
128        }
129        return null;
130    }
131
132    public void setOffsetX(final int offsetX) {
133        this.offsetX = offsetX;
134    }
135
136    public void setOffsetZ(final int offsetZ) {
137        this.offsetZ = offsetZ;
138    }
139
140    @Override
141    public int size() {
142        return height * width * length;
143    }
144
145    @Override
146    public boolean setBiome(final int x, final int z, @NonNull final BiomeType biome) {
147        //do nothing
148        return false;
149    }
150
151    @Override
152    public boolean setBiome(final int x, final int y, final int z, @NonNull final BiomeType biome) {
153        //do nothing
154        return false;
155    }
156
157    @Override
158    public void fillBiome(final BiomeType biome) {
159        //do nothing
160    }
161
162    @Override
163    public boolean setTile(final int x, final int y, final int z, @NonNull final CompoundTag tag) {
164        //do nothing
165        return false;
166    }
167
168}