package openblocks.common.tileentity;
import com.google.common.collect.Maps;
import java.util.EnumMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.oredict.OreDictionary;
import openblocks.OpenBlocks;
import openblocks.client.gui.GuiPaintMixer;
import openblocks.common.container.ContainerPaintMixer;
import openblocks.common.item.ItemPaintCan;
import openblocks.rpc.IColorChanger;
import openmods.api.IHasGui;
import openmods.api.IInventoryCallback;
import openmods.api.IValueProvider;
import openmods.gamelogic.WorkerLogic;
import openmods.include.IncludeInterface;
import openmods.inventory.GenericInventory;
import openmods.inventory.IInventoryProvider;
import openmods.inventory.TileEntityInventory;
import openmods.sync.SyncableFlags;
import openmods.sync.SyncableFloat;
import openmods.sync.SyncableInt;
import openmods.sync.drops.DroppableTileEntity;
import openmods.sync.drops.StoreOnDrop;
import openmods.utils.ColorUtils;
import openmods.utils.MiscUtils;
import org.apache.commons.lang3.ArrayUtils;
public class TileEntityPaintMixer extends DroppableTileEntity implements IInventoryProvider, IHasGui, IInventoryCallback, IColorChanger {
private static final ItemStack PAINT_CAN = new ItemStack(OpenBlocks.Blocks.paintCan);
private static final ItemStack MILK_BUCKET = new ItemStack(Items.milk_bucket);
public static final int PROGRESS_TICKS = 300;
public static enum Slots {
paint,
reserved, // old output slot, now merged with input
dyeCyan,
dyeMagenta,
dyeYellow,
dyeBlack
}
public static enum DyeSlot {
cyan,
magenta,
yellow,
black
}
private static EnumMap<Slots, Integer> ALLOWED_COLORS = Maps.newEnumMap(Slots.class);
static {
ALLOWED_COLORS.put(Slots.dyeBlack, OreDictionary.getOreID("dyeBlack"));
ALLOWED_COLORS.put(Slots.dyeCyan, OreDictionary.getOreID("dyeCyan"));
ALLOWED_COLORS.put(Slots.dyeMagenta, OreDictionary.getOreID("dyeMagenta"));
ALLOWED_COLORS.put(Slots.dyeYellow, OreDictionary.getOreID("dyeYellow"));
}
public enum Flags {
hasPaint
}
private SyncableInt canColor;
@StoreOnDrop
private SyncableInt color;
private SyncableInt progress;
private SyncableFlags flags;
private final WorkerLogic logic = new WorkerLogic(progress, PROGRESS_TICKS);
// These could be optimized with a byte array later
// Not important for release
// Levels should be 0-2, so that if there is 0.3 left, 1 can be consumed and
// not overflow ;)
@StoreOnDrop
public SyncableFloat lvlCyan;
@StoreOnDrop
public SyncableFloat lvlMagenta;
@StoreOnDrop
public SyncableFloat lvlYellow;
@StoreOnDrop
public SyncableFloat lvlBlack;
private GenericInventory inventory = new TileEntityInventory(this, "paintmixer", true, 6) {
@Override
public boolean isItemValidForSlot(int slotId, ItemStack stack) {
Slots[] values = Slots.values();
if (stack == null || slotId < 0 || slotId > values.length) return false;
Slots slot = values[slotId];
if (slot == Slots.paint) return PAINT_CAN.isItemEqual(stack) || MILK_BUCKET.isItemEqual(stack);
return isValidForSlot(slot, stack);
}
};
public TileEntityPaintMixer() {
inventory.addCallback(this);
}
@Override
public void updateEntity() {
super.updateEntity();
if (!worldObj.isRemote) {
if (logic.isWorking()) {
if (!hasValidInput() || !hasSufficientInk()) {
logic.reset();
} else if (logic.update()) {
consumeInk();
ItemStack output = ItemPaintCan.createStack(color.get(), ItemPaintCan.FULL_CAN_SIZE);
inventory.setInventorySlotContents(Slots.paint.ordinal(), output);
canColor.set(color.get());
}
}
checkAutoConsumption();
sync();
}
}
private void checkAutoConsumption() {
if (lvlCyan.get() <= 1f) { /* We can store 2.0, so <= */
if (tryUseInk(Slots.dyeCyan, 1)) {
lvlCyan.set(lvlCyan.get() + 1f);
}
}
if (lvlMagenta.get() <= 1f) {
if (tryUseInk(Slots.dyeMagenta, 1)) {
lvlMagenta.set(lvlMagenta.get() + 1f);
}
}
if (lvlYellow.get() <= 1f) {
if (tryUseInk(Slots.dyeYellow, 1)) {
lvlYellow.set(lvlYellow.get() + 1f);
}
}
if (lvlBlack.get() <= 1f) {
if (tryUseInk(Slots.dyeBlack, 1)) {
lvlBlack.set(lvlBlack.get() + 1f);
}
}
}
private void consumeInk() {
ColorUtils.CYMK cymk = new ColorUtils.RGB(color.get()).toCYMK();
lvlCyan.set(lvlCyan.get() - cymk.getCyan());
lvlBlack.set(lvlBlack.get() - cymk.getKey());
lvlYellow.set(lvlYellow.get() - cymk.getYellow());
lvlMagenta.set(lvlMagenta.get() - cymk.getMagenta());
}
private boolean hasSufficientInk() {
ColorUtils.CYMK cymk = new ColorUtils.RGB(color.get()).toCYMK();
if (cymk.getCyan() > lvlCyan.get()) {
if (tryUseInk(Slots.dyeCyan, 1)) {
lvlCyan.set(lvlCyan.get() + 1f);
} else {
return false;
}
}
if (cymk.getYellow() > lvlYellow.get()) {
if (tryUseInk(Slots.dyeYellow, 1)) {
lvlYellow.set(lvlYellow.get() + 1f);
} else {
return false;
}
}
if (cymk.getMagenta() > lvlMagenta.get()) {
if (tryUseInk(Slots.dyeMagenta, 1)) {
lvlMagenta.set(lvlMagenta.get() + 1f);
} else {
return false;
}
}
if (cymk.getKey() > lvlBlack.get()) {
if (tryUseInk(Slots.dyeBlack, 1)) {
lvlBlack.set(lvlBlack.get() + 1f);
} else {
return false;
}
}
return true;
}
public boolean tryUseInk(Slots slot, int consume) {
ItemStack stack = inventory.getStackInSlot(slot);
return isValidForSlot(slot, stack) && inventory.decrStackSize(slot.ordinal(), consume) != null;
}
private static boolean isValidForSlot(Slots slot, ItemStack stack) {
Integer allowedColor = ALLOWED_COLORS.get(slot);
if (allowedColor == null || stack == null) return false;
int[] oreIds = OreDictionary.getOreIDs(stack);
return ArrayUtils.contains(oreIds, allowedColor);
}
@Override
protected void createSyncedFields() {
color = new SyncableInt(0xFF0000);
flags = SyncableFlags.create(Flags.values().length);
progress = new SyncableInt();
lvlBlack = new SyncableFloat();
lvlCyan = new SyncableFloat();
lvlMagenta = new SyncableFloat();
lvlYellow = new SyncableFloat();
canColor = new SyncableInt(0xFFFFFF);
}
@Override
public Object getServerGui(EntityPlayer player) {
return new ContainerPaintMixer(player.inventory, this);
}
@Override
public Object getClientGui(EntityPlayer player) {
return new GuiPaintMixer(new ContainerPaintMixer(player.inventory, this));
}
@Override
public boolean canOpenGui(EntityPlayer player) {
return true;
}
@Override
public void changeColor(int requestedColor) {
if (!worldObj.isRemote) {
if (logic.isWorking()) {
if (requestedColor != color.get()) logic.reset();
else return;
}
color.set(requestedColor);
logic.start();
}
}
public IValueProvider<Integer> getProgress() {
return progress;
}
public IValueProvider<Integer> getColor() {
return color;
}
public IValueProvider<Float> getDyeSlot(DyeSlot slot) {
switch (slot) {
case black:
return lvlBlack;
case cyan:
return lvlCyan;
case magenta:
return lvlMagenta;
case yellow:
return lvlYellow;
default:
throw MiscUtils.unhandledEnum(slot);
}
}
public boolean hasPaint() {
return flags.get(Flags.hasPaint);
}
public int getCanColor() {
return canColor.get();
}
public boolean isEnabled() {
return progress.get() > 0;
}
public boolean hasValidInput() {
return hasStack(Slots.paint, PAINT_CAN) || hasStack(Slots.paint, MILK_BUCKET);
}
private static Integer getColor(ItemStack stack, boolean canColor) {
if (stack.isItemEqual(PAINT_CAN)) return ItemPaintCan.getColorFromStack(stack);
else if (canColor && stack.isItemEqual(MILK_BUCKET)) return 0xFFFFFF;
return null;
}
@Override
public void onInventoryChanged(IInventory invent, int slotNumber) {
if (!worldObj.isRemote) {
boolean hasPaint = false;
ItemStack can = inventory.getStackInSlot(Slots.paint);
if (can != null) {
Integer pickerColor = getColor(can, false);
if (pickerColor != null && !logic.isWorking()) {
color.set(pickerColor);
// force GUI refresh
color.markDirty();
}
Integer canColor = getColor(can, true);
if (canColor != null) {
this.canColor.set(canColor);
hasPaint = true;
}
}
flags.set(Flags.hasPaint, hasPaint);
sync();
markUpdated();
}
}
private boolean hasStack(Slots slot, ItemStack stack) {
ItemStack gotStack = inventory.getStackInSlot(slot);
if (gotStack == null) { return false; }
return gotStack.isItemEqual(stack);
}
@Override
@IncludeInterface
public IInventory getInventory() {
return inventory;
}
@Override
public void writeToNBT(NBTTagCompound tag) {
super.writeToNBT(tag);
inventory.writeToNBT(tag);
}
@Override
public void readFromNBT(NBTTagCompound tag) {
super.readFromNBT(tag);
inventory.readFromNBT(tag);
}
public IColorChanger createRpcProxy() {
return createClientRpcProxy(IColorChanger.class);
}
@Override
public ItemStack getPickBlock() {
return getRawDrop();
}
}