pala M-afk: kick inactivite + bypass grade (wiki reglement)

This commit is contained in:
Anaïs Saraiva
2026-10-19 03:46:47 +02:00
parent 1720463a87
commit 77fbb485d7
6 changed files with 85 additions and 1 deletions
+5
View File
@@ -591,6 +591,11 @@ avant M4 (TODO:crafts-machines).
vert = +50 000 XP fermier, rainbow = +50 000 aux 4 metiers (wiki VERIFIE). Autres couleurs
= mapping non publie (TODO:mapping-bonbons, sans effet). VERIFIE : build SUCCESSFUL, boot
Done, 0 erreur, lang 228 cles. UNVERIFIED en jeu.
- M-afk LIVRE 2026-10-19 ~03:50 : kick AFK (wiki reglement/grades) : inactivite pos+rot
controlee chaque seconde, limite afkKickMinutes (defaut 10), bypass pala.afk.bypass.
Lecon : authlib absent du compileClasspath (getGameProfile inutilisable) -> PermissionSet
joueur (player.permissions()). VERIFIE : build SUCCESSFUL, boot Done, 0 erreur, 20 cles.
UNVERIFIED en jeu (10 min d'inactivite requises).
- Client/mod : boucle visuelle OPERATIONNELLE 2026-10-19 (Xvfb :99 + runClient SDL x11 +
captures Java Robot + pilotage xdotool + vision_analyze) : menu, Select World, monde New World
(creatif, cheats), /give, pose de bloc, inventaire, F3+T. Screens : scratch vis*.png.
@@ -67,6 +67,9 @@ public final class PalaConfig {
public String discordUrl = "https://discord.gg/paladium";
public String shopUrl = "https://boutique.paladium-pvp.fr/";
// M-afk (wiki reglement/grades) : kick apres N minutes sans activite (defaut 10).
public int afkKickMinutes = 10;
// Cooldowns sticks PvP en secondes. UNVERIFIED (durees balance staff, M5).
public Map<String, Integer> stickCooldowns = new HashMap<>(Map.of(
"heal_stick", 60, "speed_stick", 30, "hyper_jump_stick", 30,
@@ -204,7 +207,8 @@ public final class PalaConfig {
"rankNodes", "hunterKills", "farmerHarvest", "crusherXp",
"crusherResults", "crusherFuels", "crusherInfiniteFuels",
"furnaceSmelts", "furnaceFuels",
"serverName", "wikiUrl", "discordUrl", "shopUrl");
"serverName", "wikiUrl", "discordUrl", "shopUrl",
"afkKickMinutes");
boolean complete = true;
try (Reader keysReader = Files.newBufferedReader(path)) {
com.google.gson.JsonObject obj =
@@ -27,6 +27,22 @@ public final class PalaPermissions {
PalaStorage.get().markDirty();
}
/** OP niveau 2+ bypass tout (PermissionSet joueur, meme pattern que has) ; sinon rang. */
public static boolean hasNode(ServerPlayer player, String node) {
if (net.minecraft.commands.Commands.LEVEL_ADMINS.check(player.permissions())) {
return true;
}
List<String> nodes = PalaConfig.get().rankNodes.getOrDefault(rankOf(player), List.of());
if (nodes.contains(node) || nodes.contains("pala.*")) {
return true;
}
int dot = node.lastIndexOf('.');
if (dot > 0 && nodes.contains(node.substring(0, dot) + ".*")) {
return true;
}
return false;
}
/** OP niveau 2+ (LEVEL_ADMINS) bypass tout ; sinon noeud exact ou wildcard pala.* du rang.
* Prend la source (PermissionSet vanilla 26.3, verifie au javap) + le joueur (rang interne). */
public static boolean has(CommandSourceStack source, ServerPlayer player, String node) {
@@ -0,0 +1,58 @@
package fr.surviepote.pala.events;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import fr.surviepote.pala.core.PalaConfig;
import fr.surviepote.pala.core.PalaPermissions;
// M-afk (wiki reglement + grades) : les fermes AFK sont interdites et le kick AFK existe
// (durees par grade : 10/15/20 min + bonus). Ici : limite unique en config (defaut 10 min,
// afkKickMinutes), bypass par noeud pala.afk.bypass (grades via /pala rank + rankNodes).
// Activite = position + rotation : identiques d'un controle a l'autre (1 s) = inactif.
public final class PalaAfk {
private PalaAfk() {
}
private record Snapshot(double x, double y, double z, float yaw, float pitch, long seconds) {
}
private static final java.util.Map<java.util.UUID, Snapshot> SEEN = new java.util.HashMap<>();
private static int tick;
public static void register() {
ServerTickEvents.END_SERVER_TICK.register(server -> {
if (++tick % 20 != 0) {
return;
}
int limit = PalaConfig.get().afkKickMinutes * 60;
for (ServerPlayer player : server.getPlayerList().getPlayers()) {
Snapshot prev = SEEN.get(player.getUUID());
Snapshot now = new Snapshot(player.getX(), player.getY(), player.getZ(),
player.getYRot(), player.getXRot(), 0);
if (prev != null && prev.x() == now.x() && prev.y() == now.y()
&& prev.z() == now.z() && prev.yaw() == now.yaw()
&& prev.pitch() == now.pitch()) {
long seconds = prev.seconds() + 1;
if (seconds >= limit
&& !PalaPermissions.hasNode(player, "pala.afk.bypass")) {
SEEN.remove(player.getUUID());
player.connection.disconnect(Component.literal(
"§cExpulse pour AFK (" + PalaConfig.get().afkKickMinutes
+ " min sans activite)."));
continue;
}
SEEN.put(player.getUUID(),
new Snapshot(now.x(), now.y(), now.z(), now.yaw(), now.pitch(),
seconds));
} else {
SEEN.put(player.getUUID(),
new Snapshot(now.x(), now.y(), now.z(), now.yaw(), now.pitch(), 0));
}
}
});
}
}
@@ -34,6 +34,7 @@ public final class PalaEvents {
}
public static void registerAll() {
PalaAfk.register();
PalaArmorEvents.register();
PalaItemUseEvents.register();
PalaToolEvents.register();
Binary file not shown.