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}