Commit 22cbe748 authored by Magix's avatar Magix Committed by GitHub
Browse files

Merge pull request #802 from Grasscutters/better-config

Implement a better config structure
parents 54cf45a7 812f4b37
......@@ -31,6 +31,8 @@ import emu.grasscutter.scripts.data.ScriptArgs;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import static emu.grasscutter.Configuration.*;
public class SceneScriptManager {
private final Scene scene;
private final ScriptLib scriptLib;
......@@ -164,7 +166,7 @@ public class SceneScriptManager {
private void init() {
// Get compiled script if cached
CompiledScript cs = ScriptLoader.getScriptByPath(
Grasscutter.getConfig().SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "." + ScriptLoader.getScriptType());
SCRIPT("Scene/" + getScene().getId() + "/scene" + getScene().getId() + "." + ScriptLoader.getScriptType()));
if (cs == null) {
Grasscutter.getLogger().warn("No script found for scene " + getScene().getId());
......@@ -211,7 +213,7 @@ public class SceneScriptManager {
private void loadBlockFromScript(SceneBlock block) {
CompiledScript cs = ScriptLoader.getScriptByPath(
Grasscutter.getConfig().SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "_block" + block.id + "." + ScriptLoader.getScriptType());
SCRIPT("Scene/" + getScene().getId() + "/scene" + getScene().getId() + "_block" + block.id + "." + ScriptLoader.getScriptType()));
if (cs == null) {
return;
......@@ -234,7 +236,7 @@ public class SceneScriptManager {
group.setLoaded(true);
CompiledScript cs = ScriptLoader.getScriptByPath(
Grasscutter.getConfig().SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "_group" + group.id + "." + ScriptLoader.getScriptType());
SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "_group" + group.id + "." + ScriptLoader.getScriptType());
if (cs == null) {
return;
......@@ -281,9 +283,7 @@ public class SceneScriptManager {
if (gadget != null) {
suite.sceneGadgets.add(gadget);
}
} catch (Exception e) {
continue;
}
} catch (Exception ignored) { }
}
}
this.sceneGroups.put(group.id, group);
......
......@@ -10,26 +10,29 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.util.Objects;
import static emu.grasscutter.Configuration.*;
public final class AnnouncementHandler implements HttpContextHandler {
@Override
public void handle(Request request, Response response) throws IOException {//event
if (Objects.equals(request.baseUrl(), "/common/hk4e_global/announcement/api/getAnnContent")) {
response.send("{\"retcode\":0,\"message\":\"OK\",\"data\":" + readToString(new File(Grasscutter.getConfig().DATA_FOLDER + "GameAnnouncement.json")) +"}");
response.send("{\"retcode\":0,\"message\":\"OK\",\"data\":" + readToString(new File(DATA("GameAnnouncement.json"))) +"}");
} else if (Objects.equals(request.baseUrl(), "/common/hk4e_global/announcement/api/getAnnList")) {
String data = readToString(new File(Grasscutter.getConfig().DATA_FOLDER + "GameAnnouncementList.json")).replace("System.currentTimeMillis()",String.valueOf(System.currentTimeMillis()));
String data = readToString(new File(DATA("GameAnnouncementList.json"))).replace("System.currentTimeMillis()",String.valueOf(System.currentTimeMillis()));
response.send("{\"retcode\":0,\"message\":\"OK\",\"data\": "+data +"}");
}
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private static String readToString(File file) {
Long filelength = file.length();
byte[] filecontent = new byte[filelength.intValue()];
long length = file.length();
byte[] content = new byte[(int) length];
try {
FileInputStream in = new FileInputStream(file);
in.read(filecontent);
in.close();
} catch (IOException fileNotFoundException) {
fileNotFoundException.printStackTrace();
in.read(content); in.close();
} catch (IOException ignored) {
Grasscutter.getLogger().warn("File not found: " + file.getAbsolutePath());
}
return new String(filecontent);
return new String(content);
}
}
\ No newline at end of file
......@@ -11,6 +11,7 @@ import express.http.Request;
import express.http.Response;
import static emu.grasscutter.utils.Language.translate;
import static emu.grasscutter.Configuration.*;
public final class DispatchHttpJsonHandler implements HttpContextHandler {
private final String response;
......@@ -34,8 +35,8 @@ public final class DispatchHttpJsonHandler implements HttpContextHandler {
@Override
public void handle(Request req, Response res) throws IOException {
// Checking for ALL here isn't required as when ALL is enabled enableDevLogging() gets enabled
if(Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING && Arrays.stream(missingRoutes).anyMatch(x -> Objects.equals(x, req.baseUrl()))) {
Grasscutter.getLogger().info(translate("messages.dispatch.request", req.ip(), req.method(), req.baseUrl()) + (Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING ? "(MISSING)" : ""));
if(SERVER.debugLevel == ServerDebugMode.MISSING && Arrays.stream(missingRoutes).anyMatch(x -> Objects.equals(x, req.baseUrl()))) {
Grasscutter.getLogger().info(translate("messages.dispatch.request", req.ip(), req.method(), req.baseUrl()) + (SERVER.debugLevel == ServerDebugMode.MISSING ? "(MISSING)" : ""));
}
res.send(response);
}
......
......@@ -4,7 +4,6 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.protobuf.ByteString;
import emu.grasscutter.Config;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.Grasscutter.ServerDebugMode;
import emu.grasscutter.Grasscutter.ServerRunMode;
......@@ -33,9 +32,11 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
import java.io.*;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static emu.grasscutter.utils.Language.translate;
import static emu.grasscutter.Configuration.*;
public final class DispatchServer {
public static String query_region_list = "";
......@@ -64,7 +65,7 @@ public final class DispatchServer {
public void setHttpServer(Express httpServer) {
this.httpServer.stop();
this.httpServer = httpServer;
this.httpServer.listen(Grasscutter.getConfig().getDispatchOptions().Port);
this.httpServer.listen(DISPATCH_INFO.bindPort);
}
public Gson getGsonFactory() {
......@@ -73,7 +74,7 @@ public final class DispatchServer {
public QueryCurrRegionHttpRsp getCurrRegion() {
// Needs to be fixed by having the game servers connect to the dispatch server.
if (Grasscutter.getConfig().RunMode == ServerRunMode.HYBRID) {
if (SERVER.runMode == ServerRunMode.HYBRID) {
return regions.get(defaultServerName).parsedRegionQuery;
}
......@@ -84,14 +85,14 @@ public final class DispatchServer {
public void loadQueries() {
File file;
file = new File(Grasscutter.getConfig().DATA_FOLDER + "query_region_list.txt");
file = new File(DATA("query_region_list.txt"));
if (file.exists()) {
query_region_list = new String(FileUtils.read(file));
} else {
Grasscutter.getLogger().warn("[Dispatch] query_region_list not found! Using default region list.");
}
file = new File(Grasscutter.getConfig().DATA_FOLDER + "query_cur_region.txt");
file = new File(DATA("query_cur_region.txt"));
if (file.exists()) {
query_cur_region = new String(FileUtils.read(file));
} else {
......@@ -108,52 +109,37 @@ public final class DispatchServer {
QueryCurrRegionHttpRsp regionQuery = QueryCurrRegionHttpRsp.parseFrom(decoded2);
List<RegionSimpleInfo> servers = new ArrayList<>();
List<String> usedNames = new ArrayList<>(); // List to check for potential naming conflicts
if (Grasscutter.getConfig().RunMode == ServerRunMode.HYBRID) { // Automatically add the game server if in
// hybrid mode
List<String> usedNames = new ArrayList<>(); // List to check for potential naming conflicts.
if (SERVER.runMode == ServerRunMode.HYBRID) { // Automatically add the game server if in hybrid mode.
RegionSimpleInfo server = RegionSimpleInfo.newBuilder()
.setName("os_usa")
.setTitle(Grasscutter.getConfig().getGameServerOptions().Name)
.setTitle(DISPATCH_INFO.defaultName)
.setType("DEV_PUBLIC")
.setDispatchUrl(
"http" + (Grasscutter.getConfig().getDispatchOptions().FrontHTTPS ? "s" : "") + "://"
+ (Grasscutter.getConfig().getDispatchOptions().PublicIp.isEmpty()
? Grasscutter.getConfig().getDispatchOptions().Ip
: Grasscutter.getConfig().getDispatchOptions().PublicIp)
+ ":"
+ (Grasscutter.getConfig().getDispatchOptions().PublicPort != 0
? Grasscutter.getConfig().getDispatchOptions().PublicPort
: Grasscutter.getConfig().getDispatchOptions().Port)
"http" + (DISPATCH_ENCRYPTION.useEncryption ? "s" : "") + "://"
+ lr(DISPATCH_INFO.accessAddress, DISPATCH_INFO.bindAddress) + ":"
+ lr(DISPATCH_INFO.accessPort, DISPATCH_INFO.bindPort)
+ "/query_cur_region/" + defaultServerName)
.build();
usedNames.add(defaultServerName);
servers.add(server);
RegionInfo serverRegion = regionQuery.getRegionInfo().toBuilder()
.setGateserverIp((Grasscutter.getConfig().getGameServerOptions().PublicIp.isEmpty()
? Grasscutter.getConfig().getGameServerOptions().Ip
: Grasscutter.getConfig().getGameServerOptions().PublicIp))
.setGateserverPort(Grasscutter.getConfig().getGameServerOptions().PublicPort != 0
? Grasscutter.getConfig().getGameServerOptions().PublicPort
: Grasscutter.getConfig().getGameServerOptions().Port)
.setSecretKey(ByteString
.copyFrom(FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "dispatchSeed.bin")))
.setGateserverIp(lr(DISPATCH_INFO.accessAddress, DISPATCH_INFO.bindAddress))
.setGateserverPort(lr(DISPATCH_INFO.accessPort, DISPATCH_INFO.bindPort))
.setSecretKey(ByteString.copyFrom(FileUtils.read(KEYS_FOLDER + "/dispatchSeed.bin")))
.build();
QueryCurrRegionHttpRsp parsedRegionQuery = regionQuery.toBuilder().setRegionInfo(serverRegion).build();
regions.put(defaultServerName, new RegionData(parsedRegionQuery,
Base64.getEncoder().encodeToString(parsedRegionQuery.toByteString().toByteArray())));
} else {
if (Grasscutter.getConfig().getDispatchOptions().getGameServers().length == 0) {
Grasscutter.getLogger()
.error("[Dispatch] There are no game servers available. Exiting due to unplayable state.");
System.exit(1);
}
} else if (DISPATCH_INFO.regions.length == 0) {
Grasscutter.getLogger().error("[Dispatch] There are no game servers available. Exiting due to unplayable state.");
System.exit(1);
}
for (Config.DispatchServerOptions.RegionInfo regionInfo : Grasscutter.getConfig().getDispatchOptions()
.getGameServers()) {
for (var regionInfo : DISPATCH_INFO.regions) {
if (usedNames.contains(regionInfo.Name)) {
Grasscutter.getLogger().error("Region name already in use.");
continue;
......@@ -163,13 +149,10 @@ public final class DispatchServer {
.setTitle(regionInfo.Title)
.setType("DEV_PUBLIC")
.setDispatchUrl(
"http" + (Grasscutter.getConfig().getDispatchOptions().FrontHTTPS ? "s" : "") + "://"
+ (Grasscutter.getConfig().getDispatchOptions().PublicIp.isEmpty()
? Grasscutter.getConfig().getDispatchOptions().Ip
: Grasscutter.getConfig().getDispatchOptions().PublicIp)
+ ":" + (Grasscutter.getConfig().getDispatchOptions().PublicPort != 0
? Grasscutter.getConfig().getDispatchOptions().PublicPort
: Grasscutter.getConfig().getDispatchOptions().Port) + "/query_cur_region/" + regionInfo.Name)
"http" + (DISPATCH_ENCRYPTION.useEncryption ? "s" : "") + "://"
+ lr(DISPATCH_INFO.accessAddress, DISPATCH_INFO.bindAddress) + ":"
+ lr(DISPATCH_INFO.accessPort, DISPATCH_INFO.bindPort)
+ "/query_cur_region/" + regionInfo.Name)
.build();
usedNames.add(regionInfo.Name);
servers.add(server);
......@@ -178,7 +161,7 @@ public final class DispatchServer {
.setGateserverIp(regionInfo.Ip)
.setGateserverPort(regionInfo.Port)
.setSecretKey(ByteString
.copyFrom(FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "dispatchSeed.bin")))
.copyFrom(FileUtils.read(KEYS_FOLDER + "/dispatchSeed.bin")))
.build();
QueryCurrRegionHttpRsp parsedRegionQuery = regionQuery.toBuilder().setRegionInfo(serverRegion).build();
......@@ -194,8 +177,8 @@ public final class DispatchServer {
.build();
this.regionListBase64 = Base64.getEncoder().encodeToString(regionList.toByteString().toByteArray());
} catch (Exception e) {
Grasscutter.getLogger().error("[Dispatch] Error while initializing region info!", e);
} catch (Exception exception) {
Grasscutter.getLogger().error("[Dispatch] Error while initializing region info!", exception);
}
}
......@@ -205,14 +188,14 @@ public final class DispatchServer {
Server server = new Server();
ServerConnector serverConnector;
if(Grasscutter.getConfig().getDispatchOptions().UseSSL) {
if(DISPATCH_ENCRYPTION.useEncryption) {
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
File keystoreFile = new File(Grasscutter.getConfig().getDispatchOptions().KeystorePath);
File keystoreFile = new File(DISPATCH_ENCRYPTION.keystore);
if(keystoreFile.exists()) {
try {
sslContextFactory.setKeyStorePath(keystoreFile.getPath());
sslContextFactory.setKeyStorePassword(Grasscutter.getConfig().getDispatchOptions().KeystorePassword);
sslContextFactory.setKeyStorePassword(DISPATCH_ENCRYPTION.keystorePassword);
} catch (Exception e) {
e.printStackTrace();
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.password_error"));
......@@ -230,7 +213,7 @@ public final class DispatchServer {
serverConnector = new ServerConnector(server, sslContextFactory);
} else {
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.no_keystore_error"));
Grasscutter.getConfig().getDispatchOptions().UseSSL = false;
DISPATCH_ENCRYPTION.useEncryption = false;
serverConnector = new ServerConnector(server);
}
......@@ -238,24 +221,27 @@ public final class DispatchServer {
serverConnector = new ServerConnector(server);
}
serverConnector.setPort(Grasscutter.getConfig().getDispatchOptions().Port);
serverConnector.setPort(DISPATCH_INFO.bindPort);
server.setConnectors(new Connector[]{serverConnector});
return server;
});
config.enforceSsl = Grasscutter.getConfig().getDispatchOptions().UseSSL;
if(Grasscutter.getConfig().DebugMode == ServerDebugMode.ALL) {
config.enforceSsl = DISPATCH_ENCRYPTION.useEncryption;
if(SERVER.debugLevel == ServerDebugMode.ALL) {
config.enableDevLogging();
}
if (Grasscutter.getConfig().getDispatchOptions().CORS){
if (Grasscutter.getConfig().getDispatchOptions().CORSAllowedOrigins.length > 0) config.enableCorsForOrigin(Grasscutter.getConfig().getDispatchOptions().CORSAllowedOrigins);
if (DISPATCH_POLICIES.cors.enabled) {
var corsPolicy = DISPATCH_POLICIES.cors;
if (corsPolicy.allowedOrigins.length > 0)
config.enableCorsForOrigin(corsPolicy.allowedOrigins);
else config.enableCorsForAllOrigins();
}
});
httpServer.get("/", (req, res) -> res.send("<!doctype html><html><head><meta charset=\"utf8\"></head><body>" + translate("messages.status.welcome") + "</body></html>"));
httpServer.raw().error(404, ctx -> {
if(Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING) {
if(SERVER.debugLevel == ServerDebugMode.MISSING) {
Grasscutter.getLogger().info(translate("messages.dispatch.unhandled_request_error", ctx.method(), ctx.url()));
}
ctx.contentType("text/html");
......@@ -450,7 +436,7 @@ public final class DispatchServer {
httpServer.get("/admin/mi18n/plat_oversea/m202003048/m202003048-version.json", new DispatchHttpJsonHandler("{\"version\":51}"));
// gacha record.
String gachaMappingsPath = Utils.toFilePath(Grasscutter.getConfig().DATA_FOLDER + "/gacha_mappings.js");
String gachaMappingsPath = Utils.toFilePath(DATA("/gacha_mappings.js"));
// TODO: Only serve the html page and have a subsequent request to fetch the gacha data.
httpServer.get("/gacha", new GachaRecordHandler());
if(!(new File(gachaMappingsPath).exists())) {
......@@ -462,7 +448,7 @@ public final class DispatchServer {
// static file support for plugins
httpServer.raw().config.precompressStaticFiles = false; // If this isn't set to false, files such as images may appear corrupted when serving static files
httpServer.listen(Grasscutter.getConfig().getDispatchOptions().Port);
httpServer.listen(DISPATCH_INFO.bindPort);
Grasscutter.getLogger().info(translate("messages.dispatch.port_bind", Integer.toString(httpServer.raw().port())));
}
......@@ -481,15 +467,11 @@ public final class DispatchServer {
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
if (eqPos < 0 || eqPos > next) {
result.put(URLDecoder.decode(qs.substring(last, next), StandardCharsets.UTF_8), "");
} else {
result.put(URLDecoder.decode(qs.substring(last, eqPos), StandardCharsets.UTF_8),
URLDecoder.decode(qs.substring(eqPos + 1, next), StandardCharsets.UTF_8));
}
}
last = next + 1;
......
......@@ -9,6 +9,7 @@ import express.http.Request;
import express.http.Response;
import static emu.grasscutter.utils.Language.translate;
import static emu.grasscutter.Configuration.*;
public class DefaultAuthenticationHandler implements AuthenticationHandler {
......@@ -37,11 +38,11 @@ public class DefaultAuthenticationHandler implements AuthenticationHandler {
// Check if account exists, else create a new one.
if (account == null) {
// Account doesn't exist, so we can either auto create it if the config value is set.
if (Grasscutter.getConfig().getDispatchOptions().AutomaticallyCreateAccounts) {
if (ACCOUNT.autoCreate) {
// This account has been created AUTOMATICALLY. There will be no permissions added.
account = DatabaseHelper.createAccountWithId(requestData.account, 0);
for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) {
for (String permission : ACCOUNT.defaultPermissions) {
account.addPermission(permission);
}
......
......@@ -3,7 +3,6 @@ package emu.grasscutter.server.dispatch.http;
import java.io.File;
import java.io.IOException;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account;
import emu.grasscutter.utils.FileUtils;
......@@ -12,10 +11,12 @@ import express.http.HttpContextHandler;
import express.http.Request;
import express.http.Response;
import static emu.grasscutter.Configuration.*;
public final class GachaRecordHandler implements HttpContextHandler {
String render_template;
public GachaRecordHandler() {
File template = new File(Utils.toFilePath(Grasscutter.getConfig().DATA_FOLDER + "/gacha_records.html"));
File template = new File(Utils.toFilePath(DATA("/gacha_records.html")));
if (template.exists()) {
// Load from cache
render_template = new String(FileUtils.read(template));
......@@ -31,11 +32,11 @@ public final class GachaRecordHandler implements HttpContextHandler {
int page = 0;
int gachaType = 0;
if (req.query("p") != null) {
page = Integer.valueOf(req.query("p"));
page = Integer.parseInt(req.query("p"));
}
if (req.query("gachaType") != null) {
gachaType = Integer.valueOf(req.query("gachaType"));
gachaType = Integer.parseInt(req.query("gachaType"));
}
Account account = DatabaseHelper.getAccountBySessionKey(sessionKey);
......
......@@ -30,11 +30,9 @@ import java.net.InetSocketAddress;
import java.time.OffsetDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static emu.grasscutter.utils.Language.translate;
import static emu.grasscutter.Configuration.*;
public final class GameServer extends KcpServer {
private final InetSocketAddress address;
......@@ -59,8 +57,8 @@ public final class GameServer extends KcpServer {
public GameServer() {
this(new InetSocketAddress(
Grasscutter.getConfig().getGameServerOptions().Ip,
Grasscutter.getConfig().getGameServerOptions().Port
GAME_INFO.bindAddress,
GAME_INFO.bindPort
));
}
......
......@@ -14,6 +14,8 @@ import emu.grasscutter.server.game.GameSession.SessionState;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import static emu.grasscutter.Configuration.*;
@SuppressWarnings("unchecked")
public class GameServerPacketHandler {
private final Int2ObjectMap<PacketHandler> handlers;
......@@ -92,7 +94,7 @@ public class GameServerPacketHandler {
}
// Log unhandled packets
if (Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING) {
if (SERVER.debugLevel == ServerDebugMode.MISSING) {
Grasscutter.getLogger().info("Unhandled packet (" + opcode + "): " + emu.grasscutter.net.packet.PacketOpcodesUtil.getOpcodeName(opcode));
}
}
......
......@@ -3,7 +3,6 @@ package emu.grasscutter.server.game;
import java.io.File;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;
import emu.grasscutter.Grasscutter;
......@@ -23,9 +22,10 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import static emu.grasscutter.utils.Language.translate;
import static emu.grasscutter.Configuration.*;
public class GameSession extends KcpChannel {
private GameServer server;
private final GameServer server;
private Account account;
private Player player;
......@@ -140,7 +140,7 @@ public class GameSession extends KcpChannel {
}
public void replayPacket(int opcode, String name) {
String filePath = Grasscutter.getConfig().PACKETS_FOLDER + name;
String filePath = PACKETS_FOLDER + name;
File p = new File(filePath);
if (!p.exists()) return;
......@@ -172,7 +172,7 @@ public class GameSession extends KcpChannel {
}
// Log
if (Grasscutter.getConfig().DebugMode == ServerDebugMode.ALL) {
if (SERVER.debugLevel == ServerDebugMode.ALL) {
logPacket(packet);
}
......@@ -239,7 +239,7 @@ public class GameSession extends KcpChannel {
}
// Log packet
if (Grasscutter.getConfig().DebugMode == ServerDebugMode.ALL) {
if (SERVER.debugLevel == ServerDebugMode.ALL) {
if (!loopPacket.contains(opcode)) {
Grasscutter.getLogger().info("RECV: " + PacketOpcodesUtil.getOpcodeName(opcode) + " (" + opcode + ")");
System.out.println(Utils.bytesToHex(payload));
......
......@@ -19,6 +19,8 @@ import emu.grasscutter.server.game.GameSession.SessionState;
import java.util.Arrays;
import static emu.grasscutter.Configuration.*;
@Opcodes(PacketOpcodes.SetPlayerBornDataReq)
public class HandlerSetPlayerBornDataReq extends PacketHandler {
......@@ -85,12 +87,13 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler {
session.send(new BasePacket(PacketOpcodes.SetPlayerBornDataRsp));
// Default mail
var welcomeMail = GAME_INFO.joinOptions.welcomeMail;
MailBuilder mailBuilder = new MailBuilder(player.getUid(), new Mail());
mailBuilder.mail.mailContent.title = Grasscutter.getConfig().GameServer.WelcomeMailTitle;
mailBuilder.mail.mailContent.sender = Grasscutter.getConfig().GameServer.WelcomeMailSender;
mailBuilder.mail.mailContent.title = welcomeMail.title;
mailBuilder.mail.mailContent.sender = welcomeMail.sender;
// Please credit Grasscutter if changing something here. We don't condone commercial use of the project.
mailBuilder.mail.mailContent.content = Grasscutter.getConfig().GameServer.WelcomeMailContent + "\n<type=\"browser\" text=\"GitHub\" href=\"https://github.com/Melledy/Grasscutter\"/>";
mailBuilder.mail.itemList.addAll(Arrays.asList(Grasscutter.getConfig().GameServer.WelcomeMailItems));
mailBuilder.mail.mailContent.content = welcomeMail.content + "\n<type=\"browser\" text=\"GitHub\" href=\"https://github.com/Melledy/Grasscutter\"/>";
mailBuilder.mail.itemList.addAll(Arrays.asList(welcomeMail.items));
mailBuilder.mail.importance = 1;
player.sendMail(mailBuilder.mail);
} catch (Exception e) {
......
package emu.grasscutter.server.packet.send;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.friends.Friendship;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
......@@ -12,20 +11,23 @@ import emu.grasscutter.net.proto.GetPlayerFriendListRspOuterClass.GetPlayerFrien
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
import emu.grasscutter.net.proto.PlatformTypeOuterClass;
import static emu.grasscutter.Configuration.*;
public class PacketGetPlayerFriendListRsp extends BasePacket {
public PacketGetPlayerFriendListRsp(Player player) {
super(PacketOpcodes.GetPlayerFriendListRsp);
var serverAccount = GAME_INFO.serverAccount;
FriendBrief serverFriend = FriendBrief.newBuilder()
.setUid(GameConstants.SERVER_CONSOLE_UID)
.setNickname(Grasscutter.getConfig().getGameServerOptions().ServerNickname)
.setLevel(Grasscutter.getConfig().getGameServerOptions().ServerLevel)
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(Grasscutter.getConfig().getGameServerOptions().ServerAvatarId))
.setWorldLevel(Grasscutter.getConfig().getGameServerOptions().ServerWorldLevel)
.setSignature(Grasscutter.getConfig().getGameServerOptions().ServerSignature)
.setNickname(serverAccount.nickName)
.setLevel(serverAccount.adventureRank)
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(serverAccount.avatarId))
.setWorldLevel(serverAccount.worldLevel)
.setSignature(serverAccount.signature)
.setLastActiveTime((int) (System.currentTimeMillis() / 1000f))
.setNameCardId(Grasscutter.getConfig().getGameServerOptions().ServerNameCardId)
.setNameCardId(serverAccount.nameCardId)
.setOnlineState(FriendOnlineState.FRIEND_ONLINE)
.setParam(1)
.setIsGameSource(true)
......@@ -37,10 +39,12 @@ public class PacketGetPlayerFriendListRsp extends BasePacket {
for (Friendship friendship : player.getFriendsList().getFriends().values()) {
proto.addFriendList(friendship.toProto());
}
for (Friendship friendship : player.getFriendsList().getPendingFriends().values()) {
if (friendship.getAskerId() == player.getUid()) {
continue;
}
proto.addAskFriendList(friendship.toProto());
}
......
......@@ -2,7 +2,6 @@ package emu.grasscutter.server.packet.send;
import com.google.protobuf.ByteString;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.Grasscutter.ServerDebugMode;
import emu.grasscutter.Grasscutter.ServerRunMode;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
......@@ -13,9 +12,10 @@ import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.utils.FileUtils;
import java.io.File;
import java.net.URL;
import java.util.Base64;
import static emu.grasscutter.Configuration.*;
public class PacketPlayerLoginRsp extends BasePacket {
private static QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionCache;
......@@ -27,10 +27,10 @@ public class PacketPlayerLoginRsp extends BasePacket {
RegionInfo info;
if (Grasscutter.getConfig().RunMode == ServerRunMode.GAME_ONLY) {
if (SERVER.runMode == ServerRunMode.GAME_ONLY) {
if (regionCache == null) {
try {
File file = new File(Grasscutter.getConfig().DATA_FOLDER + "query_cur_region.txt");
File file = new File(DATA("query_cur_region.txt"));
String query_cur_region = "";
if (file.exists()) {
query_cur_region = new String(FileUtils.read(file));
......@@ -42,9 +42,9 @@ public class PacketPlayerLoginRsp extends BasePacket {
QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionQuery = QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp.parseFrom(decodedCurRegion);
RegionInfo serverRegion = regionQuery.getRegionInfo().toBuilder()
.setGateserverIp((Grasscutter.getConfig().getGameServerOptions().PublicIp.isEmpty() ? Grasscutter.getConfig().getGameServerOptions().Ip : Grasscutter.getConfig().getGameServerOptions().PublicIp))
.setGateserverPort(Grasscutter.getConfig().getGameServerOptions().PublicPort != 0 ? Grasscutter.getConfig().getGameServerOptions().PublicPort : Grasscutter.getConfig().getGameServerOptions().Port)
.setSecretKey(ByteString.copyFrom(FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "dispatchSeed.bin")))
.setGateserverIp(lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress))
.setGateserverPort(lr(GAME_INFO.accessPort, GAME_INFO.bindPort))
.setSecretKey(ByteString.copyFrom(FileUtils.read(KEYS_FOLDER + "/dispatchSeed.bin")))
.build();
regionCache = regionQuery.toBuilder().setRegionInfo(serverRegion).build();
......
package emu.grasscutter.server.packet.send;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
......@@ -10,6 +8,8 @@ import emu.grasscutter.net.proto.ItemOuterClass.Item;
import emu.grasscutter.net.proto.PlayerStoreNotifyOuterClass.PlayerStoreNotify;
import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType;
import static emu.grasscutter.Configuration.*;
public class PacketPlayerStoreNotify extends BasePacket {
public PacketPlayerStoreNotify(Player player) {
......@@ -19,7 +19,7 @@ public class PacketPlayerStoreNotify extends BasePacket {
PlayerStoreNotify.Builder p = PlayerStoreNotify.newBuilder()
.setStoreType(StoreType.STORE_PACK)
.setWeightLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitAll);
.setWeightLimit(GAME_OPTIONS.inventoryLimits.all);
for (GameItem item : player.getInventory()) {
Item itemProto = item.toProto();
......
package emu.grasscutter.server.packet.send;
import emu.grasscutter.Config.GameServerOptions;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo;
import emu.grasscutter.net.proto.PullRecentChatRspOuterClass.PullRecentChatRsp;
import emu.grasscutter.utils.Utils;
import static emu.grasscutter.Configuration.*;
public class PacketPullRecentChatRsp extends BasePacket {
public PacketPullRecentChatRsp(Player player) {
super(PacketOpcodes.PullRecentChatRsp);
GameServerOptions serverOptions = Grasscutter.getConfig().getGameServerOptions();
var joinOptions = GAME_INFO.joinOptions;
PullRecentChatRsp.Builder proto = PullRecentChatRsp.newBuilder();
if (serverOptions.WelcomeEmotes != null && serverOptions.WelcomeEmotes.length > 0) {
if (joinOptions.welcomeEmotes != null && joinOptions.welcomeEmotes.length > 0) {
ChatInfo welcomeEmote = ChatInfo.newBuilder()
.setTime((int) (System.currentTimeMillis() / 1000))
.setUid(GameConstants.SERVER_CONSOLE_UID)
.setToUid(player.getUid())
.setIcon(serverOptions.WelcomeEmotes[Utils.randomRange(0, serverOptions.WelcomeEmotes.length - 1)])
.setIcon(joinOptions.welcomeEmotes[Utils.randomRange(0, joinOptions.welcomeEmotes.length - 1)])
.build();
proto.addChatInfo(welcomeEmote);
}
if (serverOptions.WelcomeMotd != null && serverOptions.WelcomeMotd.length() > 0) {
ChatInfo welcomeMotd = ChatInfo.newBuilder()
if (joinOptions.welcomeMessage != null && joinOptions.welcomeMessage.length() > 0) {
ChatInfo welcomeMessage = ChatInfo.newBuilder()
.setTime((int) (System.currentTimeMillis() / 1000))
.setUid(GameConstants.SERVER_CONSOLE_UID)
.setToUid(player.getUid())
.setText(Grasscutter.getConfig().getGameServerOptions().WelcomeMotd)
.setText(joinOptions.welcomeMessage)
.build();
proto.addChatInfo(welcomeMotd);
proto.addChatInfo(welcomeMessage);
}
this.setData(proto);
......
package emu.grasscutter.server.packet.send;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType;
import emu.grasscutter.net.proto.StoreWeightLimitNotifyOuterClass.StoreWeightLimitNotify;
import static emu.grasscutter.Configuration.*;
public class PacketStoreWeightLimitNotify extends BasePacket {
public PacketStoreWeightLimitNotify() {
......@@ -13,11 +14,11 @@ public class PacketStoreWeightLimitNotify extends BasePacket {
StoreWeightLimitNotify p = StoreWeightLimitNotify.newBuilder()
.setStoreType(StoreType.STORE_PACK)
.setWeightLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitAll)
.setWeaponCountLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitWeapon)
.setReliquaryCountLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitRelic)
.setMaterialCountLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitMaterial)
.setFurnitureCountLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitFurniture)
.setWeightLimit(INVENTORY_LIMITS.all)
.setWeaponCountLimit(INVENTORY_LIMITS.weapons)
.setReliquaryCountLimit(INVENTORY_LIMITS.relics)
.setMaterialCountLimit(INVENTORY_LIMITS.materials)
.setFurnitureCountLimit(INVENTORY_LIMITS.furniture)
.build();
this.setData(p);
......
package emu.grasscutter.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
......@@ -14,14 +10,12 @@ import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import com.google.gson.reflect.TypeToken;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.command.CommandMap;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.ResourceLoader;
......@@ -32,6 +26,7 @@ import emu.grasscutter.data.def.SceneData;
import emu.grasscutter.utils.Utils;
import static emu.grasscutter.utils.Language.translate;
import static emu.grasscutter.Configuration.*;
public final class Tools {
public static void createGmHandbook() throws Exception {
......@@ -42,50 +37,45 @@ public final class Tools {
ToolsWithLanguageOption.createGachaMapping(location, getLanguageOption());
}
public static List<String> getAvailableLanguage() throws Exception {
File textMapFolder = new File(Grasscutter.getConfig().RESOURCE_FOLDER + "TextMap");
List<String> availableLangList = new ArrayList<String>();
for (String textMapFileName : textMapFolder.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.startsWith("TextMap") && name.endsWith(".json")){
return true;
}
return false;
}
})) {
availableLangList.add(textMapFileName.replace("TextMap","").replace(".json","").toLowerCase());
}
return availableLangList;
public static List<String> getAvailableLanguage() {
File textMapFolder = new File(RESOURCE("TextMap"));
List<String> availableLangList = new ArrayList<>();
for (String textMapFileName : Objects.requireNonNull(textMapFolder.list((dir, name) -> name.startsWith("TextMap") && name.endsWith(".json")))) {
availableLangList.add(textMapFileName.replace("TextMap", "").replace(".json", "").toLowerCase());
} return availableLangList;
}
public static String getLanguageOption() throws Exception {
public static String getLanguageOption() {
List<String> availableLangList = getAvailableLanguage();
// Use system out for better format
if (availableLangList.size() == 1) {
return availableLangList.get(0).toUpperCase();
}
String stagedMessage = "";
stagedMessage += "The following languages mappings are available, please select one: [default: EN]\n";
String groupedLangList = ">\t";
StringBuilder stagedMessage = new StringBuilder();
stagedMessage.append("The following languages mappings are available, please select one: [default: EN] \n");
StringBuilder groupedLangList = new StringBuilder(">\t"); String input;
int groupedLangCount = 0;
String input = "";
for (String availableLanguage: availableLangList){
groupedLangCount++;
groupedLangList = groupedLangList + "" + availableLanguage + "\t";
groupedLangList.append(availableLanguage).append("\t");
if (groupedLangCount == 6) {
stagedMessage += groupedLangList + "\n";
stagedMessage.append(groupedLangList).append("\n");
groupedLangCount = 0;
groupedLangList = ">\t";
groupedLangList = new StringBuilder(">\t");
}
}
if (groupedLangCount > 0) {
stagedMessage += groupedLangList + "\n";
stagedMessage.append(groupedLangList).append("\n");
}
stagedMessage += "\nYour choice:[EN] ";
input = Grasscutter.getConsole().readLine(stagedMessage);
stagedMessage.append("\nYour choice:[EN] ");
input = Grasscutter.getConsole().readLine(stagedMessage.toString());
if (availableLangList.contains(input.toLowerCase())) {
return input.toUpperCase();
}
......@@ -101,7 +91,7 @@ final class ToolsWithLanguageOption {
ResourceLoader.loadResources();
Map<Long, String> map;
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(Grasscutter.getConfig().RESOURCE_FOLDER + "TextMap/TextMap"+language+".json")), StandardCharsets.UTF_8)) {
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap"+language+".json"))), StandardCharsets.UTF_8)) {
map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken<Map<Long, String>>() {}.getType());
}
......@@ -119,9 +109,9 @@ final class ToolsWithLanguageOption {
writer.println("// Commands");
for (Command cmd : cmdList) {
String cmdName = cmd.label();
StringBuilder cmdName = new StringBuilder(cmd.label());
while (cmdName.length() <= 15) {
cmdName = " " + cmdName;
cmdName.insert(0, " ");
}
writer.println(cmdName + " : " + translate(cmd.description()));
}
......@@ -178,16 +168,13 @@ final class ToolsWithLanguageOption {
ResourceLoader.loadResources();
Map<Long, String> map;
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(Grasscutter.getConfig().RESOURCE_FOLDER + "TextMap/TextMap"+language+".json")), StandardCharsets.UTF_8)) {
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap" + language + ".json"))), StandardCharsets.UTF_8)) {
map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken<Map<Long, String>>() {}.getType());
}
List<Integer> list;
String fileName = location;
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), false)) {
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(location), StandardCharsets.UTF_8), false)) {
list = new ArrayList<>(GameData.getAvatarDataMap().keySet());
Collections.sort(list);
......@@ -209,18 +196,11 @@ final class ToolsWithLanguageOption {
} else {
writer.print(",");
}
String color;
switch (data.getQualityType()){
case "QUALITY_PURPLE":
color = "purple";
break;
case "QUALITY_ORANGE":
color = "yellow";
break;
case "QUALITY_BLUE":
default:
color = "blue";
}
String color = switch (data.getQualityType()) {
case "QUALITY_PURPLE" -> "purple";
case "QUALITY_ORANGE" -> "yellow";
default -> "blue";
};
// Got the magic number 4233146695 from manually search in the json file
writer.println(
"\"" + (avatarID % 1000 + 1000) + "\" : [\""
......
package emu.grasscutter.utils;
import com.google.gson.JsonObject;
import emu.grasscutter.Grasscutter;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Locale;
import static emu.grasscutter.Grasscutter.config;
/**
* *when your JVM fails*
*/
public class ConfigContainer {
private static int version() {
return 1;
}
/**
* Attempts to update the server's existing configuration to the latest
*/
public static void updateConfig() {
try { // Check if the server is using a legacy config.
JsonObject configObject = Grasscutter.getGsonFactory()
.fromJson(new FileReader(Grasscutter.configFile), JsonObject.class);
if(!configObject.has("version")) {
Grasscutter.getLogger().info("Updating legacy ..");
Grasscutter.saveConfig(null);
}
} catch (Exception ignored) { }
var existing = config.version;
var latest = version();
if(existing == latest)
return;
// Create a new configuration instance.
ConfigContainer updated = new ConfigContainer();
// Update all configuration fields.
Field[] fields = ConfigContainer.class.getDeclaredFields();
Arrays.stream(fields).forEach(field -> {
try {
field.set(updated, field.get(config));
} catch (Exception exception) {
Grasscutter.getLogger().error("Failed to update a configuration field.", exception);
}
}); updated.version = version();
try { // Save configuration & reload.
Grasscutter.saveConfig(updated);
Grasscutter.loadConfig();
} catch (Exception exception) {
Grasscutter.getLogger().warn("Failed to inject the updated ", exception);
}
}
public Structure folderStructure = new Structure();
public Database databaseInfo = new Database();
public Language language = new Language();
public Account account = new Account();
public Server server = new Server();
// DO NOT. TOUCH. THE VERSION NUMBER.
public int version = version();
/* Option containers. */
public static class Database {
public String connectionUri = "mongodb://localhost:27017";
public String collection = "grasscutter";
}
public static class Structure {
public String resources = "./resources/";
public String data = "./data/";
public String packets = "./packets/";
public String keys = "./keys/";
public String scripts = "./resources/scripts/";
public String plugins = "./plugins/";
// UNUSED (potentially added later?)
// public String dumps = "./dumps/";
}
public static class Server {
public Grasscutter.ServerDebugMode debugLevel = Grasscutter.ServerDebugMode.NONE;
public Grasscutter.ServerRunMode runMode = Grasscutter.ServerRunMode.HYBRID;
public Dispatch dispatch = new Dispatch();
public Game game = new Game();
}
public static class Language {
public Locale language = Locale.getDefault();
public Locale fallback = Locale.US;
}
public static class Account {
public boolean autoCreate = false;
public String[] defaultPermissions = {};
}
/* Server options. */
public static class Dispatch {
public String bindAddress = "0.0.0.0";
/* This is the address used in URLs. */
public String accessAddress = "127.0.0.1";
public int bindPort = 443;
/* This is the port used in URLs. */
public int accessPort = 443;
public Encryption encryption = new Encryption();
public Policies policies = new Policies();
public Region[] regions = {};
public String defaultName = "Grasscutter";
}
public static class Game {
public String bindAddress = "0.0.0.0";
/* This is the address used in the default region. */
public String accessAddress = "127.0.0.1";
public int bindPort = 443;
/* This is the port used in the default region. */
public int accessPort = 443;
public GameOptions gameOptions = new GameOptions();
public JoinOptions joinOptions = new JoinOptions();
public ConsoleAccount serverAccount = new ConsoleAccount();
}
/* Data containers. */
public static class Encryption {
public boolean useEncryption = true;
/* Should 'https' be appended to URLs? */
public boolean useInRouting = true;
public String keystore = "./keystore.p12";
public String keystorePassword = "123456";
}
public static class Policies {
public Policies.CORS cors = new Policies.CORS();
public static class CORS {
public boolean enabled = false;
public String[] allowedOrigins = new String[]{"*"};
}
}
public static class GameOptions {
public GameOptions.InventoryLimits inventoryLimits = new GameOptions.InventoryLimits();
public GameOptions.AvatarLimits avatarLimits = new GameOptions.AvatarLimits();
public int worldEntityLimit = 1000; // Unenforced. TODO: Implement.
public boolean watchGachaConfig = false;
public boolean enableShopItems = true;
public boolean staminaUsage = true;
public GameOptions.Rates rates = new GameOptions.Rates();
public Database databaseInfo = new Database();
public static class InventoryLimits {
public int weapons = 2000;
public int relics = 2000;
public int materials = 2000;
public int furniture = 2000;
public int all = 30000;
}
public static class AvatarLimits {
public int singlePlayerTeam = 4;
public int multiplayerTeam = 4;
}
public static class Rates {
public float adventureExp = 1.0f;
public float mora = 1.0f;
public float leyLines = 1.0f;
}
}
public static class JoinOptions {
public int[] welcomeEmotes = {2007, 1002, 4010};
public String welcomeMessage = "Welcome to a Grasscutter server.";
public JoinOptions.Mail welcomeMail = new JoinOptions.Mail();
public static class Mail {
public String title = "Welcome to Grasscutter!";
public String content = """
Hi there!\r
First of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r
\r
Check out our:\r
<type="browser" text="Discord" href="https://discord.gg/T5vZU6UyeG"/>
""";
public String sender = "Lawnmower";
public emu.grasscutter.game.mail.Mail.MailItem[] items = {
new emu.grasscutter.game.mail.Mail.MailItem(13509, 1, 1),
new emu.grasscutter.game.mail.Mail.MailItem(201, 99999, 1)
};
}
}
public static class ConsoleAccount {
public int avatarId = 10000007;
public int nameCardId = 210001;
public int adventureRank = 1;
public int worldLevel = 0;
public String nickName = "Server";
public String signature = "Welcome to Grasscutter!";
}
/* Objects. */
public static class Region {
public String Name = "os_usa";
public String Title = "Grasscutter";
public String Ip = "127.0.0.1";
public int Port = 22102;
}
}
......@@ -7,6 +7,8 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.proto.GetPlayerTokenRspOuterClass.GetPlayerTokenRsp;
import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp;
import static emu.grasscutter.Configuration.*;
public final class Crypto {
private static final SecureRandom secureRandom = new SecureRandom();
public static final long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968");
......@@ -16,9 +18,9 @@ public final class Crypto {
public static byte[] ENCRYPT_KEY;
public static void loadKeys() {
DISPATCH_KEY = FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "dispatchKey.bin");
ENCRYPT_KEY = FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "secretKey.bin");
ENCRYPT_SEED_BUFFER = FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "secretKeyBuffer.bin");
DISPATCH_KEY = FileUtils.read(KEYS_FOLDER + "/dispatchKey.bin");
ENCRYPT_KEY = FileUtils.read(KEYS_FOLDER + "/secretKey.bin");
ENCRYPT_SEED_BUFFER = FileUtils.read(KEYS_FOLDER + "/secretKeyBuffer.bin");
}
public static void xor(byte[] packet, byte[] key) {
......@@ -34,7 +36,7 @@ public final class Crypto {
public static void extractSecretKeyBuffer(byte[] data) {
try {
GetPlayerTokenRsp p = GetPlayerTokenRsp.parseFrom(data);
FileUtils.write(Grasscutter.getConfig().KEY_FOLDER + "secretKeyBuffer.bin", p.getSecretKeyBytes().toByteArray());
FileUtils.write(KEYS_FOLDER + "/secretKeyBuffer.bin", p.getSecretKeyBytes().toByteArray());
Grasscutter.getLogger().info("Secret Key: " + p.getSecretKey());
} catch (Exception e) {
Grasscutter.getLogger().error("Crypto error.", e);
......@@ -44,7 +46,7 @@ public final class Crypto {
public static void extractDispatchSeed(String data) {
try {
QueryCurrRegionHttpRsp p = QueryCurrRegionHttpRsp.parseFrom(Base64.getDecoder().decode(data));
FileUtils.write(Grasscutter.getConfig().KEY_FOLDER + "dispatchSeed.bin", p.getRegionInfo().getSecretKey().toByteArray());
FileUtils.write(KEYS_FOLDER + "/dispatchSeed.bin", p.getRegionInfo().getSecretKey().toByteArray());
} catch (Exception e) {
Grasscutter.getLogger().error("Crypto error.", e);
}
......
......@@ -10,6 +10,8 @@ import java.io.InputStream;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import static emu.grasscutter.Configuration.*;
public final class Language {
private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
......@@ -27,8 +29,8 @@ public final class Language {
return cachedLanguages.get(langCode);
}
var fallbackLanguageCode = Utils.getLanguageCode(Grasscutter.getConfig().DefaultLanguage);
var description = getLanguageFileStreamDescripter(langCode, fallbackLanguageCode);
var fallbackLanguageCode = Utils.getLanguageCode(FALLBACK_LANGUAGE);
var description = getLanguageFileDescription(langCode, fallbackLanguageCode);
var actualLanguageCode = description.getLanguageCode();
Language languageInst;
......@@ -111,7 +113,7 @@ public final class Language {
* @param languageCode The name of the language code.
* @param fallbackLanguageCode The name of the fallback language code.
*/
private static LanguageStreamDescription getLanguageFileStreamDescripter(String languageCode, String fallbackLanguageCode) {
private static LanguageStreamDescription getLanguageFileDescription(String languageCode, String fallbackLanguageCode) {
var fileName = languageCode + ".json";
var fallback = fallbackLanguageCode + ".json";
......
......@@ -11,7 +11,6 @@ import java.util.Map;
import java.util.Random;
import java.util.Locale;
import emu.grasscutter.Config;
import emu.grasscutter.Grasscutter;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
......@@ -175,12 +174,12 @@ public final class Utils {
* Checks for required files and folders before startup.
*/
public static void startupCheck() {
Config config = Grasscutter.getConfig();
ConfigContainer config = Grasscutter.getConfig();
Logger logger = Grasscutter.getLogger();
boolean exit = false;
String resourcesFolder = config.RESOURCE_FOLDER;
String dataFolder = config.DATA_FOLDER;
String resourcesFolder = config.folderStructure.resources;
String dataFolder = config.folderStructure.data;
// Check for resources folder.
if(!fileExists(resourcesFolder)) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment