/* * This file is part of Matter Overdrive * Copyright (c) 2015., Simeon Radivoev, All rights reserved. * * Matter Overdrive is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Matter Overdrive is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Matter Overdrive. If not, see <http://www.gnu.org/licenses>. */ package matteroverdrive.machines; import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import matteroverdrive.MatterOverdrive; import matteroverdrive.Reference; import matteroverdrive.api.IMOTileEntity; import matteroverdrive.api.IUpgradeable; import matteroverdrive.api.inventory.IUpgrade; import matteroverdrive.api.inventory.UpgradeTypes; import matteroverdrive.api.machines.IUpgradeHandler; import matteroverdrive.blocks.includes.MOBlock; import matteroverdrive.blocks.includes.MOBlockMachine; import matteroverdrive.client.sound.MachineSound; import matteroverdrive.data.Inventory; import matteroverdrive.data.TileEntityInventory; import matteroverdrive.data.inventory.UpgradeSlot; import matteroverdrive.fx.VentParticle; import matteroverdrive.items.SecurityProtocol; import matteroverdrive.machines.components.ComponentConfigs; import matteroverdrive.machines.configs.ConfigPropertyStringList; import matteroverdrive.tile.MOTileEntity; import matteroverdrive.util.MOStringHelper; import matteroverdrive.util.MatterHelper; import matteroverdrive.util.math.MOMathHelper; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.util.ForgeDirection; import org.apache.logging.log4j.Level; import org.lwjgl.util.vector.Matrix4f; import org.lwjgl.util.vector.Vector3f; import org.lwjgl.util.vector.Vector4f; import java.util.*; /** * @autor Simeon * @since 3/11/2015 */ public abstract class MOTileEntityMachine extends MOTileEntity implements IMOTileEntity, ISidedInventory, IUpgradeable { protected static Random random = new Random(); protected static UpgradeHandlerMinimum basicUpgradeHandler = new UpgradeHandlerMinimum(0.05).addUpgradeMinimum(UpgradeTypes.Speed,0.1); //client syncs private boolean lastActive; private boolean activeState; @SideOnly(Side.CLIENT) protected MachineSound sound; protected ResourceLocation soundRes; protected boolean redstoneState; protected boolean redstoneStateDirty = true; protected boolean forceClientUpdate; protected UUID owner; protected Inventory inventory; private int upgradeSlotCount; private int[] upgrade_slots; protected List<IMachineComponent> components; protected boolean playerSlotsHotbar,playerSlotsMain; protected ComponentConfigs configs; public MOTileEntityMachine(int upgradeCount) { components = new ArrayList<>(); soundRes = getSoundFor(getSound()); this.upgradeSlotCount = upgradeCount; upgrade_slots = new int[upgradeCount]; inventory = new TileEntityInventory(this,""); registerComponents(); RegisterSlots(inventory); } @Override public void updateEntity() { super.updateEntity(); if(worldObj.isRemote) { manageSound(); if(forceClientUpdate) { updateBlock(); forceClientUpdate = false; } return; } else { activeState = getServerActive(); if (lastActive != activeState) { forceSync(); onActiveChange(); lastActive = activeState; } } manageRedstoneState(); manageClientSync(); if(lastActive != isActive()) { onActiveChange(); lastActive = isActive(); } for (IMachineComponent component : components) { try { component.update(this); }catch (Exception e) { MatterOverdrive.log.log(Level.FATAL,e,"There was a problem while ticking %s component %s",this,component); } } } protected void RegisterSlots(Inventory inventory) { for (int i = 0;i < upgrade_slots.length; i++) { upgrade_slots[i] = inventory.AddSlot(new UpgradeSlot(false,this)); } for (IMachineComponent component : components) { component.registerSlots(inventory); } } protected void registerComponents() { configs = new ComponentConfigs(this); configs.addProperty(new ConfigPropertyStringList( "redstoneMode", "gui.config.redstone", new String[]{ MOStringHelper.translateToLocal("gui.redstone_mode.low"), MOStringHelper.translateToLocal("gui.redstone_mode.high"), MOStringHelper.translateToLocal("gui.redstone_mode.disabled")}, 0 )); addComponent(configs); } private static ResourceLocation getSoundFor(String sound) { return sound == null ? null : new ResourceLocation(Reference.MOD_ID + ":" + sound); } public abstract String getSound(); public abstract boolean hasSound(); public abstract boolean getServerActive(); public abstract float soundVolume(); public void onContainerOpen(Side side) { } public boolean getRedstoneActive() { if (getRedstoneMode() == Reference.MODE_REDSTONE_HIGH) { return redstoneState; }else if (getRedstoneMode() == Reference.MODE_REDSTONE_LOW) { return !redstoneState; } return true; } @SideOnly(Side.CLIENT) protected void manageSound() { if(hasSound() && soundVolume() > 0) { if (isActive() && !isInvalid()) { if (sound == null) { float soundMultiply = 1; if (getBlockType() instanceof MOBlockMachine) { soundMultiply = ((MOBlockMachine) getBlockType()).volume; } if (soundMultiply > 0) { sound = new MachineSound(soundRes, xCoord, yCoord, zCoord, soundVolume() * soundMultiply, 1); FMLClientHandler.instance().getClient().getSoundHandler().playSound(sound); } } else if (FMLClientHandler.instance().getClient().getSoundHandler().isSoundPlaying(sound)) { sound.setVolume(soundVolume()); } else { sound = null; } } else if (sound != null) { stopSound(); } } } @SideOnly(Side.CLIENT) void stopSound() { if (sound != null) { sound.stopPlaying(); FMLClientHandler.instance().getClient().getSoundHandler().stopSound(sound); sound = null; } } @Override public void onChunkUnload() { super.onChunkUnload(); if (worldObj.isRemote) { stopSound(); } } //region NBT @Override public void readCustomNBT(NBTTagCompound nbt, EnumSet<MachineNBTCategory> categories) { if (categories.contains(MachineNBTCategory.DATA)) { redstoneState = nbt.getBoolean("redstoneState"); forceClientUpdate = nbt.getBoolean("forceClientUpdate"); activeState = nbt.getBoolean("activeState"); if (nbt.hasKey("Owner", 8) && !nbt.getString("Owner").isEmpty()) { try { owner = UUID.fromString(nbt.getString("Owner")); } catch (Exception e) { FMLLog.log(Level.ERROR, "Invalid Owner ID: " + nbt.getString("Owner")); } } } if (categories.contains(MachineNBTCategory.INVENTORY)) { inventory.readFromNBT(nbt); } for (IMachineComponent component : components) { component.readFromNBT(nbt, categories); } } @Override public void writeCustomNBT(NBTTagCompound nbt, EnumSet<MachineNBTCategory> categories, boolean toDisk) { if (categories.contains(MachineNBTCategory.DATA)) { nbt.setBoolean("forceClientUpdate", forceClientUpdate); nbt.setBoolean("redstoneState", redstoneState); nbt.setBoolean("activeState",activeState); if (toDisk) { if (owner != null) nbt.setString("Owner", owner.toString()); else if (nbt.hasKey("Owner", 6)) { nbt.removeTag("Owner"); } } } forceClientUpdate = false; if (categories.contains(MachineNBTCategory.INVENTORY)) { inventory.writeToNBT(nbt,toDisk); } for (IMachineComponent component : components) { component.writeToNBT(nbt,categories, toDisk); } } @Override public void writeToDropItem(ItemStack itemStack) { boolean saveTagFlag = false; if (!itemStack.hasTagCompound()) itemStack.setTagCompound(new NBTTagCompound()); NBTTagCompound machineTag = new NBTTagCompound(); NBTTagList itemTagList = new NBTTagList(); for (int i = 0; i < getSizeInventory(); ++i) { if (inventory.getSlot(i).keepOnDismantle() && inventory.getStackInSlot(i) != null) { NBTTagCompound itemTag = new NBTTagCompound(); itemTag.setByte("Slot", (byte)i); getStackInSlot(i).writeToNBT(itemTag); itemTagList.appendTag(itemTag); saveTagFlag = true; } } if (saveTagFlag) machineTag.setTag("Items", itemTagList); writeCustomNBT(machineTag, EnumSet.of(MachineNBTCategory.CONFIGS, MachineNBTCategory.DATA), true); if (hasOwner()) { machineTag.setString("Owner", owner.toString()); saveTagFlag = true; } itemStack.getTagCompound().setTag("Machine", machineTag); } @Override public void readFromPlaceItem(ItemStack itemStack) { if (itemStack.hasTagCompound()) { NBTTagCompound machineTag = itemStack.getTagCompound().getCompoundTag("Machine"); NBTTagList itemTagList = machineTag.getTagList("Items", 10); for (int i = 0; i < itemTagList.tagCount(); ++i) { NBTTagCompound itemTag = itemTagList.getCompoundTagAt(i); byte b0 = itemTag.getByte("Slot"); inventory.setInventorySlotContents(b0, ItemStack.loadItemStackFromNBT(itemTag)); } readCustomNBT(machineTag, EnumSet.of(MachineNBTCategory.CONFIGS, MachineNBTCategory.DATA)); if (machineTag.hasKey("Owner", 8)) { try { this.owner = UUID.fromString(machineTag.getString("Owner")); }catch (Exception e) { FMLLog.log(Level.ERROR,e,"Invalid Owner ID: " + machineTag.getString("Owner")); } } } } @Override public Packet getDescriptionPacket() { NBTTagCompound syncData = new NBTTagCompound(); writeCustomNBT(syncData, MachineNBTCategory.ALL_OPTS,false); return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 1, syncData); } @Override public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { //System.out.println("Receiving Packet From Server"); NBTTagCompound syncData = pkt.func_148857_g(); if(syncData != null) { readCustomNBT(syncData, MachineNBTCategory.ALL_OPTS); } } protected void manageRedstoneState() { if(redstoneStateDirty) { boolean flag = redstoneState; redstoneState = worldObj.getBlockPowerInput(xCoord,yCoord,zCoord) > 0; redstoneStateDirty = false; if(flag != redstoneState) forceClientUpdate = true; } } protected void manageClientSync() { if(forceClientUpdate) { updateBlock(); markDirty(); } } @Override public void invalidate() { super.invalidate(); if(worldObj.isRemote) { manageSound(); } } protected abstract void onActiveChange(); @Override public void onNeighborBlockChange() { redstoneStateDirty = true; } //region Inventory Methods public boolean isItemValidForSlot(int slot, ItemStack item) { return getInventory() != null && getInventory().isItemValidForSlot(slot, item); } @Override public int[] getAccessibleSlotsFromSide(int side) { return new int[0]; } @Override public boolean canInsertItem(int slot, ItemStack item, int side) { return isItemValidForSlot(slot, item); } @Override public boolean canExtractItem(int slot, ItemStack item, int side) { return false; } @Override public int getSizeInventory() { if (getInventory() != null) return getInventory().getSizeInventory(); else return 0; } @Override public ItemStack getStackInSlot(int slot) { if (getInventory() != null) return getInventory().getStackInSlot(slot); else return null; } @Override public ItemStack decrStackSize(int slot, int size) { if (getInventory() != null) return getInventory().decrStackSize(slot, size); else return null; } @Override public ItemStack getStackInSlotOnClosing(int slot) { if (getInventory() != null) return getInventory().getStackInSlotOnClosing(slot); else return null; } @Override public void setInventorySlotContents(int slot, ItemStack itemStack) { if (getInventory() != null) getInventory().setInventorySlotContents(slot, itemStack); } @Override public String getInventoryName() { if (getInventory() != null && !getInventory().getInventoryName().isEmpty()) return getInventory().getInventoryName(); else if (getBlockType() != null) { return getBlockType().getLocalizedName(); }else { return ""; } } @Override public boolean hasCustomInventoryName() { return getInventory() != null && getInventory().hasCustomInventoryName(); } @Override public int getInventoryStackLimit() { if (getInventory() != null) return getInventory().getInventoryStackLimit(); else return 0; } @Override public boolean isUseableByPlayer(EntityPlayer player) { if (hasOwner()) { if (player.getGameProfile().getId().equals(owner) || player.capabilities.isCreativeMode) { return true; }else { for (int i = 0;i < player.inventory.getSizeInventory();i++) { ItemStack itemStack = player.inventory.getStackInSlot(i); if (itemStack != null && itemStack.getItem() instanceof SecurityProtocol) { if (itemStack.hasTagCompound() && itemStack.getItemDamage() == 2 && UUID.fromString(itemStack.getTagCompound().getString("Owner")).equals(owner)) { return true; } } } } }else { return true; } return false; } @Override public void openInventory() { System.out.println("Inventory Open"); } @Override public void closeInventory() { } public IInventory getInventory() { return inventory; } public Inventory getInventoryContainer() { return inventory; } //endregion public void forceSync() { forceClientUpdate = true; } @SideOnly(Side.CLIENT) public void sendConfigsToServer(boolean forceUpdate) { sendNBTToServer(EnumSet.of(MachineNBTCategory.CONFIGS),forceUpdate); } //region Upgrades public double getUpgradeMultiply(UpgradeTypes type) { double multiply = 1; //check to see if the machine is affected by this type of Update if (isAffectedByUpgrade(type)) { for (int i = 0; i < inventory.getSizeInventory(); i++) { if (inventory.getSlot(i) instanceof UpgradeSlot) { ItemStack upgradeItem = inventory.getStackInSlot(i); if (upgradeItem != null && MatterHelper.isUpgrade(upgradeItem)) { Map<UpgradeTypes, Double> upgrades = ((IUpgrade) upgradeItem.getItem()).getUpgrades(upgradeItem); if (upgrades.containsKey(type)) { multiply *= upgrades.get(type); } } } } if (getUpgradeHandler() != null) { multiply = getUpgradeHandler().affectUpgrade(type,multiply); } } return multiply; } //endregion @SideOnly(Side.CLIENT) protected void SpawnVentParticles(float speed,ForgeDirection side,int count) { for (int i = 0;i < count;i++) { Matrix4f rotation = new Matrix4f(); Vector3f offset = new Vector3f(); if (side == ForgeDirection.UP) { rotation.rotate((float) Math.PI / 2f, new Vector3f(0, 0, 1)); offset = new Vector3f(0.5f,0.7f,0.5f); } else if (side == ForgeDirection.WEST) { rotation.rotate((float) Math.PI / 2f, new Vector3f(0, 0, 1)); offset = new Vector3f(-0.2f,0.5f,0.5f); } else if (side == ForgeDirection.EAST) { rotation.rotate((float) Math.PI / 2f, new Vector3f(0, 0, -1)); offset = new Vector3f(1.2f,0.5f,0.5f); } else if (side == ForgeDirection.SOUTH) { rotation.rotate((float) Math.PI / 2f, new Vector3f(1, 0, 0)); offset = new Vector3f(0.5f,0.5f,1.2f); } else if (side == ForgeDirection.NORTH) { rotation.rotate((float) Math.PI / 2f, new Vector3f(-1, 0, 0)); offset = new Vector3f(0.5f,0.5f,-0.2f); } Vector3f circle = MOMathHelper.randomCirclePoint(random.nextFloat(), random); circle.scale(0.4f); Vector4f circleTransformed = new Vector4f(circle.x,circle.y,circle.z,1); Matrix4f.transform(rotation, circleTransformed, circleTransformed); float scale = 3f; VentParticle ventParticle = new VentParticle(this.worldObj,this.xCoord + offset.x + circleTransformed.x,this.yCoord + offset.y + circleTransformed.y,this.zCoord + offset.z + circleTransformed.z,side.offsetX * speed,side.offsetY * speed,side.offsetZ * speed,scale); ventParticle.setAlphaF(0.05f); Minecraft.getMinecraft().effectRenderer.addEffect(ventParticle); } } //region Getters and settrs public <T extends MOBlock> T getBlockType(Class<T> type) { if (this.blockType == null) { this.blockType = this.worldObj.getBlock(this.xCoord, this.yCoord, this.zCoord); } if (type.isInstance(this.blockType)) { return type.cast(this.blockType); } return null; } public int getRedstoneMode() { return getConfigs().getEnum("redstoneMode", 0); } public UUID getOwner() { return owner; } public boolean hasOwner() { return owner != null; } public boolean claim(ItemStack security_protocol) { try { if (owner == null) { if (security_protocol.hasTagCompound() && security_protocol.getTagCompound().hasKey("Owner", 8)) { owner = UUID.fromString(security_protocol.getTagCompound().getString("Owner")); forceSync(); return true; } } }catch (Exception e) { e.printStackTrace(); } return false; } public boolean unclaim(ItemStack security_protocol) { try { if (owner != null) { if (security_protocol.hasTagCompound() && security_protocol.getTagCompound().hasKey("Owner", 8) && owner.equals(UUID.fromString(security_protocol.getTagCompound().getString("Owner")))) { owner = null; forceSync(); return true; } } }catch (Exception e) { e.printStackTrace(); } return false; } public void addComponent(IMachineComponent component) { components.add(component); } public boolean removeComponent(IMachineComponent component) { return components.remove(component); } public IMachineComponent removeComponent(int index) { return components.remove(index); } public IMachineComponent getComponent(int index) { return components.get(index); } public <T extends IMachineComponent> T getComponent(Class<T> componentClasss) { for (IMachineComponent component : components) { if (componentClasss.isInstance(component)) { return componentClasss.cast(component); } } return null; } public boolean hasPlayerSlotsHotbar(){return playerSlotsHotbar;} public boolean hasPlayerSlotsMain(){return playerSlotsMain;} public float getProgress(){return 0;} public boolean isActive() { return activeState; } public void setActive(boolean active) { activeState = active; } public ComponentConfigs getConfigs(){return configs;} public IUpgradeHandler getUpgradeHandler(){return basicUpgradeHandler;} //endregion }