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