/*
* Copyright (C) 2011-2014 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.orebfuscator.obfuscation;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import com.lishid.orebfuscator.DeprecatedMethods;
import com.lishid.orebfuscator.Orebfuscator;
import com.lishid.orebfuscator.cache.ObfuscatedCachedChunk;
import com.lishid.orebfuscator.cache.ObfuscatedDataCache;
import com.lishid.orebfuscator.config.WorldConfig;
import com.lishid.orebfuscator.nms.IBlockInfo;
import com.lishid.orebfuscator.types.ChunkCoord;
public class BlockUpdate {
public static boolean needsUpdate(Block block) {
return !Orebfuscator.config.isBlockTransparent(DeprecatedMethods.getTypeId(block));
}
public static void update(Block block) {
if (!needsUpdate(block)) {
return;
}
update(Arrays.asList(new Block[]{block}));
}
public static void update(List<Block> blocks) {
if (blocks.isEmpty()) {
return;
}
World world = blocks.get(0).getWorld();
WorldConfig worldConfig = Orebfuscator.configManager.getWorld(world);
HashSet<IBlockInfo> updateBlocks = new HashSet<IBlockInfo>();
HashSet<ChunkCoord> invalidChunks = new HashSet<ChunkCoord>();
int updateRadius = Orebfuscator.config.getUpdateRadius();
for (Block block : blocks) {
if (needsUpdate(block)) {
IBlockInfo blockInfo = Orebfuscator.nms.getBlockInfo(world, block.getX(), block.getY(), block.getZ());
getAjacentBlocks(updateBlocks, world, worldConfig, blockInfo, updateRadius);
if((blockInfo.getX() & 0xf) == 0) {
invalidChunks.add(new ChunkCoord((blockInfo.getX() >> 4) - 1, blockInfo.getZ() >> 4));
} else if(((blockInfo.getX() + 1) & 0xf) == 0) {
invalidChunks.add(new ChunkCoord((blockInfo.getX() >> 4) + 1, blockInfo.getZ() >> 4));
} else if(((blockInfo.getZ()) & 0xf) == 0) {
invalidChunks.add(new ChunkCoord(blockInfo.getX() >> 4, (blockInfo.getZ() >> 4) - 1));
} else if(((blockInfo.getZ() + 1) & 0xf) == 0) {
invalidChunks.add(new ChunkCoord(blockInfo.getX() >> 4, (blockInfo.getZ() >> 4) + 1));
}
}
}
sendUpdates(world, updateBlocks);
invalidateCachedChunks(world, invalidChunks);
}
//This method is used in CastleGates plugin
public static void updateByLocations(List<Location> locations, int updateRadius) {
if (locations.isEmpty()) {
return;
}
World world = locations.get(0).getWorld();
WorldConfig worldConfig = Orebfuscator.configManager.getWorld(world);
HashSet<IBlockInfo> updateBlocks = new HashSet<IBlockInfo>();
HashSet<ChunkCoord> invalidChunks = new HashSet<ChunkCoord>();
for (Location location : locations) {
IBlockInfo blockInfo = Orebfuscator.nms.getBlockInfo(world, location.getBlockX(), location.getBlockY(), location.getBlockZ());
getAjacentBlocks(updateBlocks, world, worldConfig, blockInfo, updateRadius);
if((blockInfo.getX() & 0xf) == 0) {
invalidChunks.add(new ChunkCoord((blockInfo.getX() >> 4) - 1, blockInfo.getZ() >> 4));
} else if(((blockInfo.getX() + 1) & 0xf) == 0) {
invalidChunks.add(new ChunkCoord((blockInfo.getX() >> 4) + 1, blockInfo.getZ() >> 4));
} else if(((blockInfo.getZ()) & 0xf) == 0) {
invalidChunks.add(new ChunkCoord(blockInfo.getX() >> 4, (blockInfo.getZ() >> 4) - 1));
} else if(((blockInfo.getZ() + 1) & 0xf) == 0) {
invalidChunks.add(new ChunkCoord(blockInfo.getX() >> 4, (blockInfo.getZ() >> 4) + 1));
}
}
sendUpdates(world, updateBlocks);
invalidateCachedChunks(world, invalidChunks);
}
private static void sendUpdates(World world, Set<IBlockInfo> blocks) {
//Orebfuscator.log("Notify block change for " + blocks.size() + " blocks");/*debug*/
for (IBlockInfo blockInfo : blocks) {
Orebfuscator.nms.notifyBlockChange(world, blockInfo);
}
}
private static void invalidateCachedChunks(World world, Set<ChunkCoord> invalidChunks) {
if(invalidChunks.isEmpty() || !Orebfuscator.config.isUseCache()) return;
File cacheFolder = new File(ObfuscatedDataCache.getCacheFolder(), world.getName());
for(ChunkCoord chunk : invalidChunks) {
ObfuscatedCachedChunk cache = new ObfuscatedCachedChunk(cacheFolder, chunk.x, chunk.z);
cache.invalidate();
//Orebfuscator.log("Chunk x = " + chunk.x + ", z = " + chunk.z + " is invalidated");/*debug*/
}
}
private static void getAjacentBlocks(
HashSet<IBlockInfo> allBlocks,
World world,
WorldConfig worldConfig,
IBlockInfo blockInfo,
int countdown
)
{
if (blockInfo == null) return;
int blockId = blockInfo.getTypeId();
if ((worldConfig.isObfuscated(blockId) || worldConfig.isDarknessObfuscated(blockId))) {
allBlocks.add(blockInfo);
}
if (countdown > 0) {
countdown--;
getAjacentBlocks(allBlocks, world, worldConfig, Orebfuscator.nms.getBlockInfo(world, blockInfo.getX() + 1, blockInfo.getY(), blockInfo.getZ()), countdown);
getAjacentBlocks(allBlocks, world, worldConfig, Orebfuscator.nms.getBlockInfo(world, blockInfo.getX() - 1, blockInfo.getY(), blockInfo.getZ()), countdown);
getAjacentBlocks(allBlocks, world, worldConfig, Orebfuscator.nms.getBlockInfo(world, blockInfo.getX(), blockInfo.getY() + 1, blockInfo.getZ()), countdown);
getAjacentBlocks(allBlocks, world, worldConfig, Orebfuscator.nms.getBlockInfo(world, blockInfo.getX(), blockInfo.getY() - 1, blockInfo.getZ()), countdown);
getAjacentBlocks(allBlocks, world, worldConfig, Orebfuscator.nms.getBlockInfo(world, blockInfo.getX(), blockInfo.getY(), blockInfo.getZ() + 1), countdown);
getAjacentBlocks(allBlocks, world, worldConfig, Orebfuscator.nms.getBlockInfo(world, blockInfo.getX(), blockInfo.getY(), blockInfo.getZ() - 1), countdown);
}
}
}