From 068369d52a9520129daf8c4f175e21d3eff59ec6 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 522c7f2..4950db4 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -56,6 +56,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 797a84f..df6801f 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;
@@ -283,8 +283,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));
             }
         }
@@ -303,8 +306,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) {
@@ -334,7 +340,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;
 
@@ -343,7 +351,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
                         }
@@ -495,4 +503,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) {
+            removePlayer(player);
+            player.setViewDistance(viewDistance);
+            addPlayer(player);
+        }
+    }
+    // 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 64c9c1c..e09dc78 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1438,6 +1438,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.9.0.windows.1