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 }