You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			641 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Java
		
	
			
		
		
	
	
			641 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Java
		
	
package net.minecraft.server.management;
 | 
						|
 | 
						|
import java.util.ArrayList;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.List;
 | 
						|
import net.minecraft.entity.player.EntityPlayerMP;
 | 
						|
import net.minecraft.network.Packet;
 | 
						|
import net.minecraft.network.play.server.S21PacketChunkData;
 | 
						|
import net.minecraft.network.play.server.S22PacketMultiBlockChange;
 | 
						|
import net.minecraft.network.play.server.S23PacketBlockChange;
 | 
						|
import net.minecraft.tileentity.TileEntity;
 | 
						|
import net.minecraft.util.LongHashMap;
 | 
						|
import net.minecraft.util.MathHelper;
 | 
						|
import net.minecraft.world.ChunkCoordIntPair;
 | 
						|
import net.minecraft.world.WorldProvider;
 | 
						|
import net.minecraft.world.WorldServer;
 | 
						|
import net.minecraft.world.chunk.Chunk;
 | 
						|
import org.apache.logging.log4j.LogManager;
 | 
						|
import org.apache.logging.log4j.Logger;
 | 
						|
 | 
						|
public class PlayerManager
 | 
						|
{
 | 
						|
    private static final Logger field_152627_a = LogManager.getLogger();
 | 
						|
    private final WorldServer theWorldServer;
 | 
						|
    /** players in the current instance */
 | 
						|
    private final List players = new ArrayList();
 | 
						|
    /** A map of chunk position (two ints concatenated into a long) to PlayerInstance */
 | 
						|
    private final LongHashMap playerInstances = new LongHashMap();
 | 
						|
    /**
 | 
						|
     * contains a PlayerInstance for every chunk they can see. the "player instance" cotains a list of all players who
 | 
						|
     * can also that chunk
 | 
						|
     */
 | 
						|
    private final List chunkWatcherWithPlayers = new ArrayList();
 | 
						|
    /** This field is using when chunk should be processed (every 8000 ticks) */
 | 
						|
    private final List playerInstanceList = new ArrayList();
 | 
						|
    /** Number of chunks the server sends to the client. Valid 3<=x<=15. In server.properties. */
 | 
						|
    private int playerViewRadius;
 | 
						|
    /** time what is using to check if InhabitedTime should be calculated */
 | 
						|
    private long previousTotalWorldTime;
 | 
						|
    /** x, z direction vectors: east, south, west, north */
 | 
						|
    private final int[][] xzDirectionsConst = new int[][] {{1, 0}, {0, 1}, { -1, 0}, {0, -1}};
 | 
						|
    private static final String __OBFID = "CL_00001434";
 | 
						|
 | 
						|
    public PlayerManager(WorldServer p_i1176_1_)
 | 
						|
    {
 | 
						|
        this.theWorldServer = p_i1176_1_;
 | 
						|
        this.func_152622_a(p_i1176_1_.func_73046_m().getConfigurationManager().getViewDistance());
 | 
						|
    }
 | 
						|
 | 
						|
    public WorldServer getWorldServer()
 | 
						|
    {
 | 
						|
        return this.theWorldServer;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * updates all the player instances that need to be updated
 | 
						|
     */
 | 
						|
    public void updatePlayerInstances()
 | 
						|
    {
 | 
						|
        long i = this.theWorldServer.getTotalWorldTime();
 | 
						|
        int j;
 | 
						|
        PlayerManager.PlayerInstance playerinstance;
 | 
						|
 | 
						|
        if (i - this.previousTotalWorldTime > 8000L)
 | 
						|
        {
 | 
						|
            this.previousTotalWorldTime = i;
 | 
						|
 | 
						|
            for (j = 0; j < this.playerInstanceList.size(); ++j)
 | 
						|
            {
 | 
						|
                playerinstance = (PlayerManager.PlayerInstance)this.playerInstanceList.get(j);
 | 
						|
                playerinstance.sendChunkUpdate();
 | 
						|
                playerinstance.processChunk();
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            for (j = 0; j < this.chunkWatcherWithPlayers.size(); ++j)
 | 
						|
            {
 | 
						|
                playerinstance = (PlayerManager.PlayerInstance)this.chunkWatcherWithPlayers.get(j);
 | 
						|
                playerinstance.sendChunkUpdate();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        this.chunkWatcherWithPlayers.clear();
 | 
						|
 | 
						|
        if (this.players.isEmpty())
 | 
						|
        {
 | 
						|
            WorldProvider worldprovider = this.theWorldServer.provider;
 | 
						|
 | 
						|
            if (!worldprovider.canRespawnHere())
 | 
						|
            {
 | 
						|
                this.theWorldServer.theChunkProviderServer.unloadAllChunks();
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public boolean func_152621_a(int p_152621_1_, int p_152621_2_)
 | 
						|
    {
 | 
						|
        long k = (long)p_152621_1_ + 2147483647L | (long)p_152621_2_ + 2147483647L << 32;
 | 
						|
        return this.playerInstances.getValueByKey(k) != null;
 | 
						|
    }
 | 
						|
 | 
						|
    private PlayerManager.PlayerInstance getOrCreateChunkWatcher(int p_72690_1_, int p_72690_2_, boolean p_72690_3_)
 | 
						|
    {
 | 
						|
        long k = (long)p_72690_1_ + 2147483647L | (long)p_72690_2_ + 2147483647L << 32;
 | 
						|
        PlayerManager.PlayerInstance playerinstance = (PlayerManager.PlayerInstance)this.playerInstances.getValueByKey(k);
 | 
						|
 | 
						|
        if (playerinstance == null && p_72690_3_)
 | 
						|
        {
 | 
						|
            playerinstance = new PlayerManager.PlayerInstance(p_72690_1_, p_72690_2_);
 | 
						|
            this.playerInstances.add(k, playerinstance);
 | 
						|
            this.playerInstanceList.add(playerinstance);
 | 
						|
        }
 | 
						|
 | 
						|
        return playerinstance;
 | 
						|
    }
 | 
						|
 | 
						|
    public void markBlockForUpdate(int p_151250_1_, int p_151250_2_, int p_151250_3_)
 | 
						|
    {
 | 
						|
        int l = p_151250_1_ >> 4;
 | 
						|
        int i1 = p_151250_3_ >> 4;
 | 
						|
        PlayerManager.PlayerInstance playerinstance = this.getOrCreateChunkWatcher(l, i1, false);
 | 
						|
 | 
						|
        if (playerinstance != null)
 | 
						|
        {
 | 
						|
            playerinstance.flagChunkForUpdate(p_151250_1_ & 15, p_151250_2_, p_151250_3_ & 15);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds an EntityPlayerMP to the PlayerManager.
 | 
						|
     */
 | 
						|
    public void addPlayer(EntityPlayerMP p_72683_1_)
 | 
						|
    {
 | 
						|
        int i = (int)p_72683_1_.posX >> 4;
 | 
						|
        int j = (int)p_72683_1_.posZ >> 4;
 | 
						|
        p_72683_1_.managedPosX = p_72683_1_.posX;
 | 
						|
        p_72683_1_.managedPosZ = p_72683_1_.posZ;
 | 
						|
        // Load nearby chunks first
 | 
						|
        List<ChunkCoordIntPair> chunkList = new ArrayList<ChunkCoordIntPair>();
 | 
						|
 | 
						|
        for (int k = i - this.playerViewRadius; k <= i + this.playerViewRadius; ++k)
 | 
						|
        {
 | 
						|
            for (int l = j - this.playerViewRadius; l <= j + this.playerViewRadius; ++l)
 | 
						|
            {
 | 
						|
                chunkList.add(new ChunkCoordIntPair(k, l));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        java.util.Collections.sort(chunkList, new net.minecraftforge.common.util.ChunkCoordComparator(p_72683_1_));
 | 
						|
 | 
						|
        for (ChunkCoordIntPair pair : chunkList)
 | 
						|
        {
 | 
						|
            this.getOrCreateChunkWatcher(pair.chunkXPos, pair.chunkZPos, true).addPlayer(p_72683_1_);
 | 
						|
        }
 | 
						|
 | 
						|
        this.players.add(p_72683_1_);
 | 
						|
        this.filterChunkLoadQueue(p_72683_1_);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Removes all chunks from the given player's chunk load queue that are not in viewing range of the player.
 | 
						|
     */
 | 
						|
    public void filterChunkLoadQueue(EntityPlayerMP p_72691_1_)
 | 
						|
    {
 | 
						|
        ArrayList arraylist = new ArrayList(p_72691_1_.loadedChunks);
 | 
						|
        int i = 0;
 | 
						|
        int j = this.playerViewRadius;
 | 
						|
        int k = (int)p_72691_1_.posX >> 4;
 | 
						|
        int l = (int)p_72691_1_.posZ >> 4;
 | 
						|
        int i1 = 0;
 | 
						|
        int j1 = 0;
 | 
						|
        ChunkCoordIntPair chunkcoordintpair = this.getOrCreateChunkWatcher(k, l, true).chunkLocation;
 | 
						|
        p_72691_1_.loadedChunks.clear();
 | 
						|
 | 
						|
        if (arraylist.contains(chunkcoordintpair))
 | 
						|
        {
 | 
						|
            p_72691_1_.loadedChunks.add(chunkcoordintpair);
 | 
						|
        }
 | 
						|
 | 
						|
        int k1;
 | 
						|
 | 
						|
        for (k1 = 1; k1 <= j * 2; ++k1)
 | 
						|
        {
 | 
						|
            for (int l1 = 0; l1 < 2; ++l1)
 | 
						|
            {
 | 
						|
                int[] aint = this.xzDirectionsConst[i++ % 4];
 | 
						|
 | 
						|
                for (int i2 = 0; i2 < k1; ++i2)
 | 
						|
                {
 | 
						|
                    i1 += aint[0];
 | 
						|
                    j1 += aint[1];
 | 
						|
                    chunkcoordintpair = this.getOrCreateChunkWatcher(k + i1, l + j1, true).chunkLocation;
 | 
						|
 | 
						|
                    if (arraylist.contains(chunkcoordintpair))
 | 
						|
                    {
 | 
						|
                        p_72691_1_.loadedChunks.add(chunkcoordintpair);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        i %= 4;
 | 
						|
 | 
						|
        for (k1 = 0; k1 < j * 2; ++k1)
 | 
						|
        {
 | 
						|
            i1 += this.xzDirectionsConst[i][0];
 | 
						|
            j1 += this.xzDirectionsConst[i][1];
 | 
						|
            chunkcoordintpair = this.getOrCreateChunkWatcher(k + i1, l + j1, true).chunkLocation;
 | 
						|
 | 
						|
            if (arraylist.contains(chunkcoordintpair))
 | 
						|
            {
 | 
						|
                p_72691_1_.loadedChunks.add(chunkcoordintpair);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Removes an EntityPlayerMP from the PlayerManager.
 | 
						|
     */
 | 
						|
    public void removePlayer(EntityPlayerMP p_72695_1_)
 | 
						|
    {
 | 
						|
        int i = (int)p_72695_1_.managedPosX >> 4;
 | 
						|
        int j = (int)p_72695_1_.managedPosZ >> 4;
 | 
						|
 | 
						|
        for (int k = i - this.playerViewRadius; k <= i + this.playerViewRadius; ++k)
 | 
						|
        {
 | 
						|
            for (int l = j - this.playerViewRadius; l <= j + this.playerViewRadius; ++l)
 | 
						|
            {
 | 
						|
                PlayerManager.PlayerInstance playerinstance = this.getOrCreateChunkWatcher(k, l, false);
 | 
						|
 | 
						|
                if (playerinstance != null)
 | 
						|
                {
 | 
						|
                    playerinstance.removePlayer(p_72695_1_);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        this.players.remove(p_72695_1_);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Determine if two rectangles centered at the given points overlap for the provided radius. Arguments: x1, z1, x2,
 | 
						|
     * z2, radius.
 | 
						|
     */
 | 
						|
    private boolean overlaps(int p_72684_1_, int p_72684_2_, int p_72684_3_, int p_72684_4_, int p_72684_5_)
 | 
						|
    {
 | 
						|
        int j1 = p_72684_1_ - p_72684_3_;
 | 
						|
        int k1 = p_72684_2_ - p_72684_4_;
 | 
						|
        return j1 >= -p_72684_5_ && j1 <= p_72684_5_ ? k1 >= -p_72684_5_ && k1 <= p_72684_5_ : false;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Update which chunks the player needs info on.
 | 
						|
     */
 | 
						|
    public void updatePlayerPertinentChunks(EntityPlayerMP p_72685_1_)
 | 
						|
    {
 | 
						|
        int i = (int)p_72685_1_.posX >> 4;
 | 
						|
        int j = (int)p_72685_1_.posZ >> 4;
 | 
						|
        double d0 = p_72685_1_.managedPosX - p_72685_1_.posX;
 | 
						|
        double d1 = p_72685_1_.managedPosZ - p_72685_1_.posZ;
 | 
						|
        double d2 = d0 * d0 + d1 * d1;
 | 
						|
 | 
						|
        if (d2 >= 64.0D)
 | 
						|
        {
 | 
						|
            int k = (int)p_72685_1_.managedPosX >> 4;
 | 
						|
            int l = (int)p_72685_1_.managedPosZ >> 4;
 | 
						|
            int i1 = this.playerViewRadius;
 | 
						|
            int j1 = i - k;
 | 
						|
            int k1 = j - l;
 | 
						|
            List<ChunkCoordIntPair> chunksToLoad = new ArrayList<ChunkCoordIntPair>();
 | 
						|
 | 
						|
            if (j1 != 0 || k1 != 0)
 | 
						|
            {
 | 
						|
                for (int l1 = i - i1; l1 <= i + i1; ++l1)
 | 
						|
                {
 | 
						|
                    for (int i2 = j - i1; i2 <= j + i1; ++i2)
 | 
						|
                    {
 | 
						|
                        if (!this.overlaps(l1, i2, k, l, i1))
 | 
						|
                        {
 | 
						|
                            chunksToLoad.add(new ChunkCoordIntPair(l1, i2));
 | 
						|
                        }
 | 
						|
 | 
						|
                        if (!this.overlaps(l1 - j1, i2 - k1, i, j, i1))
 | 
						|
                        {
 | 
						|
                            PlayerManager.PlayerInstance playerinstance = this.getOrCreateChunkWatcher(l1 - j1, i2 - k1, false);
 | 
						|
 | 
						|
                            if (playerinstance != null)
 | 
						|
                            {
 | 
						|
                                playerinstance.removePlayer(p_72685_1_);
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                this.filterChunkLoadQueue(p_72685_1_);
 | 
						|
                p_72685_1_.managedPosX = p_72685_1_.posX;
 | 
						|
                p_72685_1_.managedPosZ = p_72685_1_.posZ;
 | 
						|
                // send nearest chunks first
 | 
						|
                java.util.Collections.sort(chunksToLoad, new net.minecraftforge.common.util.ChunkCoordComparator(p_72685_1_));
 | 
						|
 | 
						|
                for (ChunkCoordIntPair pair : chunksToLoad)
 | 
						|
                {
 | 
						|
                    this.getOrCreateChunkWatcher(pair.chunkXPos, pair.chunkZPos, true).addPlayer(p_72685_1_);
 | 
						|
                }
 | 
						|
 | 
						|
                if (i1 > 1 || i1 < -1 || j1 > 1 || j1 < -1)
 | 
						|
                {
 | 
						|
                    java.util.Collections.sort(p_72685_1_.loadedChunks, new net.minecraftforge.common.util.ChunkCoordComparator(p_72685_1_));
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public boolean isPlayerWatchingChunk(EntityPlayerMP p_72694_1_, int p_72694_2_, int p_72694_3_)
 | 
						|
    {
 | 
						|
        PlayerManager.PlayerInstance playerinstance = this.getOrCreateChunkWatcher(p_72694_2_, p_72694_3_, false);
 | 
						|
        return playerinstance != null && playerinstance.playersWatchingChunk.contains(p_72694_1_) && !p_72694_1_.loadedChunks.contains(playerinstance.chunkLocation);
 | 
						|
    }
 | 
						|
 | 
						|
    public void func_152622_a(int p_152622_1_)
 | 
						|
    {
 | 
						|
        p_152622_1_ = MathHelper.clamp_int(p_152622_1_, 3, 20);
 | 
						|
 | 
						|
        if (p_152622_1_ != this.playerViewRadius)
 | 
						|
        {
 | 
						|
            int j = p_152622_1_ - this.playerViewRadius;
 | 
						|
            Iterator iterator = this.players.iterator();
 | 
						|
 | 
						|
            while (iterator.hasNext())
 | 
						|
            {
 | 
						|
                EntityPlayerMP entityplayermp = (EntityPlayerMP)iterator.next();
 | 
						|
                int k = (int)entityplayermp.posX >> 4;
 | 
						|
                int l = (int)entityplayermp.posZ >> 4;
 | 
						|
                int i1;
 | 
						|
                int j1;
 | 
						|
 | 
						|
                if (j > 0)
 | 
						|
                {
 | 
						|
                    for (i1 = k - p_152622_1_; i1 <= k + p_152622_1_; ++i1)
 | 
						|
                    {
 | 
						|
                        for (j1 = l - p_152622_1_; j1 <= l + p_152622_1_; ++j1)
 | 
						|
                        {
 | 
						|
                            PlayerManager.PlayerInstance playerinstance = this.getOrCreateChunkWatcher(i1, j1, true);
 | 
						|
 | 
						|
                            if (!playerinstance.playersWatchingChunk.contains(entityplayermp))
 | 
						|
                            {
 | 
						|
                                playerinstance.addPlayer(entityplayermp);
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    for (i1 = k - this.playerViewRadius; i1 <= k + this.playerViewRadius; ++i1)
 | 
						|
                    {
 | 
						|
                        for (j1 = l - this.playerViewRadius; j1 <= l + this.playerViewRadius; ++j1)
 | 
						|
                        {
 | 
						|
                            if (!this.overlaps(i1, j1, k, l, p_152622_1_))
 | 
						|
                            {
 | 
						|
                                this.getOrCreateChunkWatcher(i1, j1, true).removePlayer(entityplayermp);
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            this.playerViewRadius = p_152622_1_;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the furthest viewable block given player's view distance
 | 
						|
     */
 | 
						|
    public static int getFurthestViewableBlock(int p_72686_0_)
 | 
						|
    {
 | 
						|
        return p_72686_0_ * 16 - 16;
 | 
						|
    }
 | 
						|
 | 
						|
    class PlayerInstance
 | 
						|
    {
 | 
						|
        private final List playersWatchingChunk = new ArrayList();
 | 
						|
        /** note: this is final */
 | 
						|
        private final ChunkCoordIntPair chunkLocation;
 | 
						|
        private short[] locationOfBlockChange = new short[64];
 | 
						|
        private int numberOfTilesToUpdate;
 | 
						|
        /** Integer field where each bit means to make update 16x16x16 division of chunk (from bottom). */
 | 
						|
        private int flagsYAreasToUpdate;
 | 
						|
        /** time what is using when chunk InhabitedTime is being calculated */
 | 
						|
        private long previousWorldTime;
 | 
						|
        private final java.util.HashMap<EntityPlayerMP, Runnable> players = new java.util.HashMap<EntityPlayerMP, Runnable>();
 | 
						|
        private boolean loaded = false;
 | 
						|
        private Runnable loadedRunnable = new Runnable()
 | 
						|
        {
 | 
						|
            public void run()
 | 
						|
            {
 | 
						|
                PlayerInstance.this.loaded = true;
 | 
						|
            }
 | 
						|
        };
 | 
						|
        private static final String __OBFID = "CL_00001435";
 | 
						|
 | 
						|
        public PlayerInstance(int p_i1518_2_, int p_i1518_3_)
 | 
						|
        {
 | 
						|
            this.chunkLocation = new ChunkCoordIntPair(p_i1518_2_, p_i1518_3_);
 | 
						|
            PlayerManager.this.theWorldServer.theChunkProviderServer.loadChunk(p_i1518_2_, p_i1518_3_, this.loadedRunnable);
 | 
						|
        }
 | 
						|
 | 
						|
        public void addPlayer(final EntityPlayerMP p_73255_1_)
 | 
						|
        {
 | 
						|
            if (this.playersWatchingChunk.contains(p_73255_1_))
 | 
						|
            {
 | 
						|
                PlayerManager.field_152627_a.debug("Failed to add player. {} already is in chunk {}, {}", new Object[] {p_73255_1_, Integer.valueOf(this.chunkLocation.chunkXPos), Integer.valueOf(this.chunkLocation.chunkZPos)});
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                if (this.playersWatchingChunk.isEmpty())
 | 
						|
                {
 | 
						|
                    this.previousWorldTime = PlayerManager.this.theWorldServer.getTotalWorldTime();
 | 
						|
                }
 | 
						|
 | 
						|
                this.playersWatchingChunk.add(p_73255_1_);
 | 
						|
                Runnable playerRunnable;
 | 
						|
 | 
						|
                if (this.loaded)
 | 
						|
                {
 | 
						|
                    playerRunnable = null;
 | 
						|
                    p_73255_1_.loadedChunks.add(this.chunkLocation);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    playerRunnable = new Runnable()
 | 
						|
                    {
 | 
						|
                        public void run()
 | 
						|
                        {
 | 
						|
                            p_73255_1_.loadedChunks.add(PlayerInstance.this.chunkLocation);
 | 
						|
                        }
 | 
						|
                    };
 | 
						|
                    PlayerManager.this.getWorldServer().theChunkProviderServer.loadChunk(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos, playerRunnable);
 | 
						|
                }
 | 
						|
 | 
						|
                this.players.put(p_73255_1_, playerRunnable);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public void removePlayer(EntityPlayerMP p_73252_1_)
 | 
						|
        {
 | 
						|
            if (this.playersWatchingChunk.contains(p_73252_1_))
 | 
						|
            {
 | 
						|
                // If we haven't loaded yet don't load the chunk just so we can clean it up
 | 
						|
                if (!this.loaded)
 | 
						|
                {
 | 
						|
                    net.minecraftforge.common.chunkio.ChunkIOExecutor.dropQueuedChunkLoad(PlayerManager.this.getWorldServer(), this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos, this.players.get(p_73252_1_));
 | 
						|
                    this.playersWatchingChunk.remove(p_73252_1_);
 | 
						|
                    this.players.remove(p_73252_1_);
 | 
						|
 | 
						|
                    if (this.playersWatchingChunk.isEmpty())
 | 
						|
                    {
 | 
						|
                        net.minecraftforge.common.chunkio.ChunkIOExecutor.dropQueuedChunkLoad(PlayerManager.this.getWorldServer(), this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos, this.loadedRunnable);
 | 
						|
                        long i = (long) this.chunkLocation.chunkXPos + 2147483647L | (long) this.chunkLocation.chunkZPos + 2147483647L << 32;
 | 
						|
                        PlayerManager.this.playerInstances.remove(i);
 | 
						|
                        PlayerManager.this.playerInstanceList.remove(this);
 | 
						|
                    }
 | 
						|
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
 | 
						|
                Chunk chunk = PlayerManager.this.theWorldServer.getChunkFromChunkCoords(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos);
 | 
						|
 | 
						|
                if (chunk.func_150802_k())
 | 
						|
                {
 | 
						|
                    p_73252_1_.playerNetServerHandler.sendPacket(new S21PacketChunkData(chunk, true, 0));
 | 
						|
                }
 | 
						|
 | 
						|
                this.players.remove(p_73252_1_);
 | 
						|
                this.playersWatchingChunk.remove(p_73252_1_);
 | 
						|
                p_73252_1_.loadedChunks.remove(this.chunkLocation);
 | 
						|
 | 
						|
                net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.ChunkWatchEvent.UnWatch(chunkLocation, p_73252_1_));
 | 
						|
 | 
						|
                if (this.playersWatchingChunk.isEmpty())
 | 
						|
                {
 | 
						|
                    long i = (long)this.chunkLocation.chunkXPos + 2147483647L | (long)this.chunkLocation.chunkZPos + 2147483647L << 32;
 | 
						|
                    this.increaseInhabitedTime(chunk);
 | 
						|
                    PlayerManager.this.playerInstances.remove(i);
 | 
						|
                    PlayerManager.this.playerInstanceList.remove(this);
 | 
						|
 | 
						|
                    if (this.numberOfTilesToUpdate > 0)
 | 
						|
                    {
 | 
						|
                        PlayerManager.this.chunkWatcherWithPlayers.remove(this);
 | 
						|
                    }
 | 
						|
 | 
						|
                    PlayerManager.this.getWorldServer().theChunkProviderServer.unloadChunksIfNotNearSpawn(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * This method currently only increases chunk inhabited time. Extension is possible in next versions
 | 
						|
         */
 | 
						|
        public void processChunk()
 | 
						|
        {
 | 
						|
            this.increaseInhabitedTime(PlayerManager.this.theWorldServer.getChunkFromChunkCoords(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos));
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Increases chunk inhabited time every 8000 ticks
 | 
						|
         */
 | 
						|
        private void increaseInhabitedTime(Chunk p_111196_1_)
 | 
						|
        {
 | 
						|
            p_111196_1_.inhabitedTime += PlayerManager.this.theWorldServer.getTotalWorldTime() - this.previousWorldTime;
 | 
						|
            this.previousWorldTime = PlayerManager.this.theWorldServer.getTotalWorldTime();
 | 
						|
        }
 | 
						|
 | 
						|
        public void flagChunkForUpdate(int p_151253_1_, int p_151253_2_, int p_151253_3_)
 | 
						|
        {
 | 
						|
            if (this.numberOfTilesToUpdate == 0)
 | 
						|
            {
 | 
						|
                PlayerManager.this.chunkWatcherWithPlayers.add(this);
 | 
						|
            }
 | 
						|
 | 
						|
            this.flagsYAreasToUpdate |= 1 << (p_151253_2_ >> 4);
 | 
						|
 | 
						|
            //if (this.numberOfTilesToUpdate < 64) //Forge; Cache everything, so always run
 | 
						|
            {
 | 
						|
                short short1 = (short)(p_151253_1_ << 12 | p_151253_3_ << 8 | p_151253_2_);
 | 
						|
 | 
						|
                for (int l = 0; l < this.numberOfTilesToUpdate; ++l)
 | 
						|
                {
 | 
						|
                    if (this.locationOfBlockChange[l] == short1)
 | 
						|
                    {
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if (numberOfTilesToUpdate == locationOfBlockChange.length)
 | 
						|
                {
 | 
						|
                    locationOfBlockChange = java.util.Arrays.copyOf(locationOfBlockChange, locationOfBlockChange.length << 1);
 | 
						|
                }
 | 
						|
                this.locationOfBlockChange[this.numberOfTilesToUpdate++] = short1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public void sendToAllPlayersWatchingChunk(Packet p_151251_1_)
 | 
						|
        {
 | 
						|
            for (int i = 0; i < this.playersWatchingChunk.size(); ++i)
 | 
						|
            {
 | 
						|
                EntityPlayerMP entityplayermp = (EntityPlayerMP)this.playersWatchingChunk.get(i);
 | 
						|
 | 
						|
                if (!entityplayermp.loadedChunks.contains(this.chunkLocation))
 | 
						|
                {
 | 
						|
                    entityplayermp.playerNetServerHandler.sendPacket(p_151251_1_);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        @SuppressWarnings("unused")
 | 
						|
        public void sendChunkUpdate()
 | 
						|
        {
 | 
						|
            if (this.numberOfTilesToUpdate != 0)
 | 
						|
            {
 | 
						|
                int i;
 | 
						|
                int j;
 | 
						|
                int k;
 | 
						|
 | 
						|
                if (this.numberOfTilesToUpdate == 1)
 | 
						|
                {
 | 
						|
                    i = this.chunkLocation.chunkXPos * 16 + (this.locationOfBlockChange[0] >> 12 & 15);
 | 
						|
                    j = this.locationOfBlockChange[0] & 255;
 | 
						|
                    k = this.chunkLocation.chunkZPos * 16 + (this.locationOfBlockChange[0] >> 8 & 15);
 | 
						|
                    this.sendToAllPlayersWatchingChunk(new S23PacketBlockChange(i, j, k, PlayerManager.this.theWorldServer));
 | 
						|
 | 
						|
                    if (PlayerManager.this.theWorldServer.getBlock(i, j, k).hasTileEntity(PlayerManager.this.theWorldServer.getBlockMetadata(i, j, k)))
 | 
						|
                    {
 | 
						|
                        this.sendTileToAllPlayersWatchingChunk(PlayerManager.this.theWorldServer.getTileEntity(i, j, k));
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    int l;
 | 
						|
 | 
						|
                    if (this.numberOfTilesToUpdate >= net.minecraftforge.common.ForgeModContainer.clumpingThreshold)
 | 
						|
                    {
 | 
						|
                        i = this.chunkLocation.chunkXPos * 16;
 | 
						|
                        j = this.chunkLocation.chunkZPos * 16;
 | 
						|
                        this.sendToAllPlayersWatchingChunk(new S21PacketChunkData(PlayerManager.this.theWorldServer.getChunkFromChunkCoords(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos), false, this.flagsYAreasToUpdate));
 | 
						|
 | 
						|
                        // Forge: Grabs ALL tile entities is costly on a modded server, only send needed ones
 | 
						|
                        for (k = 0; false && k < 16; ++k)
 | 
						|
                        {
 | 
						|
                            if ((this.flagsYAreasToUpdate & 1 << k) != 0)
 | 
						|
                            {
 | 
						|
                                l = k << 4;
 | 
						|
                                List list = PlayerManager.this.theWorldServer.func_147486_a(i, l, j, i + 16, l + 16, j + 16);
 | 
						|
 | 
						|
                                for (int i1 = 0; i1 < list.size(); ++i1)
 | 
						|
                                {
 | 
						|
                                    this.sendTileToAllPlayersWatchingChunk((TileEntity)list.get(i1));
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        this.sendToAllPlayersWatchingChunk(new S22PacketMultiBlockChange(this.numberOfTilesToUpdate, this.locationOfBlockChange, PlayerManager.this.theWorldServer.getChunkFromChunkCoords(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos)));
 | 
						|
                    }
 | 
						|
 | 
						|
                    { //Forge: Send only the tile entities that are updated, Adding this brace lets us keep the indent and the patch small
 | 
						|
                        WorldServer world = PlayerManager.this.theWorldServer;
 | 
						|
                        for (i = 0; i < this.numberOfTilesToUpdate; ++i)
 | 
						|
                        {
 | 
						|
                            j = this.chunkLocation.chunkXPos * 16 + (this.locationOfBlockChange[i] >> 12 & 15);
 | 
						|
                            k = this.locationOfBlockChange[i] & 255;
 | 
						|
                            l = this.chunkLocation.chunkZPos * 16 + (this.locationOfBlockChange[i] >> 8 & 15);
 | 
						|
 | 
						|
                            if (world.getBlock(j, k, l).hasTileEntity(world.getBlockMetadata(j, k, l)))
 | 
						|
                            {
 | 
						|
                                this.sendTileToAllPlayersWatchingChunk(PlayerManager.this.theWorldServer.getTileEntity(j, k, l));
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                this.numberOfTilesToUpdate = 0;
 | 
						|
                this.flagsYAreasToUpdate = 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private void sendTileToAllPlayersWatchingChunk(TileEntity p_151252_1_)
 | 
						|
        {
 | 
						|
            if (p_151252_1_ != null)
 | 
						|
            {
 | 
						|
                Packet packet = p_151252_1_.getDescriptionPacket();
 | 
						|
 | 
						|
                if (packet != null)
 | 
						|
                {
 | 
						|
                    this.sendToAllPlayersWatchingChunk(packet);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
} |