001 package net.minecraft.world.gen.structure; 002 003 import java.util.List; 004 import java.util.Random; 005 import net.minecraft.block.Block; 006 import net.minecraft.entity.passive.EntityVillager; 007 import net.minecraft.world.World; 008 009 import net.minecraftforge.common.*; 010 import net.minecraftforge.event.Event.*; 011 import net.minecraftforge.event.terraingen.*; 012 013 public abstract class ComponentVillage extends StructureComponent 014 { 015 /** The number of villagers that have been spawned in this component. */ 016 private int villagersSpawned; 017 018 /** The starting piece of the village. */ 019 protected ComponentVillageStartPiece startPiece; 020 021 protected ComponentVillage(ComponentVillageStartPiece par1ComponentVillageStartPiece, int par2) 022 { 023 super(par2); 024 this.startPiece = par1ComponentVillageStartPiece; 025 } 026 027 /** 028 * Gets the next village component, with the bounding box shifted -1 in the X and Z direction. 029 */ 030 protected StructureComponent getNextComponentNN(ComponentVillageStartPiece par1ComponentVillageStartPiece, List par2List, Random par3Random, int par4, int par5) 031 { 032 switch (this.coordBaseMode) 033 { 034 case 0: 035 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX - 1, this.boundingBox.minY + par4, this.boundingBox.minZ + par5, 1, this.getComponentType()); 036 case 1: 037 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX + par5, this.boundingBox.minY + par4, this.boundingBox.minZ - 1, 2, this.getComponentType()); 038 case 2: 039 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX - 1, this.boundingBox.minY + par4, this.boundingBox.minZ + par5, 1, this.getComponentType()); 040 case 3: 041 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX + par5, this.boundingBox.minY + par4, this.boundingBox.minZ - 1, 2, this.getComponentType()); 042 default: 043 return null; 044 } 045 } 046 047 /** 048 * Gets the next village component, with the bounding box shifted +1 in the X and Z direction. 049 */ 050 protected StructureComponent getNextComponentPP(ComponentVillageStartPiece par1ComponentVillageStartPiece, List par2List, Random par3Random, int par4, int par5) 051 { 052 switch (this.coordBaseMode) 053 { 054 case 0: 055 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.maxX + 1, this.boundingBox.minY + par4, this.boundingBox.minZ + par5, 3, this.getComponentType()); 056 case 1: 057 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX + par5, this.boundingBox.minY + par4, this.boundingBox.maxZ + 1, 0, this.getComponentType()); 058 case 2: 059 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.maxX + 1, this.boundingBox.minY + par4, this.boundingBox.minZ + par5, 3, this.getComponentType()); 060 case 3: 061 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX + par5, this.boundingBox.minY + par4, this.boundingBox.maxZ + 1, 0, this.getComponentType()); 062 default: 063 return null; 064 } 065 } 066 067 /** 068 * Discover the y coordinate that will serve as the ground level of the supplied BoundingBox. (A median of all the 069 * levels in the BB's horizontal rectangle). 070 */ 071 protected int getAverageGroundLevel(World par1World, StructureBoundingBox par2StructureBoundingBox) 072 { 073 int var3 = 0; 074 int var4 = 0; 075 076 for (int var5 = this.boundingBox.minZ; var5 <= this.boundingBox.maxZ; ++var5) 077 { 078 for (int var6 = this.boundingBox.minX; var6 <= this.boundingBox.maxX; ++var6) 079 { 080 if (par2StructureBoundingBox.isVecInside(var6, 64, var5)) 081 { 082 var3 += Math.max(par1World.getTopSolidOrLiquidBlock(var6, var5), par1World.provider.getAverageGroundLevel()); 083 ++var4; 084 } 085 } 086 } 087 088 if (var4 == 0) 089 { 090 return -1; 091 } 092 else 093 { 094 return var3 / var4; 095 } 096 } 097 098 protected static boolean canVillageGoDeeper(StructureBoundingBox par0StructureBoundingBox) 099 { 100 return par0StructureBoundingBox != null && par0StructureBoundingBox.minY > 10; 101 } 102 103 /** 104 * Spawns a number of villagers in this component. Parameters: world, component bounding box, x offset, y offset, z 105 * offset, number of villagers 106 */ 107 protected void spawnVillagers(World par1World, StructureBoundingBox par2StructureBoundingBox, int par3, int par4, int par5, int par6) 108 { 109 if (this.villagersSpawned < par6) 110 { 111 for (int var7 = this.villagersSpawned; var7 < par6; ++var7) 112 { 113 int var8 = this.getXWithOffset(par3 + var7, par5); 114 int var9 = this.getYWithOffset(par4); 115 int var10 = this.getZWithOffset(par3 + var7, par5); 116 117 if (!par2StructureBoundingBox.isVecInside(var8, var9, var10)) 118 { 119 break; 120 } 121 122 ++this.villagersSpawned; 123 EntityVillager var11 = new EntityVillager(par1World, this.getVillagerType(var7)); 124 var11.setLocationAndAngles((double)var8 + 0.5D, (double)var9, (double)var10 + 0.5D, 0.0F, 0.0F); 125 par1World.spawnEntityInWorld(var11); 126 } 127 } 128 } 129 130 /** 131 * Returns the villager type to spawn in this component, based on the number of villagers already spawned. 132 */ 133 protected int getVillagerType(int par1) 134 { 135 return 0; 136 } 137 138 /** 139 * Gets the replacement block for the current biome 140 */ 141 protected int getBiomeSpecificBlock(int par1, int par2) 142 { 143 BiomeEvent.GetVillageBlockID event = new BiomeEvent.GetVillageBlockID(startPiece.biome, par1, par2); 144 MinecraftForge.TERRAIN_GEN_BUS.post(event); 145 if (event.getResult() == Result.DENY) return event.replacement; 146 147 if (this.startPiece.inDesert) 148 { 149 if (par1 == Block.wood.blockID) 150 { 151 return Block.sandStone.blockID; 152 } 153 154 if (par1 == Block.cobblestone.blockID) 155 { 156 return Block.sandStone.blockID; 157 } 158 159 if (par1 == Block.planks.blockID) 160 { 161 return Block.sandStone.blockID; 162 } 163 164 if (par1 == Block.stairCompactPlanks.blockID) 165 { 166 return Block.stairsSandStone.blockID; 167 } 168 169 if (par1 == Block.stairCompactCobblestone.blockID) 170 { 171 return Block.stairsSandStone.blockID; 172 } 173 174 if (par1 == Block.gravel.blockID) 175 { 176 return Block.sandStone.blockID; 177 } 178 } 179 180 return par1; 181 } 182 183 /** 184 * Gets the replacement block metadata for the current biome 185 */ 186 protected int getBiomeSpecificBlockMetadata(int par1, int par2) 187 { 188 BiomeEvent.GetVillageBlockMeta event = new BiomeEvent.GetVillageBlockMeta(startPiece.biome, par1, par2); 189 MinecraftForge.TERRAIN_GEN_BUS.post(event); 190 if (event.getResult() == Result.DENY) return event.replacement; 191 192 if (this.startPiece.inDesert) 193 { 194 if (par1 == Block.wood.blockID) 195 { 196 return 0; 197 } 198 199 if (par1 == Block.cobblestone.blockID) 200 { 201 return 0; 202 } 203 204 if (par1 == Block.planks.blockID) 205 { 206 return 2; 207 } 208 } 209 210 return par2; 211 } 212 213 /** 214 * current Position depends on currently set Coordinates mode, is computed here 215 */ 216 protected void placeBlockAtCurrentPosition(World par1World, int par2, int par3, int par4, int par5, int par6, StructureBoundingBox par7StructureBoundingBox) 217 { 218 int var8 = this.getBiomeSpecificBlock(par2, par3); 219 int var9 = this.getBiomeSpecificBlockMetadata(par2, par3); 220 super.placeBlockAtCurrentPosition(par1World, var8, var9, par4, par5, par6, par7StructureBoundingBox); 221 } 222 223 /** 224 * arguments: (World worldObj, StructureBoundingBox structBB, int minX, int minY, int minZ, int maxX, int maxY, int 225 * maxZ, int placeBlockId, int replaceBlockId, boolean alwaysreplace) 226 */ 227 protected void fillWithBlocks(World par1World, StructureBoundingBox par2StructureBoundingBox, int par3, int par4, int par5, int par6, int par7, int par8, int par9, int par10, boolean par11) 228 { 229 int var12 = this.getBiomeSpecificBlock(par9, 0); 230 int var13 = this.getBiomeSpecificBlockMetadata(par9, 0); 231 int var14 = this.getBiomeSpecificBlock(par10, 0); 232 int var15 = this.getBiomeSpecificBlockMetadata(par10, 0); 233 super.fillWithMetadataBlocks(par1World, par2StructureBoundingBox, par3, par4, par5, par6, par7, par8, var12, var13, var14, var15, par11); 234 } 235 236 /** 237 * Overwrites air and liquids from selected position downwards, stops at hitting anything else. 238 */ 239 protected void fillCurrentPositionBlocksDownwards(World par1World, int par2, int par3, int par4, int par5, int par6, StructureBoundingBox par7StructureBoundingBox) 240 { 241 int var8 = this.getBiomeSpecificBlock(par2, par3); 242 int var9 = this.getBiomeSpecificBlockMetadata(par2, par3); 243 super.fillCurrentPositionBlocksDownwards(par1World, var8, var9, par4, par5, par6, par7StructureBoundingBox); 244 } 245 }