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.util.LongHashMap; 007 import net.minecraft.world.ChunkCoordIntPair; 008 import net.minecraft.world.WorldProvider; 009 import net.minecraft.world.WorldServer; 010 011 public class PlayerManager 012 { 013 private final WorldServer theWorldServer; 014 015 /** players in the current instance */ 016 private final List players = new ArrayList(); 017 018 /** 019 * A map of chunk position (two ints concatenated into a long) to PlayerInstance 020 */ 021 private final LongHashMap playerInstances = new LongHashMap(); 022 023 /** 024 * contains a PlayerInstance for every chunk they can see. the "player instance" cotains a list of all players who 025 * can also that chunk 026 */ 027 private final List chunkWatcherWithPlayers = new ArrayList(); 028 029 /** 030 * Number of chunks the server sends to the client. Valid 3<=x<=15. In server.properties. 031 */ 032 private final int playerViewRadius; 033 034 /** x, z direction vectors: east, south, west, north */ 035 private final int[][] xzDirectionsConst = new int[][] {{1, 0}, {0, 1}, { -1, 0}, {0, -1}}; 036 037 public PlayerManager(WorldServer par1WorldServer, int par2) 038 { 039 if (par2 > 15) 040 { 041 throw new IllegalArgumentException("Too big view radius!"); 042 } 043 else if (par2 < 3) 044 { 045 throw new IllegalArgumentException("Too small view radius!"); 046 } 047 else 048 { 049 this.playerViewRadius = par2; 050 this.theWorldServer = par1WorldServer; 051 } 052 } 053 054 public WorldServer getWorldServer() 055 { 056 return this.theWorldServer; 057 } 058 059 /** 060 * updates all the player instances that need to be updated 061 */ 062 public void updatePlayerInstances() 063 { 064 for (int var1 = 0; var1 < this.chunkWatcherWithPlayers.size(); ++var1) 065 { 066 ((PlayerInstance)this.chunkWatcherWithPlayers.get(var1)).sendChunkUpdate(); 067 } 068 069 this.chunkWatcherWithPlayers.clear(); 070 071 if (this.players.isEmpty()) 072 { 073 WorldProvider var2 = this.theWorldServer.provider; 074 075 if (!var2.canRespawnHere()) 076 { 077 this.theWorldServer.theChunkProviderServer.unloadAllChunks(); 078 } 079 } 080 } 081 082 public PlayerInstance getOrCreateChunkWatcher(int par1, int par2, boolean par3) 083 { 084 long var4 = (long)par1 + 2147483647L | (long)par2 + 2147483647L << 32; 085 PlayerInstance var6 = (PlayerInstance)this.playerInstances.getValueByKey(var4); 086 087 if (var6 == null && par3) 088 { 089 var6 = new PlayerInstance(this, par1, par2); 090 this.playerInstances.add(var4, var6); 091 } 092 093 return var6; 094 } 095 096 /** 097 * the "PlayerInstance"/ chunkWatcher will send this chunk to all players who are in line of sight 098 */ 099 public void flagChunkForUpdate(int par1, int par2, int par3) 100 { 101 int var4 = par1 >> 4; 102 int var5 = par3 >> 4; 103 PlayerInstance var6 = this.getOrCreateChunkWatcher(var4, var5, false); 104 105 if (var6 != null) 106 { 107 var6.flagChunkForUpdate(par1 & 15, par2, par3 & 15); 108 } 109 } 110 111 /** 112 * Adds an EntityPlayerMP to the PlayerManager. 113 */ 114 public void addPlayer(EntityPlayerMP par1EntityPlayerMP) 115 { 116 int var2 = (int)par1EntityPlayerMP.posX >> 4; 117 int var3 = (int)par1EntityPlayerMP.posZ >> 4; 118 par1EntityPlayerMP.managedPosX = par1EntityPlayerMP.posX; 119 par1EntityPlayerMP.managedPosZ = par1EntityPlayerMP.posZ; 120 121 for (int var4 = var2 - this.playerViewRadius; var4 <= var2 + this.playerViewRadius; ++var4) 122 { 123 for (int var5 = var3 - this.playerViewRadius; var5 <= var3 + this.playerViewRadius; ++var5) 124 { 125 this.getOrCreateChunkWatcher(var4, var5, true).addPlayerToChunkWatchingList(par1EntityPlayerMP); 126 } 127 } 128 129 this.players.add(par1EntityPlayerMP); 130 this.filterChunkLoadQueue(par1EntityPlayerMP); 131 } 132 133 /** 134 * Removes all chunks from the given player's chunk load queue that are not in viewing range of the player. 135 */ 136 public void filterChunkLoadQueue(EntityPlayerMP par1EntityPlayerMP) 137 { 138 ArrayList var2 = new ArrayList(par1EntityPlayerMP.loadedChunks); 139 int var3 = 0; 140 int var4 = this.playerViewRadius; 141 int var5 = (int)par1EntityPlayerMP.posX >> 4; 142 int var6 = (int)par1EntityPlayerMP.posZ >> 4; 143 int var7 = 0; 144 int var8 = 0; 145 ChunkCoordIntPair var9 = PlayerInstance.getChunkLocation(this.getOrCreateChunkWatcher(var5, var6, true)); 146 par1EntityPlayerMP.loadedChunks.clear(); 147 148 if (var2.contains(var9)) 149 { 150 par1EntityPlayerMP.loadedChunks.add(var9); 151 } 152 153 int var10; 154 155 for (var10 = 1; var10 <= var4 * 2; ++var10) 156 { 157 for (int var11 = 0; var11 < 2; ++var11) 158 { 159 int[] var12 = this.xzDirectionsConst[var3++ % 4]; 160 161 for (int var13 = 0; var13 < var10; ++var13) 162 { 163 var7 += var12[0]; 164 var8 += var12[1]; 165 var9 = PlayerInstance.getChunkLocation(this.getOrCreateChunkWatcher(var5 + var7, var6 + var8, true)); 166 167 if (var2.contains(var9)) 168 { 169 par1EntityPlayerMP.loadedChunks.add(var9); 170 } 171 } 172 } 173 } 174 175 var3 %= 4; 176 177 for (var10 = 0; var10 < var4 * 2; ++var10) 178 { 179 var7 += this.xzDirectionsConst[var3][0]; 180 var8 += this.xzDirectionsConst[var3][1]; 181 var9 = PlayerInstance.getChunkLocation(this.getOrCreateChunkWatcher(var5 + var7, var6 + var8, true)); 182 183 if (var2.contains(var9)) 184 { 185 par1EntityPlayerMP.loadedChunks.add(var9); 186 } 187 } 188 } 189 190 /** 191 * Removes an EntityPlayerMP from the PlayerManager. 192 */ 193 public void removePlayer(EntityPlayerMP par1EntityPlayerMP) 194 { 195 int var2 = (int)par1EntityPlayerMP.managedPosX >> 4; 196 int var3 = (int)par1EntityPlayerMP.managedPosZ >> 4; 197 198 for (int var4 = var2 - this.playerViewRadius; var4 <= var2 + this.playerViewRadius; ++var4) 199 { 200 for (int var5 = var3 - this.playerViewRadius; var5 <= var3 + this.playerViewRadius; ++var5) 201 { 202 PlayerInstance var6 = this.getOrCreateChunkWatcher(var4, var5, false); 203 204 if (var6 != null) 205 { 206 var6.sendThisChunkToPlayer(par1EntityPlayerMP); 207 } 208 } 209 } 210 211 this.players.remove(par1EntityPlayerMP); 212 } 213 214 private boolean func_72684_a(int par1, int par2, int par3, int par4, int par5) 215 { 216 int var6 = par1 - par3; 217 int var7 = par2 - par4; 218 return var6 >= -par5 && var6 <= par5 ? var7 >= -par5 && var7 <= par5 : false; 219 } 220 221 /** 222 * update chunks around a player being moved by server logic (e.g. cart, boat) 223 */ 224 public void updateMountedMovingPlayer(EntityPlayerMP par1EntityPlayerMP) 225 { 226 int var2 = (int)par1EntityPlayerMP.posX >> 4; 227 int var3 = (int)par1EntityPlayerMP.posZ >> 4; 228 double var4 = par1EntityPlayerMP.managedPosX - par1EntityPlayerMP.posX; 229 double var6 = par1EntityPlayerMP.managedPosZ - par1EntityPlayerMP.posZ; 230 double var8 = var4 * var4 + var6 * var6; 231 232 if (var8 >= 64.0D) 233 { 234 int var10 = (int)par1EntityPlayerMP.managedPosX >> 4; 235 int var11 = (int)par1EntityPlayerMP.managedPosZ >> 4; 236 int var12 = this.playerViewRadius; 237 int var13 = var2 - var10; 238 int var14 = var3 - var11; 239 240 if (var13 != 0 || var14 != 0) 241 { 242 for (int var15 = var2 - var12; var15 <= var2 + var12; ++var15) 243 { 244 for (int var16 = var3 - var12; var16 <= var3 + var12; ++var16) 245 { 246 if (!this.func_72684_a(var15, var16, var10, var11, var12)) 247 { 248 this.getOrCreateChunkWatcher(var15, var16, true).addPlayerToChunkWatchingList(par1EntityPlayerMP); 249 } 250 251 if (!this.func_72684_a(var15 - var13, var16 - var14, var2, var3, var12)) 252 { 253 PlayerInstance var17 = this.getOrCreateChunkWatcher(var15 - var13, var16 - var14, false); 254 255 if (var17 != null) 256 { 257 var17.sendThisChunkToPlayer(par1EntityPlayerMP); 258 } 259 } 260 } 261 } 262 263 this.filterChunkLoadQueue(par1EntityPlayerMP); 264 par1EntityPlayerMP.managedPosX = par1EntityPlayerMP.posX; 265 par1EntityPlayerMP.managedPosZ = par1EntityPlayerMP.posZ; 266 } 267 } 268 } 269 270 public boolean isPlayerWatchingChunk(EntityPlayerMP par1EntityPlayerMP, int par2, int par3) 271 { 272 PlayerInstance var4 = this.getOrCreateChunkWatcher(par2, par3, false); 273 return var4 == null ? false : PlayerInstance.getPlayersInChunk(var4).contains(par1EntityPlayerMP) && !par1EntityPlayerMP.loadedChunks.contains(PlayerInstance.getChunkLocation(var4)); 274 } 275 276 /** 277 * Get the furthest viewable block given player's view distance 278 */ 279 public static int getFurthestViewableBlock(int par0) 280 { 281 return par0 * 16 - 16; 282 } 283 284 static WorldServer getWorldServer(PlayerManager par0PlayerManager) 285 { 286 return par0PlayerManager.theWorldServer; 287 } 288 289 static LongHashMap getChunkWatchers(PlayerManager par0PlayerManager) 290 { 291 return par0PlayerManager.playerInstances; 292 } 293 294 static List getChunkWatchersWithPlayers(PlayerManager par0PlayerManager) 295 { 296 return par0PlayerManager.chunkWatcherWithPlayers; 297 } 298 }