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