diff options
author | Andrew Ardill <andrew.ardill@gmail.com> | 2011-08-12 00:37:22 +1000 |
---|---|---|
committer | unknown <user@w.ardill@gmail.com> | 2011-08-15 14:57:25 +1000 |
commit | 12e377501ed7df16ce7e8de2bb99eed41d43fe4e (patch) | |
tree | fee981ec5c1d4d52c53480ebd6f392e1e3c91f31 /src/main/java/net/minecraft/server/PlayerManager.java | |
parent | a6c03ded28b65a936003c6f4391923da75c4f7cb (diff) | |
download | craftbukkit-12e377501ed7df16ce7e8de2bb99eed41d43fe4e.tar craftbukkit-12e377501ed7df16ce7e8de2bb99eed41d43fe4e.tar.gz craftbukkit-12e377501ed7df16ce7e8de2bb99eed41d43fe4e.tar.lz craftbukkit-12e377501ed7df16ce7e8de2bb99eed41d43fe4e.tar.xz craftbukkit-12e377501ed7df16ce7e8de2bb99eed41d43fe4e.zip |
Implements interface for changing the view distance.
Uses default view distance if player's view distance is not set
Throws an illegal argument exception if view distance is set too high
or too low.
Pushes notifications of server and world view distance changes to the player.
Move view distance functions from PlayerManger to WorldServer.
Set player minimum view distance to 1 for now.
Reset player's 'last known' position when recalculating visible chunks.
Use per-player view distance in chunk distance checks
Diffstat (limited to 'src/main/java/net/minecraft/server/PlayerManager.java')
-rw-r--r-- | src/main/java/net/minecraft/server/PlayerManager.java | 122 |
1 files changed, 104 insertions, 18 deletions
diff --git a/src/main/java/net/minecraft/server/PlayerManager.java b/src/main/java/net/minecraft/server/PlayerManager.java index 3dbb30d3..ab606fbb 100644 --- a/src/main/java/net/minecraft/server/PlayerManager.java +++ b/src/main/java/net/minecraft/server/PlayerManager.java @@ -14,15 +14,10 @@ public class PlayerManager { private final int[][] g = new int[][] { { 1, 0}, { 0, 1}, { -1, 0}, { 0, -1}}; public PlayerManager(MinecraftServer minecraftserver, int i, int j) { - if (j > 15) { - throw new IllegalArgumentException("Too big view radius!"); - } else if (j < 3) { - throw new IllegalArgumentException("Too small view radius!"); - } else { - this.f = j; - this.server = minecraftserver; - this.e = i; - } + // CraftBukkit start - no longer need to track view distance here, defers to the player. + this.server = minecraftserver; + this.e = i; + // CraftBukkit end } public WorldServer a() { @@ -66,7 +61,7 @@ public class PlayerManager { entityplayer.d = entityplayer.locX; entityplayer.e = entityplayer.locZ; int k = 0; - int l = this.f; + int l = entityplayer.getViewDistance(); // CraftBukkit - use per-player view distance rather than this.f; int i1 = 0; int j1 = 0; @@ -101,8 +96,11 @@ public class PlayerManager { int i = (int) entityplayer.d >> 4; int j = (int) entityplayer.e >> 4; - for (int k = i - this.f; k <= i + this.f; ++k) { - for (int l = j - this.f; l <= j + this.f; ++l) { + // CraftBukkit start - use per-player view distance instead of this.f + int viewDistance = entityplayer.getViewDistance(); + for (int k = i - viewDistance; k <= i + viewDistance; ++k) { + for (int l = j - viewDistance; l <= j + viewDistance; ++l) { + // CraftBukkit end PlayerInstance playerinstance = this.a(k, l, false); if (playerinstance != null) { @@ -114,12 +112,14 @@ public class PlayerManager { this.managedPlayers.remove(entityplayer); } - private boolean a(int i, int j, int k, int l) { + // CraftBukkit start - changed signature to take a reference to a player. Allows for per-player view distance checks + private boolean a(int viewDistance, int i, int j, int k, int l) { int i1 = i - k; int j1 = j - l; - return i1 >= -this.f && i1 <= this.f ? j1 >= -this.f && j1 <= this.f : false; + return i1 >= -viewDistance && i1 <= viewDistance ? j1 >= -viewDistance && j1 <= viewDistance : false; // CraftBukkit - use per-player view distance } + // CraftBukkit end public void movePlayer(EntityPlayer entityplayer) { int i = (int) entityplayer.locX >> 4; @@ -135,13 +135,16 @@ public class PlayerManager { int j1 = j - l; if (i1 != 0 || j1 != 0) { - for (int k1 = i - this.f; k1 <= i + this.f; ++k1) { - for (int l1 = j - this.f; l1 <= j + this.f; ++l1) { - if (!this.a(k1, l1, k, l)) { + // CraftBukkit start - use per-player view distance instead of this.f + int viewDistance = entityplayer.getViewDistance(); + for (int k1 = i - viewDistance; k1 <= i + viewDistance; ++k1) { + for (int l1 = j - viewDistance; l1 <= j + viewDistance; ++l1) { + if (!this.a(viewDistance, k1, l1, k, l)) { // CraftBukkit - use per-player view distance this.a(k1, l1, true).a(entityplayer); } - if (!this.a(k1 - i1, l1 - j1, i, j)) { + if (!this.a(viewDistance, k1 - i1, l1 - j1, i, j)) { // CraftBukkit - use per-player view distance + // CraftBukkit end PlayerInstance playerinstance = this.a(k1 - i1, l1 - j1, false); if (playerinstance != null) { @@ -182,4 +185,87 @@ public class PlayerManager { static List b(PlayerManager playermanager) { return playermanager.c; } + + // CraftBukkit start + /** + * This method will update references of the EntityPlayer to ensure they are being sent all and only those chunks they can see. + * Note that no attempt is made in this method to track the distance viewable. As such, care should be taken to ensure the + * EntityPlayer could indeed see as far previously as you have specified. + * + * If the chunks which the EntityPlayer can see changes, chunks will be added or removed in a spiral fashion. + * @param entityPlayer the EntityPlayer to update + * @param oldViewDistance the previous distance they could see + * @param newViewDistance the new distance they can see + */ + public void updatePlayerViewDistance(EntityPlayer entityPlayer, int oldViewDistance, int newViewDistance) { + if (oldViewDistance == newViewDistance) { + return; + } + int chunkX = (int) entityPlayer.locX >> 4; + int chunkZ = (int) entityPlayer.locZ >> 4; + + entityPlayer.d = entityPlayer.locX; // set the 'last known' position + entityPlayer.e = entityPlayer.locZ; + + // Going to add/remove players from player-chunk maps in a spiral fashion + // This will send players new chunks they don't have, as well as stop sending chunks they shouldn't have + // We move in an anticlockwise fashion, and can start at any of the four corners + // 0 is [-1,-1]; 1 is [1,-1]; 2 is [1,1]; 3 is [-1,1]; + int corner = 2; // TODO use the direction the player is facing to determine best start corner + int xStartOffset = this.g[(corner+3)%4][(corner+1)%2]; // calculate which offset to use based on corner we start in + int zStartOffset = this.g[(corner+2)%4][corner%2]; + int deltaX; + int deltaZ; + int loop; + int loopStart; + + if (newViewDistance < oldViewDistance) { + // Remove player from outer chunk loops in player-chunk map + loopStart = oldViewDistance; + + for (loop = loopStart, deltaX = xStartOffset*loopStart, deltaZ = zStartOffset*loopStart; + loop > newViewDistance; + --loop, deltaX-=xStartOffset, deltaZ-=zStartOffset) { + for (int edge = 0; edge < 4; ++edge) { + int[] direction = this.g[corner++ % 4]; + + for (int i2 = 0; i2 < loop*2; ++i2) { + deltaX += direction[0]; + deltaZ += direction[1]; + this.removePlayerFromChunk(entityPlayer, chunkX + deltaX, chunkZ + deltaZ); + } + } + } + } else if (newViewDistance > oldViewDistance) { + // Add player to outer chunk loops in player-chunk map + loopStart = oldViewDistance + 1; // start adding outside the current outer loop + + for (loop = loopStart, deltaX = xStartOffset*loopStart, deltaZ = zStartOffset*loopStart; + loop <= newViewDistance; + ++loop, deltaX+=xStartOffset, deltaZ+=zStartOffset) { + for (int edge = 0; edge < 4; ++edge) { + int[] direction = this.g[corner++ % 4]; + + for (int i2 = 0; i2 < loop*2; ++i2) { + deltaX += direction[0]; + deltaZ += direction[1]; + this.addPlayerToChunk(entityPlayer, chunkX + deltaX, chunkZ + deltaZ); + } + } + } + } + } + + private void removePlayerFromChunk(EntityPlayer entityPlayer, int chunkX, int chunkZ) { + PlayerInstance chunkPlayerMap = this.a(chunkX, chunkZ, false); // get the chunk-player map for this chunk, don't create it if it doesn't exist yet + if (chunkPlayerMap != null) { + chunkPlayerMap.b(entityPlayer); // if the chunk-player map exists, remove the player from it. + } + } + + private void addPlayerToChunk(EntityPlayer entityPlayer, int chunkX, int chunkZ) { + PlayerInstance chunkPlayerMap = this.a(chunkX, chunkZ, true); // get the chunk-player map for this chunk, create it if it doesn't exist yet + chunkPlayerMap.a(entityPlayer); // add the player to the chunk-player map + } + // CraftBukkit end } |