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

Paper Changes:
cb15cfa4 Improve Async Login so pending connections dont get exposed
f275e9cb Optimize Hoppers - Major Boost - Got2GoFast!
0106485c Improvements to watchdog changes
65934b1f Fix build for last commit. 5am commits are great
3f436029 Don't process watchdog until server has fully started and ticked.
938bd972 Don't fire BlockFade on worldgen threads - Fixes #3208
509a828e Fix loading spawn chunks when async chunks is off
8a91bfd2 Improvements to async login
bf698865 Revert "Re-track players that dismount from other players"
82b98418 Fix some issues with async login as well another source of sync loads
aa241d2b Allow multiple callbacks to schedule for Callback Executor
a2064a41 Add PlayerAttackEntityCooldownResetEvent This event is called when processing a player's attack on an entity right before their attack strength cd is reset, there are no existing events that fire within this period of time so it was impossible to capture the players attack strength via API prior to this commit.
f48d4299 Allow sleeping players to float
eeb2f67d Fix Bed respawn deviating too far from vanilla (#3195)
68a7b9fe Move player to spawn point if spawn in unloaded world
2020-04-24 08:22:02 -05:00

304 lines
14 KiB
Diff

From abb33f41016157ea033dade6e81f3e7a87afe74e 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 c211073e..9ff3e68e 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -1420,6 +1420,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 16ccabfd..5ac3c464 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 51933a49..a021c111 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -1622,8 +1622,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 89961900..d9f246b8 100644
--- a/src/main/java/net/minecraft/server/IEntityAccess.java
+++ b/src/main/java/net/minecraft/server/IEntityAccess.java
@@ -125,28 +125,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 e1fdee27..4665671e 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.b(StatisticList.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Purpur
+ 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 3c37d032..c1a4697a 100644
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
@@ -224,6 +224,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]));
}
@@ -440,6 +446,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();
@@ -1109,6 +1117,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 fe81529a..9b873948 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -393,7 +393,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;
@@ -714,7 +714,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 c6bf9395..76f8c8fe 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 b76379a1..b7571d08 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 79581717..17c4d7ec 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -146,6 +146,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 7125c047..e925e137 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