/*
* This file is part of Cubic Chunks Mod, licensed under the MIT License (MIT).
*
* Copyright (c) 2015 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package cubicchunks.util;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import cubicchunks.world.ICubeProvider;
import cubicchunks.world.ICubicWorld;
import cubicchunks.world.column.Column;
import cubicchunks.world.cube.Cube;
import static cubicchunks.util.Coords.blockToLocal;
/**
* Simple class that allows to quickly access blocks near specified cube without the overhead of getting these cubes.
* <p>
* Does not allow to set blocks, only get blocks, their opacity and get/set light values.
*/
public class FastCubeBlockAccess {
private final Cube[][][] cache;
private final int originX, originY, originZ;
private final ICubicWorld world;
public FastCubeBlockAccess(ICubeProvider cache, Cube cube, int radius) {
int n = radius*2 + 1;
this.world = cube.getCubicWorld();
this.cache = new Cube[n][n][n];
this.originX = cube.getX() - radius;
this.originY = cube.getY() - radius;
this.originZ = cube.getZ() - radius;
for (int relativeCubeX = -radius; relativeCubeX <= radius; relativeCubeX++) {
for (int relativeCubeZ = -radius; relativeCubeZ <= radius; relativeCubeZ++) {
for (int relativeCubeY = -radius; relativeCubeY <= radius; relativeCubeY++) {
this.cache[relativeCubeX + radius][relativeCubeY + radius][relativeCubeZ + radius] =
cache.getLoadedCube(originX + relativeCubeX + radius,
originY + relativeCubeY + radius,
originZ + relativeCubeZ + radius);
}
}
}
}
private Cube getCube(int blockX, int blockY, int blockZ) {
int cubeX = Coords.blockToCube(blockX);
int cubeY = Coords.blockToCube(blockY);
int cubeZ = Coords.blockToCube(blockZ);
Cube cube = this.cache[cubeX - originX][cubeY - originY][cubeZ - originZ];
return cube;
}
public IBlockState getBlockState(BlockPos pos) {
return this.getBlockState(pos.getX(), pos.getY(), pos.getZ());
}
public IBlockState getBlockState(int blockX, int blockY, int blockZ) {
return this.getCube(blockX, blockY, blockZ).getBlockState(blockX, blockY, blockZ);
}
public int getBlockLightOpacity(BlockPos pos) {
return this.getBlockState(pos.getX(), pos.getY(), pos.getZ()).getLightOpacity((World) world, pos);
}
public int getLightFor(EnumSkyBlock lightType, BlockPos pos) {
return this.getCube(pos.getX(), pos.getY(), pos.getZ()).getLightFor(lightType, pos);
}
public void setLightFor(EnumSkyBlock lightType, BlockPos pos, int val) {
this.getCube(pos.getX(), pos.getY(), pos.getZ()).setLightFor(lightType, pos, val);
}
/**
* Faster version of world.getRawLight that works for skylight
*/
public int computeLightValue(BlockPos pos) {
Cube cube = getCube(pos.getX(), pos.getY(), pos.getZ());
Column column = cube.getColumn();
int height = column.getHeightValue(blockToLocal(pos.getX()), blockToLocal(pos.getZ()));
if (pos.getY() > height) {
return 15;
}
IBlockState iblockstate = cube.getBlockState(pos);
int lightSubtract = iblockstate.getLightOpacity((IBlockAccess) world, pos);
if (lightSubtract < 1) {
lightSubtract = 1;
}
if (lightSubtract >= 15) {
return 0;
}
BlockPos.PooledMutableBlockPos currentPos = BlockPos.PooledMutableBlockPos.retain();
int maxValue = 0;
for (EnumFacing enumfacing : EnumFacing.values()) {
currentPos.setPos(pos).move(enumfacing);
int currentValue = this.getLightFor(EnumSkyBlock.SKY, currentPos) - lightSubtract;
if (currentValue > maxValue) {
maxValue = currentValue;
}
if (maxValue >= 14) {
return maxValue;
}
}
currentPos.release();
return maxValue;
}
}