package net.minecraft.server.management; import java.util.ArrayList; import java.util.List; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.Packet51MapChunk; import net.minecraft.network.packet.Packet52MultiBlockChange; import net.minecraft.network.packet.Packet53BlockChange; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.ChunkCoordIntPair; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.world.ChunkWatchEvent; public class PlayerInstance { public final List playersInChunk; /** note: this is final */ private final ChunkCoordIntPair chunkLocation; private short[] locationOfBlockChange; private int numberOfTilesToUpdate; private int field_73260_f; final PlayerManager myManager; public PlayerInstance(PlayerManager par1PlayerManager, int par2, int par3) { this.myManager = par1PlayerManager; this.playersInChunk = new ArrayList(); this.locationOfBlockChange = new short[64]; this.numberOfTilesToUpdate = 0; this.chunkLocation = new ChunkCoordIntPair(par2, par3); par1PlayerManager.getWorldServer().theChunkProviderServer.loadChunk(par2, par3); } /** * called for all chunks within the visible radius of the player */ public void addPlayerToChunkWatchingList(EntityPlayerMP par1EntityPlayerMP) { if (this.playersInChunk.contains(par1EntityPlayerMP)) { throw new IllegalStateException("Failed to add player. " + par1EntityPlayerMP + " already is in chunk " + this.chunkLocation.chunkXPos + ", " + this.chunkLocation.chunkZPos); } else { this.playersInChunk.add(par1EntityPlayerMP); par1EntityPlayerMP.loadedChunks.add(this.chunkLocation); } } public void sendThisChunkToPlayer(EntityPlayerMP par1EntityPlayerMP) { if (this.playersInChunk.contains(par1EntityPlayerMP)) { par1EntityPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet51MapChunk(PlayerManager.getWorldServer(this.myManager).getChunkFromChunkCoords(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos), true, 0)); this.playersInChunk.remove(par1EntityPlayerMP); par1EntityPlayerMP.loadedChunks.remove(this.chunkLocation); MinecraftForge.EVENT_BUS.post(new ChunkWatchEvent.UnWatch(chunkLocation, par1EntityPlayerMP)); if (this.playersInChunk.isEmpty()) { long var2 = (long)this.chunkLocation.chunkXPos + 2147483647L | (long)this.chunkLocation.chunkZPos + 2147483647L << 32; PlayerManager.getChunkWatchers(this.myManager).remove(var2); if (this.numberOfTilesToUpdate > 0) { PlayerManager.getChunkWatchersWithPlayers(this.myManager).remove(this); } this.myManager.getWorldServer().theChunkProviderServer.unloadChunksIfNotNearSpawn(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos); } } } public void flagChunkForUpdate(int par1, int par2, int par3) { if (this.numberOfTilesToUpdate == 0) { PlayerManager.getChunkWatchersWithPlayers(this.myManager).add(this); } this.field_73260_f |= 1 << (par2 >> 4); if (this.numberOfTilesToUpdate < 64) { short var4 = (short)(par1 << 12 | par3 << 8 | par2); for (int var5 = 0; var5 < this.numberOfTilesToUpdate; ++var5) { if (this.locationOfBlockChange[var5] == var4) { return; } } this.locationOfBlockChange[this.numberOfTilesToUpdate++] = var4; } } public void sendToAllPlayersWatchingChunk(Packet par1Packet) { for (int var2 = 0; var2 < this.playersInChunk.size(); ++var2) { EntityPlayerMP var3 = (EntityPlayerMP)this.playersInChunk.get(var2); if (!var3.loadedChunks.contains(this.chunkLocation)) { var3.playerNetServerHandler.sendPacketToPlayer(par1Packet); } } } public void sendChunkUpdate() { if (this.numberOfTilesToUpdate != 0) { int var1; int var2; int var3; if (this.numberOfTilesToUpdate == 1) { var1 = this.chunkLocation.chunkXPos * 16 + (this.locationOfBlockChange[0] >> 12 & 15); var2 = this.locationOfBlockChange[0] & 255; var3 = this.chunkLocation.chunkZPos * 16 + (this.locationOfBlockChange[0] >> 8 & 15); this.sendToAllPlayersWatchingChunk(new Packet53BlockChange(var1, var2, var3, PlayerManager.getWorldServer(this.myManager))); if (PlayerManager.getWorldServer(this.myManager).blockHasTileEntity(var1, var2, var3)) { this.sendTileToAllPlayersWatchingChunk(PlayerManager.getWorldServer(this.myManager).getBlockTileEntity(var1, var2, var3)); } } else { int var4; if (this.numberOfTilesToUpdate == 64) { var1 = this.chunkLocation.chunkXPos * 16; var2 = this.chunkLocation.chunkZPos * 16; this.sendToAllPlayersWatchingChunk(new Packet51MapChunk(PlayerManager.getWorldServer(this.myManager).getChunkFromChunkCoords(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos), false, this.field_73260_f)); for (var3 = 0; var3 < 16; ++var3) { if ((this.field_73260_f & 1 << var3) != 0) { var4 = var3 << 4; //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. //ToDo: Find a way to efficiently clean abandoned chunks. //List var5 = PlayerManager.getWorldServer(this.myManager).getAllTileEntityInBox(var1, var4, var2, var1 + 16, var4 + 16, var2 + 16); List var5 = PlayerManager.getWorldServer(this.myManager).getAllTileEntityInBox(var1, var4, var2, var1 + 15, var4 + 16, var2 + 15); for (int var6 = 0; var6 < var5.size(); ++var6) { this.sendTileToAllPlayersWatchingChunk((TileEntity)var5.get(var6)); } } } } else { this.sendToAllPlayersWatchingChunk(new Packet52MultiBlockChange(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos, this.locationOfBlockChange, this.numberOfTilesToUpdate, PlayerManager.getWorldServer(this.myManager))); for (var1 = 0; var1 < this.numberOfTilesToUpdate; ++var1) { var2 = this.chunkLocation.chunkXPos * 16 + (this.locationOfBlockChange[var1] >> 12 & 15); var3 = this.locationOfBlockChange[var1] & 255; var4 = this.chunkLocation.chunkZPos * 16 + (this.locationOfBlockChange[var1] >> 8 & 15); if (PlayerManager.getWorldServer(this.myManager).blockHasTileEntity(var2, var3, var4)) { this.sendTileToAllPlayersWatchingChunk(PlayerManager.getWorldServer(this.myManager).getBlockTileEntity(var2, var3, var4)); } } } } this.numberOfTilesToUpdate = 0; this.field_73260_f = 0; } } private void sendTileToAllPlayersWatchingChunk(TileEntity par1TileEntity) { if (par1TileEntity != null) { Packet var2 = par1TileEntity.getDescriptionPacket(); if (var2 != null) { this.sendToAllPlayersWatchingChunk(var2); } } } static ChunkCoordIntPair getChunkLocation(PlayerInstance par0PlayerInstance) { return par0PlayerInstance.chunkLocation; } static List getPlayersInChunk(PlayerInstance par0PlayerInstance) { return par0PlayerInstance.playersInChunk; } }