From eb08aae8bf8a9111532a0bc58cf3fd2c5803b86d Mon Sep 17 00:00:00 2001 From: Darto KLoning Date: Sat, 3 Oct 2026 21:44:23 +0700 Subject: [PATCH] two stage auth timer --- README.md | 15 +++++++++-- gradle.properties | 2 +- .../lobbysystems/AuthManager.java | 27 ++++++++++++++++--- .../lobbysystems/RulesConfig.java | 1 + 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 562b443..2169db0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Lobby Systems v1.8.3 — Fabric 26.2 +# Lobby Systems v1.8.4 — Fabric 26.2 Server-side lobby framework untuk Minecraft Fabric 26.2. Lobby Systems menangani lobby placement, portal antar-dimensi, gamemode/gamerule per dimensi, Starter Kit, penyimpanan posisi player, dan hybrid authentication untuk premium + local/cracked player. @@ -223,7 +223,7 @@ Console menampilkan `RELOAD START` dan `RELOAD COMPLETE`. Player admin yang menj - Memperbaiki crash `ConcurrentModificationException` ketika authentication timeout men-disconnect player dari dalam server tick. Auth sekarang mengiterasi snapshot player list, bukan live `ArrayList`. - Initial dialog ditunda singkat sampai player benar-benar tersedia sebagai target command; ini menghilangkan kegagalan awal `No player was found`. - Dialog tidak lagi dibuka ulang setiap `reminderIntervalSeconds`, karena itu dapat menghapus password yang sedang diketik. -- Countdown authentication ditampilkan setiap detik melalui action bar. Setelah `authenticationTimeoutSeconds` habis, player otomatis disconnect. +- Countdown sekarang memakai dua fase independen melalui action bar: Rules memakai `rules.json -> timeoutSeconds`, sedangkan Register/Login memakai `auth/config.json -> authenticationTimeoutSeconds`. Timer Register/Login dimulai ulang dari penuh setelah Rules diterima. - Rules dipindahkan ke `config/lobby/auth/rules.json` dan Rules dialog dibangun dari file tersebut. - `rulesEnabled` dan `rulesVersion` lama dipindahkan menjadi `enabled` dan `version` di `rules.json`. - `/ls reload` juga me-reload `rules.json` dan mengevaluasi ulang acceptance/session player online. @@ -243,3 +243,14 @@ All Rights Reserved. Source dan asset Lobby Systems tidak boleh didistribusikan - Countdown authentication sekarang dikirim langsung dengan vanilla `ClientboundSetActionBarTextPacket`, sehingga tetap tampil sebagai action bar tanpa bergantung pada method player yang telah dihapus. - Warna countdown menggunakan `ChatFormatting`/component styling, bukan legacy section-code di payload action bar. - Seluruh perubahan v1.8.2 (safe timeout iteration, delayed initial dialog, `rules.json`, dan global `/ls reload`) tetap dipertahankan. + + +## v1.8.4 — Two-stage auth timer + +- Informasi `Rules version: N` dihapus dari UI Rules; version tetap disimpan sebagai metadata internal untuk mekanisme re-accept. +- `rules.json` memiliki `timeoutSeconds` (default `60`) untuk batas waktu menerima Rules. +- Register/Login tetap memakai `authenticationTimeoutSeconds` (default `120`). +- Setelah Rules diterima, timer Rules dihentikan dan timer Register/Login dimulai dari awal. +- Countdown action bar memakai label sesuai fase: `Accept the rules within`, `Register within`, atau `Login within`. +- Timeout Rules dan timeout authentication memiliki pesan disconnect yang berbeda. +- `/ls reload` tetap memuat ulang seluruh konfigurasi Lobby Systems, termasuk `auth/rules.json` dan `auth/config.json`. diff --git a/gradle.properties b/gradle.properties index 446ede0..abd5122 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,6 +5,6 @@ minecraft_version=26.2 loader_version=0.19.3 loom_version=1.17-SNAPSHOT fabric_api_version=0.156.0+26.2 -mod_version=1.8.3 +mod_version=1.8.4 maven_group=id.dartokloning archives_base_name=lobby-systems diff --git a/src/main/java/id/dartokloning/lobbysystems/AuthManager.java b/src/main/java/id/dartokloning/lobbysystems/AuthManager.java index 91719fb..9506951 100644 --- a/src/main/java/id/dartokloning/lobbysystems/AuthManager.java +++ b/src/main/java/id/dartokloning/lobbysystems/AuthManager.java @@ -128,6 +128,8 @@ public final class AuthManager { } if (!s.authenticated) { s.stage = isRegistered(player.getName().getString()) ? Stage.LOGIN : Stage.REGISTER; + s.joinedAt = System.currentTimeMillis(); + s.lastCountdownSecond = -1L; showCurrentDialog(player, s); } } @@ -225,9 +227,13 @@ public final class AuthManager { for (ServerPlayer player : List.copyOf(server.getPlayerList().getPlayers())) { Session s = sessions.get(player.getUUID()); if (s == null || s.authenticated) continue; - long remainingMillis = config.authenticationTimeoutSeconds * 1000L - (now - s.joinedAt); + int timeoutSeconds = s.stage == Stage.RULES ? Math.max(1, rules.timeoutSeconds) : Math.max(1, config.authenticationTimeoutSeconds); + long remainingMillis = timeoutSeconds * 1000L - (now - s.joinedAt); if (remainingMillis <= 0L) { - player.connection.disconnect(Component.literal("Authentication timed out. Please reconnect and try again.")); + String timeoutMessage = s.stage == Stage.RULES + ? "You did not accept the server rules in time. Please reconnect and try again." + : "Authentication timed out. Please reconnect and try again."; + player.connection.disconnect(Component.literal(timeoutMessage)); continue; } // Keep the player at the safe Lobby authentication position. World safety is @@ -248,8 +254,16 @@ public final class AuthManager { long remainingSeconds = Math.max(1L, (remainingMillis + 999L) / 1000L); if (remainingSeconds != s.lastCountdownSecond) { s.lastCountdownSecond = remainingSeconds; + String countdownLabel = switch (s.stage) { + case RULES -> "Accept the rules within: "; + case REGISTER -> "Register within: "; + case LOGIN -> "Login within: "; + default -> "Time remaining: "; + }; + long minutes = remainingSeconds / 60L; + long seconds = remainingSeconds % 60L; player.connection.send(new ClientboundSetActionBarTextPacket( - Component.literal("Authentication time remaining: " + remainingSeconds + "s") + Component.literal(countdownLabel + String.format(Locale.ROOT, "%02d:%02d", minutes, seconds)) .withStyle(net.minecraft.ChatFormatting.YELLOW) )); } @@ -275,6 +289,11 @@ public final class AuthManager { a.rulesAcceptedAt = Instant.now().toString(); saveAccounts(); } + // Rules and password authentication have independent timers. Once the rules + // are accepted, start a fresh timer for REGISTER/LOGIN instead of carrying over + // time spent reading the rules. + s.joinedAt = System.currentTimeMillis(); + s.lastCountdownSecond = -1L; continueAfterRules(player); return 1; } @@ -422,7 +441,7 @@ public final class AuthManager { } } body.add(plainMessage(lines.toString(), "white")); - body.add(plainMessage(rules.footer + "\n\nRules version: " + rules.version, "gray")); + body.add(plainMessage(rules.footer, "gray")); dialog.add("body", body); com.google.gson.JsonArray inputs = new com.google.gson.JsonArray(); diff --git a/src/main/java/id/dartokloning/lobbysystems/RulesConfig.java b/src/main/java/id/dartokloning/lobbysystems/RulesConfig.java index 51bdd5a..20bb1a8 100644 --- a/src/main/java/id/dartokloning/lobbysystems/RulesConfig.java +++ b/src/main/java/id/dartokloning/lobbysystems/RulesConfig.java @@ -6,6 +6,7 @@ import java.util.List; public final class RulesConfig { public boolean enabled = true; public int version = 1; + public int timeoutSeconds = 60; public String title = "Server Rules"; public String introduction = "Please read and accept our rules:"; public List rules = new ArrayList<>(List.of(