package net.torocraft.toroquest.block; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.annotation.Nullable; import net.minecraft.block.BlockBush; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; import net.minecraft.init.Blocks; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ITickable; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.torocraft.toroquest.entities.EntityGuard; public class TileEntityToroSpawner extends TileEntity implements ITickable { private int triggerDistance = 60; private List<String> entityIds = new ArrayList<String>(); private int spawnRadius = 0; private int spawnTryCount = 0; private ItemStack helmet; private ItemStack chestplate; private ItemStack leggings; private ItemStack boots; private List<String> entityTags = new ArrayList<String>(); public TileEntityToroSpawner() { } public int getSpawnRadius() { return spawnRadius; } public void setSpawnRadius(int spawnRadius) { this.spawnRadius = spawnRadius; } public void setTriggerDistance(int triggerDistance) { this.triggerDistance = triggerDistance; } public void setEntityIds(List<String> entityIds) { this.entityIds = entityIds; } public void readFromNBT(NBTTagCompound compound) { super.readFromNBT(compound); triggerDistance = compound.getInteger("trigger_distance"); spawnRadius = compound.getInteger("spawn_radius"); helmet = readItemStack("helment", compound); boots = readItemStack("boots", compound); chestplate = readItemStack("chestplate", compound); leggings = readItemStack("leggings", compound); entityIds = new ArrayList<String>(); entityTags = new ArrayList<String>(); NBTTagList list; try { list = (NBTTagList) compound.getTag("entity_ids"); } catch (Exception e) { list = new NBTTagList(); } for (int i = 0; i < list.tagCount(); i++) { entityIds.add(list.getStringTagAt(i)); } try { list = (NBTTagList) compound.getTag("entity_tags"); } catch (Exception e) { list = new NBTTagList(); } for (int i = 0; i < list.tagCount(); i++) { entityTags.add(list.getStringTagAt(i)); } } public NBTTagCompound writeToNBT(NBTTagCompound compound) { super.writeToNBT(compound); compound.setInteger("trigger_distance", triggerDistance); compound.setInteger("spawn_radius", spawnRadius); storeItemStack("helment", helmet, compound); storeItemStack("boots", boots, compound); storeItemStack("chestplate", chestplate, compound); storeItemStack("leggings", leggings, compound); NBTTagList list = new NBTTagList(); for (String id : entityIds) { list.appendTag(new NBTTagString(id)); } compound.setTag("entity_ids", list); list = new NBTTagList(); if (entityTags != null) { for (String id : entityTags) { list.appendTag(new NBTTagString(id)); } } compound.setTag("entity_tags", list); return compound; } protected void storeItemStack(String key, ItemStack stack, NBTTagCompound compound) { if (stack == null) { return; } NBTTagCompound c = new NBTTagCompound(); stack.writeToNBT(c); compound.setTag(key, c); } protected ItemStack readItemStack(String key, NBTTagCompound compound) { if (!compound.hasKey(key)) { return null; } return new ItemStack(compound.getCompoundTag(key)); } public void update() { if (!world.isRemote && isRunTick() && withinRange()) { triggerSpawner(); } } protected void triggerSpawner() { for (String entityId : entityIds) { spawnCreature(entityId); } world.setBlockToAir(pos); } public void spawnCreature(String entityID) { Random rand = world.rand; Entity entity = getEntityForId(getWorld(), entityID); if (!(entity instanceof EntityLivingBase)) { System.out.println("entity not EntityLivingBase: " + entityID); return; } spawnEntityLiving((EntityLiving) entity, findSuitableSpawnLocation()); } private BlockPos findSuitableSpawnLocation() { Random rand = world.rand; if (spawnRadius < 1) { return getPos(); } int degrees, distance, x, z; BlockPos pos; for (int i = 0; i < 10; i++) { distance = rand.nextInt(spawnRadius); degrees = rand.nextInt(360); x = distance * (int) Math.round(Math.cos(Math.toRadians(degrees))); z = distance * (int) Math.round(Math.sin(Math.toRadians(degrees))); pos = findSurface(x, z); if (pos != null) { return pos; } } return getPos(); } private BlockPos findSurface(int x, int z) { BlockPos pos = getPos().add(x, -3, z); IBlockState blockState; int yOffset = 0; boolean groundFound = false; boolean[] airSpace = { false, false }; while (yOffset < 14) { blockState = world.getBlockState(pos); if (isGroundBlock(blockState)) { groundFound = true; airSpace[0] = false; airSpace[1] = false; } else if (airSpace[0] && airSpace[1] && groundFound) { return pos.down(); } else if (Blocks.AIR.equals(blockState.getBlock())) { if (airSpace[0]) { airSpace[1] = true; } else { airSpace[0] = true; } } pos = pos.up(); yOffset++; } return null; } private boolean isLiquid(IBlockState blockState) { return blockState.getBlock() == Blocks.WATER || blockState.getBlock() == Blocks.LAVA; } private boolean isGroundBlock(IBlockState blockState) { if (blockState.getBlock() == Blocks.LEAVES || blockState.getBlock() == Blocks.LEAVES2 || blockState.getBlock() == Blocks.LOG || blockState.getBlock() instanceof BlockBush) { return false; } return blockState.isOpaqueCube(); } public static Entity getEntityForId(World world, String entityID) { String[] parts = entityID.split(":"); String domain, entityName; if (parts.length == 2) { domain = parts[0]; entityName = parts[1]; } else { domain = "minecraft"; entityName = entityID; } return EntityList.createEntityByIDFromName(new ResourceLocation(domain, entityName), world); } protected boolean spawnEntityLiving(EntityLiving entity, BlockPos pos) { double x = pos.getX() + 0.5D; double y = pos.getY(); double z = pos.getZ() + 0.5D; entity.setLocationAndAngles(x, y, z, MathHelper.wrapDegrees(world.rand.nextFloat() * 360.0F), 0.0F); entity.rotationYawHead = entity.rotationYaw; entity.renderYawOffset = entity.rotationYaw; entity.onInitialSpawn(world.getDifficultyForLocation(new BlockPos(entity)), (IEntityLivingData) null); entity.enablePersistence(); if (entityTags != null) { for (String tag : entityTags) { entity.addTag(tag); } } if (helmet != null) { try { entity.setItemStackToSlot(EntityEquipmentSlot.HEAD, helmet); } catch (Exception e) { System.out.println("failed to add helment: " + e.getMessage()); } } if (boots != null) { try { entity.setItemStackToSlot(EntityEquipmentSlot.FEET, boots); } catch (Exception e) { System.out.println("failed to add boots: " + e.getMessage()); } } if (chestplate != null) { try { entity.setItemStackToSlot(EntityEquipmentSlot.CHEST, chestplate); } catch (Exception e) { System.out.println("failed to add chestplate: " + e.getMessage()); } } if (leggings != null) { try { entity.setItemStackToSlot(EntityEquipmentSlot.LEGS, leggings); } catch (Exception e) { System.out.println("failed to add leggings: " + e.getMessage()); } } world.spawnEntity(entity); entity.playLivingSound(); return true; } private void spawnCreature() { EntityGuard entity = new EntityGuard(world); EntityLiving entityliving = (EntityLiving) entity; entity.setLocationAndAngles((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, MathHelper.wrapDegrees(world.rand.nextFloat() * 360.0F), 0.0F); entityliving.rotationYawHead = entityliving.rotationYaw; entityliving.renderYawOffset = entityliving.rotationYaw; entityliving.onInitialSpawn(world.getDifficultyForLocation(new BlockPos(entityliving)), (IEntityLivingData) null); world.spawnEntity(entity); } private boolean withinRange() { return world.isAnyPlayerWithinRangeAt((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.triggerDistance); } private boolean isRunTick() { return world.getTotalWorldTime() % 20L == 0L; } @Nullable public SPacketUpdateTileEntity getUpdatePacket() { return new SPacketUpdateTileEntity(pos, 1, getUpdateTag()); } public NBTTagCompound getUpdateTag() { NBTTagCompound nbttagcompound = this.writeToNBT(new NBTTagCompound()); nbttagcompound.removeTag("SpawnPotentials"); return nbttagcompound; } public boolean onlyOpsCanSetNbt() { return true; } public ItemStack getHelmet() { return helmet; } public void setHelmet(ItemStack helmet) { this.helmet = helmet; } public int getTriggerDistance() { return triggerDistance; } public ItemStack getChestplate() { return chestplate; } public void setChestplate(ItemStack chestplate) { this.chestplate = chestplate; } public ItemStack getLeggings() { return leggings; } public void setLeggings(ItemStack leggings) { this.leggings = leggings; } public ItemStack getBoots() { return boots; } public void setBoots(ItemStack boots) { this.boots = boots; } public List<String> getEntityTags() { return entityTags; } public void setEntityTags(List<String> entityTags) { this.entityTags = entityTags; } public void addEntityTag(String tag) { if (entityTags == null) { entityTags = new ArrayList<String>(); } entityTags.add(tag); } }