diff --git a/README.md b/README.md index 19f2a1e3e..24269f6b9 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,14 @@ There is a dummy user named "Server" in every player's friends list that you can `!resetconst` - Resets the constellation level on your current active character, will need to relog after using the command to see any changes. -`!sethp [hp]` +`!setstats [stats] [amount]` - Changes the current character's specified stat. `!clearartifacts` - Deletes all unequipped and unlocked level 0 artifacts, **including yellow rarity ones** from your inventory +`!pos` - Gets your current coordinate. + +`!weather [weather id]` - Changes the current weather. + *More commands will be updated in the [wiki](https://github.com/Melledy/Grasscutter/wiki/).* ### Bonus diff --git a/proxy.py b/proxy.py index 2d2282af9..86145cde6 100644 --- a/proxy.py +++ b/proxy.py @@ -16,12 +16,14 @@ # - mitmdump from mitmproxy # # @author MlgmXyysd -# @version 1.0 +# @version 1.1 # ## from mitmproxy import http +from proxy_config import USE_SSL from proxy_config import REMOTE_HOST +from proxy_config import REMOTE_PORT class MlgmXyysd_Genshin_Impact_Proxy: @@ -60,7 +62,12 @@ class MlgmXyysd_Genshin_Impact_Proxy: def request(self, flow: http.HTTPFlow) -> None: if flow.request.host in self.LIST_DOMAINS: + if USE_SSL: + flow.request.scheme = "https" + else: + flow.request.scheme = "http" flow.request.host = REMOTE_HOST + flow.request.port = REMOTE_PORT addons = [ MlgmXyysd_Genshin_Impact_Proxy() diff --git a/proxy_config.py b/proxy_config.py index f048ef88c..5025a974e 100644 --- a/proxy_config.py +++ b/proxy_config.py @@ -1,2 +1,4 @@ # This can also be replaced with another IP address. -REMOTE_HOST = "localhost" \ No newline at end of file +USE_SSL = True +REMOTE_HOST = "127.0.0.1" +REMOTE_PORT = 443 \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/Config.java b/src/main/java/emu/grasscutter/Config.java index 8f2701d57..267ab67f2 100644 --- a/src/main/java/emu/grasscutter/Config.java +++ b/src/main/java/emu/grasscutter/Config.java @@ -6,7 +6,7 @@ public final class Config { public String DatabaseUrl = "mongodb://localhost:27017"; public String DatabaseCollection = "grasscutter"; - + public String RESOURCE_FOLDER = "./resources/"; public String DATA_FOLDER = "./data/"; public String PACKETS_FOLDER = "./packets/"; @@ -24,11 +24,9 @@ public final class Config { public DispatchServerOptions getDispatchOptions() { return DispatchServer; } public static class DispatchServerOptions { - public String Ip = "127.0.0.1"; - public String PublicIp = ""; + public String Ip = "0.0.0.0"; + public String PublicIp = "127.0.0.1"; public int Port = 443; - public int OverseaLogPort = 8888; - public int UploadLogPort = 80; public String KeystorePath = "./keystore.p12"; public String KeystorePassword = ""; public Boolean UseSSL = true; @@ -51,8 +49,8 @@ public final class Config { public static class GameServerOptions { public String Name = "Test"; - public String Ip = "127.0.0.1"; - public String PublicIp = ""; + public String Ip = "0.0.0.0"; + public String PublicIp = "127.0.0.1"; public int Port = 22102; public String DispatchServerDatabaseUrl = "mongodb://localhost:27017"; diff --git a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java index 7d15a4759..a533130bc 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java @@ -95,18 +95,19 @@ public final class GiveCommand implements CommandHandler { } private void item(GenshinPlayer player, ItemData itemData, int amount) { - GenshinItem genshinItem = new GenshinItem(itemData); if (itemData.isEquip()) { List items = new LinkedList<>(); for (int i = 0; i < amount; i++) { - items.add(genshinItem); + items.add(new GenshinItem(itemData)); } player.getInventory().addItems(items); player.sendPacket(new PacketItemAddHintNotify(items, ActionReason.SubfieldDrop)); } else { + GenshinItem genshinItem = new GenshinItem(itemData); genshinItem.setCount(amount); player.getInventory().addItem(genshinItem); player.sendPacket(new PacketItemAddHintNotify(genshinItem, ActionReason.SubfieldDrop)); } } } + diff --git a/src/main/java/emu/grasscutter/command/commands/ListCommand.java b/src/main/java/emu/grasscutter/command/commands/ListCommand.java new file mode 100644 index 000000000..6afca4a6d --- /dev/null +++ b/src/main/java/emu/grasscutter/command/commands/ListCommand.java @@ -0,0 +1,33 @@ +package emu.grasscutter.command.commands; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.command.Command; +import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.game.GenshinPlayer; + +import java.util.List; +import java.util.Map; + +@Command(label = "list", description = "List online players") +public class ListCommand implements CommandHandler { + + @Override + public void execute(GenshinPlayer sender, List args) { + Map playersMap = Grasscutter.getGameServer().getPlayers(); + + CommandHandler.sendMessage(sender, String.format("There are %s player(s) online:", playersMap.size())); + + if (playersMap.size() != 0) { + StringBuilder playerSet = new StringBuilder(); + + for (Map.Entry entry : playersMap.entrySet()) { + playerSet.append(entry.getValue().getNickname()); + playerSet.append(", "); + } + + String players = playerSet.toString(); + + CommandHandler.sendMessage(sender, players.substring(0, players.length() - 2)); + } + } +} diff --git a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java index f77c264eb..a058bed6b 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -1,25 +1,10 @@ package emu.grasscutter.server.dispatch; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.URI; -import java.net.URLDecoder; -import java.security.KeyStore; -import java.util.*; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.protobuf.ByteString; import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpsConfigurator; import com.sun.net.httpserver.HttpsServer; @@ -31,29 +16,31 @@ import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegio import emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.QueryRegionListHttpRsp; import emu.grasscutter.net.proto.RegionInfoOuterClass.RegionInfo; import emu.grasscutter.net.proto.RegionSimpleInfoOuterClass.RegionSimpleInfo; -import emu.grasscutter.server.dispatch.json.ComboTokenReqJson; -import emu.grasscutter.server.dispatch.json.ComboTokenResJson; -import emu.grasscutter.server.dispatch.json.LoginAccountRequestJson; -import emu.grasscutter.server.dispatch.json.LoginResultJson; -import emu.grasscutter.server.dispatch.json.LoginTokenRequestJson; +import emu.grasscutter.server.dispatch.json.*; import emu.grasscutter.server.dispatch.json.ComboTokenReqJson.LoginTokenData; import emu.grasscutter.utils.FileUtils; import emu.grasscutter.utils.Utils; -import com.sun.net.httpserver.HttpServer; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import java.io.*; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URLDecoder; +import java.security.KeyStore; +import java.util.*; public final class DispatchServer { + public static String query_region_list = ""; + public static String query_cur_region = ""; + private final InetSocketAddress address; private final Gson gson; private final String defaultServerName = "os_usa"; - //private QueryCurrRegionHttpRsp currRegion; public String regionListBase64; public HashMap regions; - public static String query_region_list = ""; - public static String query_cur_region = ""; - public DispatchServer() { this.regions = new HashMap(); this.address = new InetSocketAddress(Grasscutter.getConfig().getDispatchOptions().Ip, Grasscutter.getConfig().getDispatchOptions().Port); @@ -77,7 +64,7 @@ public final class DispatchServer { return regions.get(defaultServerName).parsedRegionQuery; } - Grasscutter.getLogger().error("Ignore the error below"); + Grasscutter.getLogger().warn("[Dispatch] Unsupported run mode for getCurrRegion()"); return null; } @@ -88,14 +75,14 @@ public final class DispatchServer { if (file.exists()) { query_region_list = new String(FileUtils.read(file)); } else { - Grasscutter.getLogger().warn("query_region_list not found! Using default region list."); + Grasscutter.getLogger().warn("[Dispatch] query_region_list not found! Using default region list."); } file = new File(Grasscutter.getConfig().DATA_FOLDER + "query_cur_region.txt"); if (file.exists()) { query_cur_region = new String(FileUtils.read(file)); } else { - Grasscutter.getLogger().warn("query_cur_region not found! Using default current region."); + Grasscutter.getLogger().warn("[Dispatch] query_cur_region not found! Using default current region."); } } @@ -130,7 +117,7 @@ public final class DispatchServer { } else { if(Grasscutter.getConfig().getDispatchOptions().getGameServers().length == 0) { - Grasscutter.getLogger().error("Dispatch server has no game servers available. Exiting due to unplayable state."); + Grasscutter.getLogger().error("[Dispatch] There are no game servers available. Exiting due to unplayable state."); System.exit(1); } } @@ -174,7 +161,7 @@ public final class DispatchServer { public void start() throws Exception { HttpServer server; - if(Grasscutter.getConfig().getDispatchOptions().UseSSL) { + if (Grasscutter.getConfig().getDispatchOptions().UseSSL) { HttpsServer httpsServer; httpsServer = HttpsServer.create(getAddress(), 0); SSLContext sslContext = SSLContext.getInstance("TLS"); @@ -190,58 +177,36 @@ public final class DispatchServer { httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext)); server = httpsServer; } catch (Exception e) { - Grasscutter.getLogger().error("No SSL cert found!"); - return; + Grasscutter.getLogger().warn("[Dispatch] No SSL cert found! Falling back to HTTP server."); + Grasscutter.getConfig().getDispatchOptions().UseSSL = false; + server = HttpServer.create(getAddress(), 0); } } else { server = HttpServer.create(getAddress(), 0); } - - server.createContext("/", t -> { - //Create a response form the request query parameters - String response = "Hello"; - //Set the response header status and length - t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8")); - t.sendResponseHeaders(200, response.getBytes().length); - //Write the response string - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); - }); + + server.createContext("/", t -> responseHTML(t, "Hello")); // Dispatch server.createContext("/query_region_list", t -> { // Log - Grasscutter.getLogger().info("Client request: query_region_list"); - // Create a response form the request query parameters - String response = regionListBase64; - // Set the response header status and length - t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8")); - t.sendResponseHeaders(200, response.getBytes().length); - // Write the response string - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s request: query_region_list", t.getRemoteAddress())); + + responseHTML(t, regionListBase64); }); for (String regionName : regions.keySet()) { server.createContext("/query_cur_region_" + regionName, t -> { String regionCurrentBase64 = regions.get(regionName).Base64; // Log - Grasscutter.getLogger().info("Client request: query_cur_region_" + regionName); + Grasscutter.getLogger().info(String.format("Client %s request: query_cur_region_%s", t.getRemoteAddress(), regionName)); // Create a response form the request query parameters URI uri = t.getRequestURI(); String response = "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw=="; if (uri.getQuery() != null && uri.getQuery().length() > 0) { response = regionCurrentBase64; } - // Set the response header status and length - t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8")); - t.sendResponseHeaders(200, response.getBytes().length); - // Write the response string - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); + responseHTML(t, response); }); } @@ -252,14 +217,15 @@ public final class DispatchServer { try { String body = Utils.toString(t.getRequestBody()); requestData = getGsonFactory().fromJson(body, LoginAccountRequestJson.class); - } catch (Exception e) { - - } + } catch (Exception ignored) { } + // Create response json if (requestData == null) { return; } LoginResultJson responseData = new LoginResultJson(); + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s is trying to log in", t.getRemoteAddress())); // Login Account account = DatabaseHelper.getAccountByName(requestData.account); @@ -270,14 +236,25 @@ public final class DispatchServer { if (Grasscutter.getConfig().getDispatchOptions().AutomaticallyCreateAccounts) { // This account has been created AUTOMATICALLY. There will be no permissions added. account = DatabaseHelper.createAccountWithId(requestData.account, 0); - - responseData.message = "OK"; - responseData.data.account.uid = account.getId(); - responseData.data.account.token = account.generateSessionKey(); - responseData.data.account.email = account.getEmail(); + + if (account != null) { + responseData.message = "OK"; + responseData.data.account.uid = account.getId(); + responseData.data.account.token = account.generateSessionKey(); + responseData.data.account.email = account.getEmail(); + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s failed to log in: Account %s created", t.getRemoteAddress(), responseData.data.account.uid)); + } else { + responseData.retcode = -201; + responseData.message = "Username not found, create failed."; + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s failed to log in: Account create failed", t.getRemoteAddress())); + } } else { responseData.retcode = -201; responseData.message = "Username not found."; + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s failed to log in: Account no found", t.getRemoteAddress())); } } else { // Account was found, log the player in @@ -285,17 +262,11 @@ public final class DispatchServer { responseData.data.account.uid = account.getId(); responseData.data.account.token = account.generateSessionKey(); responseData.data.account.email = account.getEmail(); + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s logged in as %s", t.getRemoteAddress(), responseData.data.account.uid)); } - - // Create a response - String response = getGsonFactory().toJson(responseData); - // Set the response header status and length - t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json")); - t.sendResponseHeaders(200, response.getBytes().length); - // Write the response string - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); + + responseJSON(t, responseData); }); // Login via token server.createContext("/hk4e_global/mdk/shield/api/verify", t -> { @@ -304,14 +275,14 @@ public final class DispatchServer { try { String body = Utils.toString(t.getRequestBody()); requestData = getGsonFactory().fromJson(body, LoginTokenRequestJson.class); - } catch (Exception e) { - - } + } catch (Exception ignored) { } + // Create response json if (requestData == null) { return; } LoginResultJson responseData = new LoginResultJson(); + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s is trying to log in via token", t.getRemoteAddress())); // Login Account account = DatabaseHelper.getAccountById(requestData.uid); @@ -320,22 +291,18 @@ public final class DispatchServer { if (account == null || !account.getSessionKey().equals(requestData.token)) { responseData.retcode = -111; responseData.message = "Game account cache information error"; + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s failed to log in via token", t.getRemoteAddress())); } else { responseData.message = "OK"; responseData.data.account.uid = requestData.uid; responseData.data.account.token = requestData.token; responseData.data.account.email = account.getEmail(); + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s logged in via token as %s", t.getRemoteAddress(), responseData.data.account.uid)); } - - // Create a response - String response = getGsonFactory().toJson(responseData); - // Set the response header status and length - t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json")); - t.sendResponseHeaders(200, response.getBytes().length); - // Write the response string - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); + + responseJSON(t, responseData); }); // Exchange for combo token server.createContext("/hk4e_global/combo/granter/login/v2/login", t -> { @@ -344,9 +311,8 @@ public final class DispatchServer { try { String body = Utils.toString(t.getRequestBody()); requestData = getGsonFactory().fromJson(body, ComboTokenReqJson.class); - } catch (Exception e) { - - } + } catch (Exception ignored) { } + // Create response json if (requestData == null || requestData.data == null) { return; @@ -361,22 +327,18 @@ public final class DispatchServer { if (account == null || !account.getSessionKey().equals(loginData.token)) { responseData.retcode = -201; responseData.message = "Wrong session key."; + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s failed to exchange combo token", t.getRemoteAddress())); } else { responseData.message = "OK"; responseData.data.open_id = loginData.uid; responseData.data.combo_id = "157795300"; responseData.data.combo_token = account.generateLoginToken(); + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s succeed to exchange combo token", t.getRemoteAddress())); } - - // Create a response - String response = getGsonFactory().toJson(responseData); - // Set the response header status and length - t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json")); - t.sendResponseHeaders(200, response.getBytes().length); - // Write the response string - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); + + responseJSON(t, responseData); }); // Agreement and Protocol server.createContext( // hk4e-sdk-os.hoyoverse.com @@ -444,64 +406,74 @@ public final class DispatchServer { "/perf/config/verify", new DispatchHttpJsonHandler("{\"code\":0}") ); - // Start server - server.start(); - Grasscutter.getLogger().info("Dispatch server started on port " + getAddress().getPort()); // Logging servers - HttpServer overseaLogServer = HttpServer.create(new InetSocketAddress(Grasscutter.getConfig().getDispatchOptions().Ip, Grasscutter.getConfig().getDispatchOptions().OverseaLogPort), 0); - overseaLogServer.createContext( // overseauspider.yuanshen.com - "/log", + server.createContext( // overseauspider.yuanshen.com + "/log", new DispatchHttpJsonHandler("{\"code\":0}") ); - overseaLogServer.start(); - Grasscutter.getLogger().info("Log server (overseauspider) started on port " + 8888); - - HttpServer uploadLogServer = HttpServer.create(new InetSocketAddress(Grasscutter.getConfig().getDispatchOptions().Ip, Grasscutter.getConfig().getDispatchOptions().UploadLogPort), 0); - uploadLogServer.createContext( // log-upload-os.mihoyo.com - "/crash/dataUpload", + + server.createContext( // log-upload-os.mihoyo.com + "/crash/dataUpload", new DispatchHttpJsonHandler("{\"code\":0}") ); - uploadLogServer.createContext("/gacha", t -> { - //Create a response form the request query parameters - String response = "Gacha"; - //Set the response header status and length - t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8")); - t.sendResponseHeaders(200, response.getBytes().length); - //Write the response string - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); - }); - uploadLogServer.start(); - Grasscutter.getLogger().info("Log server (log-upload-os) started on port " + Grasscutter.getConfig().getDispatchOptions().UploadLogPort); + server.createContext("/gacha", t -> responseHTML(t, "Gacha")); + + // Start server + server.start(); + Grasscutter.getLogger().info("[Dispatch] Dispatch server started on port " + getAddress().getPort()); + } + + private void responseJSON(HttpExchange t, Object data) throws IOException { + // Create a response + String response = getGsonFactory().toJson(data); + // Set the response header status and length + t.getResponseHeaders().put("Content-Type", Collections.singletonList("application/json")); + t.sendResponseHeaders(200, response.getBytes().length); + // Write the response string + OutputStream os = t.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + + private void responseHTML(HttpExchange t, String response) throws IOException { + // Set the response header status and length + t.getResponseHeaders().put("Content-Type", Collections.singletonList("text/html; charset=UTF-8")); + t.sendResponseHeaders(200, response.getBytes().length); + //Write the response string + OutputStream os = t.getResponseBody(); + os.write(response.getBytes()); + os.close(); } private Map parseQueryString(String qs) { - Map result = new HashMap<>(); - if (qs == null) - return result; + Map result = new HashMap<>(); + if (qs == null) { + return result; + } - int last = 0, next, l = qs.length(); - while (last < l) { - next = qs.indexOf('&', last); - if (next == -1) - next = l; + int last = 0, next, l = qs.length(); + while (last < l) { + next = qs.indexOf('&', last); + if (next == -1) { + next = l; + } - if (next > last) { - int eqPos = qs.indexOf('=', last); - try { - if (eqPos < 0 || eqPos > next) - result.put(URLDecoder.decode(qs.substring(last, next), "utf-8"), ""); - else - result.put(URLDecoder.decode(qs.substring(last, eqPos), "utf-8"), URLDecoder.decode(qs.substring(eqPos + 1, next), "utf-8")); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); // will never happen, utf-8 support is mandatory for java - } - } - last = next + 1; - } - return result; + if (next > last) { + int eqPos = qs.indexOf('=', last); + try { + if (eqPos < 0 || eqPos > next) { + result.put(URLDecoder.decode(qs.substring(last, next), "utf-8"), ""); + } else { + result.put(URLDecoder.decode(qs.substring(last, eqPos), "utf-8"), URLDecoder.decode(qs.substring(eqPos + 1, next), "utf-8")); + } + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); // will never happen, utf-8 support is mandatory for java + } + } + last = next + 1; + } + return result; } public static class RegionData { diff --git a/src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenReqJson.java b/src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenReqJson.java index dac26cfa4..b3497f8d4 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenReqJson.java +++ b/src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenReqJson.java @@ -7,7 +7,7 @@ public class ComboTokenReqJson { public String device; public String sign; - public class LoginTokenData { + public static class LoginTokenData { public String uid; public String token; public boolean guest; diff --git a/src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenResJson.java b/src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenResJson.java index 731d50853..7c49d1278 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenResJson.java +++ b/src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenResJson.java @@ -5,7 +5,7 @@ public class ComboTokenResJson { public int retcode; public LoginData data = new LoginData(); - public class LoginData { + public static class LoginData { public int account_type = 1; public boolean heartbeat; public String combo_id; diff --git a/src/main/java/emu/grasscutter/server/dispatch/json/LoginResultJson.java b/src/main/java/emu/grasscutter/server/dispatch/json/LoginResultJson.java index 5988752d8..88e142d4f 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/json/LoginResultJson.java +++ b/src/main/java/emu/grasscutter/server/dispatch/json/LoginResultJson.java @@ -5,7 +5,7 @@ public class LoginResultJson { public int retcode; public VerifyData data = new VerifyData(); - public class VerifyData { + public static class VerifyData { public VerifyAccountData account = new VerifyAccountData(); public boolean device_grant_required = false; public String realname_operation = "NONE"; @@ -13,7 +13,7 @@ public class LoginResultJson { public boolean safe_mobile_required = false; } - public class VerifyAccountData { + public static class VerifyAccountData { public String uid; public String name = ""; public String email; diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketSceneUnlockInfoNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketSceneUnlockInfoNotify.java index fb45bb361..bd1b30685 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketSceneUnlockInfoNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketSceneUnlockInfoNotify.java @@ -12,7 +12,7 @@ public class PacketSceneUnlockInfoNotify extends GenshinPacket { SceneUnlockInfoNotify proto = SceneUnlockInfoNotify.newBuilder() .addUnlockInfos(SceneUnlockInfo.newBuilder().setSceneId(1)) - .addUnlockInfos(SceneUnlockInfo.newBuilder().setSceneId(3)) + .addUnlockInfos(SceneUnlockInfo.newBuilder().setSceneId(3).addSceneTagIdList(102).addSceneTagIdList(113).addSceneTagIdList(117)) .addUnlockInfos(SceneUnlockInfo.newBuilder().setSceneId(4).addSceneTagIdList(106).addSceneTagIdList(109)) .addUnlockInfos(SceneUnlockInfo.newBuilder().setSceneId(5)) .addUnlockInfos(SceneUnlockInfo.newBuilder().setSceneId(6))