From b2a07044e260c573f5f72bf62f046d81e53856dc Mon Sep 17 00:00:00 2001 From: ButterCookies <44562331+Coooookies@users.noreply.github.com> Date: Fri, 20 May 2022 20:47:47 +0800 Subject: [PATCH] Set the maximum number of player on the server through the config.json (#1001) * Show server status to three-party game launcher * Set the maximum number of player on the server through the config.json * modify the logical order and show the number of maxplayer to API /status/server * Now even players who have token already cannot bypass the maxPlayer check --- .../auth/DefaultAuthenticators.java | 173 +++++++++++------- .../server/http/handlers/GenericHandler.java | 5 +- .../packet/recv/HandlerPlayerLoginReq.java | 10 +- .../grasscutter/utils/ConfigContainer.java | 1 + src/main/resources/languages/en-US.json | 4 +- src/main/resources/languages/pl-PL.json | 4 +- src/main/resources/languages/zh-CN.json | 4 +- src/main/resources/languages/zh-TW.json | 4 +- 8 files changed, 128 insertions(+), 77 deletions(-) diff --git a/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java b/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java index 0a9916a59..7c13fa1a5 100644 --- a/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java +++ b/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java @@ -23,32 +23,42 @@ public final class DefaultAuthenticators { var requestData = request.getPasswordRequest(); assert requestData != null; // This should never be null. - + int playerCount = Grasscutter.getGameServer().getPlayers().size(); + boolean successfulLogin = false; String address = request.getRequest().ip(); String responseMessage = translate("messages.dispatch.account.username_error"); - + String loggerMessage = ""; + // Get account from database. Account account = DatabaseHelper.getAccountByName(requestData.account); - - // Check if account exists. - if(account == null && ACCOUNT.autoCreate) { - // This account has been created AUTOMATICALLY. There will be no permissions added. - account = DatabaseHelper.createAccountWithId(requestData.account, 0); - - // Check if the account was created successfully. - if(account == null) { - responseMessage = translate("messages.dispatch.account.username_create_error"); - Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_error", address)); - } else { - // Continue with login. - successfulLogin = true; + if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) { + // Check if account exists. + if(account == null && ACCOUNT.autoCreate) { + // This account has been created AUTOMATICALLY. There will be no permissions added. + account = DatabaseHelper.createAccountWithId(requestData.account, 0); + + // Check if the account was created successfully. + if(account == null) { + responseMessage = translate("messages.dispatch.account.username_create_error"); + Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_error", address)); + } else { + // Continue with login. + successfulLogin = true; + + // Log the creation. + Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_success", address, response.data.account.uid)); + } + } else if(account != null) + successfulLogin = true; + else + loggerMessage = translate("messages.dispatch.account.account_login_exist_error", address); + + } else { + responseMessage = translate("messages.dispatch.account.server_max_player_limit"); + loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address); + } - // Log the creation. - Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_success", address, response.data.account.uid)); - } - } else if(account != null) - successfulLogin = true; // Set response data. if(successfulLogin) { @@ -56,17 +66,15 @@ public final class DefaultAuthenticators { response.data.account.uid = account.getId(); response.data.account.token = account.generateSessionKey(); response.data.account.email = account.getEmail(); - - // Log the login. - Grasscutter.getLogger().info(translate("messages.dispatch.account.login_success", address, account.getId())); + + loggerMessage = translate("messages.dispatch.account.login_success", address, account.getId()); } else { response.retcode = -201; response.message = responseMessage; - - // Log the failure. - Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_exist_error", address)); + } - + Grasscutter.getLogger().info(loggerMessage); + return response; } } @@ -80,36 +88,48 @@ public final class DefaultAuthenticators { var requestData = request.getTokenRequest(); assert requestData != null; - + boolean successfulLogin; String address = request.getRequest().ip(); - + String loggerMessage; + int playerCount = Grasscutter.getGameServer().getPlayers().size(); + // Log the attempt. Grasscutter.getLogger().info(translate("messages.dispatch.account.login_token_attempt", address)); - - // Get account from database. - Account account = DatabaseHelper.getAccountById(requestData.uid); - - // Check if account exists/token is valid. - successfulLogin = account != null && account.getSessionKey().equals(requestData.token); - - // Set response data. - if(successfulLogin) { - response.message = "OK"; - response.data.account.uid = account.getId(); - response.data.account.token = account.getSessionKey(); - response.data.account.email = account.getEmail(); - - // Log the login. - Grasscutter.getLogger().info(translate("messages.dispatch.account.login_token_success", address, requestData.uid)); + + if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) { + + // Get account from database. + Account account = DatabaseHelper.getAccountById(requestData.uid); + + // Check if account exists/token is valid. + successfulLogin = account != null && account.getSessionKey().equals(requestData.token); + + // Set response data. + if(successfulLogin) { + response.message = "OK"; + response.data.account.uid = account.getId(); + response.data.account.token = account.getSessionKey(); + response.data.account.email = account.getEmail(); + + // Log the login. + loggerMessage = translate("messages.dispatch.account.login_token_success", address, requestData.uid); + } else { + response.retcode = -201; + response.message = translate("messages.dispatch.account.account_cache_error"); + + // Log the failure. + loggerMessage = translate("messages.dispatch.account.login_token_error", address); + } + } else { response.retcode = -201; - response.message = translate("messages.dispatch.account.account_cache_error"); - - // Log the failure. - Grasscutter.getLogger().info(translate("messages.dispatch.account.login_token_error", address)); + response.message = translate("messages.dispatch.account.server_max_player_limit"); + + loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address); } - + + Grasscutter.getLogger().info(loggerMessage); return response; } } @@ -127,30 +147,41 @@ public final class DefaultAuthenticators { boolean successfulLogin; String address = request.getRequest().ip(); - - // Get account from database. - Account account = DatabaseHelper.getAccountById(loginData.uid); - - // Check if account exists/token is valid. - successfulLogin = account != null && account.getSessionKey().equals(loginData.token); - - // Set response data. - if(successfulLogin) { - response.message = "OK"; - response.data.open_id = account.getId(); - response.data.combo_id = "157795300"; - response.data.combo_token = account.generateLoginToken(); - - // Log the login. - Grasscutter.getLogger().info(translate("messages.dispatch.account.combo_token_success", address)); + String loggerMessage; + int playerCount = Grasscutter.getGameServer().getPlayers().size(); + + if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) { + // Get account from database. + Account account = DatabaseHelper.getAccountById(loginData.uid); + + // Check if account exists/token is valid. + successfulLogin = account != null && account.getSessionKey().equals(loginData.token); + + // Set response data. + if(successfulLogin) { + response.message = "OK"; + response.data.open_id = account.getId(); + response.data.combo_id = "157795300"; + response.data.combo_token = account.generateLoginToken(); + + // Log the login. + loggerMessage = translate("messages.dispatch.account.combo_token_success", address); + + } else { + response.retcode = -201; + response.message = translate("messages.dispatch.account.session_key_error"); + + // Log the failure. + loggerMessage = translate("messages.dispatch.account.combo_token_error", address); + } } else { response.retcode = -201; - response.message = translate("messages.dispatch.account.session_key_error"); - - // Log the failure. - Grasscutter.getLogger().info(translate("messages.dispatch.account.combo_token_error", address)); + response.message = translate("messages.dispatch.account.server_max_player_limit"); + + loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address); } - + + Grasscutter.getLogger().info(loggerMessage); return response; } } diff --git a/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java b/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java index c108ba776..6bf54cff1 100644 --- a/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java +++ b/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java @@ -9,6 +9,8 @@ import express.http.Request; import express.http.Response; import io.javalin.Javalin; +import static emu.grasscutter.Configuration.ACCOUNT; + /** * Handles all generic, hard-coded responses. */ @@ -48,8 +50,9 @@ public final class GenericHandler implements Router { private static void serverStatus(Request request, Response response) { int playerCount = Grasscutter.getGameServer().getPlayers().size(); + int maxPlayer = ACCOUNT.maxPlayer; String version = GameConstants.VERSION; - response.send("{\"retcode\":0,\"status\":{\"playerCount\":" + playerCount + ",\"version\":\"" + version + "\"}}"); + response.send("{\"retcode\":0,\"status\":{\"playerCount\":" + playerCount + ",\"maxPlayer\":" + maxPlayer + ",\"version\":\"" + version + "\"}}"); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java index cfdce5b59..d7aedb757 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java @@ -1,5 +1,6 @@ package emu.grasscutter.server.packet.recv; +import emu.grasscutter.Grasscutter; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.BasePacket; @@ -12,6 +13,8 @@ import emu.grasscutter.server.game.GameSession.SessionState; import emu.grasscutter.server.packet.send.PacketPlayerLoginRsp; import emu.grasscutter.server.packet.send.PacketTakeAchievementRewardReq; +import static emu.grasscutter.Configuration.ACCOUNT; + @Opcodes(PacketOpcodes.PlayerLoginReq) // Sends initial data packets public class HandlerPlayerLoginReq extends PacketHandler { @@ -21,7 +24,12 @@ public class HandlerPlayerLoginReq extends PacketHandler { if (session.getAccount() == null) { return; } - + + // Max players limit + if (ACCOUNT.maxPlayer > -1 && Grasscutter.getGameServer().getPlayers().size() >= ACCOUNT.maxPlayer) { + return; + } + // Parse request PlayerLoginReq req = PlayerLoginReq.parseFrom(payload); diff --git a/src/main/java/emu/grasscutter/utils/ConfigContainer.java b/src/main/java/emu/grasscutter/utils/ConfigContainer.java index 2d44659f5..654d77dd4 100644 --- a/src/main/java/emu/grasscutter/utils/ConfigContainer.java +++ b/src/main/java/emu/grasscutter/utils/ConfigContainer.java @@ -110,6 +110,7 @@ public class ConfigContainer { public static class Account { public boolean autoCreate = false; public String[] defaultPermissions = {}; + public int maxPlayer = -1; } /* Server options. */ diff --git a/src/main/resources/languages/en-US.json b/src/main/resources/languages/en-US.json index f25f94baa..8b31abd8e 100644 --- a/src/main/resources/languages/en-US.json +++ b/src/main/resources/languages/en-US.json @@ -24,6 +24,7 @@ "account": { "login_attempt": "[Dispatch] Client %s is trying to log in.", "login_success": "[Dispatch] Client %s logged in as %s.", + "login_max_player_limit": "[Dispatch] Client %s failed to log in: The number of online players has reached the limit", "login_token_attempt": "[Dispatch] Client %s is trying to log in via token.", "login_token_error": "[Dispatch] Client %s failed to log in via token.", "login_token_success": "[Dispatch] Client %s logged in via token as %s.", @@ -35,7 +36,8 @@ "account_cache_error": "Game account cache information error.", "session_key_error": "Wrong session key.", "username_error": "Username not found.", - "username_create_error": "Username not found, create failed." + "username_create_error": "Username not found, create failed.", + "server_max_player_limit": "The number of online players has reached the limit" }, "router_error": "[Dispatch] Unable to attach router." }, diff --git a/src/main/resources/languages/pl-PL.json b/src/main/resources/languages/pl-PL.json index 968d91f01..e2a3e9272 100644 --- a/src/main/resources/languages/pl-PL.json +++ b/src/main/resources/languages/pl-PL.json @@ -21,6 +21,7 @@ "account": { "login_attempt": "[Dispatch] Klient %s próbuje się zalogować", "login_success": "[Dispatch] Klient %s zalogował się jako %s", + "login_max_player_limit": "[Dispatch] Klient %s nie powiodło się: Liczba graczy online osiągnęła limit", "login_token_attempt": "[Dispatch] Klient %s próbuje się zalogować poprzez token", "login_token_error": "[Dispatch] Klient %s nie mógł się zalogować poprzez token", "login_token_success": "[Dispatch] Klient %s zalogował się poprzez token jako %s", @@ -32,7 +33,8 @@ "account_cache_error": "Błąd pamięci cache konta gry", "session_key_error": "Błędny klucz sesji.", "username_error": "Nazwa użytkownika nie znaleziona.", - "username_create_error": "Nazwa użytkownika nie znaleziona, tworzenie nie powiodło się." + "username_create_error": "Nazwa użytkownika nie znaleziona, tworzenie nie powiodło się.", + "server_max_player_limit": "Liczba graczy online osiągnęła limit" } }, "status": { diff --git a/src/main/resources/languages/zh-CN.json b/src/main/resources/languages/zh-CN.json index ccf22d4dd..e16c79d10 100644 --- a/src/main/resources/languages/zh-CN.json +++ b/src/main/resources/languages/zh-CN.json @@ -24,6 +24,7 @@ "account": { "login_attempt": "[Dispatch] 客户端 %s 正在尝试登录", "login_success": "[Dispatch] 客户端 %s 已登录,UID 为 %s", + "login_max_player_limit": "[Dispatch] 客户端 %s 登录失败:在线人数已满", "login_token_attempt": "[Dispatch] 客户端 %s 正在尝试使用 token 登录", "login_token_error": "[Dispatch] 客户端 %s 使用 token 登录失败", "login_token_success": "[Dispatch] 客户端 %s 已通过 token 登录,UID 为 %s", @@ -35,7 +36,8 @@ "account_cache_error": "游戏账号缓存信息错误", "session_key_error": "会话密钥错误", "username_error": "未找到此用户名", - "username_create_error": "未找到用户名,建立连接失败" + "username_create_error": "未找到用户名,建立连接失败", + "server_max_player_limit": "服务器在线人数已满" }, "router_error": "[Dispatch] 无法连接路由" }, diff --git a/src/main/resources/languages/zh-TW.json b/src/main/resources/languages/zh-TW.json index 859841d65..e13488e2d 100644 --- a/src/main/resources/languages/zh-TW.json +++ b/src/main/resources/languages/zh-TW.json @@ -24,6 +24,7 @@ "account": { "login_attempt": "[Dispatch] 客戶端 %s 正在嘗試登入", "login_success": "[Dispatch] 客戶端 %s 已登入,UID為 %s", + "login_max_player_limit": "[Dispatch] 客戶端 %s 登入失敗:在綫人數已滿", "login_token_attempt": "[Dispatch] 客戶端 %s 正在嘗試用憑證登入", "login_token_error": "[Dispatch] 客戶端 %s 使用憑證登入失敗", "login_token_success": "[Dispatch] 客戶端 %s 已透過憑證登入,UID為 %s", @@ -35,7 +36,8 @@ "account_cache_error": "遊戲帳號緩存資訊錯誤", "session_key_error": "對話密鑰不符。", "username_error": "未找到此用戶名。", - "username_create_error": "未找到用戶名,建立失敗。" + "username_create_error": "未找到用戶名,建立失敗。", + "server_max_player_limit": "服務器在綫人數已滿" } }, "status": {