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
This commit is contained in:
Andrew Ardill
2011-08-12 00:37:22 +10:00
committed by unknown
parent a6c03ded28
commit 12e377501e
7 changed files with 294 additions and 33 deletions

View File

@@ -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
}