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/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index d9df08cdf065b0316f43ca53988ccbe119e5106f..687f1bfa07246e2297be7124edf5bf7568a7ce09 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -1936,8 +1936,58 @@ public class ServerPlayer extends Player { public void resetLastActionTime() { this.lastActionTime = Util.getMillis(); + this.setAfk(false); // Purpur } + // Purpur Start + private boolean isAfk = false; + + @Override + public void setAfk(boolean afk) { + if (this.isAfk == afk) { + return; + } + + String msg = afk ? net.pl3x.purpur.PurpurConfig.afkBroadcastAway : net.pl3x.purpur.PurpurConfig.afkBroadcastBack; + + net.pl3x.purpur.event.PlayerAFKEvent event = new net.pl3x.purpur.event.PlayerAFKEvent(this.getBukkitEntity(), afk, level.purpurConfig.idleTimeoutKick, msg, !Bukkit.isPrimaryThread()); + if (!event.callEvent() || event.shouldKick()) { + return; + } + + this.isAfk = afk; + + if (!afk) { + resetLastActionTime(); + } + + msg = event.getBroadcastMsg(); + if (msg != null && !msg.isEmpty()) { + server.getPlayerList().broadcast(String.format(msg, this.getGameProfile().getName())); + } + + if (level.purpurConfig.idleTimeoutUpdateTabList) { + if (afk) { + getBukkitEntity().setPlayerListName(net.pl3x.purpur.PurpurConfig.afkTabListPrefix + getScoreboardName() + net.pl3x.purpur.PurpurConfig.afkTabListSuffix, true); + } else { + getBukkitEntity().setPlayerListName(getScoreboardName()); + } + } + + ((ServerLevel) level).updateSleepingPlayerList(); + } + + @Override + public boolean isAfk() { + return this.isAfk; + } + + @Override + public boolean canBeCollidedWith() { + return !this.isAfk() && super.canBeCollidedWith(); + } + // Purpur End + public ServerStatsCounter getStats() { return this.stats; } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index dbb5f0bd721b2490f727a0b2462cf215e729947d..c5863036c0fdeee755494dfc55c527f4696c92c1 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -390,6 +390,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser } if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) (this.server.getPlayerIdleTimeout() * 1000 * 60)) { + // Purpur start + this.player.setAfk(true); + if (!this.player.level.purpurConfig.idleTimeoutKick) { + return; + } + // Purpur end this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 this.disconnect(new TranslatableComponent("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause } @@ -648,6 +654,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser 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.resetLastActionTime(); // Purpur + // Skip the first time we do this if (true) { // Spigot - don't skip any move events Location oldTo = to.clone(); @@ -1373,8 +1381,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser boolean flag1 = false; if (!this.player.isChangingDimension() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.gameMode.isCreative() && this.player.gameMode.getGameModeForPlayer() != GameType.SPECTATOR) { // Spigot - flag1 = true; - ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString()); + flag1 = true; // Tuinity - diff on change, this should be moved wrongly + ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!, ({})", this.player.getName().getString(), d11); // Purpur } this.player.absMoveTo(d0, d1, d2, f, f1); @@ -1413,6 +1421,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser 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.resetLastActionTime(); // 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/players/SleepStatus.java b/src/main/java/net/minecraft/server/players/SleepStatus.java index 823efad652d8ff9e96b99375b102fef6f017716e..60f89d7c77a5e792e21e93e35ed1670bd565799a 100644 --- a/src/main/java/net/minecraft/server/players/SleepStatus.java +++ b/src/main/java/net/minecraft/server/players/SleepStatus.java @@ -19,7 +19,7 @@ public class SleepStatus { public boolean areEnoughDeepSleeping(int percentage, List players) { // CraftBukkit start - int j = (int) players.stream().filter((eh) -> { return eh.isSleepingLongEnough() || eh.fauxSleeping; }).count(); + int j = (int) players.stream().filter((eh) -> { return eh.isSleepingLongEnough() || eh.fauxSleeping || (eh.level.purpurConfig.idleTimeoutCountAsSleeping && eh.isAfk()); }).count(); // Purpur boolean anyDeepSleep = players.stream().anyMatch(Player::isSleepingLongEnough); return anyDeepSleep && j >= this.sleepersNeeded(percentage); @@ -52,7 +52,7 @@ public class SleepStatus { if (!entityplayer.isSpectator()) { ++this.activePlayers; - if (entityplayer.isSleeping() || entityplayer.fauxSleeping) { // CraftBukkit + if ((entityplayer.isSleeping() || entityplayer.fauxSleeping) || (entityplayer.level.purpurConfig.idleTimeoutCountAsSleeping && entityplayer.isAfk())) { // CraftBukkit // Purpur ++this.sleepingPlayers; } // CraftBukkit start diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java index a060cca08631fb42041e3a79a9abc422fe7757af..e7b11d1ba984ea14f0cdf8e84f9eaab46b3f1684 100644 --- a/src/main/java/net/minecraft/world/entity/EntitySelector.java +++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java @@ -27,6 +27,7 @@ public final class EntitySelector { return !entity.isSpectator(); }; public static Predicate isInsomniac = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper + public static Predicate notAfk = (player) -> !player.isAfk(); // Purpur private EntitySelector() {} // Paper start diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java index dd7e76f9e5fd05a38507f32b3e021efe43315049..995098c7e7eaa15fa1cda40fdb763cf4607f3381 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -196,6 +196,13 @@ public abstract class Player extends LivingEntity { // Purpur start public abstract void resetLastActionTime(); + public void setAfk(boolean afk) { + } + + public boolean isAfk() { + return false; + } + @Override public boolean processClick(InteractionHand hand) { Entity vehicle = getRootVehicle(); diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java index 325e244c46ec208a2e7e18d71ccbbfcc25fc1bce..3645ebf52ad1461937ce6cc0cf38a92176627227 100644 --- a/src/main/java/net/minecraft/world/level/EntityGetter.java +++ b/src/main/java/net/minecraft/world/level/EntityGetter.java @@ -145,7 +145,7 @@ public interface EntityGetter { default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) { for(Player player : this.players()) { - if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) { + if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player) && EntitySelector.notAfk.test(player)) { double d = player.distanceToSqr(x, y, z); if (range < 0.0D || d < range * range) { return true; diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java index 0373f3fb256d796c090a3eddcf6e2be0ce25ec16..d35285b58b7141f2e9f438331faf566dc293cc63 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -156,8 +156,16 @@ public class PurpurConfig { } public static String cannotRideMob = "You cannot mount that mob"; + public static String afkBroadcastAway = "%s is now AFK"; + public static String afkBroadcastBack = "%s is no longer AFK"; + public static String afkTabListPrefix = "[AFK] "; + public static String afkTabListSuffix = ""; private static void messages() { cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); + 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); + afkTabListSuffix = getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix); } public static String timingsUrl = "https://timings.pl3x.net"; diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java index 332754f541165590ecd96d650f16f40924b4263a..bfc1077dc7d5cfb48f5cc98b289b98d44474280e 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -92,6 +92,17 @@ public class PurpurWorldConfig { return value.isEmpty() ? fallback : value; } + public boolean idleTimeoutKick = true; + public boolean idleTimeoutTickNearbyEntities = true; + public boolean idleTimeoutCountAsSleeping = false; + public boolean idleTimeoutUpdateTabList = false; + private void playerSettings() { + 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 babiesAreRidable = true; public boolean untamedTamablesAreRidable = true; public boolean useNightVisionWhenRiding = false; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 2e41a1bc20f257f4f461a74623a3ffe2d3112fdd..d858590b7ffea28dcfbc48973df6e3c916886b65 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -423,10 +423,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void setPlayerListName(String name) { + // Purpur start + setPlayerListName(name, false); + } + public void setPlayerListName(String name, boolean useMM) { + // Purpur end if (name == null) { name = getName(); } - this.getHandle().listName = name.equals(getName()) ? null : CraftChatMessage.fromStringOrNull(name); + this.getHandle().listName = name.equals(getName()) ? null : useMM ? io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.get().parse(name)) : CraftChatMessage.fromStringOrNull(name); // Purpur for (ServerPlayer player : (List) server.getHandle().players) { if (player.getBukkitEntity().canSee(this)) { player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.UPDATE_DISPLAY_NAME, this.getHandle())); @@ -2475,4 +2480,21 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return this.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().resetLastActionTime(); + } + // Purpur end } diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java index a08583863f9fa08016bdfc7949a273eaa4429927..f36c97529edbd3642d0ba37887a232226f766a35 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java @@ -194,6 +194,7 @@ public class ActivationRange { player.activatedTick = MinecraftServer.currentTick; + if (!player.level.purpurConfig.idleTimeoutTickNearbyEntities && player.isAfk()) continue; // Purpur ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, 256, maxRange ); ActivationType.MISC.boundingBox = player.getBoundingBox().inflate( miscActivationRange, 256, miscActivationRange ); ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate( raiderActivationRange, 256, raiderActivationRange );