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