/*
ChunkClaim Plugin for Minecraft Bukkit Servers
Copyright (C) 2012 Felix Schmidt
This file is part of ChunkClaim.
ChunkClaim 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, either version 3 of the License, or
(at your option) any later version.
ChunkClaim 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 ChunkClaim. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.schmidtbochum.chunkclaim;
import java.util.ArrayList;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
//represents a visualization sent to a player
public class Visualization {
public ArrayList<VisualizationElement> elements = new ArrayList<VisualizationElement>();
//sends a visualization to a player
public static void Apply(Player player, Visualization visualization) {
PlayerData playerData = ChunkClaim.plugin.dataStore.getPlayerData(player.getName());
//if he has any current visualization, clear it first
if(playerData.currentVisualization != null) {
Visualization.Revert(player);
}
//if he's online, create a task to send him the visualization in about half a second
if(player.isOnline()) {
playerData.currentVisualization = visualization;
ChunkClaim.plugin.getServer().getScheduler().scheduleSyncDelayedTask(ChunkClaim.plugin, new VisualizationApplicationTask(player, playerData, visualization), 10L);
//clear it after 20 seconds
ChunkClaim.plugin.getServer().getScheduler().scheduleSyncDelayedTask(ChunkClaim.plugin, new VisualizationClearTask(player, playerData, visualization), 400L);
}
}
//reverts a visualization by sending another block change list, this time with the real world block values
public static void Revert(Player player) {
PlayerData playerData = ChunkClaim.plugin.dataStore.getPlayerData(player.getName());
Visualization visualization = playerData.currentVisualization;
if(playerData.currentVisualization != null) {
if(player.isOnline()) {
for(int i = 0; i < visualization.elements.size(); i++) {
VisualizationElement element = visualization.elements.get(i);
if(element.location!=null) {
Block block = element.location.getBlock();
player.sendBlockChange(element.location, block.getType(), block.getData());
}
}
}
playerData.currentVisualization = null;
}
}
//convenience method to build a visualization from a claim
//visualizationType determines the style (gold blocks, silver, red, diamond, etc)
public static Visualization FromChunk(Chunk chunk, int height, VisualizationType visualizationType, Location not) {
Visualization visualization = new Visualization();
visualization.addChunkElements(chunk, height, visualizationType, not);
return visualization;
}
public static Visualization FromBukkitChunk(org.bukkit.Chunk bukkitChunk, int height, VisualizationType visualizationType, Location not) {
Chunk chunk = new Chunk(bukkitChunk.getX(),bukkitChunk.getZ(),bukkitChunk.getWorld().getName());
Visualization visualization = new Visualization();
visualization.addChunkElements(chunk, height, visualizationType, not);
return visualization;
}
private void addChunkElements(Chunk chunk, int height, VisualizationType visualizationType, Location not) {
World world = ChunkClaim.plugin.getServer().getWorld(chunk.worldName);
int smallx = chunk.x*16;
int smallz = chunk.z*16;
int bigx = (chunk.x+1)*16-1;
int bigz = (chunk.z+1)*16-1;
Material cornerMaterial = Material.SNOW_BLOCK;
Material accentMaterial = Material.SNOW_BLOCK;
Byte cornerByte = (byte)0;
Byte accentByte = (byte)0;
if(visualizationType == VisualizationType.Chunk) {
cornerMaterial = Material.WOOL;
accentMaterial = Material.WOOL;
cornerByte = (byte)1;
accentByte = (byte)1;
}
else if(visualizationType == VisualizationType.ErrorChunk) {
cornerMaterial = Material.NETHERRACK;
accentMaterial = Material.NETHERRACK;
}
else if(visualizationType == VisualizationType.Public) {
cornerMaterial = Material.WOOL;
accentMaterial = Material.WOOL;
cornerByte = (byte)11;
accentByte = (byte)11;
}
//bottom left corner
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, smallz, not), cornerMaterial,cornerByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 1, height, smallz, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 2, height, smallz, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, smallz + 1, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, smallz + 2, not), accentMaterial, accentByte));
//bottom right corner
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, smallz, not), cornerMaterial,cornerByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx - 1, height, smallz, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx - 2, height, smallz, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, smallz + 1, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, smallz + 2, not), accentMaterial, accentByte));
//top right corner
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, bigz, not), cornerMaterial,cornerByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx - 1, height, bigz, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx - 2, height, bigz, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, bigz - 1, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, bigz - 2, not), accentMaterial, accentByte));
//top left corner
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, bigz, not), cornerMaterial,cornerByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 1, height, bigz, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 2, height, bigz, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, bigz - 1, not), accentMaterial, accentByte));
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, bigz - 2, not), accentMaterial, accentByte));
}
//finds a block the player can probably see. this is how visualizations "cling" to the ground or ceiling
private static Location getVisibleLocation(World world, int x, int y, int z, Location not) {
Block block = world.getBlockAt(x, y, z);
BlockFace direction = (isTransparent(block)) ? BlockFace.DOWN : BlockFace.UP;
while( block.getY() >= 1 && block.getY() < world.getMaxHeight() - 1 && (!isTransparent(block.getRelative(BlockFace.UP)) || isTransparent(block))) {
block = block.getRelative(direction);
}
Location location = block.getLocation();
if(not!=null &&location.getX()==not.getX() && location.getY()==not.getY() && location.getZ()==not.getZ()) {
return null;
} else {
return location;
}
}
//helper method for above. allows visualization blocks to sit underneath partly transparent blocks like grass and fence
private static boolean isTransparent(Block block)
{
return (
block.getType() == Material.AIR ||
block.getType() == Material.LONG_GRASS ||
block.getType() == Material.FENCE ||
block.getType() == Material.LEAVES ||
block.getType() == Material.RED_ROSE ||
block.getType() == Material.CHEST ||
block.getType() == Material.YELLOW_FLOWER
);
}
}