package com.boydti.fawe.beta.implementation.filter.block; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlockMask; import com.boydti.fawe.beta.Flood; import com.boydti.fawe.beta.IBlocks; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.registry.BlockMaterial; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import static com.sk89q.worldedit.world.block.BlockTypesCache.states; public class CharFilterBlock extends ChunkFilterBlock { private static final SetDelegate FULL = (block, value) -> block.setArr[block.index] = value; private static final SetDelegate NULL = (block, value) -> block.initSet().set(block, value); private CharGetBlocks get; private IChunkSet set; private char[] getArr; @Nullable private char[] setArr; private SetDelegate delegate; // local private int layer; private int index; private int x; private int y; private int z; private int xx; private int yy; private int zz; private int chunkX; private int chunkZ; public CharFilterBlock(Extent extent) { super(extent); } @Override public final ChunkFilterBlock initChunk(int chunkX, int chunkZ) { this.chunkX = chunkX; this.chunkZ = chunkZ; this.xx = chunkX << 4; this.zz = chunkZ << 4; return this; } @Override public final ChunkFilterBlock initLayer(IBlocks iget, IChunkSet iset, int layer) { this.get = (CharGetBlocks) iget; this.layer = layer; if (!iget.hasSection(layer)) { getArr = FaweCache.IMP.EMPTY_CHAR_4096; } else { getArr = iget.load(layer); } this.set = iset; if (set.hasSection(layer)) { setArr = set.load(layer); delegate = FULL; } else { delegate = NULL; setArr = null; } this.yy = layer << 4; return this; } @Override public void flood(IChunkGet iget, IChunkSet iset, int layer, Flood flood, FilterBlockMask mask) { final int maxDepth = flood.getMaxDepth(); final boolean checkDepth = maxDepth < Character.MAX_VALUE; if (initLayer(iget, iset, layer) != null) { // TODO replace with hasSection while ((index = flood.poll()) != -1) { x = index & 15; z = index >> 4 & 15; y = index >> 8 & 15; if (mask.applyBlock(this)) { int depth = index >> 12; if (checkDepth && depth > maxDepth) { continue; } flood.apply(x, y, z, depth); } } } } @Override public void filter(Filter filter, int x, int y, int z) { this.x = x; this.y = y; this.z = z; this.index = x | z << 4 | y << 8; filter.applyBlock(this); } @Override public void filter(Filter filter, int startY, int endY) { for (y = startY, index = startY << 8; y <= endY; y++) { for (z = 0; z < 16; z++) { for (x = 0; x < 16; x++, index++) { filter.applyBlock(this); } } } } @Override public void filter(Filter filter, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { int yis = minY << 8; int zis = minZ << 4; int zie = (15 - maxZ) << 4; int xie = (15 - maxX); for (y = minY, index = yis; y <= maxY; y++) { index += zis; for (z = minZ; z <= maxZ; z++) { index += minX; for (x = minX; x <= maxX; x++, index++) { filter.applyBlock(this); } index += xie; } index += zie; } } @Override public final void filter(Filter filter, Region region) { for (y = 0, index = 0; y < 16; y++) { int absY = yy + y; for (z = 0; z < 16; z++) { int absZ = zz + z; for (x = 0; x < 16; x++, index++) { int absX = xx + x; if (region.contains(absX, absY, absZ)) { filter.applyBlock(this); } } } } } @Override public final void filter(Filter filter) { for (y = 0, index = 0; y < 16; y++) { for (z = 0; z < 16; z++) { for (x = 0; x < 16; x++, index++) { filter.applyBlock(this); } } } } @Override public void setBiome(BiomeType biome) { set.setBiome(x, y, z, biome); } @Override public final int getX() { return xx + x; } @Override public final int getY() { return yy + y; } @Override public final int getZ() { return zz + z; } @Override public final int getLocalX() { return x; } @Override public final int getLocalY() { return y; } @Override public final int getLocalZ() { return z; } @Override public final int getChunkX() { return chunkX; } @Override public final int getChunkZ() { return chunkZ; } public final char getOrdinalChar() { return getArr[index]; } @Override public final int getOrdinal() { return getArr[index]; } @Override public void setOrdinal(int ordinal) { delegate.set(this, (char) ordinal); } @Override public final BlockState getBlock() { final int ordinal = getArr[index]; return BlockTypesCache.states[ordinal]; } @Override public void setBlock(BlockState state) { delegate.set(this, state.getOrdinalChar()); } @Override public final BaseBlock getFullBlock() { final BlockState state = getBlock(); final BlockMaterial material = state.getMaterial(); if (material.hasContainer()) { final CompoundTag tag = get.getTile(x, y + yy, z); return state.toBaseBlock(tag); } return state.toBaseBlock(); } @Override public void setFullBlock(BaseBlock block) { delegate.set(this, block.getOrdinalChar()); final CompoundTag nbt = block.getNbtData(); if (nbt != null) { // TODO optimize check via ImmutableBaseBlock set.setTile(x, yy + y, z, nbt); } } @Override public final CompoundTag getNbtData() { return get.getTile(x, y + yy, z); } /* NORTH(Vector3.at(0, 0, -1), Flag.CARDINAL, 3, 1), EAST(Vector3.at(1, 0, 0), Flag.CARDINAL, 0, 2), SOUTH(Vector3.at(0, 0, 1), Flag.CARDINAL, 1, 3), WEST(Vector3.at(-1, 0, 0), Flag.CARDINAL, 2, 0), */ @Override public void setNbtData(CompoundTag tag) { if (tag != null) { set.setTile(x, y + yy, z, tag); } } @Override public boolean hasNbtData() { final BlockState state = getBlock(); final BlockMaterial material = state.getMaterial(); return material.hasContainer(); } @Override public final BlockState getBlockNorth() { if (z > 0) { return states[getArr[index - 16]]; } return getExtent().getBlock(getX(), getY(), getZ() - 1); } @Override public final BlockState getBlockEast() { if (x < 15) { return states[getArr[index + 1]]; } return getExtent().getBlock(getX() + 1, getY(), getZ()); } @Override public final BlockState getBlockSouth() { if (z < 15) { return states[getArr[index + 16]]; } return getExtent().getBlock(getX(), getY(), getZ() + 1); } @Override public final BlockState getBlockWest() { if (x > 0) { return states[getArr[index - 1]]; } return getExtent().getBlock(getX() - 1, getY(), getZ()); } @Override public final BlockState getBlockBelow() { if (y > 0) { return states[getArr[index - 256]]; } if (layer > 0) { final int newLayer = layer - 1; final CharGetBlocks chunk = this.get; return states[chunk.sections[newLayer].get(chunk, newLayer, index + 3840)]; } return BlockTypes.__RESERVED__.getDefaultState(); } @Override public final BlockState getBlockAbove() { if (y < 16) { return states[getArr[index + 256]]; } if (layer < 16) { final int newLayer = layer + 1; final CharGetBlocks chunk = this.get; return states[chunk.sections[newLayer].get(chunk, newLayer, index - 3840)]; } return BlockTypes.__RESERVED__.getDefaultState(); } @Override public final BlockState getBlockRelativeY(int y) { final int newY = this.y + y; final int layerAdd = newY >> 4; switch (layerAdd) { case 0: return states[getArr[this.index + (y << 8)]]; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: { final int newLayer = layer + layerAdd; if (newLayer < 16) { final int index = this.index + ((y & 15) << 8); return states[get.sections[newLayer].get(get, newLayer, index)]; } break; } case -1: case -2: case -3: case -4: case -5: case -6: case -7: case -8: case -9: case -10: case -11: case -12: case -13: case -14: case -15: final int newLayer = layer + layerAdd; if (newLayer >= 0) { final int index = this.index + ((y & 15) << 8); return states[get.sections[newLayer].get(get, newLayer, index)]; } break; } return BlockTypes.__RESERVED__.getDefaultState(); } /* Extent */ @Override public char getOrdinalChar(Extent orDefault) { return getOrdinalChar(); } //Set delegate private SetDelegate initSet() { setArr = set.load(layer); return delegate = FULL; } @Override public BiomeType getBiomeType(int x, int y, int z) { if (x >> 4 == chunkX && z >> 4 == chunkZ) { return get.getBiomeType(x & 15, y, z & 15); } return getExtent().getBiomeType(x, y, z); } @Override public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { return getExtent().setBlock(x, y, z, block); } @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { return setBiome(position.getX(), position.getY(), position.getBlockZ(), biome); } @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { if (x >> 4 == chunkX && z >> 4 == chunkZ) { return set.setBiome(x & 15, y, z & 15, biome); } return getExtent().setBiome(x, y, z, biome); } private interface SetDelegate { void set(@NotNull CharFilterBlock block, char value); } }