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 PlayerManager
008    {
009        private final WorldServer theWorldServer;
010    
011        /** players in the current instance */
012        private final List players = new ArrayList();
013        private final LongHashMap allChunkWathers = new LongHashMap();
014    
015        /**
016         * contains a PlayerInstance for every chunk they can see. the "player instance" cotains a list of all players who
017         * can also that chunk
018         */
019        private final List chunkWathcherWithPlayers = new ArrayList();
020        private final int playerViewDistance;
021    
022        /** x, z direction vectors: east, south, west, north */
023        private final int[][] xzDirectionsConst = new int[][] {{1, 0}, {0, 1}, { -1, 0}, {0, -1}};
024    
025        public PlayerManager(WorldServer par1WorldServer, int par2)
026        {
027            if (par2 > 15)
028            {
029                throw new IllegalArgumentException("Too big view radius!");
030            }
031            else if (par2 < 3)
032            {
033                throw new IllegalArgumentException("Too small view radius!");
034            }
035            else
036            {
037                this.playerViewDistance = par2;
038                this.theWorldServer = par1WorldServer;
039            }
040        }
041    
042        public WorldServer getWorldServer()
043        {
044            return this.theWorldServer;
045        }
046    
047        /**
048         * updates all the player instances that need to be updated
049         */
050        public void updatePlayerInstances()
051        {
052            Iterator var1 = this.chunkWathcherWithPlayers.iterator();
053    
054            while (var1.hasNext())
055            {
056                PlayerInstance var2 = (PlayerInstance)var1.next();
057                var2.sendChunkUpdate();
058            }
059    
060            this.chunkWathcherWithPlayers.clear();
061    
062            if (this.players.isEmpty())
063            {
064                WorldProvider var3 = this.theWorldServer.provider;
065    
066                if (!var3.canRespawnHere())
067                {
068                    this.theWorldServer.theChunkProviderServer.unloadAllChunks();
069                }
070            }
071        }
072    
073        private PlayerInstance getOrCreateChunkWatcher(int par1, int par2, boolean par3)
074        {
075            long var4 = (long)par1 + 2147483647L | (long)par2 + 2147483647L << 32;
076            PlayerInstance var6 = (PlayerInstance)this.allChunkWathers.getValueByKey(var4);
077    
078            if (var6 == null && par3)
079            {
080                var6 = new PlayerInstance(this, par1, par2);
081                this.allChunkWathers.add(var4, var6);
082            }
083    
084            return var6;
085        }
086    
087        /**
088         * the "PlayerInstance"/ chunkWatcher will send this chunk to all players who are in line of sight
089         */
090        public void flagChunkForUpdate(int par1, int par2, int par3)
091        {
092            int var4 = par1 >> 4;
093            int var5 = par3 >> 4;
094            PlayerInstance var6 = this.getOrCreateChunkWatcher(var4, var5, false);
095    
096            if (var6 != null)
097            {
098                var6.flagChunkForUpdate(par1 & 15, par2, par3 & 15);
099            }
100        }
101    
102        /**
103         * Adds an EntityPlayerMP to the PlayerManager.
104         */
105        public void addPlayer(EntityPlayerMP par1EntityPlayerMP)
106        {
107            int var2 = (int)par1EntityPlayerMP.posX >> 4;
108            int var3 = (int)par1EntityPlayerMP.posZ >> 4;
109            par1EntityPlayerMP.managedPosX = par1EntityPlayerMP.posX;
110            par1EntityPlayerMP.managedPosZ = par1EntityPlayerMP.posZ;
111    
112            for (int var4 = var2 - this.playerViewDistance; var4 <= var2 + this.playerViewDistance; ++var4)
113            {
114                for (int var5 = var3 - this.playerViewDistance; var5 <= var3 + this.playerViewDistance; ++var5)
115                {
116                    this.getOrCreateChunkWatcher(var4, var5, true).addPlayerToChunkWatchingList(par1EntityPlayerMP);
117                }
118            }
119    
120            this.players.add(par1EntityPlayerMP);
121            this.func_72691_b(par1EntityPlayerMP);
122        }
123    
124        public void func_72691_b(EntityPlayerMP par1EntityPlayerMP)
125        {
126            ArrayList var2 = new ArrayList(par1EntityPlayerMP.chunksToLoad);
127            int var3 = 0;
128            int var4 = this.playerViewDistance;
129            int var5 = (int)par1EntityPlayerMP.posX >> 4;
130            int var6 = (int)par1EntityPlayerMP.posZ >> 4;
131            int var7 = 0;
132            int var8 = 0;
133            ChunkCoordIntPair var9 = PlayerInstance.getChunkLocation(this.getOrCreateChunkWatcher(var5, var6, true));
134            par1EntityPlayerMP.chunksToLoad.clear();
135    
136            if (var2.contains(var9))
137            {
138                par1EntityPlayerMP.chunksToLoad.add(var9);
139            }
140    
141            int var10;
142    
143            for (var10 = 1; var10 <= var4 * 2; ++var10)
144            {
145                for (int var11 = 0; var11 < 2; ++var11)
146                {
147                    int[] var12 = this.xzDirectionsConst[var3++ % 4];
148    
149                    for (int var13 = 0; var13 < var10; ++var13)
150                    {
151                        var7 += var12[0];
152                        var8 += var12[1];
153                        var9 = PlayerInstance.getChunkLocation(this.getOrCreateChunkWatcher(var5 + var7, var6 + var8, true));
154    
155                        if (var2.contains(var9))
156                        {
157                            par1EntityPlayerMP.chunksToLoad.add(var9);
158                        }
159                    }
160                }
161            }
162    
163            var3 %= 4;
164    
165            for (var10 = 0; var10 < var4 * 2; ++var10)
166            {
167                var7 += this.xzDirectionsConst[var3][0];
168                var8 += this.xzDirectionsConst[var3][1];
169                var9 = PlayerInstance.getChunkLocation(this.getOrCreateChunkWatcher(var5 + var7, var6 + var8, true));
170    
171                if (var2.contains(var9))
172                {
173                    par1EntityPlayerMP.chunksToLoad.add(var9);
174                }
175            }
176        }
177    
178        /**
179         * Removes an EntityPlayerMP from the PlayerManager.
180         */
181        public void removePlayer(EntityPlayerMP par1EntityPlayerMP)
182        {
183            int var2 = (int)par1EntityPlayerMP.managedPosX >> 4;
184            int var3 = (int)par1EntityPlayerMP.managedPosZ >> 4;
185    
186            for (int var4 = var2 - this.playerViewDistance; var4 <= var2 + this.playerViewDistance; ++var4)
187            {
188                for (int var5 = var3 - this.playerViewDistance; var5 <= var3 + this.playerViewDistance; ++var5)
189                {
190                    PlayerInstance var6 = this.getOrCreateChunkWatcher(var4, var5, false);
191    
192                    if (var6 != null)
193                    {
194                        var6.sendThisChunkToPlayer(par1EntityPlayerMP);
195                    }
196                }
197            }
198    
199            this.players.remove(par1EntityPlayerMP);
200        }
201    
202        private boolean func_72684_a(int par1, int par2, int par3, int par4, int par5)
203        {
204            int var6 = par1 - par3;
205            int var7 = par2 - par4;
206            return var6 >= -par5 && var6 <= par5 ? var7 >= -par5 && var7 <= par5 : false;
207        }
208    
209        /**
210         * update chunks around a player being moved by server logic (e.g. cart, boat)
211         */
212        public void updateMountedMovingPlayer(EntityPlayerMP par1EntityPlayerMP)
213        {
214            int var2 = (int)par1EntityPlayerMP.posX >> 4;
215            int var3 = (int)par1EntityPlayerMP.posZ >> 4;
216            double var4 = par1EntityPlayerMP.managedPosX - par1EntityPlayerMP.posX;
217            double var6 = par1EntityPlayerMP.managedPosZ - par1EntityPlayerMP.posZ;
218            double var8 = var4 * var4 + var6 * var6;
219    
220            if (var8 >= 64.0D)
221            {
222                int var10 = (int)par1EntityPlayerMP.managedPosX >> 4;
223                int var11 = (int)par1EntityPlayerMP.managedPosZ >> 4;
224                int var12 = this.playerViewDistance;
225                int var13 = var2 - var10;
226                int var14 = var3 - var11;
227    
228                if (var13 != 0 || var14 != 0)
229                {
230                    for (int var15 = var2 - var12; var15 <= var2 + var12; ++var15)
231                    {
232                        for (int var16 = var3 - var12; var16 <= var3 + var12; ++var16)
233                        {
234                            if (!this.func_72684_a(var15, var16, var10, var11, var12))
235                            {
236                                this.getOrCreateChunkWatcher(var15, var16, true).addPlayerToChunkWatchingList(par1EntityPlayerMP);
237                            }
238    
239                            if (!this.func_72684_a(var15 - var13, var16 - var14, var2, var3, var12))
240                            {
241                                PlayerInstance var17 = this.getOrCreateChunkWatcher(var15 - var13, var16 - var14, false);
242    
243                                if (var17 != null)
244                                {
245                                    var17.sendThisChunkToPlayer(par1EntityPlayerMP);
246                                }
247                            }
248                        }
249                    }
250    
251                    this.func_72691_b(par1EntityPlayerMP);
252                    par1EntityPlayerMP.managedPosX = par1EntityPlayerMP.posX;
253                    par1EntityPlayerMP.managedPosZ = par1EntityPlayerMP.posZ;
254                }
255            }
256        }
257    
258        public boolean isPlayerWatchingChunk(EntityPlayerMP par1EntityPlayerMP, int par2, int par3)
259        {
260            PlayerInstance var4 = this.getOrCreateChunkWatcher(par2, par3, false);
261            return var4 == null ? false : PlayerInstance.getPlayersInChunk(var4).contains(par1EntityPlayerMP) && !par1EntityPlayerMP.chunksToLoad.contains(PlayerInstance.getChunkLocation(var4));
262        }
263    
264        public static int func_72686_a(int par0)
265        {
266            return par0 * 16 - 16;
267        }
268    
269        static WorldServer getWorldServer(PlayerManager par0PlayerManager)
270        {
271            return par0PlayerManager.theWorldServer;
272        }
273    
274        static LongHashMap getChunkWatchers(PlayerManager par0PlayerManager)
275        {
276            return par0PlayerManager.allChunkWathers;
277        }
278    
279        static List getChunkWatchersWithPlayers(PlayerManager par0PlayerManager)
280        {
281            return par0PlayerManager.chunkWathcherWithPlayers;
282        }
283    }