Files
Purpur/patches/server/0037-Implement-AFK-API.patch
William Blake Galbreath 9c87f5730d Updated Upstream (Paper)
Upstream has released updates that appears to apply and compile correctly

Paper Changes:
b1691e7b Remove some Streams usage in Entity Collision
d454bbd5 Implement JellySquid's Entity Collision optimisations patch
8e85f841 Optimize Collision to not load chunks
ceb824db Fix ChunkCache .getXIfLoaded to use the local chunks in the cache
2020-05-09 19:58:46 -05:00

304 lines
14 KiB
Diff

From d1cf022928b0c3dee8838a58215fc5cfef8fb2c2 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 8 Aug 2019 15:29:15 -0500
Subject: [PATCH] Implement AFK API
---
.../java/net/minecraft/server/Entity.java | 1 +
.../net/minecraft/server/EntityHuman.java | 9 ++++
.../net/minecraft/server/EntityPlayer.java | 43 +++++++++++++++++++
.../net/minecraft/server/IEntityAccess.java | 34 ++++++---------
.../net/minecraft/server/IEntitySelector.java | 2 +
.../minecraft/server/PlayerConnection.java | 10 +++++
.../net/minecraft/server/WorldServer.java | 4 +-
.../net/pl3x/purpur/PurpurWorldConfig.java | 11 +++++
.../craftbukkit/entity/CraftPlayer.java | 17 ++++++++
.../java/org/spigotmc/ActivationRange.java | 1 +
src/main/resources/purpur.lang | 4 +-
11 files changed, 111 insertions(+), 25 deletions(-)
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index e54d8f595..3533dbcd5 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -1436,6 +1436,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
return MathHelper.c(f * f + f1 * f1 + f2 * f2);
}
+ public double getDistanceSquared(double x, double y, double z) { return g(x, y, z); } // Purpur - OBFHELPER
public double g(double d0, double d1, double d2) {
double d3 = this.locX() - d0;
double d4 = this.locY() - d1;
diff --git a/src/main/java/net/minecraft/server/EntityHuman.java b/src/main/java/net/minecraft/server/EntityHuman.java
index 27cfc6654..d62174e9c 100644
--- a/src/main/java/net/minecraft/server/EntityHuman.java
+++ b/src/main/java/net/minecraft/server/EntityHuman.java
@@ -86,6 +86,15 @@ public abstract class EntityHuman extends EntityLiving {
}
// CraftBukkit end
+ // Purpur start
+ public void setAfk(boolean setAfk){
+ }
+
+ public boolean isAfk() {
+ return false;
+ }
+ // Purpur end
+
public EntityHuman(World world, GameProfile gameprofile) {
super(EntityTypes.PLAYER, world);
this.bV = ItemStack.a;
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
index f3278d356..219a274f9 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -1624,8 +1624,51 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
public void resetIdleTimer() {
this.cj = SystemUtils.getMonotonicMillis();
+ setAfk(false); // Purpur
}
+ // Purpur start
+ private boolean isAfk = false;
+
+ @Override
+ public void setAfk(boolean setAfk) {
+ if (this.isAfk == setAfk) {
+ return;
+ }
+
+ net.pl3x.purpur.event.PlayerAFKEvent event = new net.pl3x.purpur.event.PlayerAFKEvent(getBukkitEntity(), setAfk, world.purpurConfig.idleTimeoutKick, LocaleLanguage.getInstance().translateKey("idle.timeout.broadcast." + (setAfk ? "away" : "back")), !Bukkit.isPrimaryThread());
+ if (!event.callEvent() || event.shouldKick()) {
+ return;
+ }
+
+ this.isAfk = setAfk;
+
+ if (!setAfk) {
+ resetIdleTimer();
+ }
+
+ if (event.getBroadcastMsg() != null && !event.getBroadcastMsg().isEmpty()) {
+ server.getPlayerList().sendAll(new PacketPlayOutChat(new ChatMessage(event.getBroadcastMsg(), getScoreboardDisplayName())));
+ }
+
+ if (world.purpurConfig.idleTimeoutUpdateTabList) {
+ getBukkitEntity().setPlayerListName((setAfk ? "[AFK] " : "") + getName());
+ }
+
+ ((WorldServer) world).everyoneSleeping();
+ }
+
+ @Override
+ public boolean isAfk() {
+ return isAfk;
+ }
+
+ @Override
+ public boolean isCollidable(boolean ignoreClimbing) {
+ return !isAfk() && super.isCollidable(ignoreClimbing);
+ }
+ // Purpur end
+
public ServerStatisticManager getStatisticManager() {
return this.serverStatisticManager;
}
diff --git a/src/main/java/net/minecraft/server/IEntityAccess.java b/src/main/java/net/minecraft/server/IEntityAccess.java
index e0d97d2c8..e1a7926d7 100644
--- a/src/main/java/net/minecraft/server/IEntityAccess.java
+++ b/src/main/java/net/minecraft/server/IEntityAccess.java
@@ -150,28 +150,18 @@ public interface IEntityAccess {
return entityhuman;
}
- default boolean isPlayerNearby(double d0, double d1, double d2, double d3) {
- Iterator iterator = this.getPlayers().iterator();
-
- double d4;
-
- do {
- EntityHuman entityhuman;
-
- do {
- do {
- if (!iterator.hasNext()) {
- return false;
- }
-
- entityhuman = (EntityHuman) iterator.next();
- } while (!IEntitySelector.f.test(entityhuman));
- } while (!IEntitySelector.b.test(entityhuman));
-
- d4 = entityhuman.g(d0, d1, d2);
- } while (d3 >= 0.0D && d4 >= d3 * d3);
-
- return true;
+ // Purpur start
+ default boolean isPlayerNearby(double x, double y, double z, double distance) {
+ double distanceSq = distance * distance;
+ for (EntityHuman player : getPlayers()) {
+ if (IEntitySelector.notSpectator().test(player) && IEntitySelector.isLivingAlive().test(player) && IEntitySelector.notAfk.test(player)) {
+ if (distance < 0.0D || player.getDistanceSquared(x, y, z) < distanceSq) {
+ return true;
+ }
+ }
+ }
+ return false;
+ // Purpur end
}
@Nullable
diff --git a/src/main/java/net/minecraft/server/IEntitySelector.java b/src/main/java/net/minecraft/server/IEntitySelector.java
index 1398c47a2..0bf1a14b7 100644
--- a/src/main/java/net/minecraft/server/IEntitySelector.java
+++ b/src/main/java/net/minecraft/server/IEntitySelector.java
@@ -7,6 +7,7 @@ import javax.annotation.Nullable;
public final class IEntitySelector {
public static final Predicate<Entity> a = Entity::isAlive;
+ public static Predicate<EntityLiving> isLivingAlive() { return b; } // Purpur - OBFHELPER
public static final Predicate<EntityLiving> b = EntityLiving::isAlive;
public static final Predicate<Entity> c = (entity) -> {
return entity.isAlive() && !entity.isVehicle() && !entity.isPassenger();
@@ -24,6 +25,7 @@ public final class IEntitySelector {
return !entity.isSpectator();
};
public static Predicate<EntityHuman> isInsomniac = (player) -> MathHelper.clamp(((EntityPlayer) player).getStatisticManager().getStatisticValue(StatisticList.CUSTOM.get(StatisticList.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper
+ public static Predicate<EntityHuman> notAfk = (player) -> !player.isAfk(); // Purpur
public static Predicate<Entity> a(double d0, double d1, double d2, double d3) {
double d4 = d3 * d3;
diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
index c61edea48..f641aa30c 100644
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
@@ -233,6 +233,12 @@ public class PlayerConnection implements PacketListenerPlayIn {
}
if (this.player.F() > 0L && this.minecraftServer.getIdleTimeout() > 0 && SystemUtils.getMonotonicMillis() - this.player.F() > (long) (this.minecraftServer.getIdleTimeout() * 1000 * 60)) {
+ // Purpur start
+ this.player.setAfk(true);
+ if (!this.player.world.purpurConfig.idleTimeoutKick) {
+ return;
+ }
+ // Purpur end
this.player.resetIdleTimer(); // CraftBukkit - SPIGOT-854
this.disconnect(new ChatMessage("multiplayer.disconnect.idling", new Object[0]));
}
@@ -449,6 +455,8 @@ public class PlayerConnection implements PacketListenerPlayIn {
this.lastYaw = to.getYaw();
this.lastPitch = to.getPitch();
+ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ()) this.player.resetIdleTimer(); // Purpur
+
// Skip the first time we do this
if (true) { // Spigot - don't skip any move events
Location oldTo = to.clone();
@@ -1134,6 +1142,8 @@ public class PlayerConnection implements PacketListenerPlayIn {
this.lastYaw = to.getYaw();
this.lastPitch = to.getPitch();
+ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ()) this.player.resetIdleTimer(); // Purpur
+
// Skip the first time we do this
if (from.getX() != Double.MAX_VALUE) {
Location oldTo = to.clone();
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index a4a441fea..c4a09eda3 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -405,7 +405,7 @@ public class WorldServer extends World {
}
if (this.everyoneSleeping && this.players.stream().noneMatch((entityplayer) -> {
- return !entityplayer.isSpectator() && !entityplayer.isDeeplySleeping() && !entityplayer.fauxSleeping; // CraftBukkit
+ return !entityplayer.isSpectator() && !entityplayer.isDeeplySleeping() && !entityplayer.fauxSleeping && !(purpurConfig.idleTimeoutCountAsSleeping && entityplayer.isAfk()); // CraftBukkit // Purpur
})) {
// CraftBukkit start
long l = this.worldData.getDayTime() + 24000L;
@@ -723,7 +723,7 @@ public class WorldServer extends World {
while (iterator.hasNext()) {
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
- if (entityplayer.isSpectator() || (entityplayer.fauxSleeping && !entityplayer.isSleeping())) { // CraftBukkit
+ if (entityplayer.isSpectator() || (entityplayer.fauxSleeping && !entityplayer.isSleeping()) || (purpurConfig.idleTimeoutCountAsSleeping && entityplayer.isAfk())) { // CraftBukkit // Purpur
++i;
} else if (entityplayer.isSleeping()) {
++j;
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index d6405b2ec..41dd1b861 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -138,6 +138,17 @@ public class PurpurWorldConfig {
disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath);
}
+ public boolean idleTimeoutKick = true;
+ public boolean idleTimeoutTickNearbyEntities = true;
+ public boolean idleTimeoutCountAsSleeping = false;
+ public boolean idleTimeoutUpdateTabList = false;
+ private void idleTimeoutSettings() {
+ idleTimeoutKick = getBoolean("gameplay-mechanics.player.idle-timeout.kick-if-idle", idleTimeoutKick);
+ idleTimeoutTickNearbyEntities = getBoolean("gameplay-mechanics.player.idle-timeout.tick-nearby-entities", idleTimeoutTickNearbyEntities);
+ idleTimeoutCountAsSleeping = getBoolean("gameplay-mechanics.player.idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping);
+ idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList);
+ }
+
public boolean batRidable = false;
public boolean batRidableInWater = false;
public boolean batRequireShiftToMount = true;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index dcbda5b35..c14493929 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2079,4 +2079,21 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
return spigot;
}
// Spigot end
+
+ // Purpur start
+ @Override
+ public boolean isAfk() {
+ return getHandle().isAfk();
+ }
+
+ @Override
+ public void setAfk(boolean setAfk) {
+ getHandle().setAfk(setAfk);
+ }
+
+ @Override
+ public void resetIdleTimer() {
+ getHandle().resetIdleTimer();
+ }
+ // Purpur end
}
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index f735217e7..818f8070c 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -207,6 +207,7 @@ public class ActivationRange
{
player.activatedTick = MinecraftServer.currentTick;
+ if (!player.world.purpurConfig.idleTimeoutTickNearbyEntities && player.isAfk()) continue; // Purpur
maxBB = player.getBoundingBox().grow( maxRange, 256, maxRange );
ActivationType.MISC.boundingBox = player.getBoundingBox().grow( miscActivationRange, 256, miscActivationRange );
ActivationType.RAIDER.boundingBox = player.getBoundingBox().grow( raiderActivationRange, 256, raiderActivationRange );
diff --git a/src/main/resources/purpur.lang b/src/main/resources/purpur.lang
index 7125c0477..e925e1374 100644
--- a/src/main/resources/purpur.lang
+++ b/src/main/resources/purpur.lang
@@ -1,3 +1,5 @@
{
- "cannot.ride.mob": "You cannot mount that mob"
+ "cannot.ride.mob": "You cannot mount that mob",
+ "idle.timeout.broadcast.away": "§e§o%s is now AFK",
+ "idle.timeout.broadcast.back": "§e§o%s is no longer AFK"
}
--
2.24.0