/** * Copyright (c) Lambda Innovation, 2013-2016 * This file is part of the AcademyCraft mod. * https://github.com/LambdaInnovation/AcademyCraft * Licensed under GPLv3, see project root for more information. */ package cn.academy.crafting.block; import cn.academy.core.block.TileReceiverBase; import cn.academy.core.client.sound.ACSounds; import cn.academy.core.client.sound.PositionedSound; import cn.academy.core.client.sound.TileEntitySound; import cn.academy.crafting.api.MetalFormerRecipes; import cn.academy.crafting.api.MetalFormerRecipes.RecipeObject; import cn.academy.energy.IFConstants; import cn.academy.support.EnergyItemHelper; import cn.lambdalib.annoreg.core.Registrant; import cn.lambdalib.annoreg.mc.RegTileEntity; import cn.lambdalib.s11n.network.TargetPoints; import cn.lambdalib.s11n.network.NetworkMessage; import cn.lambdalib.s11n.network.NetworkMessage.Listener; import cn.lambdalib.s11n.network.NetworkMessage.NullablePar; import cn.lambdalib.s11n.network.NetworkS11n.NetworkS11nType; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; /** * @author WeAthFolD */ @Registrant @RegTileEntity public class TileMetalFormer extends TileReceiverBase implements ISidedInventory { @Override public int[] getAccessibleSlotsFromSide(int side) { switch(side) { case 0: return new int[]{SLOT_OUT, SLOT_BATTERY}; case 1: return new int[]{SLOT_IN}; default: return new int[]{SLOT_BATTERY}; } } @Override public boolean canInsertItem(int slot, ItemStack item, int side) { return this.isItemValidForSlot(slot, item); } @Override public boolean canExtractItem(int slot, ItemStack item, int side) { return side == 0; } @Registrant @NetworkS11nType public enum Mode { PLATE, INCISE, ETCH, REFINE; public final ResourceLocation texture; Mode() { texture = new ResourceLocation( "academy:textures/guis/icons/icon_former_" + this.toString().toLowerCase() + ".png"); } }; public static final int SLOT_IN = 0, SLOT_OUT = 1, SLOT_BATTERY = 2; public static final int WORK_TICKS = 60; public static final double CONSUME_PER_TICK = 13.3; // Available in both sides. public Mode mode = Mode.PLATE; public RecipeObject current; public int workCounter; public int updateCounter; public TileMetalFormer() { super("metal_former", 3, 3000, IFConstants.LATENCY_MK1); } @Override public void updateEntity() { super.updateEntity(); World world = getWorldObj(); if(!world.isRemote) { if(current != null) { // Process recipe if(this.pullEnergy(CONSUME_PER_TICK) == CONSUME_PER_TICK && !isActionBlocked()) { ++workCounter; if(workCounter == WORK_TICKS) { // Finish the job. ItemStack inputSlot = this.getStackInSlot(SLOT_IN); ItemStack outputSlot = this.getStackInSlot(SLOT_OUT); inputSlot.stackSize -= current.input.stackSize; if(inputSlot.stackSize == 0) this.setInventorySlotContents(SLOT_IN, null); if(outputSlot != null) outputSlot.stackSize += current.output.stackSize; else this.setInventorySlotContents(SLOT_OUT, current.output.copy()); current = null; workCounter = 0; } } else { current = null; workCounter = 0; } } else { if(++workCounter == 5) { current = MetalFormerRecipes.INSTANCE.getRecipe(this.getStackInSlot(SLOT_IN), mode); workCounter = 0; } } /* Process energy in/out */ { ItemStack stack = this.getStackInSlot(SLOT_BATTERY); if(stack != null && EnergyItemHelper.isSupported(stack)) { double gain = EnergyItemHelper .pull(stack, Math.min(getMaxEnergy() - getEnergy(), getBandwidth()), false); this.injectEnergy(gain); } } if(++updateCounter == 10) { updateCounter = 0; sync(); } } else { updateSounds(); } } // Cycle the mode. should be only called in SERVER. public void cycleMode(int delta) { int nextOrd = mode.ordinal() + delta; if (nextOrd >= Mode.values().length) nextOrd = 0; else if (nextOrd < 0) nextOrd = Mode.values().length - 1; mode = Mode.values()[nextOrd]; sync(); } // SERVER only private void sync() { NetworkMessage.sendToAllAround( TargetPoints.convert(this, 12), this, "sync", workCounter, current, mode ); } private boolean isActionBlocked() { if(current == null) { return true; } ItemStack inputSlot = this.getStackInSlot(SLOT_IN), outputSlot = this.getStackInSlot(SLOT_OUT); return !(current.accepts(inputSlot, mode) && (outputSlot == null || (outputSlot.getItem() == current.output.getItem() && outputSlot.getItemDamage() == current.output.getItemDamage() && outputSlot.stackSize + current.output.stackSize <= outputSlot.getMaxStackSize()))); } public boolean isWorkInProgress() { return current != null; } public double getWorkProgress() { return isWorkInProgress() ? (double) workCounter / WORK_TICKS : 0; } @Listener(channel="sync", side=Side.CLIENT) private void syncData(int counter, @NullablePar RecipeObject recipe, Mode mode) { this.workCounter = counter; this.current = recipe; this.mode = mode; } @Override public void readFromNBT(NBTTagCompound nbt) { mode = Mode.values()[nbt.getInteger("mode")]; super.readFromNBT(nbt); } @Override public void writeToNBT(NBTTagCompound nbt) { nbt.setInteger("mode", mode.ordinal()); super.writeToNBT(nbt); } // --- CLIENT EFFECTS @SideOnly(Side.CLIENT) private PositionedSound sound; @SideOnly(Side.CLIENT) private void updateSounds() { if(sound != null && !isWorkInProgress()) { sound.stop(); sound = null; } else if(sound == null && isWorkInProgress()) { sound = new TileEntitySound(this, "machine.machine_work") .setLoop().setVolume(.6f); ACSounds.playClient(sound); } } }