/**
* This class was created by <Vazkii>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [Jun 27, 2015, 2:37:22 PM (GMT)]
*/
package vazkii.botania.api.lexicon.multiblock;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ChunkCoordinates;
import vazkii.botania.api.lexicon.multiblock.component.MultiblockComponent;
/**
* This class describes a Mutiblock object. It's used to display a
* multiblock in the lexicon and to show the player in a ghost-like
* look in the world.
*/
public class Multiblock {
public List<MultiblockComponent> components = new ArrayList();
public List<ItemStack> materials = new ArrayList();
public int minX, minY, minZ, maxX, maxY, maxZ, offX, offY, offZ;
public HashMap<List<Integer>, MultiblockComponent> locationCache = new HashMap<List<Integer>, MultiblockComponent>();
/**
* Adds a multiblock component to this multiblock. The component's x y z
* coords should be pivoted to the center of the structure.
*/
public void addComponent(MultiblockComponent component) {
if(getComponentForLocation(component.relPos.posX, component.relPos.posY, component.relPos.posZ) != null)
throw new IllegalArgumentException("Location in multiblock already occupied");
components.add(component);
changeAxisForNewComponent(component.relPos.posX, component.relPos.posY, component.relPos.posZ);
calculateCostForNewComponent(component);
addComponentToLocationCache(component);
}
/**
* Constructs and adds a multiblock component to this multiblock. The x y z
* coords should be pivoted to the center of the structure.
*/
public void addComponent(int x, int y, int z, Block block, int meta) {
addComponent(new MultiblockComponent(new ChunkCoordinates(x, y, z), block, meta));
}
private void changeAxisForNewComponent(int x, int y, int z) {
if(x < minX)
minX = x;
else if(x > maxX)
maxX = x;
if(y < minY)
minY = y;
else if(y > maxY)
maxY = y;
if(z < minZ)
minZ = z;
else if(z > maxZ)
maxZ = z;
}
private void calculateCostForNewComponent(MultiblockComponent comp) {
ItemStack[] materials = comp.getMaterials();
if(materials != null)
for(ItemStack stack : materials)
addStack(stack);
}
private void addStack(ItemStack stack) {
if(stack == null)
return;
for(ItemStack oStack : materials)
if(oStack.isItemEqual(stack) && ItemStack.areItemStackTagsEqual(oStack, stack)) {
oStack.stackSize += stack.stackSize;
return;
}
materials.add(stack);
}
public void setRenderOffset(int x, int y, int z) {
offX = x;
offY = y;
offZ = z;
}
public List<MultiblockComponent> getComponents() {
return components;
}
/**
* Rotates this multiblock by the angle passed in. For the best results, use
* only multiples of pi/2.
*/
public void rotate(double angle) {
for(MultiblockComponent comp : getComponents())
comp.rotate(angle);
updateLocationCache();
}
public Multiblock copy() {
Multiblock mb = new Multiblock();
for(MultiblockComponent comp : getComponents())
mb.addComponent(comp.copy());
return mb;
}
/**
* Creates a length 4 array of all the rotations multiple of pi/2 required
* to render this multiblock in the world relevant to the 4 cardinal
* orientations.
*/
public Multiblock[] createRotations() {
Multiblock[] blocks = new Multiblock[4];
blocks[0] = this;
blocks[1] = blocks[0].copy();
blocks[1].rotate(Math.PI / 2);
blocks[2] = blocks[1].copy();
blocks[2].rotate(Math.PI / 2);
blocks[3] = blocks[2].copy();
blocks[3].rotate(Math.PI / 2);
return blocks;
}
/**
* Makes a MultiblockSet from this Multiblock and its rotations using
* createRotations().
*/
public MultiblockSet makeSet() {
return new MultiblockSet(this);
}
public int getXSize() {
return Math.abs(minX) + Math.abs(maxX) + 1;
}
public int getYSize() {
return Math.abs(minY) + Math.abs(maxY) + 1;
}
public int getZSize() {
return Math.abs(minZ) + Math.abs(maxZ) + 1;
}
/**
* Rebuilds the location cache
*/
public void updateLocationCache() {
locationCache.clear();
for(MultiblockComponent comp : components)
addComponentToLocationCache(comp);
}
/**
* Adds a single component to the location cache
*/
private void addComponentToLocationCache(MultiblockComponent comp) {
ChunkCoordinates pos = comp.getRelativePosition();
locationCache.put(Arrays.asList(
pos.posX,
pos.posY,
pos.posZ
), comp);
}
/**
* Gets the component for a given location
*/
public MultiblockComponent getComponentForLocation(int x, int y, int z) {
return locationCache.get(Arrays.asList(x, y, z));
}
}