001    package net.minecraft.src;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    
006    import net.minecraftforge.common.MinecraftForge;
007    import net.minecraftforge.event.world.ChunkWatchEvent;
008    
009    public class PlayerInstance
010    {
011        public final List playersInChunk;
012    
013        /** note: this is final */
014        private final ChunkCoordIntPair chunkLocation;
015        private short[] locationOfBlockChange;
016        private int numberOfTilesToUpdate;
017        private int field_73260_f;
018    
019        final PlayerManager myManager;
020    
021        public PlayerInstance(PlayerManager par1PlayerManager, int par2, int par3)
022        {
023            this.myManager = par1PlayerManager;
024            this.playersInChunk = new ArrayList();
025            this.locationOfBlockChange = new short[64];
026            this.numberOfTilesToUpdate = 0;
027            this.chunkLocation = new ChunkCoordIntPair(par2, par3);
028            par1PlayerManager.getWorldServer().theChunkProviderServer.loadChunk(par2, par3);
029        }
030    
031        /**
032         * called for all chunks within the visible radius of the player
033         */
034        public void addPlayerToChunkWatchingList(EntityPlayerMP par1EntityPlayerMP)
035        {
036            if (this.playersInChunk.contains(par1EntityPlayerMP))
037            {
038                throw new IllegalStateException("Failed to add player. " + par1EntityPlayerMP + " already is in chunk " + this.chunkLocation.chunkXPos + ", " + this.chunkLocation.chunkZPos);
039            }
040            else
041            {
042                this.playersInChunk.add(par1EntityPlayerMP);
043                par1EntityPlayerMP.loadedChunks.add(this.chunkLocation);
044            }
045        }
046    
047        public void sendThisChunkToPlayer(EntityPlayerMP par1EntityPlayerMP)
048        {
049            if (this.playersInChunk.contains(par1EntityPlayerMP))
050            {
051                par1EntityPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet51MapChunk(PlayerManager.getWorldServer(this.myManager).getChunkFromChunkCoords(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos), true, 0));
052                this.playersInChunk.remove(par1EntityPlayerMP);
053                par1EntityPlayerMP.loadedChunks.remove(this.chunkLocation);
054                
055                MinecraftForge.EVENT_BUS.post(new ChunkWatchEvent.UnWatch(chunkLocation, par1EntityPlayerMP));
056    
057                if (this.playersInChunk.isEmpty())
058                {
059                    long var2 = (long)this.chunkLocation.chunkXPos + 2147483647L | (long)this.chunkLocation.chunkZPos + 2147483647L << 32;
060                    PlayerManager.getChunkWatchers(this.myManager).remove(var2);
061    
062                    if (this.numberOfTilesToUpdate > 0)
063                    {
064                        PlayerManager.getChunkWatchersWithPlayers(this.myManager).remove(this);
065                    }
066    
067                    this.myManager.getWorldServer().theChunkProviderServer.unloadChunksIfNotNearSpawn(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos);
068                }
069            }
070        }
071    
072        public void flagChunkForUpdate(int par1, int par2, int par3)
073        {
074            if (this.numberOfTilesToUpdate == 0)
075            {
076                PlayerManager.getChunkWatchersWithPlayers(this.myManager).add(this);
077            }
078    
079            this.field_73260_f |= 1 << (par2 >> 4);
080    
081            if (this.numberOfTilesToUpdate < 64)
082            {
083                short var4 = (short)(par1 << 12 | par3 << 8 | par2);
084    
085                for (int var5 = 0; var5 < this.numberOfTilesToUpdate; ++var5)
086                {
087                    if (this.locationOfBlockChange[var5] == var4)
088                    {
089                        return;
090                    }
091                }
092    
093                this.locationOfBlockChange[this.numberOfTilesToUpdate++] = var4;
094            }
095        }
096    
097        public void sendToAllPlayersWatchingChunk(Packet par1Packet)
098        {
099            for (int var2 = 0; var2 < this.playersInChunk.size(); ++var2)
100            {
101                EntityPlayerMP var3 = (EntityPlayerMP)this.playersInChunk.get(var2);
102    
103                if (!var3.loadedChunks.contains(this.chunkLocation))
104                {
105                    var3.playerNetServerHandler.sendPacketToPlayer(par1Packet);
106                }
107            }
108        }
109    
110        public void sendChunkUpdate()
111        {
112            if (this.numberOfTilesToUpdate != 0)
113            {
114                int var1;
115                int var2;
116                int var3;
117    
118                if (this.numberOfTilesToUpdate == 1)
119                {
120                    var1 = this.chunkLocation.chunkXPos * 16 + (this.locationOfBlockChange[0] >> 12 & 15);
121                    var2 = this.locationOfBlockChange[0] & 255;
122                    var3 = this.chunkLocation.chunkZPos * 16 + (this.locationOfBlockChange[0] >> 8 & 15);
123                    this.sendToAllPlayersWatchingChunk(new Packet53BlockChange(var1, var2, var3, PlayerManager.getWorldServer(this.myManager)));
124    
125                    if (PlayerManager.getWorldServer(this.myManager).blockHasTileEntity(var1, var2, var3))
126                    {
127                        this.sendTileToAllPlayersWatchingChunk(PlayerManager.getWorldServer(this.myManager).getBlockTileEntity(var1, var2, var3));
128                    }
129                }
130                else
131                {
132                    int var4;
133    
134                    if (this.numberOfTilesToUpdate == 64)
135                    {
136                        var1 = this.chunkLocation.chunkXPos * 16;
137                        var2 = this.chunkLocation.chunkZPos * 16;
138                        this.sendToAllPlayersWatchingChunk(new Packet51MapChunk(PlayerManager.getWorldServer(this.myManager).getChunkFromChunkCoords(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos), false, this.field_73260_f));
139    
140                        for (var3 = 0; var3 < 16; ++var3)
141                        {
142                            if ((this.field_73260_f & 1 << var3) != 0)
143                            {
144                                var4 = var3 << 4;
145                                //BugFix: 16 makes it load an extra chunk, which isn't associated with a player, which makes it not unload unless a player walks near it.
146                                //ToDo: Find a way to efficiently clean abandoned chunks.
147                                //List var5 = PlayerManager.getWorldServer(this.myManager).getAllTileEntityInBox(var1, var4, var2, var1 + 16, var4 + 16, var2 + 16);
148                                List var5 = PlayerManager.getWorldServer(this.myManager).getAllTileEntityInBox(var1, var4, var2, var1 + 15, var4 + 16, var2 + 15);
149    
150                                for (int var6 = 0; var6 < var5.size(); ++var6)
151                                {
152                                    this.sendTileToAllPlayersWatchingChunk((TileEntity)var5.get(var6));
153                                }
154                            }
155                        }
156                    }
157                    else
158                    {
159                        this.sendToAllPlayersWatchingChunk(new Packet52MultiBlockChange(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos, this.locationOfBlockChange, this.numberOfTilesToUpdate, PlayerManager.getWorldServer(this.myManager)));
160    
161                        for (var1 = 0; var1 < this.numberOfTilesToUpdate; ++var1)
162                        {
163                            var2 = this.chunkLocation.chunkXPos * 16 + (this.locationOfBlockChange[var1] >> 12 & 15);
164                            var3 = this.locationOfBlockChange[var1] & 255;
165                            var4 = this.chunkLocation.chunkZPos * 16 + (this.locationOfBlockChange[var1] >> 8 & 15);
166    
167                            if (PlayerManager.getWorldServer(this.myManager).blockHasTileEntity(var2, var3, var4))
168                            {
169                                this.sendTileToAllPlayersWatchingChunk(PlayerManager.getWorldServer(this.myManager).getBlockTileEntity(var2, var3, var4));
170                            }
171                        }
172                    }
173                }
174    
175                this.numberOfTilesToUpdate = 0;
176                this.field_73260_f = 0;
177            }
178        }
179    
180        private void sendTileToAllPlayersWatchingChunk(TileEntity par1TileEntity)
181        {
182            if (par1TileEntity != null)
183            {
184                Packet var2 = par1TileEntity.getDescriptionPacket();
185    
186                if (var2 != null)
187                {
188                    this.sendToAllPlayersWatchingChunk(var2);
189                }
190            }
191        }
192    
193        static ChunkCoordIntPair getChunkLocation(PlayerInstance par0PlayerInstance)
194        {
195            return par0PlayerInstance.chunkLocation;
196        }
197    
198        static List getPlayersInChunk(PlayerInstance par0PlayerInstance)
199        {
200            return par0PlayerInstance.playersInChunk;
201        }
202    }