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