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            Iterator var1 = this.newDoors.iterator();
148    
149            while (var1.hasNext())
150            {
151                VillageDoorInfo var2 = (VillageDoorInfo)var1.next();
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                    break;
181                }
182            }
183    
184            this.newDoors.clear();
185        }
186    
187        private void addUnassignedWoodenDoorsAroundToNewDoorsList(ChunkCoordinates par1ChunkCoordinates)
188        {
189            byte var2 = 16;
190            byte var3 = 4;
191            byte var4 = 16;
192    
193            for (int var5 = par1ChunkCoordinates.posX - var2; var5 < par1ChunkCoordinates.posX + var2; ++var5)
194            {
195                for (int var6 = par1ChunkCoordinates.posY - var3; var6 < par1ChunkCoordinates.posY + var3; ++var6)
196                {
197                    for (int var7 = par1ChunkCoordinates.posZ - var4; var7 < par1ChunkCoordinates.posZ + var4; ++var7)
198                    {
199                        if (this.isWoodenDoorAt(var5, var6, var7))
200                        {
201                            VillageDoorInfo var8 = this.getVillageDoorAt(var5, var6, var7);
202    
203                            if (var8 == null)
204                            {
205                                this.addDoorToNewListIfAppropriate(var5, var6, var7);
206                            }
207                            else
208                            {
209                                var8.lastActivityTimestamp = this.tickCounter;
210                            }
211                        }
212                    }
213                }
214            }
215        }
216    
217        private VillageDoorInfo getVillageDoorAt(int par1, int par2, int par3)
218        {
219            Iterator var4 = this.newDoors.iterator();
220            VillageDoorInfo var5;
221    
222            do
223            {
224                if (!var4.hasNext())
225                {
226                    var4 = this.villageList.iterator();
227                    VillageDoorInfo var6;
228    
229                    do
230                    {
231                        if (!var4.hasNext())
232                        {
233                            return null;
234                        }
235    
236                        Village var7 = (Village)var4.next();
237                        var6 = var7.getVillageDoorAt(par1, par2, par3);
238                    }
239                    while (var6 == null);
240    
241                    return var6;
242                }
243    
244                var5 = (VillageDoorInfo)var4.next();
245            }
246            while (var5.posX != par1 || var5.posZ != par3 || Math.abs(var5.posY - par2) > 1);
247    
248            return var5;
249        }
250    
251        private void addDoorToNewListIfAppropriate(int par1, int par2, int par3)
252        {
253            int var4 = ((BlockDoor)Block.doorWood).getDoorOrientation(this.worldObj, par1, par2, par3);
254            int var5;
255            int var6;
256    
257            if (var4 != 0 && var4 != 2)
258            {
259                var5 = 0;
260    
261                for (var6 = -5; var6 < 0; ++var6)
262                {
263                    if (this.worldObj.canBlockSeeTheSky(par1, par2, par3 + var6))
264                    {
265                        --var5;
266                    }
267                }
268    
269                for (var6 = 1; var6 <= 5; ++var6)
270                {
271                    if (this.worldObj.canBlockSeeTheSky(par1, par2, par3 + var6))
272                    {
273                        ++var5;
274                    }
275                }
276    
277                if (var5 != 0)
278                {
279                    this.newDoors.add(new VillageDoorInfo(par1, par2, par3, 0, var5 > 0 ? -2 : 2, this.tickCounter));
280                }
281            }
282            else
283            {
284                var5 = 0;
285    
286                for (var6 = -5; var6 < 0; ++var6)
287                {
288                    if (this.worldObj.canBlockSeeTheSky(par1 + var6, par2, par3))
289                    {
290                        --var5;
291                    }
292                }
293    
294                for (var6 = 1; var6 <= 5; ++var6)
295                {
296                    if (this.worldObj.canBlockSeeTheSky(par1 + var6, par2, par3))
297                    {
298                        ++var5;
299                    }
300                }
301    
302                if (var5 != 0)
303                {
304                    this.newDoors.add(new VillageDoorInfo(par1, par2, par3, var5 > 0 ? -2 : 2, 0, this.tickCounter));
305                }
306            }
307        }
308    
309        private boolean isVillagerPositionPresent(int par1, int par2, int par3)
310        {
311            Iterator var4 = this.villagerPositionsList.iterator();
312            ChunkCoordinates var5;
313    
314            do
315            {
316                if (!var4.hasNext())
317                {
318                    return false;
319                }
320    
321                var5 = (ChunkCoordinates)var4.next();
322            }
323            while (var5.posX != par1 || var5.posY != par2 || var5.posZ != par3);
324    
325            return true;
326        }
327    
328        private boolean isWoodenDoorAt(int par1, int par2, int par3)
329        {
330            int var4 = this.worldObj.getBlockId(par1, par2, par3);
331            return var4 == Block.doorWood.blockID;
332        }
333    
334        /**
335         * reads in data from the NBTTagCompound into this MapDataBase
336         */
337        public void readFromNBT(NBTTagCompound par1NBTTagCompound)
338        {
339            this.tickCounter = par1NBTTagCompound.getInteger("Tick");
340            NBTTagList var2 = par1NBTTagCompound.getTagList("Villages");
341    
342            for (int var3 = 0; var3 < var2.tagCount(); ++var3)
343            {
344                NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
345                Village var5 = new Village();
346                var5.func_82690_a(var4);
347                this.villageList.add(var5);
348            }
349        }
350    
351        /**
352         * write data to NBTTagCompound from this MapDataBase, similar to Entities and TileEntities
353         */
354        public void writeToNBT(NBTTagCompound par1NBTTagCompound)
355        {
356            par1NBTTagCompound.setInteger("Tick", this.tickCounter);
357            NBTTagList var2 = new NBTTagList("Villages");
358            Iterator var3 = this.villageList.iterator();
359    
360            while (var3.hasNext())
361            {
362                Village var4 = (Village)var3.next();
363                NBTTagCompound var5 = new NBTTagCompound("Village");
364                var4.func_82689_b(var5);
365                var2.appendTag(var5);
366            }
367    
368            par1NBTTagCompound.setTag("Villages", var2);
369        }
370    }