From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Phoenix616 <mail@moep.tv>
Date: Sat, 1 Feb 2020 16:50:39 +0100
Subject: [PATCH] Pillager patrol spawn settings and per player options

This adds config options for defining the spawn chance, spawn delay and
spawn start day as well as toggles for handling the spawn delay and
start day per player. (Based on the time played statistic)
When not per player it will use the Vanilla mechanic of one delay per
world and the world age for the start day.

diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index c3af4c9a9fe67b7a9c0eda5606e1c97bad778927..3f44be577e32af4122b2c8b6c2849e650f4541f5 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -629,10 +629,21 @@ public class PaperWorldConfig {
     }
 
     public boolean disablePillagerPatrols = false;
+    public double patrolSpawnChance = 0.2;
+    public boolean patrolPerPlayerDelay = false;
+    public int patrolDelay = 12000;
+    public boolean patrolPerPlayerStart = false;
+    public int patrolStartDay = 5;
     private void pillagerSettings() {
         disablePillagerPatrols = getBoolean("game-mechanics.disable-pillager-patrols", disablePillagerPatrols);
+        patrolSpawnChance = getDouble("game-mechanics.pillager-patrols.spawn-chance", patrolSpawnChance);
+        patrolPerPlayerDelay = getBoolean("game-mechanics.pillager-patrols.spawn-delay.per-player", patrolPerPlayerDelay);
+        patrolDelay = getInt("game-mechanics.pillager-patrols.spawn-delay.ticks", patrolDelay);
+        patrolPerPlayerStart = getBoolean("game-mechanics.pillager-patrols.start.per-player", patrolPerPlayerStart);
+        patrolStartDay = getInt("game-mechanics.pillager-patrols.start.day", patrolStartDay);
     }
 
+
     public boolean entitiesTargetWithFollowRange = false;
     private void entitiesTargetWithFollowRange() {
         entitiesTargetWithFollowRange = getBoolean("entities-target-with-follow-range", entitiesTargetWithFollowRange);
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
index cf837bdb3b2f9c89fab94e423766c6d99d31f923..900631ebe056bc982e58201626d51d32eaeb77b0 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -77,6 +77,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
     public boolean viewingCredits;
     private int containerUpdateDelay; // Paper
     public long loginTime; // Paper
+    public int patrolSpawnDelay; // Paper - per player patrol spawns
     // Paper start - cancellable death event
     public boolean queueHealthUpdatePacket = false;
     public net.minecraft.server.PacketPlayOutUpdateHealth queuedHealthUpdatePacket;
diff --git a/src/main/java/net/minecraft/server/MobSpawnerPatrol.java b/src/main/java/net/minecraft/server/MobSpawnerPatrol.java
index a0f582807605b9cc5bbf31d84907e56fba393e2e..edca6d3abdc31701068cad4af493759f353d4407 100644
--- a/src/main/java/net/minecraft/server/MobSpawnerPatrol.java
+++ b/src/main/java/net/minecraft/server/MobSpawnerPatrol.java
@@ -4,12 +4,14 @@ import java.util.Random;
 
 public class MobSpawnerPatrol {
 
+    private int getSpawnDelay() { return a; } // Paper - OBFHELPER
+    private void setSpawnDelay(int spawnDelay) { this.a = spawnDelay; } // Paper - OBFHELPER
     private int a;
 
     public MobSpawnerPatrol() {}
 
     public int a(WorldServer worldserver, boolean flag, boolean flag1) {
-        if (worldserver.paperConfig.disablePillagerPatrols) return 0; // Paper
+        if (worldserver.paperConfig.disablePillagerPatrols || worldserver.paperConfig.patrolSpawnChance == 0) return 0; // Paper
         if (!flag) {
             return 0;
         } else if (!worldserver.getGameRules().getBoolean(GameRules.DO_PATROL_SPAWNING)) {
@@ -17,23 +19,51 @@ public class MobSpawnerPatrol {
         } else {
             Random random = worldserver.random;
 
-            --this.a;
-            if (this.a > 0) {
+            // Paper start - Patrol settings
+            // Random player selection moved up for per player spawning and configuration
+            int j = worldserver.getPlayers().size();
+            if (j < 1) {
                 return 0;
+            }
+
+            EntityPlayer entityhuman = worldserver.getPlayers().get(random.nextInt(j));
+            if (entityhuman.isSpectator()) {
+                return 0;
+            }
+
+            int patrolSpawnDelay;
+            if (worldserver.paperConfig.patrolPerPlayerDelay) {
+                --entityhuman.patrolSpawnDelay;
+                patrolSpawnDelay = entityhuman.patrolSpawnDelay;
             } else {
-                this.a += 12000 + random.nextInt(1200);
-                long i = worldserver.getDayTime() / 24000L;
+                setSpawnDelay(getSpawnDelay() - 1);
+                patrolSpawnDelay = getSpawnDelay();
+            }
+
+            if (patrolSpawnDelay > 0) {
+                return 0;
+            } else {
+                long days;
+                if (worldserver.paperConfig.patrolPerPlayerStart) {
+                    days = entityhuman.getStatisticManager().getStatisticValue(StatisticList.CUSTOM.get(StatisticList.PLAY_ONE_MINUTE)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang
+                } else {
+                    days = worldserver.getDayTime() / 24000L;
+                }
+                if (worldserver.paperConfig.patrolPerPlayerDelay) {
+                    entityhuman.patrolSpawnDelay += worldserver.paperConfig.patrolDelay + random.nextInt(1200);
+                } else {
+                    setSpawnDelay(getSpawnDelay() + worldserver.paperConfig.patrolDelay + random.nextInt(1200));
+                }
 
-                if (i >= 5L && worldserver.isDay()) {
-                    if (random.nextInt(5) != 0) {
+                if (days >= worldserver.paperConfig.patrolStartDay && worldserver.isDay()) {
+                    if (random.nextDouble() >= worldserver.paperConfig.patrolSpawnChance) {
+                        // Paper end
                         return 0;
                     } else {
-                        int j = worldserver.getPlayers().size();
 
                         if (j < 1) {
                             return 0;
                         } else {
-                            EntityHuman entityhuman = (EntityHuman) worldserver.getPlayers().get(random.nextInt(j));
 
                             if (entityhuman.isSpectator()) {
                                 return 0;
diff --git a/src/main/java/net/minecraft/server/StatisticWrapper.java b/src/main/java/net/minecraft/server/StatisticWrapper.java
index 3b6034038a4841ebc980b2392c71025d9b0dde35..9c95c0ccfcdc11d8b8bc60986365e76ca0821c68 100644
--- a/src/main/java/net/minecraft/server/StatisticWrapper.java
+++ b/src/main/java/net/minecraft/server/StatisticWrapper.java
@@ -27,6 +27,7 @@ public class StatisticWrapper<T> implements Iterable<Statistic<T>> {
         return this.b.values().iterator();
     }
 
+    public Statistic<T> get(T t) { return this.b(t); }; // Paper - OBFHELPER
     public Statistic<T> b(T t0) {
         return this.a(t0, Counter.DEFAULT);
     }
