package net.mcft.copy.backpacks.misc; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.mcft.copy.backpacks.WearableBackpacks; import net.mcft.copy.backpacks.api.BackpackHelper; import net.mcft.copy.backpacks.api.IBackpack; import net.mcft.copy.backpacks.api.IBackpackData; import net.mcft.copy.backpacks.api.IBackpackType; import net.mcft.copy.backpacks.misc.util.MiscUtils; import net.mcft.copy.backpacks.misc.util.NbtUtils; import net.mcft.copy.backpacks.misc.util.NbtUtils.NbtType; import net.mcft.copy.backpacks.network.MessageBackpackUpdate; /** Concrete implementation of the IBackpack interface and capability, used for entities. */ public class BackpackCapability implements IBackpack { public static final String TAG_STACK = "stack"; public static final String TAG_TYPE = "type"; public static final String TAG_DATA = "data"; public static final ResourceLocation IDENTIFIER = new ResourceLocation("wearablebackpacks:backpack"); public final EntityLivingBase entity; public ItemStack stack = ItemStack.EMPTY; public IBackpackData data = null; public int playersUsing = 0; public int lidTicks = 0; public int prevLidTicks = 0; // This is also null if the backpack is not equipped to the chestplate slot. public IBackpackType lastType = null; public BackpackCapability(EntityLivingBase entity) { this.entity = entity; } /** Returns if the entity is wearing the backpack in the chest armor slot. */ public boolean isChestArmor() { return ((lastType != null) || (BackpackHelper.getBackpackType( entity.getItemStackFromSlot(EntityEquipmentSlot.CHEST)) != null)); } // IBackpack implementation @Override public ItemStack getStack() { if (!stack.isEmpty()) return stack; ItemStack chestArmor = entity.getItemStackFromSlot(EntityEquipmentSlot.CHEST); return ((BackpackHelper.getBackpackType(chestArmor) != null) ? chestArmor : ItemStack.EMPTY); } @Override public void setStack(ItemStack value) { boolean setChestArmor = !value.isEmpty() // If backpack is being set, use equipAsChestArmor to // determine whether the chest armor slot is set or not. ? BackpackHelper.equipAsChestArmor // If being removed, use whether it actually is equipped there. : isChestArmor(); if (setChestArmor) { stack = ItemStack.EMPTY; lastType = BackpackHelper.getBackpackType(value); entity.setItemStackToSlot(EntityEquipmentSlot.CHEST, value); // Send the updated equipment to all players. if (entity instanceof EntityPlayer) ((EntityPlayer)entity).inventoryContainer.detectAndSendChanges(); } else { stack = value; lastType = null; // Send new value to everyone who can see the entity. WearableBackpacks.CHANNEL.sendToAllTracking( MessageBackpackUpdate.stack(entity, stack), entity, true); } } @Override public IBackpackData getData() { return data; } @Override public void setData(IBackpackData value) { data = value; } @Override public int getPlayersUsing() { return playersUsing; } @Override public void setPlayersUsing(int value) { // If the backpack is being opened or closed (# of players // using changed from 0 to non-zero or the other way around), // send an update to anyone who can see this entity. if ((value > 0) != (playersUsing > 0)) WearableBackpacks.CHANNEL.sendToAllTracking( MessageBackpackUpdate.open(entity, (value > 0)), entity, true); playersUsing = value; } @Override public int getLidTicks() { return lidTicks; } @Override public int getPrevLidTicks() { return prevLidTicks; } @Override public void setLidTicks(int value) { prevLidTicks = lidTicks; lidTicks = value; } @Override public IBackpackType getType() { return (lastType != null) ? lastType : BackpackHelper.getBackpackType(getStack()); } // Capabilities related implementations public static class Provider implements ICapabilitySerializable<NBTTagCompound> { final BackpackCapability backpack; public Provider(EntityLivingBase entity) { backpack = new BackpackCapability(entity); } // ICapabilityProvider implementation @Override public boolean hasCapability(Capability<?> capability, EnumFacing facing) { return (capability == IBackpack.CAPABILITY); } @Override @SuppressWarnings("unchecked") public <T> T getCapability(Capability<T> capability, EnumFacing facing) { return ((capability == IBackpack.CAPABILITY) ? (T)backpack : null); } // INBTSerializable implementation @Override public void deserializeNBT(NBTTagCompound compound) { backpack.stack = NbtUtils.readItem(compound.getCompoundTag(TAG_STACK)); IBackpackType type; if (backpack.stack.isEmpty()) { if (!compound.hasKey(TAG_TYPE, NbtType.STRING)) return; // If the backpack has its type saved, restore it. // This is the case when the backpack stack is equipped in // the chest armor slot, which has not yet been loaded. :'( String id = compound.getString(TAG_TYPE); backpack.lastType = type = BackpackHelper.getBackpackType(MiscUtils.getItemFromName(id)); if (type == null) return; } else type = BackpackHelper.getBackpackType(backpack.stack); if (type == null) { WearableBackpacks.LOG.error("Backpack type was null when deserializing backpack capability"); return; } backpack.data = type.createBackpackData(backpack.getStack()); NBTBase dataTag = compound.getTag(TAG_DATA); if ((backpack.data != null) && (dataTag != null)) backpack.data.deserializeNBT(dataTag); } @Override public NBTTagCompound serializeNBT() { return NbtUtils.createCompound( TAG_STACK, ((!backpack.stack.isEmpty()) ? backpack.stack.serializeNBT() : null), // If the backpack is stored in the chest armor slot, we need to save the item. See deserializeNBT. TAG_TYPE, (backpack.isChestArmor() ? backpack.getStack().getItem().getRegistryName().toString() : null), TAG_DATA, ((backpack.data != null) ? backpack.data.serializeNBT() : null)); } } public static class Storage implements Capability.IStorage<IBackpack> { @Override public NBTBase writeNBT(Capability<IBackpack> capability, IBackpack instance, EnumFacing side) { BackpackCapability backpack = (BackpackCapability)instance; return ((backpack.stack.isEmpty()) && (backpack.data == null)) ? null : NbtUtils.createCompound( TAG_STACK, ((!backpack.stack.isEmpty()) ? backpack.stack.serializeNBT() : null), TAG_DATA, ((backpack.data != null) ? backpack.data.serializeNBT() : null)); } @Override public void readNBT(Capability<IBackpack> capability, IBackpack instance, EnumFacing side, NBTBase nbt) { BackpackCapability backpack = (BackpackCapability)instance; if (!(nbt instanceof NBTTagCompound)) return; NBTTagCompound compound = (NBTTagCompound)nbt; ItemStack stack = NbtUtils.readItem(compound.getCompoundTag(TAG_STACK)); backpack.setStack(stack); IBackpackType type; if (stack.isEmpty()) { // Try to get the backpack type from the chestplate slot. stack = backpack.entity.getItemStackFromSlot(EntityEquipmentSlot.CHEST); backpack.lastType = type = BackpackHelper.getBackpackType(stack); if (type == null) return; // No backpack equipped. } else type = BackpackHelper.getBackpackType(stack); IBackpackData data = type.createBackpackData(stack); NBTBase dataTag = compound.getTag(TAG_DATA); if (dataTag != null) data.deserializeNBT(dataTag); backpack.setData(data); } } }