From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: William Blake Galbreath Date: Thu, 8 Aug 2019 15:29:15 -0500 Subject: [PATCH] AFK API diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java index b2e21e7034ad83a4ba1c99f860be5a0f5ee6a75f..598b30244e74a56d62dc4ace5362225447860a0a 100644 --- a/src/main/java/net/minecraft/server/level/EntityPlayer.java +++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java @@ -2071,8 +2071,54 @@ public class EntityPlayer extends EntityHuman implements ICrafting { public void resetIdleTimer() { this.ca = SystemUtils.getMonotonicMillis(); + setAfk(false); // Purpur } + // Purpur start + private boolean isAfk = false; + + @Override + public void setAfk(boolean setAfk) { + if (this.isAfk == setAfk) { + return; + } + + String msg = setAfk ? net.pl3x.purpur.PurpurConfig.afkBroadcastAway : net.pl3x.purpur.PurpurConfig.afkBroadcastBack; + + net.pl3x.purpur.event.PlayerAFKEvent event = new net.pl3x.purpur.event.PlayerAFKEvent(getBukkitEntity(), setAfk, world.purpurConfig.idleTimeoutKick, msg, !Bukkit.isPrimaryThread()); + if (!event.callEvent() || event.shouldKick()) { + return; + } + + this.isAfk = setAfk; + + if (!setAfk) { + resetIdleTimer(); + } + + msg = event.getBroadcastMsg(); + if (msg != null && !msg.isEmpty()) { + server.getPlayerList().sendMessage(org.bukkit.craftbukkit.util.CraftChatMessage.fromStringOrNull(String.format(msg, getProfile().getName()))); + } + + if (world.purpurConfig.idleTimeoutUpdateTabList) { + getBukkitEntity().setPlayerListName((setAfk ? net.pl3x.purpur.PurpurConfig.afkTabListPrefix : "") + getName()); + } + + ((WorldServer) world).everyoneSleeping(); + } + + @Override + public boolean isAfk() { + return isAfk; + } + + @Override + public boolean isCollidable() { + return !isAfk() && super.isCollidable(); + } + // Purpur end + public ServerStatisticManager getStatisticManager() { return this.serverStatisticManager; } diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java index 51bb2502e4efb052f55de6eabce07f59e936c9d9..4f1b055dfe38f6a48763f75c1795dcd6dae9d378 100644 --- a/src/main/java/net/minecraft/server/level/WorldServer.java +++ b/src/main/java/net/minecraft/server/level/WorldServer.java @@ -1002,7 +1002,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { // CraftBukkit end 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; @@ -1368,7 +1368,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { 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/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java index 159c38618d7745ea513ad179b1217d76c2c4897a..15349a7bddcad5a4a6db07a8aa6ae8d06163b1f6 100644 --- a/src/main/java/net/minecraft/server/network/PlayerConnection.java +++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java @@ -399,6 +399,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")); } @@ -674,6 +680,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() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetIdleTimer(); // Purpur + // Skip the first time we do this if (true) { // Spigot - don't skip any move events Location oldTo = to.clone(); @@ -1416,7 +1424,7 @@ public class PlayerConnection implements PacketListenerPlayIn { if (!this.player.H() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.playerInteractManager.isCreative() && this.player.playerInteractManager.getGameMode() != EnumGamemode.SPECTATOR) { // Spigot flag1 = true; // Tuinity - diff on change, this should be moved wrongly - PlayerConnection.LOGGER.warn("{} moved wrongly!", this.player.getDisplayName().getString()); + PlayerConnection.LOGGER.warn("{} moved wrongly! ({})", this.player.getDisplayName().getString(), d11); // Purpur } this.player.setLocation(d4, d5, d6, f, f1); @@ -1466,6 +1474,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() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) 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/world/entity/IEntitySelector.java b/src/main/java/net/minecraft/world/entity/IEntitySelector.java index f5e32faeb6d937cf90b1f3ea251b5cfc91f2338d..f9908fb7cc27a8947030c2100dccf1dc1a4e24f7 100644 --- a/src/main/java/net/minecraft/world/entity/IEntitySelector.java +++ b/src/main/java/net/minecraft/world/entity/IEntitySelector.java @@ -15,6 +15,7 @@ import net.minecraft.world.scores.ScoreboardTeamBase; 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(); @@ -35,6 +36,7 @@ public final class IEntitySelector { return !entity.isSpectator(); }; public static Predicate isInsomniac = (player) -> MathHelper.clamp(((EntityPlayer) player).getStatisticManager().getStatisticValue(StatisticList.CUSTOM.get(StatisticList.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper + public static Predicate notAfk = (player) -> !player.isAfk(); // Purpur // Paper start public static final Predicate affectsSpawning = (entity) -> { diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java index 5f9e64df007ebc40f7bcb50be495b10e51d5b87a..17e6f476e60a4f5dc278894a0a874ca5ae45ee22 100644 --- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java @@ -182,6 +182,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, BlockPosition blockposition, float f, GameProfile gameprofile) { super(EntityTypes.PLAYER, world); this.bL = ItemStack.b; diff --git a/src/main/java/net/minecraft/world/level/IEntityAccess.java b/src/main/java/net/minecraft/world/level/IEntityAccess.java index a7f2304acf8ee0a15d6eae8c42060e003be13ae7..fd56b2f15e570f266a79c25823a3b3530a693510 100644 --- a/src/main/java/net/minecraft/world/level/IEntityAccess.java +++ b/src/main/java/net/minecraft/world/level/IEntityAccess.java @@ -183,28 +183,18 @@ public interface IEntityAccess { } // Paper end - 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.g.test(entityhuman)); - } while (!IEntitySelector.b.test(entityhuman)); - - d4 = entityhuman.h(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/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java index 64682d3188c356eec62b414d50e0221fc67de895..3c81d9f1171262d17407232433e3eb0383f424c0 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -1,6 +1,7 @@ package net.pl3x.purpur; import com.google.common.base.Throwables; +import net.minecraft.locale.LocaleLanguage; import net.minecraft.server.MinecraftServer; import net.pl3x.purpur.command.PurpurCommand; import org.bukkit.Bukkit; @@ -129,6 +130,15 @@ public class PurpurConfig { return config.getString(path, config.getString(path)); } + public static String afkBroadcastAway = "§e§o%s is now AFK"; + public static String afkBroadcastBack = "§e§o%s is no longer AFK"; + public static String afkTabListPrefix = "[AFK] "; + private static void messages() { + afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); + afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack); + afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix); + } + public static String timingsUrl = "https://timings.pl3x.net"; private static void timingsSettings() { timingsUrl = getString("settings.timings.url", timingsUrl); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java index 361f7857e461578e90cb71e15027dadaf794cb69..2578a4677d1ee060f687be531e696b7c7be89e84 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -56,4 +56,15 @@ public class PurpurWorldConfig { PurpurConfig.config.addDefault("world-settings.default." + path, def); return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path)); } + + public boolean idleTimeoutKick = true; + public boolean idleTimeoutTickNearbyEntities = true; + public boolean idleTimeoutCountAsSleeping = false; + public boolean idleTimeoutUpdateTabList = false; + private void playerIdleTimeoutSettings() { + 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); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 45e786565ac988abadffda2e7ba3ff1e2880b786..f4052aaa2235894b996d65c569a083f1a09b59a3 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -2491,4 +2491,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 94910bf0c53c79588c55b89e4a023273d6c859ef..a57473fb8815545977ff08bf46d6463d2b7a9d78 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 );