From a836b78f0e2b4d5e81479f6a776c06ab7fd40e91 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Wed, 2 Mar 2016 14:35:27 -0600
Subject: [PATCH] Add player view distance API


diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
index 6a26569b9..1b8be825d 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -57,6 +57,15 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
     public boolean f;
     public int ping;
     public boolean viewingCredits;
+    // Paper start - Player view distance API
+    private int viewDistance = -1;
+    public int getViewDistance() {
+        return viewDistance == -1 ? ((WorldServer) world).getPlayerChunkMap().getViewDistance() : viewDistance;
+    }
+    public void setViewDistance(int viewDistance) {
+        this.viewDistance = viewDistance;
+    }
+    // Paper end
 
     // CraftBukkit start
     public String displayName;
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index 021dfba14..9012a63a0 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -47,7 +47,7 @@ public class PlayerChunkMap {
     private final List<PlayerChunk> g = Lists.newLinkedList();
     private final List<PlayerChunk> h = Lists.newLinkedList();
     private final List<PlayerChunk> i = Lists.newArrayList();
-    private int j;
+    private int j;public int getViewDistance() { return j; } // Paper OBFHELPER
     private long k;
     private boolean l = true;
     private boolean m = true;
@@ -291,8 +291,11 @@ public class PlayerChunkMap {
         // CraftBukkit start - Load nearby chunks first
         List<ChunkCoordIntPair> chunkList = new LinkedList<ChunkCoordIntPair>();
 
-        for (int k = i - this.j; k <= i + this.j; ++k) {
-            for (int l = j - this.j; l <= j + this.j; ++l) {
+        // Paper start - Player view distance API
+        int viewDistance = entityplayer.getViewDistance();
+        for (int k = i - viewDistance; k <= i + viewDistance; ++k) {
+            for (int l = j - viewDistance; l <= j + viewDistance; ++l) {
+                // Paper end
                 chunkList.add(new ChunkCoordIntPair(k, l));
             }
         }
@@ -311,8 +314,11 @@ public class PlayerChunkMap {
         int i = (int) entityplayer.d >> 4;
         int j = (int) entityplayer.e >> 4;
 
-        for (int k = i - this.j; k <= i + this.j; ++k) {
-            for (int l = j - this.j; l <= j + this.j; ++l) {
+        // Paper start - Player view distance API
+        int viewDistance = entityplayer.getViewDistance();
+        for (int k = i - viewDistance; k <= i + viewDistance; ++k) {
+            for (int l = j - viewDistance; l <= j + viewDistance; ++l) {
+                // Paper end
                 PlayerChunk playerchunk = this.getChunk(k, l);
 
                 if (playerchunk != null) {
@@ -342,7 +348,9 @@ public class PlayerChunkMap {
         if (d2 >= 64.0D) {
             int k = (int) entityplayer.d >> 4;
             int l = (int) entityplayer.e >> 4;
-            int i1 = this.j;
+            final int viewDistance = entityplayer.getViewDistance(); // Paper - Player view distance API
+            int i1 = Math.max(getViewDistance(), viewDistance); // Paper - Player view distance API
+
             int j1 = i - k;
             int k1 = j - l;
 
@@ -351,7 +359,7 @@ public class PlayerChunkMap {
             if (j1 != 0 || k1 != 0) {
                 for (int l1 = i - i1; l1 <= i + i1; ++l1) {
                     for (int i2 = j - i1; i2 <= j + i1; ++i2) {
-                        if (!this.a(l1, i2, k, l, i1)) {
+                        if (!this.a(l1, i2, k, l, viewDistance)) { // Paper - Player view distance API
                             // this.c(l1, i2).a(entityplayer);
                             chunksToLoad.add(new ChunkCoordIntPair(l1, i2)); // CraftBukkit
                         }
@@ -386,6 +394,8 @@ public class PlayerChunkMap {
         return playerchunk != null && playerchunk.d(entityplayer) && playerchunk.e();
     }
 
+    public final void setViewDistanceForAll(int viewDistance) { this.a(viewDistance); } // Paper - OBFHELPER
+    // Paper start - Separate into two methods
     public void a(int i) {
         i = MathHelper.clamp(i, 3, 32);
         if (i != this.j) {
@@ -395,36 +405,55 @@ public class PlayerChunkMap {
 
             while (iterator.hasNext()) {
                 EntityPlayer entityplayer = (EntityPlayer) iterator.next();
-                int k = (int) entityplayer.locX >> 4;
-                int l = (int) entityplayer.locZ >> 4;
-                int i1;
-                int j1;
-
-                if (j > 0) {
-                    for (i1 = k - i; i1 <= k + i; ++i1) {
-                        for (j1 = l - i; j1 <= l + i; ++j1) {
-                            PlayerChunk playerchunk = this.c(i1, j1);
-
-                            if (!playerchunk.d(entityplayer)) {
-                                playerchunk.a(entityplayer);
-                            }
+                this.setViewDistance(entityplayer, i, false); // Paper - Split, don't mark sort pending, we'll handle it after
+            }
+
+            this.j = i;
+            this.e();
+        }
+    }
+
+    public void setViewDistance(EntityPlayer entityplayer, int i) {
+        this.setViewDistance(entityplayer, i, true); // Mark sort pending by default so we don't have to remember to do so all the time
+    }
+    
+    // Copied from above with minor changes
+    public void setViewDistance(EntityPlayer entityplayer, int i, boolean markSort) {
+        i = MathHelper.clamp(i, 3, 32);
+        int oldViewDistance = entityplayer.getViewDistance();
+        if (i != oldViewDistance) {
+            int j = i - oldViewDistance;
+            
+            int k = (int) entityplayer.locX >> 4;
+            int l = (int) entityplayer.locZ >> 4;
+            int i1;
+            int j1;
+
+            if (j > 0) {
+                for (i1 = k - i; i1 <= k + i; ++i1) {
+                    for (j1 = l - i; j1 <= l + i; ++j1) {
+                        PlayerChunk playerchunk = this.c(i1, j1);
+
+                        if (!playerchunk.d(entityplayer)) {
+                            playerchunk.a(entityplayer);
                         }
                     }
-                } else {
-                    for (i1 = k - this.j; i1 <= k + this.j; ++i1) {
-                        for (j1 = l - this.j; j1 <= l + this.j; ++j1) {
-                            if (!this.a(i1, j1, k, l, i)) {
-                                this.c(i1, j1).b(entityplayer);
-                            }
+                }
+            } else {
+                for (i1 = k - oldViewDistance; i1 <= k + oldViewDistance; ++i1) {
+                    for (j1 = l - oldViewDistance; j1 <= l + oldViewDistance; ++j1) {
+                        if (!this.a(i1, j1, k, l, i)) {
+                            this.c(i1, j1).b(entityplayer);
                         }
                     }
                 }
+                if (markSort) {
+                    this.e();
+                }
             }
-
-            this.j = i;
-            this.e();
         }
     }
+    // Paper end
 
     private void e() {
         this.l = true;
@@ -503,4 +532,20 @@ public class PlayerChunkMap {
         }
     }
     // CraftBukkit end
+
+    // Paper start - Player view distance API
+    public void updateViewDistance(EntityPlayer player, int toSet) {
+        final int oldViewDistance = player.getViewDistance();
+
+        int viewDistance = MathHelper.clamp(toSet, 3, 32);
+        if (toSet < 0) {
+            viewDistance = -1;
+        }
+        if (viewDistance != oldViewDistance) {
+            // Order matters
+            this.setViewDistance(player, viewDistance);
+            player.setViewDistance(viewDistance);
+        }
+    }
+    // Paper end
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 3e4e0801c..318b4608e 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1468,6 +1468,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
         return this.getHandle().affectsSpawning;
     }
 
+    @Override
+    public int getViewDistance() {
+        return getHandle().getViewDistance();
+    }
+
+    @Override
+    public void setViewDistance(int viewDistance) {
+        ((WorldServer) getHandle().world).getPlayerChunkMap().updateViewDistance(getHandle(), viewDistance);
+    }
+
     // Spigot start
     private final Player.Spigot spigot = new Player.Spigot()
     {
-- 
2.11.0.windows.3