001    package net.minecraft.village;
002    
003    import java.util.ArrayList;
004    import java.util.Iterator;
005    import java.util.List;
006    import net.minecraft.block.Block;
007    import net.minecraft.block.BlockDoor;
008    import net.minecraft.nbt.NBTTagCompound;
009    import net.minecraft.nbt.NBTTagList;
010    import net.minecraft.util.ChunkCoordinates;
011    import net.minecraft.world.World;
012    import net.minecraft.world.WorldSavedData;
013    
014    public 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    }