package crazypants.enderio.machine.spawner;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.block.BlockMobSpawner;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.MobSpawnerBaseLogic;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityMobSpawner;
import net.minecraft.util.StatCollector;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.AnvilUpdateEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.BlockEvent.BreakEvent;
import com.enderio.core.api.client.gui.IAdvancedTooltipProvider;
import com.enderio.core.client.handlers.SpecialTooltipHandler;
import com.enderio.core.common.util.BlockCoord;
import com.enderio.core.common.util.Util;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier;
import cpw.mods.fml.relauncher.ReflectionHelper;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import crazypants.enderio.EnderIO;
import crazypants.enderio.GuiHandler;
import crazypants.enderio.Log;
import crazypants.enderio.ModObject;
import crazypants.enderio.config.Config;
import crazypants.enderio.machine.AbstractMachineBlock;
import crazypants.enderio.machine.MachineRecipeRegistry;
import crazypants.enderio.network.PacketHandler;
import crazypants.enderio.waila.IWailaInfoProvider;
public class BlockPoweredSpawner extends AbstractMachineBlock<TilePoweredSpawner> implements IAdvancedTooltipProvider {
public static void writeMobTypeToNBT(NBTTagCompound nbt, String type) {
if(nbt == null) {
return;
}
if(type == null) {
nbt.removeTag("mobType");
} else {
nbt.setString("mobType", type);
}
}
public static String readMobTypeFromNBT(NBTTagCompound nbt) {
if(nbt == null) {
return null;
}
if(!nbt.hasKey("mobType")) {
return null;
}
return nbt.getString("mobType");
}
public static String getSpawnerTypeFromItemStack(ItemStack stack) {
if(stack == null || stack.getItem() != Item.getItemFromBlock(EnderIO.blockPoweredSpawner)) {
return null;
}
return readMobTypeFromNBT(stack.stackTagCompound);
}
public static final String KEY_SPAWNED_BY_POWERED_SPAWNER = "spawnedByPoweredSpawner";
public static BlockPoweredSpawner create() {
MachineRecipeRegistry.instance.registerRecipe(ModObject.blockPoweredSpawner.unlocalisedName, new DummyRecipe());
PacketHandler.INSTANCE.registerMessage(PacketMode.class, PacketMode.class, PacketHandler.nextID(), Side.SERVER);
//Ensure costs are loaded at startup
PoweredSpawnerConfig.getInstance();
BlockPoweredSpawner res = new BlockPoweredSpawner();
MinecraftForge.EVENT_BUS.register(res);
FMLCommonHandler.instance().bus().register(res);
res.init();
return res;
}
private final List<UniqueIdentifier> toolBlackList = new ArrayList<UniqueIdentifier>();
private Field fieldpersistenceRequired;
protected BlockPoweredSpawner() {
super(ModObject.blockPoweredSpawner, TilePoweredSpawner.class);
String[] blackListNames = Config.brokenSpawnerToolBlacklist;
for (String name : blackListNames) {
toolBlackList.add(new UniqueIdentifier(name));
}
try {
fieldpersistenceRequired = ReflectionHelper.findField(EntityLiving.class, "field_82179_bU", "persistenceRequired");
} catch (Exception e) {
Log.error("BlockPoweredSpawner: Could not find field: persistenceRequired");
}
}
private final Map<BlockCoord, ItemStack> dropCache = new HashMap<BlockCoord, ItemStack>();
@SubscribeEvent
public void onBreakEvent(BlockEvent.BreakEvent evt) {
if(evt.block instanceof BlockMobSpawner) {
if(evt.getPlayer() != null && !evt.getPlayer().capabilities.isCreativeMode && !evt.getPlayer().worldObj.isRemote && !evt.isCanceled()) {
TileEntity tile = evt.getPlayer().worldObj.getTileEntity(evt.x, evt.y, evt.z);
if(tile instanceof TileEntityMobSpawner) {
if(Math.random() > Config.brokenSpawnerDropChance) {
return;
}
ItemStack equipped = evt.getPlayer().getCurrentEquippedItem();
if(equipped != null) {
for (UniqueIdentifier uid : toolBlackList) {
Item blackListItem = GameRegistry.findItem(uid.modId, uid.name);
if(blackListItem == equipped.getItem()) {
return;
}
}
}
TileEntityMobSpawner spawner = (TileEntityMobSpawner) tile;
MobSpawnerBaseLogic logic = spawner.func_145881_a();
if(logic != null) {
String name = logic.getEntityNameToSpawn();
if(name != null && !isBlackListed(name)) {
ItemStack drop = ItemBrokenSpawner.createStackForMobType(name);
dropCache.put(new BlockCoord(evt.x, evt.y, evt.z), drop);
for (int i = (int) (Math.random() * 7); i > 0; i--) {
logic.spawnDelay = 0;
logic.updateSpawner();
}
}
}
}
} else {
dropCache.put(new BlockCoord(evt.x, evt.y, evt.z), null);
}
}
}
@SubscribeEvent
public void onHarvestDropsEvent(BlockEvent.HarvestDropsEvent evt) {
if (!evt.isCanceled() && evt.block instanceof BlockMobSpawner) {
BlockCoord bc = new BlockCoord(evt.x, evt.y, evt.z);
if (dropCache.containsKey(bc)) {
ItemStack stack = dropCache.get(bc);
if (stack != null) {
evt.drops.add(stack);
}
} else {
// A spawner was broken---but not by a player. The TE has been
// invalidated already, but we might be able to recover it.
try {
for (Object object : evt.world.loadedTileEntityList) {
if (object instanceof TileEntityMobSpawner) {
TileEntityMobSpawner spawner = (TileEntityMobSpawner) object;
if (spawner.getWorldObj() == evt.world && spawner.xCoord == evt.x && spawner.yCoord == evt.y
&& spawner.zCoord == evt.z) {
// Bingo!
MobSpawnerBaseLogic logic = spawner.func_145881_a();
if (logic != null) {
String name = logic.getEntityNameToSpawn();
if (name != null && !isBlackListed(name)) {
evt.drops.add(ItemBrokenSpawner.createStackForMobType(name));
}
}
}
}
}
} catch (Exception e) {
// Risky recovery failed. Happens.
}
}
}
}
@SubscribeEvent
public void onServerTick(TickEvent.ServerTickEvent event) {
if (event.phase == TickEvent.Phase.END) {
dropCache.clear();
}
}
@SubscribeEvent
public void handleAnvilEvent(AnvilUpdateEvent evt) {
if(evt.left == null || evt.left.stackSize != 1 || evt.left.getItem() != Item.getItemFromBlock(EnderIO.blockPoweredSpawner) ||
evt.right == null || ItemBrokenSpawner.getMobTypeFromStack(evt.right) == null) {
return;
}
String spawnerType = ItemBrokenSpawner.getMobTypeFromStack(evt.right);
if(isBlackListed(spawnerType)) {
return;
}
evt.cost = Config.powerSpawnerAddSpawnerCost;
evt.output = evt.left.copy();
if(evt.output.stackTagCompound == null) {
evt.output.stackTagCompound = new NBTTagCompound();
}
evt.output.stackTagCompound.setBoolean("eio.abstractMachine", true);
writeMobTypeToNBT(evt.output.stackTagCompound, spawnerType);
}
@SubscribeEvent
public void onLivingUpdate(LivingUpdateEvent livingUpdate) {
Entity ent = livingUpdate.entityLiving;
if(!ent.getEntityData().hasKey(KEY_SPAWNED_BY_POWERED_SPAWNER)) {
return;
}
if(fieldpersistenceRequired == null) {
ent.getEntityData().removeTag(KEY_SPAWNED_BY_POWERED_SPAWNER);
return;
}
long spawnTime = ent.getEntityData().getLong(KEY_SPAWNED_BY_POWERED_SPAWNER);
long livedFor = livingUpdate.entity.worldObj.getTotalWorldTime() - spawnTime;
if(livedFor > Config.poweredSpawnerDespawnTimeSeconds*20) {
try {
fieldpersistenceRequired.setBoolean(livingUpdate.entityLiving, false);
ent.getEntityData().removeTag(KEY_SPAWNED_BY_POWERED_SPAWNER);
} catch (Exception e) {
Log.warn("BlockPoweredSpawner.onLivingUpdate: Error occured allowing entity to despawn: " + e);
ent.getEntityData().removeTag(KEY_SPAWNED_BY_POWERED_SPAWNER);
}
}
}
public boolean isBlackListed(String entityId) {
return PoweredSpawnerConfig.getInstance().isBlackListed(entityId);
}
@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
TileEntity te = world.getTileEntity(x, y, z);
if(te instanceof TilePoweredSpawner) {
return new ContainerPoweredSpawner(player.inventory, (TilePoweredSpawner) te);
}
return null;
}
@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
TileEntity te = world.getTileEntity(x, y, z);
if(te instanceof TilePoweredSpawner) {
return new GuiPoweredSpawner(player.inventory, (TilePoweredSpawner) te);
}
return null;
}
@Override
protected int getGuiId() {
return GuiHandler.GUI_ID_POWERED_SPAWNER;
}
@Override
protected String getMachineFrontIconKey(boolean active) {
if(active) {
return "enderio:poweredSpawnerFrontActive";
}
return "enderio:poweredSpawnerFront";
}
@Override
public boolean isOpaqueCube() {
return false;
}
@Override
public void addCommonEntries(ItemStack itemstack, EntityPlayer entityplayer, List list, boolean flag) {
String type = getSpawnerTypeFromItemStack(itemstack);
if(type != null) {
list.add(StatCollector.translateToLocal("entity." + type + ".name"));
} else {
list.add(EnderIO.lang.localizeExact("tile.blockPoweredSpawner.tooltip.empty"));
}
}
@Override
public void addBasicEntries(ItemStack itemstack, EntityPlayer entityplayer, List list, boolean flag) {
}
@Override
public void addDetailedEntries(ItemStack itemstack, EntityPlayer entityplayer, List list, boolean flag) {
String type = getSpawnerTypeFromItemStack(itemstack);
if(type == null) {
SpecialTooltipHandler.addDetailedTooltipFromResources(list, "tile.blockPoweredSpawner.empty");
} else {
SpecialTooltipHandler.addDetailedTooltipFromResources(list, "tile.blockPoweredSpawner");
}
}
@Override
public void getWailaInfo(List<String> tooltip, EntityPlayer player, World world, int x, int y, int z) {
TilePoweredSpawner te = (TilePoweredSpawner) world.getTileEntity(x, y, z);
tooltip.add(te.getEntityName());
}
@Override
public int getDefaultDisplayMask(World world, int x, int y, int z) {
return IWailaInfoProvider.BIT_DETAILED;
}
@Override
@SideOnly(Side.CLIENT)
public void getSubBlocks(Item item, CreativeTabs tab, List list) {
super.getSubBlocks(item, tab, list);
list.add(createItemStackForMob("Enderman"));
list.add(createItemStackForMob("Chicken"));
}
protected ItemStack createItemStackForMob(String mob) {
ItemStack stack = new ItemStack(this);
stack.stackTagCompound = new NBTTagCompound();
stack.stackTagCompound.setBoolean("eio.abstractMachine", true);
writeMobTypeToNBT(stack.stackTagCompound, mob);
return stack;
}
private static class DropInfo {
BlockEvent.BreakEvent evt;
ItemStack drop;
DropInfo(BreakEvent evt, ItemStack stack) {
super();
this.evt = evt;
drop = stack;
}
void doDrop() {
if(evt.isCanceled()) {
return;
}
Util.dropItems(evt.getPlayer().worldObj, drop, evt.x, evt.y, evt.z, true);
}
}
}