From a812fd3b8c0aef3ba27d7a49f4b721ee73d9db5a Mon Sep 17 00:00:00 2001 From: William Blake Galbreath 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 | 16 +++++++ .../craftbukkit/entity/CraftPlayer.java | 17 ++++++++ .../java/org/spigotmc/ActivationRange.java | 1 + 10 files changed, 113 insertions(+), 24 deletions(-) diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java index dee92e5a72..5e99ad8144 100644 --- a/src/main/java/net/minecraft/server/Entity.java +++ b/src/main/java/net/minecraft/server/Entity.java @@ -1374,6 +1374,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke return MathHelper.c(f * f + f1 * f1 + f2 * f2); } + public double getDistanceSq(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 57c528d532..3c9f180960 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 8565ad9c76..50a922ff1b 100644 --- a/src/main/java/net/minecraft/server/EntityPlayer.java +++ b/src/main/java/net/minecraft/server/EntityPlayer.java @@ -1583,8 +1583,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, setAfk ? world.purpurConfig.idleTimeoutBroadcastAway : world.purpurConfig.idleTimeoutBroadcastBack); + if (!event.callEvent() || event.shouldKick()) { + return; + } + + this.isAfk = setAfk; + + if (!setAfk) { + resetIdleTimer(); + } + + if (event.getBroadcastMsg() != null && !event.getBroadcastMsg().isEmpty()) { + ((WorldServer) world).getMinecraftServer().server.broadcastMessage(event.getBroadcastMsg().replace("{player}", getName())); + } + + 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 8b36252ae1..5e2d56d5de 100644 --- a/src/main/java/net/minecraft/server/IEntityAccess.java +++ b/src/main/java/net/minecraft/server/IEntityAccess.java @@ -116,28 +116,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.getDistanceSq(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 8d7273a38b..71c61dc45e 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 a = Entity::isAlive; + public static Predicate isLivingAlive() { return b; } // Purpur - OBFHELPER public static final Predicate b = EntityLiving::isAlive; public static final Predicate c = (entity) -> { return entity.isAlive() && !entity.isVehicle() && !entity.isPassenger(); @@ -23,6 +24,7 @@ public final class IEntitySelector { public static final Predicate f = (entity) -> { return !entity.isSpectator(); }; + public static Predicate notAfk = (player) -> !player.isAfk(); // Purpur public static Predicate 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 a4af019bc6..2db59c55ca 100644 --- a/src/main/java/net/minecraft/server/PlayerConnection.java +++ b/src/main/java/net/minecraft/server/PlayerConnection.java @@ -277,6 +277,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])); } @@ -493,6 +499,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(); @@ -1162,6 +1170,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 0a9df816c2..84c0693303 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -367,7 +367,7 @@ public class WorldServer extends World { } if (this.C && 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; @@ -648,7 +648,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 06d6275809..259f6fa287 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -1,6 +1,7 @@ package net.pl3x.purpur; import com.destroystokyo.paper.PaperWorldConfig; +import org.bukkit.ChatColor; import org.bukkit.configuration.file.YamlConfiguration; import org.spigotmc.SpigotWorldConfig; @@ -132,6 +133,21 @@ public class PurpurWorldConfig { elytraDamagePerTridentBoost = getInt("elytra.damage-per-boost.trident", elytraDamagePerTridentBoost); } + public boolean idleTimeoutKick = true; + public boolean idleTimeoutTickNearbyEntities = false; + public boolean idleTimeoutCountAsSleeping = false; + public boolean idleTimeoutUpdateTabList = true; + public String idleTimeoutBroadcastAway = "&e&o{player} is now AFK"; + public String idleTimeoutBroadcastBack = "&e&o{player} is no longer AFK"; + private void playerIdleTimeoutSettings() { + idleTimeoutKick = getBoolean("idle-timeout.kick-if-idle", idleTimeoutKick); + idleTimeoutTickNearbyEntities = getBoolean("idle-timeout.tick-nearby-entities", idleTimeoutTickNearbyEntities); + idleTimeoutCountAsSleeping = getBoolean("idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping); + idleTimeoutUpdateTabList = getBoolean("idle-timeout.update-tab-list", idleTimeoutUpdateTabList); + idleTimeoutBroadcastAway = ChatColor.translateAlternateColorCodes('&', getString("idle-timeout.broadcast.away", idleTimeoutBroadcastAway)); + idleTimeoutBroadcastBack = ChatColor.translateAlternateColorCodes('&', getString("idle-timeout.broadcast.back", idleTimeoutBroadcastBack)); + } + public int pillagerLimitOutpostSpawns = 10; private void pillagerSettings() { pillagerLimitOutpostSpawns = getInt("mobs.pillager.limit-outpost-spawns", pillagerLimitOutpostSpawns); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 712056cad1..c12d52e5df 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -2063,4 +2063,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 92601c581c..185717c804 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java @@ -128,6 +128,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 ); -- 2.24.0