    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 iterator = this.villageList.iterator();
    043
    044        while (iterator.hasNext())
    045        {
    046            Village village = (Village)iterator.next();
    047            village.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 iterator = this.villageList.iterator();
    073
    074        while (iterator.hasNext())
    075        {
    076            Village village = (Village)iterator.next();
    077            village.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 iterator = this.villageList.iterator();
    093
    094        while (iterator.hasNext())
    095        {
    096            Village village = (Village)iterator.next();
    097
    098            if (village.isAnnihilated())
    099            {
    100                iterator.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 village = null;
    121        float f = Float.MAX_VALUE;
    122        Iterator iterator = this.villageList.iterator();
    123
    124        while (iterator.hasNext())
    125        {
    126            Village village1 = (Village)iterator.next();
    127            float f1 = village1.getCenter().getDistanceSquared(par1, par2, par3);
    128
    129            if (f1 < f)
    130            {
    131                int i1 = par4 + village1.getVillageRadius();
    132
    133                if (f1 <= (float)(i1 * i1))
    134                {
    135                    village = village1;
    136                    f = f1;
    137                }
    138            }
    139        }
    140
    141        return village;
    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 i = 0;
    155
    156        while (i < this.newDoors.size())
    157        {
    158            VillageDoorInfo villagedoorinfo = (VillageDoorInfo)this.newDoors.get(i);
    159            boolean flag = false;
    160            Iterator iterator = this.villageList.iterator();
    161
    162            while (true)
    163            {
    164                if (iterator.hasNext())
    165                {
    166                    Village village = (Village)iterator.next();
    167                    int j = (int)village.getCenter().getDistanceSquared(villagedoorinfo.posX, villagedoorinfo.posY, villagedoorinfo.posZ);
    168                    int k = 32 + village.getVillageRadius();
    169
    170                    if (j > k * k)
    171                    {
    172                        continue;
    173                    }
    174
    175                    village.addVillageDoorInfo(villagedoorinfo);
    176                    flag = true;
    177                }
    178
    179                if (!flag)
    180                {
    181                    Village village1 = new Village(this.worldObj);
    182                    village1.addVillageDoorInfo(villagedoorinfo);
    183                    this.villageList.add(village1);
    184                    this.markDirty();
    185                }
    186
    187                ++i;
    188                break;
    189            }
    190        }
    191
    192        this.newDoors.clear();
    193    }
    194
    195    private void addUnassignedWoodenDoorsAroundToNewDoorsList(ChunkCoordinates par1ChunkCoordinates)
    196    {
    197        byte b0 = 16;
    198        byte b1 = 4;
    199        byte b2 = 16;
    200
    201        for (int i = par1ChunkCoordinates.posX - b0; i < par1ChunkCoordinates.posX + b0; ++i)
    202        {
    203            for (int j = par1ChunkCoordinates.posY - b1; j < par1ChunkCoordinates.posY + b1; ++j)
    204            {
    205                for (int k = par1ChunkCoordinates.posZ - b2; k < par1ChunkCoordinates.posZ + b2; ++k)
    206                {
    207                    if (this.isWoodenDoorAt(i, j, k))
    208                    {
    209                        VillageDoorInfo villagedoorinfo = this.getVillageDoorAt(i, j, k);
    210
    211                        if (villagedoorinfo == null)
    212                        {
    213                            this.addDoorToNewListIfAppropriate(i, j, k);
    214                        }
    215                        else
    216                        {
    217                            villagedoorinfo.lastActivityTimestamp = this.tickCounter;
    218                        }
    219                    }
    220                }
    221            }
    222        }
    223    }
    224
    225    private VillageDoorInfo getVillageDoorAt(int par1, int par2, int par3)
    226    {
    227        Iterator iterator = this.newDoors.iterator();
    228        VillageDoorInfo villagedoorinfo;
    229
    230        do
    231        {
    232            if (!iterator.hasNext())
    233            {
    234                iterator = this.villageList.iterator();
    235                VillageDoorInfo villagedoorinfo1;
    236
    237                do
    238                {
    239                    if (!iterator.hasNext())
    240                    {
    241                        return null;
    242                    }
    243
    244                    Village village = (Village)iterator.next();
    245                    villagedoorinfo1 = village.getVillageDoorAt(par1, par2, par3);
    246                }
    247                while (villagedoorinfo1 == null);
    248
    249                return villagedoorinfo1;
    250            }
    251
    252            villagedoorinfo = (VillageDoorInfo)iterator.next();
    253        }
    254        while (villagedoorinfo.posX != par1 || villagedoorinfo.posZ != par3 || Math.abs(villagedoorinfo.posY - par2) > 1);
    255
    256        return villagedoorinfo;
    257    }
    258
    259    private void addDoorToNewListIfAppropriate(int par1, int par2, int par3)
    260    {
    261        int l = ((BlockDoor)Block.doorWood).getDoorOrientation(this.worldObj, par1, par2, par3);
    262        int i1;
    263        int j1;
    264
    265        if (l != 0 && l != 2)
    266        {
    267            i1 = 0;
    268
    269            for (j1 = -5; j1 < 0; ++j1)
    270            {
    271                if (this.worldObj.canBlockSeeTheSky(par1, par2, par3 + j1))
    272                {
    273                    --i1;
    274                }
    275            }
    276
    277            for (j1 = 1; j1 <= 5; ++j1)
    278            {
    279                if (this.worldObj.canBlockSeeTheSky(par1, par2, par3 + j1))
    280                {
    281                    ++i1;
    282                }
    283            }
    284
    285            if (i1 != 0)
    286            {
    287                this.newDoors.add(new VillageDoorInfo(par1, par2, par3, 0, i1 > 0 ? -2 : 2, this.tickCounter));
    288            }
    289        }
    290        else
    291        {
    292            i1 = 0;
    293
    294            for (j1 = -5; j1 < 0; ++j1)
    295            {
    296                if (this.worldObj.canBlockSeeTheSky(par1 + j1, par2, par3))
    297                {
    298                    --i1;
    299                }
    300            }
    301
    302            for (j1 = 1; j1 <= 5; ++j1)
    303            {
    304                if (this.worldObj.canBlockSeeTheSky(par1 + j1, par2, par3))
    305                {
    306                    ++i1;
    307                }
    308            }
    309
    310            if (i1 != 0)
    311            {
    312                this.newDoors.add(new VillageDoorInfo(par1, par2, par3, i1 > 0 ? -2 : 2, 0, this.tickCounter));
    313            }
    314        }
    315    }
    316
    317    private boolean isVillagerPositionPresent(int par1, int par2, int par3)
    318    {
    319        Iterator iterator = this.villagerPositionsList.iterator();
    320        ChunkCoordinates chunkcoordinates;
    321
    322        do
    323        {
    324            if (!iterator.hasNext())
    325            {
    326                return false;
    327            }
    328
    329            chunkcoordinates = (ChunkCoordinates)iterator.next();
    330        }
    331        while (chunkcoordinates.posX != par1 || chunkcoordinates.posY != par2 || chunkcoordinates.posZ != par3);
    332
    333        return true;
    334    }
    335
    336    private boolean isWoodenDoorAt(int par1, int par2, int par3)
    337    {
    338        int l = this.worldObj.getBlockId(par1, par2, par3);
    339        return l == 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 nbttaglist = par1NBTTagCompound.getTagList("Villages");
    349
    350        for (int i = 0; i < nbttaglist.tagCount(); ++i)
    351        {
    352            NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
    353            Village village = new Village();
    354            village.readVillageDataFromNBT(nbttagcompound1);
    355            this.villageList.add(village);
    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 nbttaglist = new NBTTagList("Villages");
    366        Iterator iterator = this.villageList.iterator();
    367
    368        while (iterator.hasNext())
    369        {
    370            Village village = (Village)iterator.next();
    371            NBTTagCompound nbttagcompound1 = new NBTTagCompound("Village");
    372            village.writeVillageDataToNBT(nbttagcompound1);
    373            nbttaglist.appendTag(nbttagcompound1);
    374        }
    375
    376        par1NBTTagCompound.setTag("Villages", nbttaglist);
    377    }
    378}