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.NotPublic;
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 * <p>
040 * Internal use only. Subject to change at any time and created for specific use cases.
041 */
042@NotPublic
043public class BlockArrayCacheScopedQueueCoordinator extends ZeroedDelegateScopedQueueCoordinator {
044
045    private final BlockState[][][] blockStates;
046    private final int height;
047    private final int width;
048    private final int length;
049    private final int minY;
050    private final int maxY;
051    private final int scopeMinX;
052    private final int scopeMinZ;
053    private final int scopeMaxX;
054    private final int scopeMaxZ;
055    private int offsetX = 0;
056    private int offsetZ = 0;
057
058    /**
059     * Construct a new instance
060     *
061     * @param min Inclusive location of the minimum point to limit the scope to.
062     * @param max Inclusive location of the maximum point to limit the scope to.
063     * @since 6.8.0
064     */
065    public BlockArrayCacheScopedQueueCoordinator(Location min, Location max) {
066        super(null, min, max);
067        this.width = max.getX() - min.getX() + 1;
068        this.length = max.getZ() - min.getZ() + 1;
069        this.minY = min.getY();
070        this.maxY = max.getY();
071        this.height = maxY - minY + 1;
072
073        this.scopeMinX = min.getX() & 15;
074        this.scopeMinZ = min.getZ() & 15;
075        this.scopeMaxX = scopeMinX + width;
076        this.scopeMaxZ = scopeMinZ + length;
077        this.blockStates = new BlockState[height][width][length];
078    }
079
080    public BlockState[][][] getBlockStates() {
081        return blockStates;
082    }
083
084    @Override
085    public boolean setBlock(int x, final int y, int z, final @NonNull BlockState id) {
086        x += offsetX;
087        z += offsetZ;
088        if (x >= scopeMinX && x < scopeMaxX && y >= minY && y <= maxY && z >= scopeMinZ && z < scopeMaxZ) {
089            blockStates[y - minY][x - scopeMinX][z - scopeMinZ] = id;
090        }
091        return false;
092    }
093
094    @Override
095    public boolean setBlock(final int x, final int y, final int z, @NonNull final Pattern pattern) {
096        int rx = x + offsetX;
097        int rz = z + offsetZ;
098        if (rx >= scopeMinX && rx < scopeMaxX && y >= minY && y <= maxY && rz >= scopeMinZ && rz < scopeMaxZ) {
099            BlockState state = pattern
100                    .applyBlock(super.getMin().getBlockVector3().add(BlockVector3.at(x, y, z)))
101                    .toImmutableState();
102            blockStates[y - minY][rx - scopeMinX][rz - scopeMinZ] = state;
103        }
104        return false;
105    }
106
107    @Override
108    public @NonNull Location getMin() {
109        return super.getMin().add(offsetX - scopeMinX, 0, offsetZ - scopeMinZ);
110    }
111
112    @Override
113    public @NonNull Location getMax() {
114        return getMin().add(15, 0, 15).withY(maxY);
115    }
116
117    @Override
118    public boolean setBlock(int x, int y, int z, final @NonNull BaseBlock id) {
119        x += offsetX;
120        z += offsetZ;
121        if (x >= scopeMinX && x < scopeMaxX && y >= minY && y <= maxY && z >= scopeMinZ && z < scopeMaxZ) {
122            blockStates[y - minY][x - scopeMinX][z - scopeMinZ] = id.toImmutableState();
123        }
124        return false;
125    }
126
127    @Override
128    public @Nullable BlockState getBlock(final int x, final int y, final int z) {
129        if (x >= 0 && x < width && y >= minY && y <= maxY && z >= 0 && z < length) {
130            return blockStates[y - minY][x][z];
131        }
132        return null;
133    }
134
135    public void setOffsetX(final int offsetX) {
136        this.offsetX = offsetX;
137    }
138
139    public void setOffsetZ(final int offsetZ) {
140        this.offsetZ = offsetZ;
141    }
142
143    @Override
144    public int size() {
145        return height * width * length;
146    }
147
148    @Override
149    public boolean setBiome(final int x, final int z, @NonNull final BiomeType biome) {
150        //do nothing
151        return false;
152    }
153
154    @Override
155    public boolean setBiome(final int x, final int y, final int z, @NonNull final BiomeType biome) {
156        //do nothing
157        return false;
158    }
159
160    @Override
161    public void fillBiome(final BiomeType biome) {
162        //do nothing
163    }
164
165    @Override
166    public boolean setTile(final int x, final int y, final int z, @NonNull final CompoundTag tag) {
167        //do nothing
168        return false;
169    }
170
171}