mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-17 16:37:43 +01:00
Upstream has released updates that appear to apply and compile correctly Paper Changes: PaperMC/Paper@a07d526 [ci skip] Fix JavaDoc mistake in BlockPistonRetractEvent (#10250) PaperMC/Paper@9a66f2b [ci skip] Fix javadoc mistake in PluginMeta (#10258) PaperMC/Paper@1964b22 Scoreboard objective number format api (#10036) PaperMC/Paper@d95341e FluidState API (#9951) PaperMC/Paper@351923d Run round-trip adventure codec tests with JSON, NBT, and Java ops. Use JavaOps for conversions. (#10031) PaperMC/Paper@4939f87 Add more ResourceLocation checks, some cleanup
331 lines
19 KiB
Diff
331 lines
19 KiB
Diff
From 0000000000000000000000000000000000000000 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] 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 44409eed0b603a1e8203a35ff0263d360d81be32..cdb3cf1b9a809e3936164dbbcf9ccdfc21b9906c 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
@@ -2234,8 +2234,68 @@ 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 ? org.purpurmc.purpur.PurpurConfig.afkBroadcastAway : org.purpurmc.purpur.PurpurConfig.afkBroadcastBack;
|
|
+
|
|
+ org.purpurmc.purpur.event.PlayerAFKEvent event = new org.purpurmc.purpur.event.PlayerAFKEvent(this.getBukkitEntity(), afk, this.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()) {
|
|
+ String playerName = this.getGameProfile().getName();
|
|
+ if (org.purpurmc.purpur.PurpurConfig.afkBroadcastUseDisplayName) {
|
|
+ net.kyori.adventure.text.Component playerDisplayNameComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(this.getBukkitEntity().getDisplayName());
|
|
+ playerName = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText().serialize(playerDisplayNameComponent);
|
|
+ }
|
|
+ server.getPlayerList().broadcastMiniMessage(String.format(msg, playerName), false);
|
|
+ }
|
|
+
|
|
+ if (this.level().purpurConfig.idleTimeoutUpdateTabList) {
|
|
+ String scoreboardName = getScoreboardName();
|
|
+ String playerListName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().serialize(getBukkitEntity().playerListName());
|
|
+ String[] split = playerListName.split(scoreboardName);
|
|
+ String prefix = (split.length > 0 ? split[0] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix, "");
|
|
+ String suffix = (split.length > 1 ? split[1] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, "");
|
|
+ if (afk) {
|
|
+ getBukkitEntity().setPlayerListName(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix + prefix + scoreboardName + suffix + org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, true);
|
|
+ } else {
|
|
+ getBukkitEntity().setPlayerListName(prefix + scoreboardName + suffix);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ((ServerLevel) this.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 88eaf67ee621e06025f23657fe870cc2c9cb9b8f..56589f5c674670534ecf0b97c73c97e302716b9c 100644
|
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
@@ -324,6 +324,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
private boolean justTeleported = false;
|
|
// CraftBukkit end
|
|
|
|
+ // Purpur start
|
|
+ private final com.google.common.cache.LoadingCache<CraftPlayer, Boolean> kickPermissionCache = com.google.common.cache.CacheBuilder.newBuilder()
|
|
+ .maximumSize(1000)
|
|
+ .expireAfterWrite(1, java.util.concurrent.TimeUnit.MINUTES)
|
|
+ .build(
|
|
+ new com.google.common.cache.CacheLoader<>() {
|
|
+ @Override
|
|
+ public Boolean load(CraftPlayer player) {
|
|
+ return player.hasPermission("purpur.bypassIdleKick");
|
|
+ }
|
|
+ }
|
|
+ );
|
|
+ // Purpur end
|
|
+
|
|
@Override
|
|
public void tick() {
|
|
if (this.ackBlockChangesUpTo > -1) {
|
|
@@ -391,6 +405,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
}
|
|
|
|
if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L && !this.player.wonGame) { // Paper - Prevent AFK kick while watching end credits
|
|
+ // Purpur start
|
|
+ this.player.setAfk(true);
|
|
+ if (!this.player.level().purpurConfig.idleTimeoutKick || (!Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK")) && kickPermissionCache.getUnchecked(this.player.getBukkitEntity()))) {
|
|
+ return;
|
|
+ }
|
|
+ // Purpur end
|
|
this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854
|
|
this.disconnect(Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause
|
|
}
|
|
@@ -638,6 +658,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
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
|
|
+
|
|
Location oldTo = to.clone();
|
|
PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
|
|
this.cserver.getPluginManager().callEvent(event);
|
|
@@ -1505,7 +1527,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
if (!event.isAllowed()) {
|
|
movedWrongly = true;
|
|
if (event.getLogWarning())
|
|
- ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString());
|
|
+ ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!, ({})", this.player.getName().getString(), d11); // Purpur
|
|
}
|
|
}
|
|
|
|
@@ -1572,6 +1594,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
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
|
|
+
|
|
Location oldTo = to.clone();
|
|
PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
|
|
this.cserver.getPluginManager().callEvent(event);
|
|
diff --git a/src/main/java/net/minecraft/server/players/SleepStatus.java b/src/main/java/net/minecraft/server/players/SleepStatus.java
|
|
index 823efad652d8ff9e96b99375b102fef6f017716e..caa8a69bde0c212c36dd990a67836ac2f95548c0 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<ServerPlayer> 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 d8cc5614502db7025349e085381b6b32ad32296a..f1b9e83206cc67e6ef29ebe088351b0aaa5eb349 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
|
|
@@ -40,6 +40,7 @@ public final class EntitySelector {
|
|
return net.minecraft.util.Mth.clamp(serverPlayer.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= playerInsomniaTicks;
|
|
};
|
|
// Paper end - Ability to control player's insomnia and phantoms
|
|
+ public static Predicate<Player> notAfk = (player) -> !player.isAfk(); // Purpur
|
|
|
|
private EntitySelector() {}
|
|
// Paper start - Affects Spawning API
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
|
index 931cbbe41905d7ed3fd46c53d3ddd06a6b9a7c8a..d8642979b7296737d08529f6db4f64e463d9f936 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
|
@@ -64,6 +64,10 @@ public class TargetingConditions {
|
|
return false;
|
|
} else if (this.selector != null && !this.selector.test(targetEntity)) {
|
|
return false;
|
|
+ // Purpur start
|
|
+ } else if (!targetEntity.level().purpurConfig.idleTimeoutTargetPlayer && targetEntity instanceof net.minecraft.server.level.ServerPlayer player && player.isAfk()) {
|
|
+ return false;
|
|
+ // Purpur end
|
|
} else {
|
|
if (baseEntity == null) {
|
|
if (this.isCombat && (!targetEntity.canBeSeenAsEnemy() || targetEntity.level().getDifficulty() == Difficulty.PEACEFUL)) {
|
|
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 0c06194b9a182447459815d88a8dcb96b7b4b896..e1e5837c6f90c811f63053bbca80c512229cd727 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
|
@@ -188,6 +188,13 @@ public abstract class Player extends LivingEntity {
|
|
public boolean fauxSleeping;
|
|
public int oldLevel = -1;
|
|
|
|
+ public void setAfk(boolean afk) {
|
|
+ }
|
|
+
|
|
+ public boolean isAfk() {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
@Override
|
|
public CraftHumanEntity getBukkitEntity() {
|
|
return (CraftHumanEntity) super.getBukkitEntity();
|
|
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
|
|
index ed84c87a3f76bc0254c1abb189e6b8b808823465..5bc68b1ef33f297e9a4b1bdd7d69f86a46ad6fbd 100644
|
|
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
|
|
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
|
|
@@ -191,7 +191,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/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
index ab96c92d3d995a64ea9fd1c3996da35148195c48..008da41d0fa6d80dc731e4eeb9aa4d4cb4b1873e 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
@@ -488,10 +488,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 = this.getName();
|
|
}
|
|
- this.getHandle().listName = name.equals(this.getName()) ? null : CraftChatMessage.fromStringOrNull(name);
|
|
+ this.getHandle().listName = name.equals(this.getName()) ? null : useMM ? io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name)) : CraftChatMessage.fromStringOrNull(name); // Purpur
|
|
for (ServerPlayer player : (List<ServerPlayer>) this.server.getHandle().players) {
|
|
if (player.getBukkitEntity().canSee(this)) {
|
|
player.connection.send(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, this.getHandle()));
|
|
@@ -3433,5 +3438,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
public boolean usesPurpurClient() {
|
|
return getHandle().purpurClient;
|
|
}
|
|
+
|
|
+ @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/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
|
|
index a0eb18409f72afe393581e6dc8e2260b3a25197f..7312ae7323032a0ba3c47aa7bdfe5dffe9674535 100644
|
|
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
|
|
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
|
|
@@ -174,8 +174,18 @@ public class PurpurConfig {
|
|
}
|
|
|
|
public static String cannotRideMob = "<red>You cannot mount that mob";
|
|
+ public static String afkBroadcastAway = "<yellow><italic>%s is now AFK";
|
|
+ public static String afkBroadcastBack = "<yellow><italic>%s is no longer AFK";
|
|
+ public static boolean afkBroadcastUseDisplayName = false;
|
|
+ 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);
|
|
+ afkBroadcastUseDisplayName = getBoolean("settings.messages.afk-broadcast-use-display-name", afkBroadcastUseDisplayName);
|
|
+ afkTabListPrefix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix)));
|
|
+ afkTabListSuffix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix)));
|
|
}
|
|
|
|
public static int barrelRows = 3;
|
|
diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
|
|
index e248395ad5f5f012aeefecf367d54f90cade0996..70f53ccb22de2c05c9ead68f8bd29d0b69d0993f 100644
|
|
--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
|
|
+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java
|
|
@@ -90,6 +90,24 @@ public class PurpurWorldConfig {
|
|
return value.isEmpty() ? fallback : value;
|
|
}
|
|
|
|
+ public boolean idleTimeoutKick = true;
|
|
+ public boolean idleTimeoutTickNearbyEntities = true;
|
|
+ public boolean idleTimeoutCountAsSleeping = false;
|
|
+ public boolean idleTimeoutUpdateTabList = false;
|
|
+ public boolean idleTimeoutTargetPlayer = true;
|
|
+ private void playerSettings() {
|
|
+ if (PurpurConfig.version < 19) {
|
|
+ boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer);
|
|
+ set("gameplay-mechanics.player.idle-timeout.mods-target", null);
|
|
+ set("gameplay-mechanics.player.idle-timeout.mobs-target", oldVal);
|
|
+ }
|
|
+ idleTimeoutKick = System.getenv("PURPUR_FORCE_IDLE_KICK") == null ? getBoolean("gameplay-mechanics.player.idle-timeout.kick-if-idle", idleTimeoutKick) : Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK"));
|
|
+ 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);
|
|
+ idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer);
|
|
+ }
|
|
+
|
|
public boolean babiesAreRidable = true;
|
|
public boolean untamedTamablesAreRidable = true;
|
|
public boolean useNightVisionWhenRiding = false;
|
|
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
|
index 41cddf7e42f0e8f80973e482a95e55d3bd19f659..b73bb349aed01a96515e5d4d7fe67d28bd80189f 100644
|
|
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
|
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
|
@@ -203,6 +203,7 @@ public class ActivationRange
|
|
continue;
|
|
}
|
|
|
|
+ if (!player.level().purpurConfig.idleTimeoutTickNearbyEntities && player.isAfk()) continue; // Purpur
|
|
// Paper start
|
|
int worldHeight = world.getHeight();
|
|
ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, worldHeight, maxRange );
|