/*
* Copyright 2014 Alex Bennett & Alexander Chauncey
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.demigodsrpg.util.schematic;
import com.demigodsrpg.util.misc.RandomUtil;
import com.google.common.base.Objects;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@SuppressWarnings("deprecation")
public class Selection {
private int X, Y, Z, XX, YY, ZZ;
private int eX, eY, eZ, eXX, eYY, eZZ;
private boolean cuboid;
private boolean exclude;
private boolean excludeSelection;
private List<PotentialMaterial> blockData;
/**
* Constructor for a Selection (non-cuboid), useful for getting 1 location back.
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
*/
public Selection(int X, int Y, int Z) {
this.X = this.XX = X;
this.Y = this.YY = Y;
this.Z = this.ZZ = Z;
this.cuboid = false;
this.exclude = false;
this.excludeSelection = false;
this.blockData = Lists.newArrayList();
}
/**
* Constructor for a Selection (cuboid), useful for getting only locations back.
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param XX The second relative X coordinate of the schematic from the reference location, creating a cuboid.
* @param YY The second relative Y coordinate of the schematic from the reference location, creating a cuboid.
* @param ZZ The second relative Z coordinate of the schematic from the reference location, creating a cuboid.
*/
public Selection(int X, int Y, int Z, int XX, int YY, int ZZ) {
this.X = X;
this.Y = Y;
this.Z = Z;
this.XX = XX;
this.YY = YY;
this.ZZ = ZZ;
this.cuboid = true;
this.exclude = false;
this.excludeSelection = false;
this.blockData = Lists.newArrayList();
}
/**
* Constructor for a Selection (non-cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param material The StoaMaterialData objects of this schematic.
*/
public Selection(int X, int Y, int Z, String material) {
this.X = this.XX = X;
this.Y = this.YY = Y;
this.Z = this.ZZ = Z;
this.cuboid = false;
this.exclude = false;
this.excludeSelection = false;
this.blockData = Lists.newArrayList(new PotentialMaterial(material));
}
/**
* Constructor for a Selection (cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param XX The second relative X coordinate of the schematic from the reference location, creating a cuboid.
* @param YY The second relative Y coordinate of the schematic from the reference location, creating a cuboid.
* @param ZZ The second relative Z coordinate of the schematic from the reference location, creating a cuboid.
* @param material The MaterialData objects of this schematic.
*/
public Selection(int X, int Y, int Z, int XX, int YY, int ZZ, String material) {
this.X = X;
this.Y = Y;
this.Z = Z;
this.XX = XX;
this.YY = YY;
this.ZZ = ZZ;
this.cuboid = true;
this.exclude = false;
this.excludeSelection = false;
this.blockData = Lists.newArrayList(new PotentialMaterial(material));
}
/**
* Constructor for a Selection (non-cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param material The StoaMaterialData objects of this schematic.
*/
public Selection(int X, int Y, int Z, String material, byte data) {
this.X = this.XX = X;
this.Y = this.YY = Y;
this.Z = this.ZZ = Z;
this.cuboid = false;
this.exclude = false;
this.excludeSelection = false;
this.blockData = Lists.newArrayList(new PotentialMaterial(material, data));
}
/**
* Constructor for a Selection (cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param XX The second relative X coordinate of the schematic from the reference location, creating a cuboid.
* @param YY The second relative Y coordinate of the schematic from the reference location, creating a cuboid.
* @param ZZ The second relative Z coordinate of the schematic from the reference location, creating a cuboid.
* @param material The material id of this schematic.
* @param data The material byte data of this schematic.
*/
public Selection(int X, int Y, int Z, int XX, int YY, int ZZ, String material, byte data) {
this.X = X;
this.Y = Y;
this.Z = Z;
this.XX = XX;
this.YY = YY;
this.ZZ = ZZ;
this.cuboid = true;
this.exclude = false;
this.excludeSelection = false;
this.blockData = Lists.newArrayList(new PotentialMaterial(material, data));
}
/**
* Constructor for a Selection (non-cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param blockData The potential material of this schematic.
*/
public Selection(int X, int Y, int Z, PotentialMaterial blockData) {
this.X = this.XX = X;
this.Y = this.YY = Y;
this.Z = this.ZZ = Z;
this.cuboid = false;
this.exclude = false;
this.excludeSelection = false;
this.blockData = Lists.newArrayList(blockData);
}
/**
* Constructor for a Selection (cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param XX The second relative X coordinate of the schematic from the reference location, creating a cuboid.
* @param YY The second relative Y coordinate of the schematic from the reference location, creating a cuboid.
* @param ZZ The second relative Z coordinate of the schematic from the reference location, creating a cuboid.
* @param blockData The potential material of this schematic.
*/
public Selection(int X, int Y, int Z, int XX, int YY, int ZZ, PotentialMaterial blockData) {
this.X = X;
this.Y = Y;
this.Z = Z;
this.XX = XX;
this.YY = YY;
this.ZZ = ZZ;
this.cuboid = true;
this.exclude = false;
this.excludeSelection = false;
this.blockData = Lists.newArrayList(blockData);
}
/**
* Constructor for a Selection (non-cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param blockData The potential materials of this schematic.
*/
public Selection(int X, int Y, int Z, List<PotentialMaterial> blockData) {
this.X = this.XX = X;
this.Y = this.YY = Y;
this.Z = this.ZZ = Z;
this.cuboid = false;
this.exclude = false;
this.excludeSelection = false;
this.blockData = blockData;
}
/**
* Constructor for a Selection (cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param XX The second relative X coordinate of the schematic from the reference location, creating a cuboid.
* @param YY The second relative Y coordinate of the schematic from the reference location, creating a cuboid.
* @param ZZ The second relative Z coordinate of the schematic from the reference location, creating a cuboid.
* @param blockData The potential materials of this schematic.
*/
public Selection(int X, int Y, int Z, int XX, int YY, int ZZ, List<PotentialMaterial> blockData) {
this.X = X;
this.Y = Y;
this.Z = Z;
this.XX = XX;
this.YY = YY;
this.ZZ = ZZ;
this.cuboid = true;
this.exclude = false;
this.excludeSelection = false;
this.blockData = blockData;
}
/**
* Collect a cuboid of selections from the point of view of referenceA, centered around referenceB.
*
* @param referenceA Location of view for the selections.
* @param referenceB Center of the cuboid.
* @param radius Radius of cuboid.
* @return List of Selections.
*/
public static List<Selection> getCuboid(Location referenceA, Location referenceB, int radius) {
List<Selection> selections = Lists.newArrayList();
int X = referenceB.getBlockX() - radius, Y = referenceB.getBlockY() - radius,
Z = referenceB.getBlockZ() - radius, XX = referenceB.getBlockX() + radius,
YY = referenceB.getBlockY() + radius, ZZ = referenceB.getBlockZ() + radius;
int differenceX = referenceB.getBlockX() - referenceA.getBlockX();
int differenceY = referenceB.getBlockY() - referenceA.getBlockY();
int differenceZ = referenceB.getBlockZ() - referenceA.getBlockZ();
for (int x = (X < XX ? X : XX); x <= (X < XX ? XX : X); x++)
for (int y = (Y < YY ? Y : YY); y <= (Y < YY ? YY : Y); y++)
for (int z = (Z < ZZ ? Z : ZZ); z <= (Z < ZZ ? ZZ : Z); z++)
selections.add(new Selection(x + differenceX, y + differenceY, z + differenceZ,
getMaterialData(referenceA)));
return selections;
}
/**
* Get the material data from a specified locaiton.
*
* @param location The location.
* @return A material.
*/
public static PotentialMaterial getMaterialData(Location location) {
Block block = location.getBlock();
return new PotentialMaterial(block.getType().name(), block.getData());
}
/**
* Excluding for a Selection (non-cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @return This schematic.
*/
public Selection exclude(int X, int Y, int Z) {
this.eX = this.eXX = X;
this.eY = this.eYY = Y;
this.eZ = this.eZZ = Z;
this.exclude = true;
return this;
}
/**
* Excluding for a Selection (cuboid).
*
* @param X The relative X coordinate of the schematic from the reference location.
* @param Y The relative Y coordinate of the schematic from the reference location.
* @param Z The relative Z coordinate of the schematic from the reference location.
* @param XX The second relative X coordinate of the schematic from the reference location, creating a cuboid.
* @param YY The second relative Y coordinate of the schematic from the reference location, creating a cuboid.
* @param ZZ The second relative Z coordinate of the schematic from the reference location, creating a cuboid.
* @return This schematic.
*/
public Selection exclude(int X, int Y, int Z, int XX, int YY, int ZZ) {
this.eX = X;
this.eY = Y;
this.eZ = Z;
this.eXX = XX;
this.eYY = YY;
this.eZZ = ZZ;
this.exclude = true;
this.excludeSelection = true;
return this;
}
/**
* Get the material of the object (a random material is chosen based on the configured odds).
*
* @return A material.
*/
public PotentialMaterial getStructureMaterialData() {
final int roll = RandomUtil.generateIntRange(1, 100);
Collection<PotentialMaterial> check = Collections2.filter(blockData, blockData1 -> blockData1.getOdds() >= roll);
if (check.isEmpty()) return getStructureMaterialData();
return Lists.newArrayList(check).get(RandomUtil.generateIntRange(0, check.size() - 1));
}
/**
* Get the block locations in this object.
*
* @param reference The reference location.
* @return A set of locations.
*/
public Set<Location> getBlockLocations(final Location reference) {
if (cuboid) {
if (exclude) {
if (excludeSelection)
return Sets.difference(rangeLoop(reference, X, XX, Y, YY, Z, ZZ), rangeLoop(reference, eX, eXX, eY,
eYY, eZ, eZZ));
return Sets.difference(rangeLoop(reference, X, XX, Y, YY, Z, ZZ), Sets.newHashSet(getLocation(reference,
eX, eY, eZ)));
}
return rangeLoop(reference, X, XX, Y, YY, Z, ZZ);
}
return Sets.newHashSet(getLocation(reference, X, Y, Z));
}
/**
* Generate this schematic.
*
* @param reference The reference Location.
*/
public void generate(Location reference) {
if (blockData.isEmpty()) return;
for (Location location : getBlockLocations(reference)) {
PotentialMaterial data = getStructureMaterialData();
Material material = Material.valueOf(data.getMaterial());
location.getBlock().setType(material);
location.getBlock().setData(data.getData());
}
}
/**
* Get a relative location, based on the <code>X</code>, <code>Y</code>, <code>Z</code> coordinates relative to the
* object's central location.
*
* @param reference The reference point.
* @param X Relative X coordinate.
* @param Y Relative Y coordinate.
* @param Z Relative Z coordinate.
* @return New relative location.
*/
public Location getLocation(Location reference, int X, int Y, int Z) {
return reference.add(X, Y, Z);
}
/**
* Get a cuboid selection as a HashSet.
*
* @param reference The reference location.
* @param X The relative X coordinate.
* @param XX The second relative X coordinate.
* @param Y The relative Y coordinate.
* @param YY The second relative Y coordinate.
* @param Z The relative Z coordinate.
* @param ZZ The second relative Z coordinate.
* @return The HashSet collection of a cuboid selection.
*/
public Set<Location> rangeLoop(final Location reference, final int X, final int XX, final int Y, final int YY,
final int Z, final int ZZ) {
Set<Location> set = new HashSet<>();
for (int x = (X < XX ? X : XX); x <= (X < XX ? XX : X); x++)
for (int y = (Y < YY ? Y : YY); y <= (Y < YY ? YY : Y); y++)
for (int z = (Z < ZZ ? Z : ZZ); z <= (Z < ZZ ? ZZ : Z); z++)
set.add(getLocation(reference, x, y, z));
return set;
}
@Override
public String toString() {
return Objects.toStringHelper(this).add("X", X).add("Y", Y).add("Z", Z).toString();
}
@Override
public int hashCode() {
return Objects.hashCode(X, Y, Z);
}
@Override
public boolean equals(Object object) {
return object instanceof Selection && Objects.equal(this, object);
}
}