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}