two stage auth timer
This commit is contained in:
@@ -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.
|
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`.
|
- 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`.
|
- 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.
|
- 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.
|
- 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`.
|
- `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.
|
- `/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.
|
- 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.
|
- 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.
|
- 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`.
|
||||||
|
|||||||
+1
-1
@@ -5,6 +5,6 @@ minecraft_version=26.2
|
|||||||
loader_version=0.19.3
|
loader_version=0.19.3
|
||||||
loom_version=1.17-SNAPSHOT
|
loom_version=1.17-SNAPSHOT
|
||||||
fabric_api_version=0.156.0+26.2
|
fabric_api_version=0.156.0+26.2
|
||||||
mod_version=1.8.3
|
mod_version=1.8.4
|
||||||
maven_group=id.dartokloning
|
maven_group=id.dartokloning
|
||||||
archives_base_name=lobby-systems
|
archives_base_name=lobby-systems
|
||||||
|
|||||||
@@ -128,6 +128,8 @@ public final class AuthManager {
|
|||||||
}
|
}
|
||||||
if (!s.authenticated) {
|
if (!s.authenticated) {
|
||||||
s.stage = isRegistered(player.getName().getString()) ? Stage.LOGIN : Stage.REGISTER;
|
s.stage = isRegistered(player.getName().getString()) ? Stage.LOGIN : Stage.REGISTER;
|
||||||
|
s.joinedAt = System.currentTimeMillis();
|
||||||
|
s.lastCountdownSecond = -1L;
|
||||||
showCurrentDialog(player, s);
|
showCurrentDialog(player, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,9 +227,13 @@ public final class AuthManager {
|
|||||||
for (ServerPlayer player : List.copyOf(server.getPlayerList().getPlayers())) {
|
for (ServerPlayer player : List.copyOf(server.getPlayerList().getPlayers())) {
|
||||||
Session s = sessions.get(player.getUUID());
|
Session s = sessions.get(player.getUUID());
|
||||||
if (s == null || s.authenticated) continue;
|
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) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
// Keep the player at the safe Lobby authentication position. World safety is
|
// 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);
|
long remainingSeconds = Math.max(1L, (remainingMillis + 999L) / 1000L);
|
||||||
if (remainingSeconds != s.lastCountdownSecond) {
|
if (remainingSeconds != s.lastCountdownSecond) {
|
||||||
s.lastCountdownSecond = remainingSeconds;
|
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(
|
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)
|
.withStyle(net.minecraft.ChatFormatting.YELLOW)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -275,6 +289,11 @@ public final class AuthManager {
|
|||||||
a.rulesAcceptedAt = Instant.now().toString();
|
a.rulesAcceptedAt = Instant.now().toString();
|
||||||
saveAccounts();
|
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);
|
continueAfterRules(player);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -422,7 +441,7 @@ public final class AuthManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
body.add(plainMessage(lines.toString(), "white"));
|
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);
|
dialog.add("body", body);
|
||||||
|
|
||||||
com.google.gson.JsonArray inputs = new com.google.gson.JsonArray();
|
com.google.gson.JsonArray inputs = new com.google.gson.JsonArray();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import java.util.List;
|
|||||||
public final class RulesConfig {
|
public final class RulesConfig {
|
||||||
public boolean enabled = true;
|
public boolean enabled = true;
|
||||||
public int version = 1;
|
public int version = 1;
|
||||||
|
public int timeoutSeconds = 60;
|
||||||
public String title = "Server Rules";
|
public String title = "Server Rules";
|
||||||
public String introduction = "Please read and accept our rules:";
|
public String introduction = "Please read and accept our rules:";
|
||||||
public List<String> rules = new ArrayList<>(List.of(
|
public List<String> rules = new ArrayList<>(List.of(
|
||||||
|
|||||||
Reference in New Issue
Block a user