package am2.api.blocks;
import java.util.ArrayList;
import java.util.HashMap;
import net.minecraft.block.Block;
import net.minecraft.world.World;
public class MultiblockStructureDefinition{
public class BlockDec{
Block block;
int meta;
public BlockDec(Block block, int meta){
this.block = block;
this.meta = meta;
}
public Block getBlock(){
return block;
}
public int getMeta(){
return meta;
}
@Override
public String toString() {
String blockName = "";
if (block != null){
blockName = block.getLocalizedName();
}else{
blockName = "Unknown";
}
return String.format("Block: %s, meta: %d", blockName, meta);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BlockDec){
return this.block == ((BlockDec)obj).block && (this.meta == -1 || ((BlockDec)obj).meta == -1 || this.meta == ((BlockDec)obj).meta);
}
return false;
}
@Override
public int hashCode() {
return Block.getIdFromBlock(block);
}
}
public class BlockCoord implements Comparable<BlockCoord>{
public int x;
public int y;
public int z;
public BlockCoord(int offsetX, int offsetY, int offsetZ){
this.x = offsetX;
this.y = offsetY;
this.z = offsetZ;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BlockCoord){
return this.x == ((BlockCoord)obj).x && this.y == ((BlockCoord)obj).y && this.z == ((BlockCoord)obj).z;
}
return false;
}
@Override
public int hashCode() {
return this.x + this.y + this.z;
}
public int getX(){
return this.x;
}
public int getY(){
return this.y;
}
public int getZ(){
return this.z;
}
@Override
public String toString() {
return String.format("BlockCoord: %d, %d, %d", x, y, z);
}
@Override
public int compareTo(BlockCoord o) {
return this.z > o.z ? 1 : this.z < o.z ? -1 : this.x > o.x ? 1 : this.x < o.x ? -1 : this.y > o.y ? 1 : this.y < o.y ? -1 : 0;
}
}
public class StructureGroup
{
String name;
int mutex;
HashMap<BlockCoord, ArrayList<BlockDec>> allowedBlocks;
public StructureGroup(String name, int mutex){
this.name = name;
this.mutex = mutex;
allowedBlocks = new HashMap<BlockCoord, ArrayList<BlockDec>>();
}
void addAllowedBlock(int offsetX, int offsetY, int offsetZ, Block block, int meta){
BlockCoord originOffset = new BlockCoord(offsetX, offsetY, offsetZ);
if (!allowedBlocks.containsKey(originOffset)){
allowedBlocks.put(originOffset, new ArrayList<BlockDec>());
}
ArrayList<BlockDec> positionReplacements = allowedBlocks.get(originOffset);
positionReplacements.add(new BlockDec(block, meta));
}
ArrayList<BlockDec> getAllowedBlocksAt(BlockCoord coord){
return allowedBlocks.get(coord);
}
boolean matchGroup(World world, int originX, int originY, int originZ){
for (BlockCoord offset : allowedBlocks.keySet()){
Block block = world.getBlock(originX + offset.x, originY + offset.y, originZ + offset.z);
int meta = world.getBlockMetadata(originX + offset.x, originY + offset.y, originZ + offset.z);
ArrayList<BlockDec> positionReplacements = allowedBlocks.get(offset);
boolean valid = false;
for (BlockDec bd : positionReplacements){
if (bd.block == block && (bd.meta == -1 || bd.meta == meta)){
valid = true;
}
}
if (!valid) return false;
}
return true;
}
HashMap<BlockCoord, ArrayList<BlockDec>> getStructureLayer(int layer){
HashMap<BlockCoord, ArrayList<BlockDec>> toReturn = new HashMap<MultiblockStructureDefinition.BlockCoord, ArrayList<BlockDec>>();
if (layer > getMaxLayer() || layer < getMinLayer()){
return toReturn;
}
for (BlockCoord bc : allowedBlocks.keySet()){
if (bc.y == layer){
toReturn.put(bc, allowedBlocks.get(bc));
}
}
return toReturn;
}
public void replaceAllBlocksOfType(Block originalBlock, Block newBlock){
replaceAllBlocksOfType(originalBlock, -1, newBlock, -1);
}
public void replaceAllBlocksOfType(Block originalBlock, int originalMeta, Block newBlock, int newMeta){
for (BlockCoord bc : allowedBlocks.keySet()){
for (BlockDec bd : allowedBlocks.get(bc)){
if (bd.block == originalBlock){
if (bd.meta == originalMeta || originalMeta == -1){
bd.block = newBlock;
if (newMeta != -1){
bd.meta = newMeta;
}
}
}
}
}
}
public HashMap<BlockCoord, ArrayList<BlockDec>> getAllowedBlocks(){
return (HashMap<BlockCoord, ArrayList<BlockDec>>) allowedBlocks.clone();
}
public void deleteBlocksFromWorld(World world, int x, int y, int z) {
for (BlockCoord offset : allowedBlocks.keySet()){
world.setBlockToAir(x + offset.x, y + offset.y, z + offset.z);
}
}
}
private StructureGroup mainGroup;
private ArrayList<StructureGroup> blockGroups;
private ArrayList<Integer> mutexCache;
public static final int MAINGROUP_MUTEX = 1;
private String id;
private int maxX = 0;
private int minX = 0;
private int maxY = 0;
private int minY = 0;
private int maxZ = 0;
private int minZ = 0;
public MultiblockStructureDefinition(String id){
blockGroups = new ArrayList<StructureGroup>();
mutexCache = new ArrayList<Integer>();
this.id = id;
//default group
mainGroup = createGroup("main", MAINGROUP_MUTEX);
}
public String getID(){
return this.id;
}
public ArrayList<Integer> getMutexList(){
return mutexCache;
}
public ArrayList<StructureGroup> getGroupsForMutex(int mutex){
ArrayList<StructureGroup> toReturn = new ArrayList<StructureGroup>();
for (StructureGroup group : blockGroups){
if (group.mutex == mutex){
toReturn.add(group);
}
}
return toReturn;
}
public ArrayList<BlockDec> getAllowedBlocksAt(StructureGroup group, BlockCoord coord){
return group.getAllowedBlocksAt(coord);
}
public ArrayList<BlockDec> getAllowedBlocksAt(BlockCoord coord){
return mainGroup.getAllowedBlocksAt(coord);
}
public void addAllowedBlock(int offsetX, int offsetY, int offsetZ, Block block, int meta){
if (offsetY > maxY){
maxY = offsetY;
}else if (offsetY < minY){
minY = offsetY;
}
if (offsetX > maxX){
maxX = offsetX;
}else if (offsetX < minX){
minX = offsetX;
}
if (offsetZ > maxZ){
maxZ = offsetZ;
}else if (offsetZ < minZ){
minZ = offsetZ;
}
mainGroup.addAllowedBlock(offsetX, offsetY, offsetZ, block, meta);
}
public void addAllowedBlock(int offsetX, int offsetY, int offsetZ, Block block){
addAllowedBlock(offsetX, offsetY, offsetZ, block, -1);
}
public void addAllowedBlock(StructureGroup group, int offsetX, int offsetY, int offsetZ, Block block, int meta){
if (!blockGroups.contains(group)){
blockGroups.add(group);
}
if (offsetY > maxY){
maxY = offsetY;
}else if (offsetY < minY){
minY = offsetY;
}
if (offsetX > maxX){
maxX = offsetX;
}else if (offsetX < minX){
minX = offsetX;
}
if (offsetZ > maxZ){
maxZ = offsetZ;
}else if (offsetZ < minZ){
minZ = offsetZ;
}
group.addAllowedBlock(offsetX, offsetY, offsetZ, block, meta);
}
public void addAllowedBlock(StructureGroup group, int offsetX, int offsetY, int offsetZ, Block block){
addAllowedBlock(group, offsetX, offsetY, offsetZ, block, -1);
}
public StructureGroup createGroup(String name, int mutex){
if (!mutexCache.contains(mutex)){
mutexCache.add(mutex);
}
StructureGroup group = new StructureGroup(name, mutex);
blockGroups.add(group);
return group;
}
public StructureGroup copyGroup(String originalName, String destinationName, int newMutex){
StructureGroup copyGroup = null;
for (StructureGroup group : blockGroups){
if (group.name.equals(originalName)){
copyGroup = group;
break;
}
}
if (copyGroup == null) return null;
StructureGroup newGroup;
if (newMutex > -1){
newGroup = new StructureGroup(destinationName, newMutex);
}else{
newGroup = new StructureGroup(destinationName, copyGroup.mutex);
}
for (BlockCoord bc : copyGroup.allowedBlocks.keySet()){
for (BlockDec bd : copyGroup.allowedBlocks.get(bc)){
newGroup.addAllowedBlock(bc.x, bc.y, bc.z, bd.block, bd.meta);
}
}
blockGroups.add(newGroup);
return newGroup;
}
public StructureGroup copyGroup(String originalName, String destinationName){
return copyGroup(originalName, destinationName, -1);
}
public ArrayList<StructureGroup> getMatchedGroups(int mutex, World world, int originX, int originY, int originZ){
ArrayList<StructureGroup> toReturn = new ArrayList<StructureGroup>();
for (StructureGroup group : blockGroups){
if ((group.mutex & mutex) == group.mutex){
if (group.matchGroup(world, originX, originY, originZ)){
toReturn.add(group);
}
}
}
return toReturn;
}
private boolean matchMutex(int mutex, World world, int originX, int originY, int originZ){
for (StructureGroup group : blockGroups){
if ((group.mutex & mutex) == group.mutex){
if (group.matchGroup(world, originX, originY, originZ)){
return true;
}
}
}
return false;
}
public boolean checkStructure(World world, int originX, int originY, int originZ){
boolean valid = true;
for (int i: mutexCache){
valid &= matchMutex(i, world, originX, originY, originZ);
if (!valid) break;
}
return valid;
}
public int getMinLayer(){
return this.minY;
}
public int getMaxLayer(){
return this.maxY;
}
public int getHeight(){
return this.maxY - this.minY;
}
public int getWidth(){
return this.maxX - this.minX;
}
public int getLength(){
return this.maxZ - this.minZ;
}
public HashMap<BlockCoord, ArrayList<BlockDec>> getStructureLayer(int layer){
return mainGroup.getStructureLayer(layer);
}
public HashMap<BlockCoord, ArrayList<BlockDec>> getStructureLayer(StructureGroup group, int layer){
return group.getStructureLayer(layer);
}
public void removeMutex(int mutex, World world, int x, int y, int z){
for (StructureGroup group : blockGroups){
if (group.mutex == mutex){
group.deleteBlocksFromWorld(world, x, y, z);
}
}
}
}