    001package net.minecraft.village;
    002
    003import java.util.ArrayList;
    004import java.util.Iterator;
    005import java.util.List;
    006import net.minecraft.block.Block;
    007import net.minecraft.block.BlockDoor;
    008import net.minecraft.nbt.NBTTagCompound;
    009import net.minecraft.nbt.NBTTagList;
    010import net.minecraft.util.ChunkCoordinates;
    011import net.minecraft.world.World;
    012import net.minecraft.world.WorldSavedData;
    013
    014public class VillageCollection extends WorldSavedData
    015{
    016    private World worldObj;
    017
    018    /**
    019     * This is a black hole. You can add data to this list through a public interface, but you can't query that
    020     * information in any way and it's not used internally either.
    021     */
    022    private final List villagerPositionsList = new ArrayList();
    023    private final List newDoors = new ArrayList();
    024    private final List villageList = new ArrayList();
    025    private int tickCounter = 0;
    026
    027    public VillageCollection(String par1Str)
    028    {
    029        super(par1Str);
    030    }
    031
    032    public VillageCollection(World par1World)
    033    {
    034        super("villages");
    035        this.worldObj = par1World;
    036        this.markDirty();
    037    }
    038
    039    public void func_82566_a(World par1World)
    040    {
    041        this.worldObj = par1World;
    042        Iterator var2 = this.villageList.iterator();
    043
    044        while (var2.hasNext())
    045        {
    046            Village var3 = (Village)var2.next();
    047            var3.func_82691_a(par1World);
    048        }
    049    }
    050
    051    /**
    052     * This is a black hole. You can add data to this list through a public interface, but you can't query that
    053     * information in any way and it's not used internally either.
    054     */
    055    public void addVillagerPosition(int par1, int par2, int par3)
    056    {
    057        if (this.villagerPositionsList.size() <= 64)
    058        {
    059            if (!this.isVillagerPositionPresent(par1, par2, par3))
    060            {
    061                this.villagerPositionsList.add(new ChunkCoordinates(par1, par2, par3));
    062            }
    063        }
    064    }
    065
    066    /**
    067     * Runs a single tick for the village collection
    068     */
    069    public void tick()
    070    {
    071        ++this.tickCounter;
    072        Iterator var1 = this.villageList.iterator();
    073
    074        while (var1.hasNext())
    075        {
    076            Village var2 = (Village)var1.next();
    077            var2.tick(this.tickCounter);
    078        }
    079
    080        this.removeAnnihilatedVillages();
    081        this.dropOldestVillagerPosition();
    082        this.addNewDoorsToVillageOrCreateVillage();
    083
    084        if (this.tickCounter % 400 == 0)
    085        {
    086            this.markDirty();
    087        }
    088    }
    089
    090    private void removeAnnihilatedVillages()
    091    {
    092        Iterator var1 = this.villageList.iterator();
    093
    094        while (var1.hasNext())
    095        {
    096            Village var2 = (Village)var1.next();
    097
    098            if (var2.isAnnihilated())
    099            {
    100                var1.remove();
    101                this.markDirty();
    102            }
    103        }
    104    }
    105
    106    /**
    107     * Get a list of villages.
    108     */
    109    public List getVillageList()
    110    {
    111        return this.villageList;
    112    }
    113
    114    /**
    115     * Finds the nearest village, but only the given coordinates are withing it's bounding box plus the given the
    116     * distance.
    117     */
    118    public Village findNearestVillage(int par1, int par2, int par3, int par4)
    119    {
    120        Village var5 = null;
    121        float var6 = Float.MAX_VALUE;
    122        Iterator var7 = this.villageList.iterator();
    123
    124        while (var7.hasNext())
    125        {
    126            Village var8 = (Village)var7.next();
    127            float var9 = var8.getCenter().getDistanceSquared(par1, par2, par3);
    128
    129            if (var9 < var6)
    130            {
    131                int var10 = par4 + var8.getVillageRadius();
    132
    133                if (var9 <= (float)(var10 * var10))
    134                {
    135                    var5 = var8;
    136                    var6 = var9;
    137                }
    138            }
    139        }
    140
    141        return var5;
    142    }
    143
    144    private void dropOldestVillagerPosition()
    145    {
    146        if (!this.villagerPositionsList.isEmpty())
    147        {
    148            this.addUnassignedWoodenDoorsAroundToNewDoorsList((ChunkCoordinates)this.villagerPositionsList.remove(0));
    149        }
    150    }
    151
    152    private void addNewDoorsToVillageOrCreateVillage()
    153    {
    154        int var1 = 0;
    155
    156        while (var1 < this.newDoors.size())
    157        {
    158            VillageDoorInfo var2 = (VillageDoorInfo)this.newDoors.get(var1);
    159            boolean var3 = false;
    160            Iterator var4 = this.villageList.iterator();
    161
    162            while (true)
    163            {
    164                if (var4.hasNext())
    165                {
    166                    Village var5 = (Village)var4.next();
    167                    int var6 = (int)var5.getCenter().getDistanceSquared(var2.posX, var2.posY, var2.posZ);
    168                    int var7 = 32 + var5.getVillageRadius();
    169
    170                    if (var6 > var7 * var7)
    171                    {
    172                        continue;
    173                    }
    174
    175                    var5.addVillageDoorInfo(var2);
    176                    var3 = true;
    177                }
    178
    179                if (!var3)
    180                {
    181                    Village var8 = new Village(this.worldObj);
    182                    var8.addVillageDoorInfo(var2);
    183                    this.villageList.add(var8);
    184                    this.markDirty();
    185                }
    186
    187                ++var1;
    188                break;
    189            }
    190        }
    191
    192        this.newDoors.clear();
    193    }
    194
    195    private void addUnassignedWoodenDoorsAroundToNewDoorsList(ChunkCoordinates par1ChunkCoordinates)
    196    {
    197        byte var2 = 16;
    198        byte var3 = 4;
    199        byte var4 = 16;
    200
    201        for (int var5 = par1ChunkCoordinates.posX - var2; var5 < par1ChunkCoordinates.posX + var2; ++var5)
    202        {
    203            for (int var6 = par1ChunkCoordinates.posY - var3; var6 < par1ChunkCoordinates.posY + var3; ++var6)
    204            {
    205                for (int var7 = par1ChunkCoordinates.posZ - var4; var7 < par1ChunkCoordinates.posZ + var4; ++var7)
    206                {
    207                    if (this.isWoodenDoorAt(var5, var6, var7))
    208                    {
    209                        VillageDoorInfo var8 = this.getVillageDoorAt(var5, var6, var7);
    210
    211                        if (var8 == null)
    212                        {
    213                            this.addDoorToNewListIfAppropriate(var5, var6, var7);
    214                        }
    215                        else
    216                        {
    217                            var8.lastActivityTimestamp = this.tickCounter;
    218                        }
    219                    }
    220                }
    221            }
    222        }
    223    }
    224
    225    private VillageDoorInfo getVillageDoorAt(int par1, int par2, int par3)
    226    {
    227        Iterator var4 = this.newDoors.iterator();
    228        VillageDoorInfo var5;
    229
    230        do
    231        {
    232            if (!var4.hasNext())
    233            {
    234                var4 = this.villageList.iterator();
    235                VillageDoorInfo var6;
    236
    237                do
    238                {
    239                    if (!var4.hasNext())
    240                    {
    241                        return null;
    242                    }
    243
    244                    Village var7 = (Village)var4.next();
    245                    var6 = var7.getVillageDoorAt(par1, par2, par3);
    246                }
    247                while (var6 == null);
    248
    249                return var6;
    250            }
    251
    252            var5 = (VillageDoorInfo)var4.next();
    253        }
    254        while (var5.posX != par1 || var5.posZ != par3 || Math.abs(var5.posY - par2) > 1);
    255
    256        return var5;
    257    }
    258
    259    private void addDoorToNewListIfAppropriate(int par1, int par2, int par3)
    260    {
    261        int var4 = ((BlockDoor)Block.doorWood).getDoorOrientation(this.worldObj, par1, par2, par3);
    262        int var5;
    263        int var6;
    264
    265        if (var4 != 0 && var4 != 2)
    266        {
    267            var5 = 0;
    268
    269            for (var6 = -5; var6 < 0; ++var6)
    270            {
    271                if (this.worldObj.canBlockSeeTheSky(par1, par2, par3 + var6))
    272                {
    273                    --var5;
    274                }
    275            }
    276
    277            for (var6 = 1; var6 <= 5; ++var6)
    278            {
    279                if (this.worldObj.canBlockSeeTheSky(par1, par2, par3 + var6))
    280                {
    281                    ++var5;
    282                }
    283            }
    284
    285            if (var5 != 0)
    286            {
    287                this.newDoors.add(new VillageDoorInfo(par1, par2, par3, 0, var5 > 0 ? -2 : 2, this.tickCounter));
    288            }
    289        }
    290        else
    291        {
    292            var5 = 0;
    293
    294            for (var6 = -5; var6 < 0; ++var6)
    295            {
    296                if (this.worldObj.canBlockSeeTheSky(par1 + var6, par2, par3))
    297                {
    298                    --var5;
    299                }
    300            }
    301
    302            for (var6 = 1; var6 <= 5; ++var6)
    303            {
    304                if (this.worldObj.canBlockSeeTheSky(par1 + var6, par2, par3))
    305                {
    306                    ++var5;
    307                }
    308            }
    309
    310            if (var5 != 0)
    311            {
    312                this.newDoors.add(new VillageDoorInfo(par1, par2, par3, var5 > 0 ? -2 : 2, 0, this.tickCounter));
    313            }
    314        }
    315    }
    316
    317    private boolean isVillagerPositionPresent(int par1, int par2, int par3)
    318    {
    319        Iterator var4 = this.villagerPositionsList.iterator();
    320        ChunkCoordinates var5;
    321
    322        do
    323        {
    324            if (!var4.hasNext())
    325            {
    326                return false;
    327            }
    328
    329            var5 = (ChunkCoordinates)var4.next();
    330        }
    331        while (var5.posX != par1 || var5.posY != par2 || var5.posZ != par3);
    332
    333        return true;
    334    }
    335
    336    private boolean isWoodenDoorAt(int par1, int par2, int par3)
    337    {
    338        int var4 = this.worldObj.getBlockId(par1, par2, par3);
    339        return var4 == Block.doorWood.blockID;
    340    }
    341
    342    /**
    343     * reads in data from the NBTTagCompound into this MapDataBase
    344     */
    345    public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    346    {
    347        this.tickCounter = par1NBTTagCompound.getInteger("Tick");
    348        NBTTagList var2 = par1NBTTagCompound.getTagList("Villages");
    349
    350        for (int var3 = 0; var3 < var2.tagCount(); ++var3)
    351        {
    352            NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
    353            Village var5 = new Village();
    354            var5.readVillageDataFromNBT(var4);
    355            this.villageList.add(var5);
    356        }
    357    }
    358
    359    /**
    360     * write data to NBTTagCompound from this MapDataBase, similar to Entities and TileEntities
    361     */
    362    public void writeToNBT(NBTTagCompound par1NBTTagCompound)
    363    {
    364        par1NBTTagCompound.setInteger("Tick", this.tickCounter);
    365        NBTTagList var2 = new NBTTagList("Villages");
    366        Iterator var3 = this.villageList.iterator();
    367
    368        while (var3.hasNext())
    369        {
    370            Village var4 = (Village)var3.next();
    371            NBTTagCompound var5 = new NBTTagCompound("Village");
    372            var4.writeVillageDataToNBT(var5);
    373            var2.appendTag(var5);
    374        }
    375
    376        par1NBTTagCompound.setTag("Villages", var2);
    377    }
    378}