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 }