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