mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-01-26 18:22:54 +08:00
Merge branch 'development' into dev-quests
This commit is contained in:
commit
51844b6535
@ -1,110 +0,0 @@
|
|||||||
package emu.grasscutter;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
|
||||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
|
||||||
import emu.grasscutter.game.mail.Mail;
|
|
||||||
|
|
||||||
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/";
|
|
||||||
public String DUMPS_FOLDER = "./dumps/";
|
|
||||||
public String KEY_FOLDER = "./keys/";
|
|
||||||
public String SCRIPTS_FOLDER = "./resources/Scripts/";
|
|
||||||
public String PLUGINS_FOLDER = "./plugins/";
|
|
||||||
|
|
||||||
public ServerDebugMode DebugMode = ServerDebugMode.NONE; // ALL, MISSING, NONE
|
|
||||||
public ServerRunMode RunMode = ServerRunMode.HYBRID; // HYBRID, DISPATCH_ONLY, GAME_ONLY
|
|
||||||
public GameServerOptions GameServer = new GameServerOptions();
|
|
||||||
public DispatchServerOptions DispatchServer = new DispatchServerOptions();
|
|
||||||
public Locale LocaleLanguage = Locale.getDefault();
|
|
||||||
public Locale DefaultLanguage = Locale.US;
|
|
||||||
|
|
||||||
public Boolean OpenStamina = true;
|
|
||||||
public GameServerOptions getGameServerOptions() {
|
|
||||||
return GameServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DispatchServerOptions getDispatchOptions() { return DispatchServer; }
|
|
||||||
|
|
||||||
public static class DispatchServerOptions {
|
|
||||||
public String Ip = "0.0.0.0";
|
|
||||||
public String PublicIp = "127.0.0.1";
|
|
||||||
public int Port = 443;
|
|
||||||
public int PublicPort = 0;
|
|
||||||
public String KeystorePath = "./keystore.p12";
|
|
||||||
public String KeystorePassword = "123456";
|
|
||||||
public Boolean UseSSL = true;
|
|
||||||
public Boolean FrontHTTPS = true;
|
|
||||||
public Boolean CORS = false;
|
|
||||||
public String[] CORSAllowedOrigins = new String[] { "*" };
|
|
||||||
|
|
||||||
public boolean AutomaticallyCreateAccounts = false;
|
|
||||||
public String[] defaultPermissions = new String[] { "" };
|
|
||||||
|
|
||||||
public RegionInfo[] GameServers = {};
|
|
||||||
|
|
||||||
public RegionInfo[] getGameServers() {
|
|
||||||
return GameServers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RegionInfo {
|
|
||||||
public String Name = "os_usa";
|
|
||||||
public String Title = "Test";
|
|
||||||
public String Ip = "127.0.0.1";
|
|
||||||
public int Port = 22102;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class GameServerOptions {
|
|
||||||
public String Name = "Test";
|
|
||||||
public String Ip = "0.0.0.0";
|
|
||||||
public String PublicIp = "127.0.0.1";
|
|
||||||
public int Port = 22102;
|
|
||||||
public int PublicPort = 0;
|
|
||||||
|
|
||||||
public String DispatchServerDatabaseUrl = "mongodb://localhost:27017";
|
|
||||||
public String DispatchServerDatabaseCollection = "grasscutter";
|
|
||||||
|
|
||||||
public int InventoryLimitWeapon = 2000;
|
|
||||||
public int InventoryLimitRelic = 2000;
|
|
||||||
public int InventoryLimitMaterial = 2000;
|
|
||||||
public int InventoryLimitFurniture = 2000;
|
|
||||||
public int InventoryLimitAll = 30000;
|
|
||||||
public int MaxAvatarsInTeam = 4;
|
|
||||||
public int MaxAvatarsInTeamMultiplayer = 4;
|
|
||||||
public int MaxEntityLimit = 1000; // Max entity limit per world. // TODO: Enforce later.
|
|
||||||
public boolean WatchGacha = false;
|
|
||||||
public String ServerNickname = "Server";
|
|
||||||
public int ServerAvatarId = 10000007;
|
|
||||||
public int ServerNameCardId = 210001;
|
|
||||||
public int ServerLevel = 1;
|
|
||||||
public int ServerWorldLevel = 1;
|
|
||||||
public String ServerSignature = "Server Signature";
|
|
||||||
public int[] WelcomeEmotes = {2007, 1002, 4010};
|
|
||||||
public String WelcomeMotd = "Welcome to Grasscutter emu";
|
|
||||||
public String WelcomeMailTitle = "Welcome to Grasscutter!";
|
|
||||||
public String WelcomeMailSender = "Lawnmower";
|
|
||||||
public String WelcomeMailContent = "Hi there!\r\nFirst of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r\n\r\nCheck out our:\r\n<type=\"browser\" text=\"Discord\" href=\"https://discord.gg/T5vZU6UyeG\"/>";
|
|
||||||
public Mail.MailItem[] WelcomeMailItems = {
|
|
||||||
new Mail.MailItem(13509, 1, 1),
|
|
||||||
new Mail.MailItem(201, 10000, 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
public boolean EnableOfficialShop = true;
|
|
||||||
|
|
||||||
public GameRates Game = new GameRates();
|
|
||||||
|
|
||||||
public GameRates getGameRates() { return Game; }
|
|
||||||
|
|
||||||
public static class GameRates {
|
|
||||||
public float ADVENTURE_EXP_RATE = 1.0f;
|
|
||||||
public float MORA_RATE = 1.0f;
|
|
||||||
public float DOMAIN_DROP_RATE = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
91
src/main/java/emu/grasscutter/Configuration.java
Normal file
91
src/main/java/emu/grasscutter/Configuration.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package emu.grasscutter;
|
||||||
|
|
||||||
|
import emu.grasscutter.utils.ConfigContainer;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Grasscutter.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data container for the server's configuration.
|
||||||
|
*
|
||||||
|
* Use `import static emu.grasscutter.Configuration.*;`
|
||||||
|
* to import all configuration constants.
|
||||||
|
*/
|
||||||
|
public final class Configuration extends ConfigContainer {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constants
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 'c' is short for 'config' and makes code look 'cleaner'.
|
||||||
|
public static final ConfigContainer c = config;
|
||||||
|
|
||||||
|
public static final Locale LANGUAGE = config.language.language;
|
||||||
|
public static final Locale FALLBACK_LANGUAGE = config.language.fallback;
|
||||||
|
public static final String DATA_FOLDER = config.folderStructure.data;
|
||||||
|
public static final String RESOURCES_FOLDER = config.folderStructure.resources;
|
||||||
|
public static final String KEYS_FOLDER = config.folderStructure.keys;
|
||||||
|
public static final String PLUGINS_FOLDER = config.folderStructure.plugins;
|
||||||
|
public static final String SCRIPTS_FOLDER = config.folderStructure.scripts;
|
||||||
|
public static final String PACKETS_FOLDER = config.folderStructure.packets;
|
||||||
|
|
||||||
|
public static final Server SERVER = config.server;
|
||||||
|
public static final Database DATABASE = config.databaseInfo;
|
||||||
|
public static final Account ACCOUNT = config.account;
|
||||||
|
|
||||||
|
public static final Dispatch DISPATCH_INFO = config.server.dispatch;
|
||||||
|
public static final Game GAME_INFO = config.server.game;
|
||||||
|
|
||||||
|
public static final Encryption DISPATCH_ENCRYPTION = config.server.dispatch.encryption;
|
||||||
|
public static final Policies DISPATCH_POLICIES = config.server.dispatch.policies;
|
||||||
|
|
||||||
|
public static final GameOptions GAME_OPTIONS = config.server.game.gameOptions;
|
||||||
|
public static final GameOptions.InventoryLimits INVENTORY_LIMITS = config.server.game.gameOptions.inventoryLimits;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static String DATA(String path) {
|
||||||
|
return DATA_FOLDER + "/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String RESOURCE(String path) {
|
||||||
|
return RESOURCES_FOLDER + "/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String SCRIPT(String path) {
|
||||||
|
return SCRIPTS_FOLDER + "/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fallback method.
|
||||||
|
* @param left Attempt to use.
|
||||||
|
* @param right Use if left is undefined.
|
||||||
|
* @return Left or right.
|
||||||
|
*/
|
||||||
|
public static <T> T lr(T left, T right) {
|
||||||
|
return left == null ? right : left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Configuration#lr(Object, Object)} for {@link String}s.
|
||||||
|
* @param left Attempt to use.
|
||||||
|
* @param right Use if left is empty.
|
||||||
|
* @return Left or right.
|
||||||
|
*/
|
||||||
|
public static String lr(String left, String right) {
|
||||||
|
return left.isEmpty() ? right : left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Configuration#lr(Object, Object)} for {@link Integer}s.
|
||||||
|
* @param left Attempt to use.
|
||||||
|
* @param right Use if left is 0.
|
||||||
|
* @return Left or right.
|
||||||
|
*/
|
||||||
|
public static int lr(int left, int right) {
|
||||||
|
return left == 0 ? right : left;
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,13 @@
|
|||||||
package emu.grasscutter;
|
package emu.grasscutter;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOError;
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
import emu.grasscutter.command.CommandMap;
|
import emu.grasscutter.command.CommandMap;
|
||||||
import emu.grasscutter.plugin.PluginManager;
|
import emu.grasscutter.plugin.PluginManager;
|
||||||
import emu.grasscutter.plugin.api.ServerHook;
|
import emu.grasscutter.plugin.api.ServerHook;
|
||||||
import emu.grasscutter.scripts.ScriptLoader;
|
import emu.grasscutter.scripts.ScriptLoader;
|
||||||
|
import emu.grasscutter.utils.ConfigContainer;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import org.jline.reader.EndOfFileException;
|
import org.jline.reader.EndOfFileException;
|
||||||
import org.jline.reader.LineReader;
|
import org.jline.reader.LineReader;
|
||||||
@ -32,17 +30,19 @@ import emu.grasscutter.server.game.GameServer;
|
|||||||
import emu.grasscutter.tools.Tools;
|
import emu.grasscutter.tools.Tools;
|
||||||
import emu.grasscutter.utils.Crypto;
|
import emu.grasscutter.utils.Crypto;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class Grasscutter {
|
public final class Grasscutter {
|
||||||
private static final Logger log = (Logger) LoggerFactory.getLogger(Grasscutter.class);
|
private static final Logger log = (Logger) LoggerFactory.getLogger(Grasscutter.class);
|
||||||
private static LineReader consoleLineReader = null;
|
private static LineReader consoleLineReader = null;
|
||||||
|
|
||||||
private static Config config;
|
|
||||||
private static Language language;
|
private static Language language;
|
||||||
|
|
||||||
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||||
private static final File configFile = new File("./config.json");
|
public static final File configFile = new File("./config.json");
|
||||||
|
|
||||||
private static int day; // Current day of week.
|
private static int day; // Current day of week.
|
||||||
|
|
||||||
@ -51,6 +51,7 @@ public final class Grasscutter {
|
|||||||
private static PluginManager pluginManager;
|
private static PluginManager pluginManager;
|
||||||
|
|
||||||
public static final Reflections reflector = new Reflections("emu.grasscutter");
|
public static final Reflections reflector = new Reflections("emu.grasscutter");
|
||||||
|
public static ConfigContainer config;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Declare logback configuration.
|
// Declare logback configuration.
|
||||||
@ -58,6 +59,8 @@ public final class Grasscutter {
|
|||||||
|
|
||||||
// Load server configuration.
|
// Load server configuration.
|
||||||
Grasscutter.loadConfig();
|
Grasscutter.loadConfig();
|
||||||
|
// Attempt to update configuration.
|
||||||
|
ConfigContainer.updateConfig();
|
||||||
|
|
||||||
// Load translation files.
|
// Load translation files.
|
||||||
Grasscutter.loadLanguage();
|
Grasscutter.loadLanguage();
|
||||||
@ -66,9 +69,9 @@ public final class Grasscutter {
|
|||||||
Utils.startupCheck();
|
Utils.startupCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
Crypto.loadKeys(); // Load keys from buffers.
|
Crypto.loadKeys(); // Load keys from buffers.
|
||||||
|
|
||||||
// Parse arguments.
|
// Parse arguments.
|
||||||
boolean exitEarly = false;
|
boolean exitEarly = false;
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
@ -77,25 +80,25 @@ public final class Grasscutter {
|
|||||||
Tools.createGmHandbook(); exitEarly = true;
|
Tools.createGmHandbook(); exitEarly = true;
|
||||||
}
|
}
|
||||||
case "-gachamap" -> {
|
case "-gachamap" -> {
|
||||||
Tools.createGachaMapping(Grasscutter.getConfig().DATA_FOLDER + "/gacha_mappings.js"); exitEarly = true;
|
Tools.createGachaMapping(DATA("gacha_mappings.js")); exitEarly = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit early if argument sets it.
|
// Exit early if argument sets it.
|
||||||
if(exitEarly) System.exit(0);
|
if(exitEarly) System.exit(0);
|
||||||
|
|
||||||
// Initialize server.
|
// Initialize server.
|
||||||
Grasscutter.getLogger().info(translate("messages.status.starting"));
|
Grasscutter.getLogger().info(translate("messages.status.starting"));
|
||||||
|
|
||||||
// Load all resources.
|
// Load all resources.
|
||||||
Grasscutter.updateDayOfWeek();
|
Grasscutter.updateDayOfWeek();
|
||||||
ResourceLoader.loadAll();
|
ResourceLoader.loadAll();
|
||||||
ScriptLoader.init();
|
ScriptLoader.init();
|
||||||
|
|
||||||
// Initialize database.
|
// Initialize database.
|
||||||
DatabaseManager.initialize();
|
DatabaseManager.initialize();
|
||||||
|
|
||||||
// Create server instances.
|
// Create server instances.
|
||||||
dispatchServer = new DispatchServer();
|
dispatchServer = new DispatchServer();
|
||||||
gameServer = new GameServer();
|
gameServer = new GameServer();
|
||||||
@ -103,31 +106,32 @@ public final class Grasscutter {
|
|||||||
new ServerHook(gameServer, dispatchServer);
|
new ServerHook(gameServer, dispatchServer);
|
||||||
// Create plugin manager instance.
|
// Create plugin manager instance.
|
||||||
pluginManager = new PluginManager();
|
pluginManager = new PluginManager();
|
||||||
|
|
||||||
// Start servers.
|
// Start servers.
|
||||||
if (getConfig().RunMode == ServerRunMode.HYBRID) {
|
var runMode = SERVER.runMode;
|
||||||
|
if (runMode == ServerRunMode.HYBRID) {
|
||||||
dispatchServer.start();
|
dispatchServer.start();
|
||||||
gameServer.start();
|
gameServer.start();
|
||||||
} else if (getConfig().RunMode == ServerRunMode.DISPATCH_ONLY) {
|
} else if (runMode == ServerRunMode.DISPATCH_ONLY) {
|
||||||
dispatchServer.start();
|
dispatchServer.start();
|
||||||
} else if (getConfig().RunMode == ServerRunMode.GAME_ONLY) {
|
} else if (runMode == ServerRunMode.GAME_ONLY) {
|
||||||
gameServer.start();
|
gameServer.start();
|
||||||
} else {
|
} else {
|
||||||
getLogger().error(translate("messages.status.run_mode_error", getConfig().RunMode));
|
getLogger().error(translate("messages.status.run_mode_error", runMode));
|
||||||
getLogger().error(translate("messages.status.run_mode_help"));
|
getLogger().error(translate("messages.status.run_mode_help"));
|
||||||
getLogger().error(translate("messages.status.shutdown"));
|
getLogger().error(translate("messages.status.shutdown"));
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable all plugins.
|
// Enable all plugins.
|
||||||
pluginManager.enablePlugins();
|
pluginManager.enablePlugins();
|
||||||
|
|
||||||
// Hook into shutdown event.
|
// Hook into shutdown event.
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(Grasscutter::onShutdown));
|
Runtime.getRuntime().addShutdownHook(new Thread(Grasscutter::onShutdown));
|
||||||
|
|
||||||
// Open console.
|
// Open console.
|
||||||
startConsole();
|
startConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server shutdown event.
|
* Server shutdown event.
|
||||||
@ -137,32 +141,46 @@ public final class Grasscutter {
|
|||||||
pluginManager.disablePlugins();
|
pluginManager.disablePlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to load the configuration from a file.
|
||||||
|
*/
|
||||||
public static void loadConfig() {
|
public static void loadConfig() {
|
||||||
try (FileReader file = new FileReader(configFile)) {
|
try (FileReader file = new FileReader(configFile)) {
|
||||||
config = gson.fromJson(file, Config.class);
|
config = gson.fromJson(file, ConfigContainer.class);
|
||||||
saveConfig();
|
} catch (Exception exception) {
|
||||||
} catch (Exception e) {
|
Grasscutter.saveConfig(null);
|
||||||
Grasscutter.config = new Config();
|
config = new ConfigContainer();
|
||||||
saveConfig();
|
} catch (Error error) {
|
||||||
|
// Occurred probably from an outdated config file.
|
||||||
|
Grasscutter.saveConfig(null);
|
||||||
|
config = new ConfigContainer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void loadLanguage() {
|
public static void loadLanguage() {
|
||||||
var locale = config.LocaleLanguage;
|
var locale = config.language.language;
|
||||||
language = Language.getLanguage(Utils.getLanguageCode(locale));
|
language = Language.getLanguage(Utils.getLanguageCode(locale));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveConfig() {
|
/**
|
||||||
|
* Saves the provided server configuration.
|
||||||
|
* @param config The configuration to save, or null for a new one.
|
||||||
|
*/
|
||||||
|
public static void saveConfig(@Nullable ConfigContainer config) {
|
||||||
|
if(config == null) config = new ConfigContainer();
|
||||||
|
|
||||||
try (FileWriter file = new FileWriter(configFile)) {
|
try (FileWriter file = new FileWriter(configFile)) {
|
||||||
file.write(gson.toJson(config));
|
file.write(gson.toJson(config));
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
Grasscutter.getLogger().error("Unable to write to config file.");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Unable to save config file.");
|
Grasscutter.getLogger().error("Unable to save config file.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void startConsole() {
|
public static void startConsole() {
|
||||||
// Console should not start in dispatch only mode.
|
// Console should not start in dispatch only mode.
|
||||||
if (getConfig().RunMode == ServerRunMode.DISPATCH_ONLY) {
|
if (SERVER.runMode == ServerRunMode.DISPATCH_ONLY) {
|
||||||
getLogger().info(translate("messages.dispatch.no_commands_error"));
|
getLogger().info(translate("messages.dispatch.no_commands_error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -198,7 +216,7 @@ public final class Grasscutter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Config getConfig() {
|
public static ConfigContainer getConfig() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +63,10 @@ public final class GiveCharCommand implements CommandHandler {
|
|||||||
// Calculate ascension level.
|
// Calculate ascension level.
|
||||||
int ascension;
|
int ascension;
|
||||||
if (level <= 40) {
|
if (level <= 40) {
|
||||||
ascension = (int) Math.ceil(level / 20f);
|
ascension = (int) Math.ceil(level / 20f) - 1;
|
||||||
} else {
|
} else {
|
||||||
ascension = (int) Math.ceil(level / 10f) - 3;
|
ascension = (int) Math.ceil(level / 10f) - 3;
|
||||||
|
ascension = Math.min(ascension, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar avatar = new Avatar(avatarId);
|
Avatar avatar = new Avatar(avatarId);
|
||||||
|
@ -31,19 +31,26 @@ public final class LanguageCommand implements CommandHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String langCode = args.get(0);
|
String langCode = args.get(0);
|
||||||
String actualLangCode = null;
|
|
||||||
|
var languageInst = Grasscutter.getLanguage(langCode);
|
||||||
|
var actualLangCode = languageInst.getLanguageCode();
|
||||||
|
var locale = Locale.forLanguageTag(actualLangCode);
|
||||||
if (sender != null) {
|
if (sender != null) {
|
||||||
var locale = Locale.forLanguageTag(langCode);
|
|
||||||
actualLangCode = Utils.getLanguageCode(locale);
|
|
||||||
var account = sender.getAccount();
|
var account = sender.getAccount();
|
||||||
account.setLocale(locale);
|
account.setLocale(locale);
|
||||||
account.save();
|
account.save();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var languageInst = Grasscutter.getLanguage(langCode);
|
|
||||||
actualLangCode = languageInst.getLanguageCode();
|
|
||||||
Grasscutter.setLanguage(languageInst);
|
Grasscutter.setLanguage(languageInst);
|
||||||
|
var config = Grasscutter.getConfig();
|
||||||
|
config.language.language = locale;
|
||||||
|
Grasscutter.saveConfig(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!langCode.equals(actualLangCode)) {
|
||||||
|
CommandHandler.sendMessage(sender, translate(sender, "commands.language.language_not_found", langCode));
|
||||||
|
}
|
||||||
|
|
||||||
CommandHandler.sendMessage(sender, translate(sender, "commands.language.language_changed", actualLangCode));
|
CommandHandler.sendMessage(sender, translate(sender, "commands.language.language_changed", actualLangCode));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,11 @@ import emu.grasscutter.data.custom.QuestConfig;
|
|||||||
import emu.grasscutter.data.custom.QuestConfigData;
|
import emu.grasscutter.data.custom.QuestConfigData;
|
||||||
import emu.grasscutter.data.custom.QuestConfigData.SubQuestConfigData;
|
import emu.grasscutter.data.custom.QuestConfigData.SubQuestConfigData;
|
||||||
import emu.grasscutter.data.custom.ScenePointEntry;
|
import emu.grasscutter.data.custom.ScenePointEntry;
|
||||||
import emu.grasscutter.game.world.SpawnDataEntry;
|
import emu.grasscutter.game.world.SpawnDataEntry.*;
|
||||||
import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class ResourceLoader {
|
public class ResourceLoader {
|
||||||
|
|
||||||
public static List<Class<?>> getResourceDefClasses() {
|
public static List<Class<?>> getResourceDefClasses() {
|
||||||
@ -131,7 +132,7 @@ public class ResourceLoader {
|
|||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
protected static void loadFromResource(Class<?> c, String fileName, Int2ObjectMap map) throws Exception {
|
protected static void loadFromResource(Class<?> c, String fileName, Int2ObjectMap map) throws Exception {
|
||||||
FileReader fileReader = new FileReader(Grasscutter.getConfig().RESOURCE_FOLDER + "ExcelBinOutput/" + fileName);
|
FileReader fileReader = new FileReader(RESOURCE("ExcelBinOutput/" + fileName));
|
||||||
Gson gson = Grasscutter.getGsonFactory();
|
Gson gson = Grasscutter.getGsonFactory();
|
||||||
List list = gson.fromJson(fileReader, List.class);
|
List list = gson.fromJson(fileReader, List.class);
|
||||||
|
|
||||||
@ -145,7 +146,7 @@ public class ResourceLoader {
|
|||||||
|
|
||||||
private static void loadScenePoints() {
|
private static void loadScenePoints() {
|
||||||
Pattern pattern = Pattern.compile("(?<=scene)(.*?)(?=_point.json)");
|
Pattern pattern = Pattern.compile("(?<=scene)(.*?)(?=_point.json)");
|
||||||
File folder = new File(Grasscutter.getConfig().RESOURCE_FOLDER + "BinOutput/Scene/Point");
|
File folder = new File(RESOURCE("BinOutput/Scene/Point"));
|
||||||
|
|
||||||
if (!folder.isDirectory() || !folder.exists() || folder.listFiles() == null) {
|
if (!folder.isDirectory() || !folder.exists() || folder.listFiles() == null) {
|
||||||
Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!");
|
Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!");
|
||||||
@ -154,8 +155,7 @@ public class ResourceLoader {
|
|||||||
|
|
||||||
List<ScenePointEntry> scenePointList = new ArrayList<>();
|
List<ScenePointEntry> scenePointList = new ArrayList<>();
|
||||||
for (File file : Objects.requireNonNull(folder.listFiles())) {
|
for (File file : Objects.requireNonNull(folder.listFiles())) {
|
||||||
ScenePointConfig config = null;
|
ScenePointConfig config; Integer sceneId;
|
||||||
Integer sceneId = null;
|
|
||||||
|
|
||||||
Matcher matcher = pattern.matcher(file.getName());
|
Matcher matcher = pattern.matcher(file.getName());
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
@ -194,7 +194,7 @@ public class ResourceLoader {
|
|||||||
|
|
||||||
private static void loadAbilityEmbryos() {
|
private static void loadAbilityEmbryos() {
|
||||||
// Read from cached file if exists
|
// Read from cached file if exists
|
||||||
File embryoCache = new File(Grasscutter.getConfig().DATA_FOLDER + "AbilityEmbryos.json");
|
File embryoCache = new File(DATA("AbilityEmbryos.json"));
|
||||||
List<AbilityEmbryoEntry> embryoList = null;
|
List<AbilityEmbryoEntry> embryoList = null;
|
||||||
|
|
||||||
if (embryoCache.exists()) {
|
if (embryoCache.exists()) {
|
||||||
@ -209,7 +209,7 @@ public class ResourceLoader {
|
|||||||
Pattern pattern = Pattern.compile("(?<=ConfigAvatar_)(.*?)(?=.json)");
|
Pattern pattern = Pattern.compile("(?<=ConfigAvatar_)(.*?)(?=.json)");
|
||||||
|
|
||||||
embryoList = new LinkedList<>();
|
embryoList = new LinkedList<>();
|
||||||
File folder = new File(Utils.toFilePath(Grasscutter.getConfig().RESOURCE_FOLDER + "BinOutput/Avatar/"));
|
File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Avatar/")));
|
||||||
File[] files = folder.listFiles();
|
File[] files = folder.listFiles();
|
||||||
if(files == null) {
|
if(files == null) {
|
||||||
Grasscutter.getLogger().error("Error loading ability embryos: no files found in " + folder.getAbsolutePath());
|
Grasscutter.getLogger().error("Error loading ability embryos: no files found in " + folder.getAbsolutePath());
|
||||||
@ -256,7 +256,7 @@ public class ResourceLoader {
|
|||||||
|
|
||||||
private static void loadAbilityModifiers() {
|
private static void loadAbilityModifiers() {
|
||||||
// Load from BinOutput
|
// Load from BinOutput
|
||||||
File folder = new File(Utils.toFilePath(Grasscutter.getConfig().RESOURCE_FOLDER + "BinOutput/Ability/Temp/AvatarAbilities/"));
|
File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Ability/Temp/AvatarAbilities/")));
|
||||||
File[] files = folder.listFiles();
|
File[] files = folder.listFiles();
|
||||||
if (files == null) {
|
if (files == null) {
|
||||||
Grasscutter.getLogger().error("Error loading ability modifiers: no files found in " + folder.getAbsolutePath());
|
Grasscutter.getLogger().error("Error loading ability modifiers: no files found in " + folder.getAbsolutePath());
|
||||||
@ -264,7 +264,7 @@ public class ResourceLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
List<AbilityConfigData> abilityConfigList = null;
|
List<AbilityConfigData> abilityConfigList;
|
||||||
|
|
||||||
try (FileReader fileReader = new FileReader(file)) {
|
try (FileReader fileReader = new FileReader(file)) {
|
||||||
abilityConfigList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, AbilityConfigData.class).getType());
|
abilityConfigList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, AbilityConfigData.class).getType());
|
||||||
@ -319,7 +319,7 @@ public class ResourceLoader {
|
|||||||
|
|
||||||
private static void loadSpawnData() {
|
private static void loadSpawnData() {
|
||||||
// Read from cached file if exists
|
// Read from cached file if exists
|
||||||
File spawnDataEntries = new File(Grasscutter.getConfig().DATA_FOLDER + "Spawns.json");
|
File spawnDataEntries = new File(DATA("Spawns.json"));
|
||||||
List<SpawnGroupEntry> spawnEntryList = null;
|
List<SpawnGroupEntry> spawnEntryList = null;
|
||||||
|
|
||||||
if (spawnDataEntries.exists()) {
|
if (spawnDataEntries.exists()) {
|
||||||
@ -337,16 +337,14 @@ public class ResourceLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (SpawnGroupEntry entry : spawnEntryList) {
|
for (SpawnGroupEntry entry : spawnEntryList) {
|
||||||
entry.getSpawns().stream().forEach(s -> {
|
entry.getSpawns().forEach(s -> s.setGroup(entry));
|
||||||
s.setGroup(entry);
|
|
||||||
});
|
|
||||||
GameDepot.getSpawnListById(entry.getSceneId()).insert(entry, entry.getPos().getX(), entry.getPos().getZ());
|
GameDepot.getSpawnListById(entry.getSceneId()).insert(entry, entry.getPos().getX(), entry.getPos().getZ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadOpenConfig() {
|
private static void loadOpenConfig() {
|
||||||
// Read from cached file if exists
|
// Read from cached file if exists
|
||||||
File openConfigCache = new File(Grasscutter.getConfig().DATA_FOLDER + "OpenConfig.json");
|
File openConfigCache = new File(DATA("OpenConfig.json"));
|
||||||
List<OpenConfigEntry> list = null;
|
List<OpenConfigEntry> list = null;
|
||||||
|
|
||||||
if (openConfigCache.exists()) {
|
if (openConfigCache.exists()) {
|
||||||
@ -361,7 +359,7 @@ public class ResourceLoader {
|
|||||||
String[] folderNames = {"BinOutput/Talent/EquipTalents/", "BinOutput/Talent/AvatarTalents/"};
|
String[] folderNames = {"BinOutput/Talent/EquipTalents/", "BinOutput/Talent/AvatarTalents/"};
|
||||||
|
|
||||||
for (String name : folderNames) {
|
for (String name : folderNames) {
|
||||||
File folder = new File(Utils.toFilePath(Grasscutter.getConfig().RESOURCE_FOLDER + name));
|
File folder = new File(Utils.toFilePath(RESOURCE(name)));
|
||||||
File[] files = folder.listFiles();
|
File[] files = folder.listFiles();
|
||||||
if(files == null) {
|
if(files == null) {
|
||||||
Grasscutter.getLogger().error("Error loading open config: no files found in " + folder.getAbsolutePath()); return;
|
Grasscutter.getLogger().error("Error loading open config: no files found in " + folder.getAbsolutePath()); return;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package emu.grasscutter.database;
|
package emu.grasscutter.database;
|
||||||
|
|
||||||
import com.mongodb.MongoClientURI;
|
|
||||||
import com.mongodb.MongoCommandException;
|
import com.mongodb.MongoCommandException;
|
||||||
import com.mongodb.client.MongoClient;
|
import com.mongodb.client.MongoClient;
|
||||||
import com.mongodb.client.MongoClients;
|
import com.mongodb.client.MongoClients;
|
||||||
@ -23,11 +22,9 @@ import emu.grasscutter.game.player.Player;
|
|||||||
import emu.grasscutter.game.quest.GameMainQuest;
|
import emu.grasscutter.game.quest.GameMainQuest;
|
||||||
import emu.grasscutter.game.quest.GameQuest;
|
import emu.grasscutter.game.quest.GameQuest;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class DatabaseManager {
|
public final class DatabaseManager {
|
||||||
|
|
||||||
private static MongoClient mongoClient;
|
|
||||||
private static MongoClient dispatchMongoClient;
|
|
||||||
|
|
||||||
private static Datastore datastore;
|
private static Datastore datastore;
|
||||||
private static Datastore dispatchDatastore;
|
private static Datastore dispatchDatastore;
|
||||||
|
|
||||||
@ -47,7 +44,7 @@ public final class DatabaseManager {
|
|||||||
// Yes. I very dislike this method. However, this will be good for now.
|
// Yes. I very dislike this method. However, this will be good for now.
|
||||||
// TODO: Add dispatch routes for player account management
|
// TODO: Add dispatch routes for player account management
|
||||||
public static Datastore getAccountDatastore() {
|
public static Datastore getAccountDatastore() {
|
||||||
if(Grasscutter.getConfig().RunMode == ServerRunMode.GAME_ONLY) {
|
if(SERVER.runMode == ServerRunMode.GAME_ONLY) {
|
||||||
return dispatchDatastore;
|
return dispatchDatastore;
|
||||||
} else {
|
} else {
|
||||||
return datastore;
|
return datastore;
|
||||||
@ -56,13 +53,13 @@ public final class DatabaseManager {
|
|||||||
|
|
||||||
public static void initialize() {
|
public static void initialize() {
|
||||||
// Initialize
|
// Initialize
|
||||||
MongoClient mongoClient = MongoClients.create(Grasscutter.getConfig().DatabaseUrl);
|
MongoClient mongoClient = MongoClients.create(DATABASE.connectionUri);
|
||||||
|
|
||||||
// Set mapper options.
|
// Set mapper options.
|
||||||
MapperOptions mapperOptions = MapperOptions.builder()
|
MapperOptions mapperOptions = MapperOptions.builder()
|
||||||
.storeEmpties(true).storeNulls(false).build();
|
.storeEmpties(true).storeNulls(false).build();
|
||||||
// Create data store.
|
// Create data store.
|
||||||
datastore = Morphia.createDatastore(mongoClient, Grasscutter.getConfig().DatabaseCollection, mapperOptions);
|
datastore = Morphia.createDatastore(mongoClient, DATABASE.collection, mapperOptions);
|
||||||
// Map classes.
|
// Map classes.
|
||||||
datastore.getMapper().map(mappedClasses);
|
datastore.getMapper().map(mappedClasses);
|
||||||
|
|
||||||
@ -83,9 +80,9 @@ public final class DatabaseManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Grasscutter.getConfig().RunMode == ServerRunMode.GAME_ONLY) {
|
if(SERVER.runMode == ServerRunMode.GAME_ONLY) {
|
||||||
dispatchMongoClient = MongoClients.create(Grasscutter.getConfig().getGameServerOptions().DispatchServerDatabaseUrl);
|
MongoClient dispatchMongoClient = MongoClients.create(GAME_OPTIONS.databaseInfo.connectionUri);
|
||||||
dispatchDatastore = Morphia.createDatastore(dispatchMongoClient, Grasscutter.getConfig().getGameServerOptions().DispatchServerDatabaseCollection);
|
dispatchDatastore = Morphia.createDatastore(dispatchMongoClient, GAME_OPTIONS.databaseInfo.collection);
|
||||||
|
|
||||||
// Ensure indexes for dispatch server
|
// Ensure indexes for dispatch server
|
||||||
try {
|
try {
|
||||||
|
@ -12,7 +12,7 @@ import java.util.Locale;
|
|||||||
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
|
|
||||||
import com.mongodb.DBObject;
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
@Entity(value = "accounts", useDiscriminator = false)
|
@Entity(value = "accounts", useDiscriminator = false)
|
||||||
public class Account {
|
public class Account {
|
||||||
@ -34,7 +34,7 @@ public class Account {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public Account() {
|
public Account() {
|
||||||
this.permissions = new ArrayList<>();
|
this.permissions = new ArrayList<>();
|
||||||
this.locale = Grasscutter.getConfig().LocaleLanguage;
|
this.locale = LANGUAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
@ -180,7 +180,7 @@ public class Account {
|
|||||||
|
|
||||||
// Set account default language as server default language
|
// Set account default language as server default language
|
||||||
if (!document.containsKey("locale")) {
|
if (!document.containsKey("locale")) {
|
||||||
this.locale = Grasscutter.getConfig().LocaleLanguage;
|
this.locale = LANGUAGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ import java.io.FileReader;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class DropManager {
|
public class DropManager {
|
||||||
public GameServer getGameServer() {
|
public GameServer getGameServer() {
|
||||||
return gameServer;
|
return gameServer;
|
||||||
@ -41,7 +43,7 @@ public class DropManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void load() {
|
public synchronized void load() {
|
||||||
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "Drop.json")) {
|
try (FileReader fileReader = new FileReader(DATA("Drop.json"))) {
|
||||||
getDropData().clear();
|
getDropData().clear();
|
||||||
List<DropInfo> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DropInfo.class).getType());
|
List<DropInfo> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DropInfo.class).getType());
|
||||||
if(banners.size() > 0) {
|
if(banners.size() > 0) {
|
||||||
@ -69,9 +71,7 @@ public class DropManager {
|
|||||||
} else {
|
} else {
|
||||||
// target is null if items will be added are shared. no one could pick it up because of the combination(give + shared)
|
// target is null if items will be added are shared. no one could pick it up because of the combination(give + shared)
|
||||||
// so it will be sent to all players' inventories directly.
|
// so it will be sent to all players' inventories directly.
|
||||||
dropScene.getPlayers().forEach(x -> {
|
dropScene.getPlayers().forEach(x -> x.getInventory().addItem(new GameItem(itemData, num), ActionReason.SubfieldDrop, true));
|
||||||
x.getInventory().addItem(new GameItem(itemData, num), ActionReason.SubfieldDrop, true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import java.io.FileReader;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class ExpeditionManager {
|
public class ExpeditionManager {
|
||||||
public GameServer getGameServer() {
|
public GameServer getGameServer() {
|
||||||
return gameServer;
|
return gameServer;
|
||||||
@ -28,7 +30,7 @@ public class ExpeditionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void load() {
|
public synchronized void load() {
|
||||||
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "ExpeditionReward.json")) {
|
try (FileReader fileReader = new FileReader(DATA("ExpeditionReward.json"))) {
|
||||||
getExpeditionRewardDataList().clear();
|
getExpeditionRewardDataList().clear();
|
||||||
List<ExpeditionRewardInfo> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ExpeditionRewardInfo.class).getType());
|
List<ExpeditionRewardInfo> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ExpeditionRewardInfo.class).getType());
|
||||||
if(banners.size() > 0) {
|
if(banners.size() > 0) {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package emu.grasscutter.game.gacha;
|
package emu.grasscutter.game.gacha;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
|
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
|
||||||
import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo;
|
import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class GachaBanner {
|
public class GachaBanner {
|
||||||
private int gachaType;
|
private int gachaType;
|
||||||
private int scheduleId;
|
private int scheduleId;
|
||||||
@ -95,15 +96,11 @@ public class GachaBanner {
|
|||||||
public GachaInfo toProto() {
|
public GachaInfo toProto() {
|
||||||
return toProto("");
|
return toProto("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public GachaInfo toProto(String sessionKey) {
|
public GachaInfo toProto(String sessionKey) {
|
||||||
String record = "http" + (Grasscutter.getConfig().getDispatchOptions().FrontHTTPS ? "s" : "") + "://"
|
String record = "http" + (DISPATCH_INFO.encryption.useInRouting ? "s" : "") + "://"
|
||||||
+ (Grasscutter.getConfig().getDispatchOptions().PublicIp.isEmpty() ?
|
+ lr(DISPATCH_INFO.accessAddress, DISPATCH_INFO.bindAddress) + ":"
|
||||||
Grasscutter.getConfig().getDispatchOptions().Ip :
|
+ lr(DISPATCH_INFO.accessPort, DISPATCH_INFO.bindPort)
|
||||||
Grasscutter.getConfig().getDispatchOptions().PublicIp)
|
|
||||||
+ ":"
|
|
||||||
+ Integer.toString(Grasscutter.getConfig().getDispatchOptions().PublicPort == 0 ?
|
|
||||||
Grasscutter.getConfig().getDispatchOptions().Port :
|
|
||||||
Grasscutter.getConfig().getDispatchOptions().PublicPort)
|
|
||||||
+ "/gacha?s=" + sessionKey + "&gachaType=" + gachaType;
|
+ "/gacha?s=" + sessionKey + "&gachaType=" + gachaType;
|
||||||
// Grasscutter.getLogger().info("record = " + record);
|
// Grasscutter.getLogger().info("record = " + record);
|
||||||
GachaInfo.Builder info = GachaInfo.newBuilder()
|
GachaInfo.Builder info = GachaInfo.newBuilder()
|
||||||
|
@ -34,20 +34,22 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
|
|||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import org.greenrobot.eventbus.Subscribe;
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class GachaManager {
|
public class GachaManager {
|
||||||
private final GameServer server;
|
private final GameServer server;
|
||||||
private final Int2ObjectMap<GachaBanner> gachaBanners;
|
private final Int2ObjectMap<GachaBanner> gachaBanners;
|
||||||
private GetGachaInfoRsp cachedProto;
|
private GetGachaInfoRsp cachedProto;
|
||||||
WatchService watchService;
|
WatchService watchService;
|
||||||
|
|
||||||
private int[] yellowAvatars = new int[] {1003, 1016, 1042, 1035, 1041};
|
private final int[] yellowAvatars = new int[] {1003, 1016, 1042, 1035, 1041};
|
||||||
private int[] yellowWeapons = new int[] {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502};
|
private final int[] yellowWeapons = new int[] {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502};
|
||||||
private int[] purpleAvatars = new int[] {1006, 1014, 1015, 1020, 1021, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1064};
|
private final int[] purpleAvatars = new int[] {1006, 1014, 1015, 1020, 1021, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1064};
|
||||||
private int[] purpleWeapons = new int[] {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405};
|
private final int[] purpleWeapons = new int[] {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405};
|
||||||
private int[] blueWeapons = new int[] {11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304};
|
private final int[] blueWeapons = new int[] {11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304};
|
||||||
|
|
||||||
private static int starglitterId = 221;
|
private static final int starglitterId = 221;
|
||||||
private static int stardustId = 222;
|
private static final int stardustId = 222;
|
||||||
|
|
||||||
public GachaManager(GameServer server) {
|
public GachaManager(GameServer server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
@ -73,7 +75,7 @@ public class GachaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void load() {
|
public synchronized void load() {
|
||||||
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "Banners.json")) {
|
try (FileReader fileReader = new FileReader(DATA("Banners.json"))) {
|
||||||
getGachaBanners().clear();
|
getGachaBanners().clear();
|
||||||
List<GachaBanner> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, GachaBanner.class).getType());
|
List<GachaBanner> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, GachaBanner.class).getType());
|
||||||
if(banners.size() > 0) {
|
if(banners.size() > 0) {
|
||||||
@ -242,15 +244,9 @@ public class GachaManager {
|
|||||||
} else {
|
} else {
|
||||||
// Is weapon
|
// Is weapon
|
||||||
switch (itemData.getRankLevel()) {
|
switch (itemData.getRankLevel()) {
|
||||||
case 5:
|
case 5 -> addStarglitter = 10;
|
||||||
addStarglitter = 10;
|
case 4 -> addStarglitter = 2;
|
||||||
break;
|
case 3 -> addStardust = 15;
|
||||||
case 4:
|
|
||||||
addStarglitter = 2;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
addStardust = 15;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +286,7 @@ public class GachaManager {
|
|||||||
if(this.watchService == null) {
|
if(this.watchService == null) {
|
||||||
try {
|
try {
|
||||||
this.watchService = FileSystems.getDefault().newWatchService();
|
this.watchService = FileSystems.getDefault().newWatchService();
|
||||||
Path path = new File(Grasscutter.getConfig().DATA_FOLDER).toPath();
|
Path path = new File(DATA_FOLDER).toPath();
|
||||||
path.register(watchService, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH);
|
path.register(watchService, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload");
|
Grasscutter.getLogger().error("Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload");
|
||||||
@ -303,7 +299,7 @@ public class GachaManager {
|
|||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public synchronized void watchBannerJson(GameServerTickEvent tickEvent) {
|
public synchronized void watchBannerJson(GameServerTickEvent tickEvent) {
|
||||||
if(Grasscutter.getConfig().getGameServerOptions().WatchGacha) {
|
if(GAME_OPTIONS.watchGachaConfig) {
|
||||||
try {
|
try {
|
||||||
WatchKey watchKey = watchService.take();
|
WatchKey watchKey = watchService.take();
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.def.AvatarCostumeData;
|
import emu.grasscutter.data.def.AvatarCostumeData;
|
||||||
import emu.grasscutter.data.def.AvatarData;
|
import emu.grasscutter.data.def.AvatarData;
|
||||||
@ -15,7 +14,6 @@ import emu.grasscutter.data.def.ItemData;
|
|||||||
import emu.grasscutter.database.DatabaseHelper;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
import emu.grasscutter.game.avatar.AvatarStorage;
|
import emu.grasscutter.game.avatar.AvatarStorage;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.ActionReason;
|
import emu.grasscutter.game.props.ActionReason;
|
||||||
import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam;
|
import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam;
|
||||||
@ -28,6 +26,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class Inventory implements Iterable<GameItem> {
|
public class Inventory implements Iterable<GameItem> {
|
||||||
private final Player player;
|
private final Player player;
|
||||||
|
|
||||||
@ -39,10 +39,10 @@ public class Inventory implements Iterable<GameItem> {
|
|||||||
this.store = new Long2ObjectOpenHashMap<>();
|
this.store = new Long2ObjectOpenHashMap<>();
|
||||||
this.inventoryTypes = new Int2ObjectOpenHashMap<>();
|
this.inventoryTypes = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
this.createInventoryTab(ItemType.ITEM_WEAPON, new EquipInventoryTab(Grasscutter.getConfig().getGameServerOptions().InventoryLimitWeapon));
|
this.createInventoryTab(ItemType.ITEM_WEAPON, new EquipInventoryTab(INVENTORY_LIMITS.weapons));
|
||||||
this.createInventoryTab(ItemType.ITEM_RELIQUARY, new EquipInventoryTab(Grasscutter.getConfig().getGameServerOptions().InventoryLimitRelic));
|
this.createInventoryTab(ItemType.ITEM_RELIQUARY, new EquipInventoryTab(INVENTORY_LIMITS.relics));
|
||||||
this.createInventoryTab(ItemType.ITEM_MATERIAL, new MaterialInventoryTab(Grasscutter.getConfig().getGameServerOptions().InventoryLimitMaterial));
|
this.createInventoryTab(ItemType.ITEM_MATERIAL, new MaterialInventoryTab(INVENTORY_LIMITS.materials));
|
||||||
this.createInventoryTab(ItemType.ITEM_FURNITURE, new MaterialInventoryTab(Grasscutter.getConfig().getGameServerOptions().InventoryLimitFurniture));
|
this.createInventoryTab(ItemType.ITEM_FURNITURE, new MaterialInventoryTab(INVENTORY_LIMITS.furniture));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
@ -242,24 +242,18 @@ public class Inventory implements Iterable<GameItem> {
|
|||||||
|
|
||||||
private void addVirtualItem(int itemId, int count) {
|
private void addVirtualItem(int itemId, int count) {
|
||||||
switch (itemId) {
|
switch (itemId) {
|
||||||
case 101: // Character exp
|
case 101 -> // Character exp
|
||||||
getPlayer().getServer().getInventoryManager().upgradeAvatar(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
getPlayer().getServer().getInventoryManager().upgradeAvatar(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||||
break;
|
case 102 -> // Adventure exp
|
||||||
case 102: // Adventure exp
|
getPlayer().addExpDirectly(count);
|
||||||
getPlayer().addExpDirectly(count);
|
case 105 -> // Companionship exp
|
||||||
break;
|
getPlayer().getServer().getInventoryManager().upgradeAvatarFetterLevel(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||||
case 105: // Companionship exp
|
case 201 -> // Primogem
|
||||||
getPlayer().getServer().getInventoryManager().upgradeAvatarFetterLevel(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
getPlayer().setPrimogems(player.getPrimogems() + count);
|
||||||
break;
|
case 202 -> // Mora
|
||||||
case 201: // Primogem
|
getPlayer().setMora(player.getMora() + count);
|
||||||
getPlayer().setPrimogems(player.getPrimogems() + count);
|
case 203 -> // Genesis Crystals
|
||||||
break;
|
getPlayer().setCrystals(player.getCrystals() + count);
|
||||||
case 202: // Mora
|
|
||||||
getPlayer().setMora(player.getMora() + count);
|
|
||||||
break;
|
|
||||||
case 203: // Genesis Crystals
|
|
||||||
getPlayer().setCrystals(player.getCrystals() + count);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import java.lang.Math;
|
import java.lang.Math;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class StaminaManager {
|
public class StaminaManager {
|
||||||
|
|
||||||
// TODO: Skiff state detection?
|
// TODO: Skiff state detection?
|
||||||
@ -293,9 +295,10 @@ public class StaminaManager {
|
|||||||
|
|
||||||
// Returns new stamina and sends PlayerPropNotify
|
// Returns new stamina and sends PlayerPropNotify
|
||||||
public int setStamina(GameSession session, String reason, int newStamina) {
|
public int setStamina(GameSession session, String reason, int newStamina) {
|
||||||
if (!Grasscutter.getConfig().OpenStamina) {
|
if (!GAME_OPTIONS.staminaUsage) {
|
||||||
newStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
newStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set stamina
|
// set stamina
|
||||||
player.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
|
player.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
|
||||||
session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
||||||
|
@ -63,6 +63,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
@Entity(value = "players", useDiscriminator = false)
|
@Entity(value = "players", useDiscriminator = false)
|
||||||
public class Player {
|
public class Player {
|
||||||
|
|
||||||
@ -358,7 +360,7 @@ public class Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private float getExpModifier() {
|
private float getExpModifier() {
|
||||||
return Grasscutter.getConfig().getGameServerOptions().getGameRates().ADVENTURE_EXP_RATE;
|
return GAME_OPTIONS.rates.adventureExp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Affected by exp rate
|
// Affected by exp rate
|
||||||
@ -1248,7 +1250,7 @@ public class Player {
|
|||||||
} else if (prop == PlayerProperty.PROP_LAST_CHANGE_AVATAR_TIME) { // 10001
|
} else if (prop == PlayerProperty.PROP_LAST_CHANGE_AVATAR_TIME) { // 10001
|
||||||
// TODO: implement sanity check
|
// TODO: implement sanity check
|
||||||
} else if (prop == PlayerProperty.PROP_MAX_SPRING_VOLUME) { // 10002
|
} else if (prop == PlayerProperty.PROP_MAX_SPRING_VOLUME) { // 10002
|
||||||
if (!(value >= 0 && value <= getSotSManager().GlobalMaximumSpringVolume)) { return false; }
|
if (!(value >= 0 && value <= SotSManager.GlobalMaximumSpringVolume)) { return false; }
|
||||||
} else if (prop == PlayerProperty.PROP_CUR_SPRING_VOLUME) { // 10003
|
} else if (prop == PlayerProperty.PROP_CUR_SPRING_VOLUME) { // 10003
|
||||||
int playerMaximumSpringVolume = getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
|
int playerMaximumSpringVolume = getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
|
||||||
if (!(value >= 0 && value <= playerMaximumSpringVolume)) { return false; }
|
if (!(value >= 0 && value <= playerMaximumSpringVolume)) { return false; }
|
||||||
@ -1265,7 +1267,7 @@ public class Player {
|
|||||||
} else if (prop == PlayerProperty.PROP_IS_TRANSFERABLE) { // 10009
|
} else if (prop == PlayerProperty.PROP_IS_TRANSFERABLE) { // 10009
|
||||||
if (!(0 <= value && value <= 1)) { return false; }
|
if (!(0 <= value && value <= 1)) { return false; }
|
||||||
} else if (prop == PlayerProperty.PROP_MAX_STAMINA) { // 10010
|
} else if (prop == PlayerProperty.PROP_MAX_STAMINA) { // 10010
|
||||||
if (!(value >= 0 && value <= getStaminaManager().GlobalMaximumStamina)) { return false; }
|
if (!(value >= 0 && value <= StaminaManager.GlobalMaximumStamina)) { return false; }
|
||||||
} else if (prop == PlayerProperty.PROP_CUR_PERSIST_STAMINA) { // 10011
|
} else if (prop == PlayerProperty.PROP_CUR_PERSIST_STAMINA) { // 10011
|
||||||
int playerMaximumStamina = getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
int playerMaximumStamina = getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||||
if (!(value >= 0 && value <= playerMaximumStamina)) { return false; }
|
if (!(value >= 0 && value <= playerMaximumStamina)) { return false; }
|
||||||
|
@ -4,10 +4,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import dev.morphia.annotations.Entity;
|
import dev.morphia.annotations.Entity;
|
||||||
import emu.grasscutter.GameConstants;
|
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class TeamInfo {
|
public class TeamInfo {
|
||||||
private String name;
|
private String name;
|
||||||
@ -15,7 +15,7 @@ public class TeamInfo {
|
|||||||
|
|
||||||
public TeamInfo() {
|
public TeamInfo() {
|
||||||
this.name = "";
|
this.name = "";
|
||||||
this.avatars = new ArrayList<>(Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeam);
|
this.avatars = new ArrayList<>(GAME_OPTIONS.avatarLimits.singlePlayerTeam);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TeamInfo(List<Integer> avatars) {
|
public TeamInfo(List<Integer> avatars) {
|
||||||
@ -44,7 +44,7 @@ public class TeamInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean addAvatar(Avatar avatar) {
|
public boolean addAvatar(Avatar avatar) {
|
||||||
if (size() >= Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeam || contains(avatar)) {
|
if (size() >= GAME_OPTIONS.avatarLimits.singlePlayerTeam || contains(avatar)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ public class TeamInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void copyFrom(TeamInfo team) {
|
public void copyFrom(TeamInfo team) {
|
||||||
copyFrom(team, Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeam);
|
copyFrom(team, GAME_OPTIONS.avatarLimits.singlePlayerTeam);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyFrom(TeamInfo team, int maxTeamSize) {
|
public void copyFrom(TeamInfo team, int maxTeamSize) {
|
||||||
|
@ -5,7 +5,6 @@ import java.util.*;
|
|||||||
import dev.morphia.annotations.Entity;
|
import dev.morphia.annotations.Entity;
|
||||||
import dev.morphia.annotations.Transient;
|
import dev.morphia.annotations.Transient;
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
import emu.grasscutter.game.entity.EntityAvatar;
|
||||||
@ -40,6 +39,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class TeamManager {
|
public class TeamManager {
|
||||||
@Transient private Player player;
|
@Transient private Player player;
|
||||||
@ -174,13 +175,14 @@ public class TeamManager {
|
|||||||
|
|
||||||
public int getMaxTeamSize() {
|
public int getMaxTeamSize() {
|
||||||
if (getPlayer().isInMultiplayer()) {
|
if (getPlayer().isInMultiplayer()) {
|
||||||
int max = Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeamMultiplayer;
|
int max = GAME_OPTIONS.avatarLimits.multiplayerTeam;
|
||||||
if (getPlayer().getWorld().getHost() == this.getPlayer()) {
|
if (getPlayer().getWorld().getHost() == this.getPlayer()) {
|
||||||
return Math.max(1, (int) Math.ceil(max / (double) getWorld().getPlayerCount()));
|
return Math.max(1, (int) Math.ceil(max / (double) getWorld().getPlayerCount()));
|
||||||
}
|
}
|
||||||
return Math.max(1, (int) Math.floor(max / (double) getWorld().getPlayerCount()));
|
return Math.max(1, (int) Math.floor(max / (double) getWorld().getPlayerCount()));
|
||||||
}
|
}
|
||||||
return Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeam;
|
|
||||||
|
return GAME_OPTIONS.avatarLimits.singlePlayerTeam;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
@ -236,7 +238,7 @@ public class TeamManager {
|
|||||||
// Add back entities into team
|
// Add back entities into team
|
||||||
for (int i = 0; i < this.getCurrentTeamInfo().getAvatars().size(); i++) {
|
for (int i = 0; i < this.getCurrentTeamInfo().getAvatars().size(); i++) {
|
||||||
int avatarId = this.getCurrentTeamInfo().getAvatars().get(i);
|
int avatarId = this.getCurrentTeamInfo().getAvatars().get(i);
|
||||||
EntityAvatar entity = null;
|
EntityAvatar entity;
|
||||||
|
|
||||||
if (existingAvatars.containsKey(avatarId)) {
|
if (existingAvatars.containsKey(avatarId)) {
|
||||||
entity = existingAvatars.get(avatarId);
|
entity = existingAvatars.get(avatarId);
|
||||||
@ -303,8 +305,8 @@ public class TeamManager {
|
|||||||
|
|
||||||
// Set team data
|
// Set team data
|
||||||
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
|
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (Long aLong : list) {
|
||||||
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(list.get(i));
|
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong);
|
||||||
if (avatar == null || newTeam.contains(avatar)) {
|
if (avatar == null || newTeam.contains(avatar)) {
|
||||||
// Should never happen
|
// Should never happen
|
||||||
return;
|
return;
|
||||||
@ -339,8 +341,8 @@ public class TeamManager {
|
|||||||
|
|
||||||
// Set team data
|
// Set team data
|
||||||
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
|
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (Long aLong : list) {
|
||||||
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(list.get(i));
|
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong);
|
||||||
if (avatar == null || newTeam.contains(avatar)) {
|
if (avatar == null || newTeam.contains(avatar)) {
|
||||||
// Should never happen
|
// Should never happen
|
||||||
return;
|
return;
|
||||||
@ -359,7 +361,7 @@ public class TeamManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setupTemporaryTeam(List<List<Long>> guidList) {
|
public void setupTemporaryTeam(List<List<Long>> guidList) {
|
||||||
var team = guidList.stream().map(list -> {
|
this.temporaryTeam = guidList.stream().map(list -> {
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
if (list.size() == 0 || list.size() > getMaxTeamSize()) {
|
if (list.size() == 0 || list.size() > getMaxTeamSize()) {
|
||||||
return null;
|
return null;
|
||||||
@ -367,8 +369,8 @@ public class TeamManager {
|
|||||||
|
|
||||||
// Set team data
|
// Set team data
|
||||||
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
|
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (Long aLong : list) {
|
||||||
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(list.get(i));
|
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong);
|
||||||
if (avatar == null || newTeam.contains(avatar)) {
|
if (avatar == null || newTeam.contains(avatar)) {
|
||||||
// Should never happen
|
// Should never happen
|
||||||
return null;
|
return null;
|
||||||
@ -384,7 +386,6 @@ public class TeamManager {
|
|||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.map(TeamInfo::new)
|
.map(TeamInfo::new)
|
||||||
.toList();
|
.toList();
|
||||||
this.temporaryTeam = team;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void useTemporaryTeam(int index) {
|
public void useTemporaryTeam(int index) {
|
||||||
|
@ -16,6 +16,8 @@ import java.util.Collection;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class ShopManager {
|
public class ShopManager {
|
||||||
private final GameServer server;
|
private final GameServer server;
|
||||||
|
|
||||||
@ -56,7 +58,7 @@ public class ShopManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadShop() {
|
private void loadShop() {
|
||||||
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "Shop.json")) {
|
try (FileReader fileReader = new FileReader(DATA("Shop.json"))) {
|
||||||
getShopData().clear();
|
getShopData().clear();
|
||||||
List<ShopTable> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopTable.class).getType());
|
List<ShopTable> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopTable.class).getType());
|
||||||
if(banners.size() > 0) {
|
if(banners.size() > 0) {
|
||||||
@ -84,7 +86,7 @@ public class ShopManager {
|
|||||||
Grasscutter.getLogger().error("Unable to load shop data. Shop data size is 0.");
|
Grasscutter.getLogger().error("Unable to load shop data. Shop data size is 0.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grasscutter.getConfig().getGameServerOptions().EnableOfficialShop) {
|
if (GAME_OPTIONS.enableShopItems) {
|
||||||
GameData.getShopGoodsDataEntries().forEach((k, v) -> {
|
GameData.getShopGoodsDataEntries().forEach((k, v) -> {
|
||||||
if (!getShopData().containsKey(k.intValue()))
|
if (!getShopData().containsKey(k.intValue()))
|
||||||
getShopData().put(k.intValue(), new ArrayList<>());
|
getShopData().put(k.intValue(), new ArrayList<>());
|
||||||
@ -100,7 +102,7 @@ public class ShopManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadShopChest() {
|
private void loadShopChest() {
|
||||||
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "ShopChest.json")) {
|
try (FileReader fileReader = new FileReader(DATA("ShopChest.json"))) {
|
||||||
getShopChestData().clear();
|
getShopChestData().clear();
|
||||||
List<ShopChestTable> shopChestTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestTable.class).getType());
|
List<ShopChestTable> shopChestTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestTable.class).getType());
|
||||||
if (shopChestTableList.size() > 0) {
|
if (shopChestTableList.size() > 0) {
|
||||||
@ -115,7 +117,7 @@ public class ShopManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadShopChestBatchUse() {
|
private void loadShopChestBatchUse() {
|
||||||
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "ShopChestBatchUse.json")) {
|
try (FileReader fileReader = new FileReader(DATA("ShopChestBatchUse.json"))) {
|
||||||
getShopChestBatchUseData().clear();
|
getShopChestBatchUseData().clear();
|
||||||
List<ShopChestBatchUseTable> shopChestBatchUseTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestBatchUseTable.class).getType());
|
List<ShopChestBatchUseTable> shopChestBatchUseTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestBatchUseTable.class).getType());
|
||||||
if (shopChestBatchUseTableList.size() > 0) {
|
if (shopChestBatchUseTableList.size() > 0) {
|
||||||
|
@ -8,6 +8,8 @@ import emu.grasscutter.server.game.GameServer;
|
|||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class TowerScheduleManager {
|
public class TowerScheduleManager {
|
||||||
private final GameServer gameServer;
|
private final GameServer gameServer;
|
||||||
|
|
||||||
@ -23,9 +25,8 @@ public class TowerScheduleManager {
|
|||||||
private TowerScheduleConfig towerScheduleConfig;
|
private TowerScheduleConfig towerScheduleConfig;
|
||||||
|
|
||||||
public synchronized void load(){
|
public synchronized void load(){
|
||||||
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "TowerSchedule.json")) {
|
try (FileReader fileReader = new FileReader(DATA("TowerSchedule.json"))) {
|
||||||
towerScheduleConfig = Grasscutter.getGsonFactory().fromJson(fileReader, TowerScheduleConfig.class);
|
towerScheduleConfig = Grasscutter.getGsonFactory().fromJson(fileReader, TowerScheduleConfig.class);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Unable to load tower schedule config.", e);
|
Grasscutter.getLogger().error("Unable to load tower schedule config.", e);
|
||||||
}
|
}
|
||||||
@ -40,6 +41,7 @@ public class TowerScheduleManager {
|
|||||||
if(data == null){
|
if(data == null){
|
||||||
Grasscutter.getLogger().error("Could not get current tower schedule data by config:{}", towerScheduleConfig);
|
Grasscutter.getLogger().error("Could not get current tower schedule data by config:{}", towerScheduleConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,28 +53,31 @@ public class TowerScheduleManager {
|
|||||||
var entranceFloors = getCurrentTowerScheduleData().getEntranceFloorId();
|
var entranceFloors = getCurrentTowerScheduleData().getEntranceFloorId();
|
||||||
var scheduleFloors = getScheduleFloors();
|
var scheduleFloors = getScheduleFloors();
|
||||||
var nextId = 0;
|
var nextId = 0;
|
||||||
|
|
||||||
// find in entrance floors first
|
// find in entrance floors first
|
||||||
for(int i=0;i<entranceFloors.size()-1;i++){
|
for(int i=0;i<entranceFloors.size()-1;i++){
|
||||||
if(floorId == entranceFloors.get(i)){
|
if(floorId == entranceFloors.get(i)){
|
||||||
nextId = entranceFloors.get(i+1);
|
nextId = entranceFloors.get(i+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(floorId == entranceFloors.get(entranceFloors.size()-1)){
|
if(floorId == entranceFloors.get(entranceFloors.size()-1)){
|
||||||
nextId = scheduleFloors.get(0);
|
nextId = scheduleFloors.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nextId != 0){
|
if(nextId != 0){
|
||||||
return nextId;
|
return nextId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find in schedule floors
|
// find in schedule floors
|
||||||
for(int i=0;i<scheduleFloors.size()-1;i++){
|
for(int i=0; i < scheduleFloors.size() - 1; i++){
|
||||||
if(floorId == scheduleFloors.get(i)){
|
if(floorId == scheduleFloors.get(i)){
|
||||||
nextId = scheduleFloors.get(i+1);
|
nextId = scheduleFloors.get(i + 1);
|
||||||
}
|
}
|
||||||
}
|
}return nextId;
|
||||||
return nextId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getLastEntranceFloor() {
|
public Integer getLastEntranceFloor() {
|
||||||
return getCurrentTowerScheduleData().getEntranceFloorId().get(getCurrentTowerScheduleData().getEntranceFloorId().size()-1);
|
return getCurrentTowerScheduleData().getEntranceFloorId().get(getCurrentTowerScheduleData().getEntranceFloorId().size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,24 @@
|
|||||||
package emu.grasscutter.game.world;
|
package emu.grasscutter.game.world;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.player.Player.SceneLoadState;
|
import emu.grasscutter.game.player.Player.SceneLoadState;
|
||||||
import emu.grasscutter.game.props.ClimateType;
|
|
||||||
import emu.grasscutter.game.props.EnterReason;
|
import emu.grasscutter.game.props.EnterReason;
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
|
||||||
import emu.grasscutter.game.props.LifeState;
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.def.DungeonData;
|
import emu.grasscutter.data.def.DungeonData;
|
||||||
import emu.grasscutter.data.def.SceneData;
|
import emu.grasscutter.data.def.SceneData;
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
|
||||||
import emu.grasscutter.game.entity.EntityClientGadget;
|
|
||||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
|
||||||
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
|
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
|
||||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
|
||||||
import emu.grasscutter.scripts.data.SceneConfig;
|
import emu.grasscutter.scripts.data.SceneConfig;
|
||||||
import emu.grasscutter.server.game.GameServer;
|
import emu.grasscutter.server.game.GameServer;
|
||||||
import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
|
import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
|
||||||
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
|
|
||||||
import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
|
import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
|
|
||||||
import emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify;
|
|
||||||
import emu.grasscutter.server.packet.send.PacketScenePlayerInfoNotify;
|
import emu.grasscutter.server.packet.send.PacketScenePlayerInfoNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketSyncScenePlayTeamEntityNotify;
|
import emu.grasscutter.server.packet.send.PacketSyncScenePlayTeamEntityNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketSyncTeamEntityNotify;
|
import emu.grasscutter.server.packet.send.PacketSyncTeamEntityNotify;
|
||||||
|
@ -8,6 +8,8 @@ import java.io.File;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base class for all plugins to extend.
|
* The base class for all plugins to extend.
|
||||||
*/
|
*/
|
||||||
@ -32,7 +34,7 @@ public abstract class Plugin {
|
|||||||
|
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.dataFolder = new File(Grasscutter.getConfig().PLUGINS_FOLDER, identifier.name);
|
this.dataFolder = new File(PLUGINS_FOLDER, identifier.name);
|
||||||
|
|
||||||
if(!this.dataFolder.exists() && !this.dataFolder.mkdirs()) {
|
if(!this.dataFolder.exists() && !this.dataFolder.mkdirs()) {
|
||||||
Grasscutter.getLogger().warn("Failed to create plugin data folder for " + this.identifier.name);
|
Grasscutter.getLogger().warn("Failed to create plugin data folder for " + this.identifier.name);
|
||||||
|
@ -16,6 +16,8 @@ import java.util.*;
|
|||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the server's plugins and the event system.
|
* Manages the server's plugins and the event system.
|
||||||
*/
|
*/
|
||||||
@ -31,8 +33,7 @@ public final class PluginManager {
|
|||||||
* Loads plugins from the config-specified directory.
|
* Loads plugins from the config-specified directory.
|
||||||
*/
|
*/
|
||||||
private void loadPlugins() {
|
private void loadPlugins() {
|
||||||
String directory = Grasscutter.getConfig().PLUGINS_FOLDER;
|
File pluginsDir = new File(Utils.toFilePath(PLUGINS_FOLDER));
|
||||||
File pluginsDir = new File(Utils.toFilePath(directory));
|
|
||||||
if(!pluginsDir.exists() && !pluginsDir.mkdirs()) {
|
if(!pluginsDir.exists() && !pluginsDir.mkdirs()) {
|
||||||
Grasscutter.getLogger().error("Failed to create plugins directory: " + pluginsDir.getAbsolutePath());
|
Grasscutter.getLogger().error("Failed to create plugins directory: " + pluginsDir.getAbsolutePath());
|
||||||
return;
|
return;
|
||||||
|
@ -31,6 +31,8 @@ import emu.grasscutter.scripts.data.ScriptArgs;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class SceneScriptManager {
|
public class SceneScriptManager {
|
||||||
private final Scene scene;
|
private final Scene scene;
|
||||||
private final ScriptLib scriptLib;
|
private final ScriptLib scriptLib;
|
||||||
@ -164,7 +166,7 @@ public class SceneScriptManager {
|
|||||||
private void init() {
|
private void init() {
|
||||||
// Get compiled script if cached
|
// Get compiled script if cached
|
||||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
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) {
|
if (cs == null) {
|
||||||
Grasscutter.getLogger().warn("No script found for scene " + getScene().getId());
|
Grasscutter.getLogger().warn("No script found for scene " + getScene().getId());
|
||||||
@ -211,7 +213,7 @@ public class SceneScriptManager {
|
|||||||
|
|
||||||
private void loadBlockFromScript(SceneBlock block) {
|
private void loadBlockFromScript(SceneBlock block) {
|
||||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
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) {
|
if (cs == null) {
|
||||||
return;
|
return;
|
||||||
@ -234,7 +236,7 @@ public class SceneScriptManager {
|
|||||||
group.setLoaded(true);
|
group.setLoaded(true);
|
||||||
|
|
||||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
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) {
|
if (cs == null) {
|
||||||
return;
|
return;
|
||||||
@ -281,9 +283,7 @@ public class SceneScriptManager {
|
|||||||
if (gadget != null) {
|
if (gadget != null) {
|
||||||
suite.sceneGadgets.add(gadget);
|
suite.sceneGadgets.add(gadget);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception ignored) { }
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.sceneGroups.put(group.id, group);
|
this.sceneGroups.put(group.id, group);
|
||||||
|
@ -10,26 +10,29 @@ import java.io.FileInputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class AnnouncementHandler implements HttpContextHandler {
|
public final class AnnouncementHandler implements HttpContextHandler {
|
||||||
@Override
|
@Override
|
||||||
public void handle(Request request, Response response) throws IOException {//event
|
public void handle(Request request, Response response) throws IOException {//event
|
||||||
if (Objects.equals(request.baseUrl(), "/common/hk4e_global/announcement/api/getAnnContent")) {
|
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")) {
|
} 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 +"}");
|
response.send("{\"retcode\":0,\"message\":\"OK\",\"data\": "+data +"}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||||
private static String readToString(File file) {
|
private static String readToString(File file) {
|
||||||
Long filelength = file.length();
|
long length = file.length();
|
||||||
byte[] filecontent = new byte[filelength.intValue()];
|
byte[] content = new byte[(int) length];
|
||||||
try {
|
try {
|
||||||
FileInputStream in = new FileInputStream(file);
|
FileInputStream in = new FileInputStream(file);
|
||||||
in.read(filecontent);
|
in.read(content); in.close();
|
||||||
in.close();
|
} catch (IOException ignored) {
|
||||||
} catch (IOException fileNotFoundException) {
|
Grasscutter.getLogger().warn("File not found: " + file.getAbsolutePath());
|
||||||
fileNotFoundException.printStackTrace();
|
|
||||||
}
|
}
|
||||||
return new String(filecontent);
|
|
||||||
|
return new String(content);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,6 +11,7 @@ import express.http.Request;
|
|||||||
import express.http.Response;
|
import express.http.Response;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class DispatchHttpJsonHandler implements HttpContextHandler {
|
public final class DispatchHttpJsonHandler implements HttpContextHandler {
|
||||||
private final String response;
|
private final String response;
|
||||||
@ -34,8 +35,8 @@ public final class DispatchHttpJsonHandler implements HttpContextHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(Request req, Response res) throws IOException {
|
public void handle(Request req, Response res) throws IOException {
|
||||||
// Checking for ALL here isn't required as when ALL is enabled enableDevLogging() gets enabled
|
// 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()))) {
|
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()) + (Grasscutter.getConfig().DebugMode == ServerDebugMode.MISSING ? "(MISSING)" : ""));
|
Grasscutter.getLogger().info(translate("messages.dispatch.request", req.ip(), req.method(), req.baseUrl()) + (SERVER.debugLevel == ServerDebugMode.MISSING ? "(MISSING)" : ""));
|
||||||
}
|
}
|
||||||
res.send(response);
|
res.send(response);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import com.google.gson.Gson;
|
|||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
import emu.grasscutter.Config;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
||||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||||
@ -33,9 +33,11 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class DispatchServer {
|
public final class DispatchServer {
|
||||||
public static String query_region_list = "";
|
public static String query_region_list = "";
|
||||||
@ -64,7 +66,7 @@ public final class DispatchServer {
|
|||||||
public void setHttpServer(Express httpServer) {
|
public void setHttpServer(Express httpServer) {
|
||||||
this.httpServer.stop();
|
this.httpServer.stop();
|
||||||
this.httpServer = httpServer;
|
this.httpServer = httpServer;
|
||||||
this.httpServer.listen(Grasscutter.getConfig().getDispatchOptions().Port);
|
this.httpServer.listen(DISPATCH_INFO.bindPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Gson getGsonFactory() {
|
public Gson getGsonFactory() {
|
||||||
@ -73,7 +75,7 @@ public final class DispatchServer {
|
|||||||
|
|
||||||
public QueryCurrRegionHttpRsp getCurrRegion() {
|
public QueryCurrRegionHttpRsp getCurrRegion() {
|
||||||
// Needs to be fixed by having the game servers connect to the dispatch server.
|
// 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;
|
return regions.get(defaultServerName).parsedRegionQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,14 +86,14 @@ public final class DispatchServer {
|
|||||||
public void loadQueries() {
|
public void loadQueries() {
|
||||||
File file;
|
File file;
|
||||||
|
|
||||||
file = new File(Grasscutter.getConfig().DATA_FOLDER + "query_region_list.txt");
|
file = new File(DATA("query_region_list.txt"));
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
query_region_list = new String(FileUtils.read(file));
|
query_region_list = new String(FileUtils.read(file));
|
||||||
} else {
|
} else {
|
||||||
Grasscutter.getLogger().warn("[Dispatch] 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");
|
file = new File(DATA("query_cur_region.txt"));
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
query_cur_region = new String(FileUtils.read(file));
|
query_cur_region = new String(FileUtils.read(file));
|
||||||
} else {
|
} else {
|
||||||
@ -108,52 +110,37 @@ public final class DispatchServer {
|
|||||||
QueryCurrRegionHttpRsp regionQuery = QueryCurrRegionHttpRsp.parseFrom(decoded2);
|
QueryCurrRegionHttpRsp regionQuery = QueryCurrRegionHttpRsp.parseFrom(decoded2);
|
||||||
|
|
||||||
List<RegionSimpleInfo> servers = new ArrayList<>();
|
List<RegionSimpleInfo> servers = new ArrayList<>();
|
||||||
List<String> usedNames = new ArrayList<>(); // List to check for potential naming conflicts
|
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
|
if (SERVER.runMode == ServerRunMode.HYBRID) { // Automatically add the game server if in hybrid mode.
|
||||||
// hybrid mode
|
|
||||||
RegionSimpleInfo server = RegionSimpleInfo.newBuilder()
|
RegionSimpleInfo server = RegionSimpleInfo.newBuilder()
|
||||||
.setName("os_usa")
|
.setName("os_usa")
|
||||||
.setTitle(Grasscutter.getConfig().getGameServerOptions().Name)
|
.setTitle(DISPATCH_INFO.defaultName)
|
||||||
.setType("DEV_PUBLIC")
|
.setType("DEV_PUBLIC")
|
||||||
.setDispatchUrl(
|
.setDispatchUrl(
|
||||||
"http" + (Grasscutter.getConfig().getDispatchOptions().FrontHTTPS ? "s" : "") + "://"
|
"http" + (DISPATCH_ENCRYPTION.useEncryption ? "s" : "") + "://"
|
||||||
+ (Grasscutter.getConfig().getDispatchOptions().PublicIp.isEmpty()
|
+ lr(DISPATCH_INFO.accessAddress, DISPATCH_INFO.bindAddress) + ":"
|
||||||
? Grasscutter.getConfig().getDispatchOptions().Ip
|
+ lr(DISPATCH_INFO.accessPort, DISPATCH_INFO.bindPort)
|
||||||
: Grasscutter.getConfig().getDispatchOptions().PublicIp)
|
|
||||||
+ ":"
|
|
||||||
+ (Grasscutter.getConfig().getDispatchOptions().PublicPort != 0
|
|
||||||
? Grasscutter.getConfig().getDispatchOptions().PublicPort
|
|
||||||
: Grasscutter.getConfig().getDispatchOptions().Port)
|
|
||||||
+ "/query_cur_region/" + defaultServerName)
|
+ "/query_cur_region/" + defaultServerName)
|
||||||
.build();
|
.build();
|
||||||
usedNames.add(defaultServerName);
|
usedNames.add(defaultServerName);
|
||||||
servers.add(server);
|
servers.add(server);
|
||||||
|
|
||||||
RegionInfo serverRegion = regionQuery.getRegionInfo().toBuilder()
|
RegionInfo serverRegion = regionQuery.getRegionInfo().toBuilder()
|
||||||
.setGateserverIp((Grasscutter.getConfig().getGameServerOptions().PublicIp.isEmpty()
|
.setGateserverIp(lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress))
|
||||||
? Grasscutter.getConfig().getGameServerOptions().Ip
|
.setGateserverPort(lr(GAME_INFO.accessPort, GAME_INFO.bindPort))
|
||||||
: Grasscutter.getConfig().getGameServerOptions().PublicIp))
|
.setSecretKey(ByteString.copyFrom(FileUtils.read(KEYS_FOLDER + "/dispatchSeed.bin")))
|
||||||
.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")))
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
QueryCurrRegionHttpRsp parsedRegionQuery = regionQuery.toBuilder().setRegionInfo(serverRegion).build();
|
QueryCurrRegionHttpRsp parsedRegionQuery = regionQuery.toBuilder().setRegionInfo(serverRegion).build();
|
||||||
regions.put(defaultServerName, new RegionData(parsedRegionQuery,
|
regions.put(defaultServerName, new RegionData(parsedRegionQuery,
|
||||||
Base64.getEncoder().encodeToString(parsedRegionQuery.toByteString().toByteArray())));
|
Base64.getEncoder().encodeToString(parsedRegionQuery.toByteString().toByteArray())));
|
||||||
|
|
||||||
} else {
|
} else if (DISPATCH_INFO.regions.length == 0) {
|
||||||
if (Grasscutter.getConfig().getDispatchOptions().getGameServers().length == 0) {
|
Grasscutter.getLogger().error("[Dispatch] There are no game servers available. Exiting due to unplayable state.");
|
||||||
Grasscutter.getLogger()
|
System.exit(1);
|
||||||
.error("[Dispatch] There are no game servers available. Exiting due to unplayable state.");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Config.DispatchServerOptions.RegionInfo regionInfo : Grasscutter.getConfig().getDispatchOptions()
|
for (var regionInfo : DISPATCH_INFO.regions) {
|
||||||
.getGameServers()) {
|
|
||||||
if (usedNames.contains(regionInfo.Name)) {
|
if (usedNames.contains(regionInfo.Name)) {
|
||||||
Grasscutter.getLogger().error("Region name already in use.");
|
Grasscutter.getLogger().error("Region name already in use.");
|
||||||
continue;
|
continue;
|
||||||
@ -163,13 +150,10 @@ public final class DispatchServer {
|
|||||||
.setTitle(regionInfo.Title)
|
.setTitle(regionInfo.Title)
|
||||||
.setType("DEV_PUBLIC")
|
.setType("DEV_PUBLIC")
|
||||||
.setDispatchUrl(
|
.setDispatchUrl(
|
||||||
"http" + (Grasscutter.getConfig().getDispatchOptions().FrontHTTPS ? "s" : "") + "://"
|
"http" + (DISPATCH_ENCRYPTION.useEncryption ? "s" : "") + "://"
|
||||||
+ (Grasscutter.getConfig().getDispatchOptions().PublicIp.isEmpty()
|
+ lr(DISPATCH_INFO.accessAddress, DISPATCH_INFO.bindAddress) + ":"
|
||||||
? Grasscutter.getConfig().getDispatchOptions().Ip
|
+ lr(DISPATCH_INFO.accessPort, DISPATCH_INFO.bindPort)
|
||||||
: Grasscutter.getConfig().getDispatchOptions().PublicIp)
|
+ "/query_cur_region/" + regionInfo.Name)
|
||||||
+ ":" + (Grasscutter.getConfig().getDispatchOptions().PublicPort != 0
|
|
||||||
? Grasscutter.getConfig().getDispatchOptions().PublicPort
|
|
||||||
: Grasscutter.getConfig().getDispatchOptions().Port) + "/query_cur_region/" + regionInfo.Name)
|
|
||||||
.build();
|
.build();
|
||||||
usedNames.add(regionInfo.Name);
|
usedNames.add(regionInfo.Name);
|
||||||
servers.add(server);
|
servers.add(server);
|
||||||
@ -178,7 +162,7 @@ public final class DispatchServer {
|
|||||||
.setGateserverIp(regionInfo.Ip)
|
.setGateserverIp(regionInfo.Ip)
|
||||||
.setGateserverPort(regionInfo.Port)
|
.setGateserverPort(regionInfo.Port)
|
||||||
.setSecretKey(ByteString
|
.setSecretKey(ByteString
|
||||||
.copyFrom(FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "dispatchSeed.bin")))
|
.copyFrom(FileUtils.read(KEYS_FOLDER + "/dispatchSeed.bin")))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
QueryCurrRegionHttpRsp parsedRegionQuery = regionQuery.toBuilder().setRegionInfo(serverRegion).build();
|
QueryCurrRegionHttpRsp parsedRegionQuery = regionQuery.toBuilder().setRegionInfo(serverRegion).build();
|
||||||
@ -194,8 +178,8 @@ public final class DispatchServer {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.regionListBase64 = Base64.getEncoder().encodeToString(regionList.toByteString().toByteArray());
|
this.regionListBase64 = Base64.getEncoder().encodeToString(regionList.toByteString().toByteArray());
|
||||||
} catch (Exception e) {
|
} catch (Exception exception) {
|
||||||
Grasscutter.getLogger().error("[Dispatch] Error while initializing region info!", e);
|
Grasscutter.getLogger().error("[Dispatch] Error while initializing region info!", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,14 +189,14 @@ public final class DispatchServer {
|
|||||||
Server server = new Server();
|
Server server = new Server();
|
||||||
ServerConnector serverConnector;
|
ServerConnector serverConnector;
|
||||||
|
|
||||||
if(Grasscutter.getConfig().getDispatchOptions().UseSSL) {
|
if(DISPATCH_ENCRYPTION.useEncryption) {
|
||||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||||
File keystoreFile = new File(Grasscutter.getConfig().getDispatchOptions().KeystorePath);
|
File keystoreFile = new File(DISPATCH_ENCRYPTION.keystore);
|
||||||
|
|
||||||
if(keystoreFile.exists()) {
|
if(keystoreFile.exists()) {
|
||||||
try {
|
try {
|
||||||
sslContextFactory.setKeyStorePath(keystoreFile.getPath());
|
sslContextFactory.setKeyStorePath(keystoreFile.getPath());
|
||||||
sslContextFactory.setKeyStorePassword(Grasscutter.getConfig().getDispatchOptions().KeystorePassword);
|
sslContextFactory.setKeyStorePassword(DISPATCH_ENCRYPTION.keystorePassword);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.password_error"));
|
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.password_error"));
|
||||||
@ -230,7 +214,7 @@ public final class DispatchServer {
|
|||||||
serverConnector = new ServerConnector(server, sslContextFactory);
|
serverConnector = new ServerConnector(server, sslContextFactory);
|
||||||
} else {
|
} else {
|
||||||
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.no_keystore_error"));
|
Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.no_keystore_error"));
|
||||||
Grasscutter.getConfig().getDispatchOptions().UseSSL = false;
|
DISPATCH_ENCRYPTION.useEncryption = false;
|
||||||
|
|
||||||
serverConnector = new ServerConnector(server);
|
serverConnector = new ServerConnector(server);
|
||||||
}
|
}
|
||||||
@ -238,24 +222,27 @@ public final class DispatchServer {
|
|||||||
serverConnector = new ServerConnector(server);
|
serverConnector = new ServerConnector(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConnector.setPort(Grasscutter.getConfig().getDispatchOptions().Port);
|
serverConnector.setPort(DISPATCH_INFO.bindPort);
|
||||||
server.setConnectors(new Connector[]{serverConnector});
|
server.setConnectors(new Connector[]{serverConnector});
|
||||||
return server;
|
return server;
|
||||||
});
|
});
|
||||||
|
|
||||||
config.enforceSsl = Grasscutter.getConfig().getDispatchOptions().UseSSL;
|
config.enforceSsl = DISPATCH_ENCRYPTION.useEncryption;
|
||||||
if(Grasscutter.getConfig().DebugMode == ServerDebugMode.ALL) {
|
if(SERVER.debugLevel == ServerDebugMode.ALL) {
|
||||||
config.enableDevLogging();
|
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();
|
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.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 -> {
|
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()));
|
Grasscutter.getLogger().info(translate("messages.dispatch.unhandled_request_error", ctx.method(), ctx.url()));
|
||||||
}
|
}
|
||||||
ctx.contentType("text/html");
|
ctx.contentType("text/html");
|
||||||
@ -272,6 +259,15 @@ public final class DispatchServer {
|
|||||||
httpServer.post("/authentication/register", (req, res) -> this.getAuthHandler().handleRegister(req, res));
|
httpServer.post("/authentication/register", (req, res) -> this.getAuthHandler().handleRegister(req, res));
|
||||||
httpServer.post("/authentication/change_password", (req, res) -> this.getAuthHandler().handleChangePassword(req, res));
|
httpServer.post("/authentication/change_password", (req, res) -> this.getAuthHandler().handleChangePassword(req, res));
|
||||||
|
|
||||||
|
// Server Status
|
||||||
|
httpServer.get("/status/server", (req, res) -> {
|
||||||
|
|
||||||
|
int playerCount = Grasscutter.getGameServer().getPlayers().size();
|
||||||
|
String version = GameConstants.VERSION;
|
||||||
|
|
||||||
|
res.send("{\"retcode\":0,\"status\":{\"playerCount\":" + playerCount + ",\"version\":\"" + version + "\"}}");
|
||||||
|
});
|
||||||
|
|
||||||
// Dispatch
|
// Dispatch
|
||||||
httpServer.get("/query_region_list", (req, res) -> {
|
httpServer.get("/query_region_list", (req, res) -> {
|
||||||
// Log
|
// Log
|
||||||
@ -450,7 +446,7 @@ public final class DispatchServer {
|
|||||||
httpServer.get("/admin/mi18n/plat_oversea/m202003048/m202003048-version.json", new DispatchHttpJsonHandler("{\"version\":51}"));
|
httpServer.get("/admin/mi18n/plat_oversea/m202003048/m202003048-version.json", new DispatchHttpJsonHandler("{\"version\":51}"));
|
||||||
|
|
||||||
// gacha record.
|
// 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.
|
// TODO: Only serve the html page and have a subsequent request to fetch the gacha data.
|
||||||
httpServer.get("/gacha", new GachaRecordHandler());
|
httpServer.get("/gacha", new GachaRecordHandler());
|
||||||
if(!(new File(gachaMappingsPath).exists())) {
|
if(!(new File(gachaMappingsPath).exists())) {
|
||||||
@ -462,7 +458,7 @@ public final class DispatchServer {
|
|||||||
// static file support for plugins
|
// 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.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())));
|
Grasscutter.getLogger().info(translate("messages.dispatch.port_bind", Integer.toString(httpServer.raw().port())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,15 +477,11 @@ public final class DispatchServer {
|
|||||||
|
|
||||||
if (next > last) {
|
if (next > last) {
|
||||||
int eqPos = qs.indexOf('=', last);
|
int eqPos = qs.indexOf('=', last);
|
||||||
try {
|
if (eqPos < 0 || eqPos > next) {
|
||||||
if (eqPos < 0 || eqPos > next) {
|
result.put(URLDecoder.decode(qs.substring(last, next), StandardCharsets.UTF_8), "");
|
||||||
result.put(URLDecoder.decode(qs.substring(last, next), "utf-8"), "");
|
} else {
|
||||||
} else {
|
result.put(URLDecoder.decode(qs.substring(last, eqPos), StandardCharsets.UTF_8),
|
||||||
result.put(URLDecoder.decode(qs.substring(last, eqPos), "utf-8"),
|
URLDecoder.decode(qs.substring(eqPos + 1, next), StandardCharsets.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;
|
last = next + 1;
|
||||||
|
@ -9,6 +9,7 @@ import express.http.Request;
|
|||||||
import express.http.Response;
|
import express.http.Response;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class DefaultAuthenticationHandler implements AuthenticationHandler {
|
public class DefaultAuthenticationHandler implements AuthenticationHandler {
|
||||||
|
|
||||||
@ -37,11 +38,11 @@ public class DefaultAuthenticationHandler implements AuthenticationHandler {
|
|||||||
// Check if account exists, else create a new one.
|
// Check if account exists, else create a new one.
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
// Account doesn't exist, so we can either auto create it if the config value is set.
|
// 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.
|
// This account has been created AUTOMATICALLY. There will be no permissions added.
|
||||||
account = DatabaseHelper.createAccountWithId(requestData.account, 0);
|
account = DatabaseHelper.createAccountWithId(requestData.account, 0);
|
||||||
|
|
||||||
for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) {
|
for (String permission : ACCOUNT.defaultPermissions) {
|
||||||
account.addPermission(permission);
|
account.addPermission(permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package emu.grasscutter.server.dispatch.http;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.database.DatabaseHelper;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
import emu.grasscutter.game.Account;
|
import emu.grasscutter.game.Account;
|
||||||
import emu.grasscutter.utils.FileUtils;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
@ -12,10 +11,12 @@ import express.http.HttpContextHandler;
|
|||||||
import express.http.Request;
|
import express.http.Request;
|
||||||
import express.http.Response;
|
import express.http.Response;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class GachaRecordHandler implements HttpContextHandler {
|
public final class GachaRecordHandler implements HttpContextHandler {
|
||||||
String render_template;
|
String render_template;
|
||||||
public GachaRecordHandler() {
|
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()) {
|
if (template.exists()) {
|
||||||
// Load from cache
|
// Load from cache
|
||||||
render_template = new String(FileUtils.read(template));
|
render_template = new String(FileUtils.read(template));
|
||||||
@ -31,11 +32,11 @@ public final class GachaRecordHandler implements HttpContextHandler {
|
|||||||
int page = 0;
|
int page = 0;
|
||||||
int gachaType = 0;
|
int gachaType = 0;
|
||||||
if (req.query("p") != null) {
|
if (req.query("p") != null) {
|
||||||
page = Integer.valueOf(req.query("p"));
|
page = Integer.parseInt(req.query("p"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.query("gachaType") != null) {
|
if (req.query("gachaType") != null) {
|
||||||
gachaType = Integer.valueOf(req.query("gachaType"));
|
gachaType = Integer.parseInt(req.query("gachaType"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Account account = DatabaseHelper.getAccountBySessionKey(sessionKey);
|
Account account = DatabaseHelper.getAccountBySessionKey(sessionKey);
|
||||||
|
@ -30,11 +30,9 @@ import java.net.InetSocketAddress;
|
|||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
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.utils.Language.translate;
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class GameServer extends KcpServer {
|
public final class GameServer extends KcpServer {
|
||||||
private final InetSocketAddress address;
|
private final InetSocketAddress address;
|
||||||
@ -59,8 +57,8 @@ public final class GameServer extends KcpServer {
|
|||||||
|
|
||||||
public GameServer() {
|
public GameServer() {
|
||||||
this(new InetSocketAddress(
|
this(new InetSocketAddress(
|
||||||
Grasscutter.getConfig().getGameServerOptions().Ip,
|
GAME_INFO.bindAddress,
|
||||||
Grasscutter.getConfig().getGameServerOptions().Port
|
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.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class GameServerPacketHandler {
|
public class GameServerPacketHandler {
|
||||||
private final Int2ObjectMap<PacketHandler> handlers;
|
private final Int2ObjectMap<PacketHandler> handlers;
|
||||||
@ -92,7 +94,7 @@ public class GameServerPacketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log unhandled packets
|
// 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));
|
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.io.File;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
@ -23,9 +22,10 @@ import io.netty.buffer.Unpooled;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class GameSession extends KcpChannel {
|
public class GameSession extends KcpChannel {
|
||||||
private GameServer server;
|
private final GameServer server;
|
||||||
|
|
||||||
private Account account;
|
private Account account;
|
||||||
private Player player;
|
private Player player;
|
||||||
@ -140,7 +140,7 @@ public class GameSession extends KcpChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void replayPacket(int opcode, String name) {
|
public void replayPacket(int opcode, String name) {
|
||||||
String filePath = Grasscutter.getConfig().PACKETS_FOLDER + name;
|
String filePath = PACKETS_FOLDER + name;
|
||||||
File p = new File(filePath);
|
File p = new File(filePath);
|
||||||
|
|
||||||
if (!p.exists()) return;
|
if (!p.exists()) return;
|
||||||
@ -172,7 +172,7 @@ public class GameSession extends KcpChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
if (Grasscutter.getConfig().DebugMode == ServerDebugMode.ALL) {
|
if (SERVER.debugLevel == ServerDebugMode.ALL) {
|
||||||
logPacket(packet);
|
logPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ public class GameSession extends KcpChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log packet
|
// Log packet
|
||||||
if (Grasscutter.getConfig().DebugMode == ServerDebugMode.ALL) {
|
if (SERVER.debugLevel == ServerDebugMode.ALL) {
|
||||||
if (!loopPacket.contains(opcode)) {
|
if (!loopPacket.contains(opcode)) {
|
||||||
Grasscutter.getLogger().info("RECV: " + PacketOpcodesUtil.getOpcodeName(opcode) + " (" + opcode + ")");
|
Grasscutter.getLogger().info("RECV: " + PacketOpcodesUtil.getOpcodeName(opcode) + " (" + opcode + ")");
|
||||||
System.out.println(Utils.bytesToHex(payload));
|
System.out.println(Utils.bytesToHex(payload));
|
||||||
|
@ -19,6 +19,8 @@ import emu.grasscutter.server.game.GameSession.SessionState;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.SetPlayerBornDataReq)
|
@Opcodes(PacketOpcodes.SetPlayerBornDataReq)
|
||||||
public class HandlerSetPlayerBornDataReq extends PacketHandler {
|
public class HandlerSetPlayerBornDataReq extends PacketHandler {
|
||||||
|
|
||||||
@ -85,12 +87,13 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler {
|
|||||||
session.send(new BasePacket(PacketOpcodes.SetPlayerBornDataRsp));
|
session.send(new BasePacket(PacketOpcodes.SetPlayerBornDataRsp));
|
||||||
|
|
||||||
// Default mail
|
// Default mail
|
||||||
|
var welcomeMail = GAME_INFO.joinOptions.welcomeMail;
|
||||||
MailBuilder mailBuilder = new MailBuilder(player.getUid(), new Mail());
|
MailBuilder mailBuilder = new MailBuilder(player.getUid(), new Mail());
|
||||||
mailBuilder.mail.mailContent.title = Grasscutter.getConfig().GameServer.WelcomeMailTitle;
|
mailBuilder.mail.mailContent.title = welcomeMail.title;
|
||||||
mailBuilder.mail.mailContent.sender = Grasscutter.getConfig().GameServer.WelcomeMailSender;
|
mailBuilder.mail.mailContent.sender = welcomeMail.sender;
|
||||||
// Please credit Grasscutter if changing something here. We don't condone commercial use of the project.
|
// 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.mailContent.content = welcomeMail.content + "\n<type=\"browser\" text=\"GitHub\" href=\"https://github.com/Melledy/Grasscutter\"/>";
|
||||||
mailBuilder.mail.itemList.addAll(Arrays.asList(Grasscutter.getConfig().GameServer.WelcomeMailItems));
|
mailBuilder.mail.itemList.addAll(Arrays.asList(welcomeMail.items));
|
||||||
mailBuilder.mail.importance = 1;
|
mailBuilder.mail.importance = 1;
|
||||||
player.sendMail(mailBuilder.mail);
|
player.sendMail(mailBuilder.mail);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.game.friends.Friendship;
|
import emu.grasscutter.game.friends.Friendship;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
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.ProfilePictureOuterClass.ProfilePicture;
|
||||||
import emu.grasscutter.net.proto.PlatformTypeOuterClass;
|
import emu.grasscutter.net.proto.PlatformTypeOuterClass;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class PacketGetPlayerFriendListRsp extends BasePacket {
|
public class PacketGetPlayerFriendListRsp extends BasePacket {
|
||||||
|
|
||||||
public PacketGetPlayerFriendListRsp(Player player) {
|
public PacketGetPlayerFriendListRsp(Player player) {
|
||||||
super(PacketOpcodes.GetPlayerFriendListRsp);
|
super(PacketOpcodes.GetPlayerFriendListRsp);
|
||||||
|
|
||||||
|
var serverAccount = GAME_INFO.serverAccount;
|
||||||
FriendBrief serverFriend = FriendBrief.newBuilder()
|
FriendBrief serverFriend = FriendBrief.newBuilder()
|
||||||
.setUid(GameConstants.SERVER_CONSOLE_UID)
|
.setUid(GameConstants.SERVER_CONSOLE_UID)
|
||||||
.setNickname(Grasscutter.getConfig().getGameServerOptions().ServerNickname)
|
.setNickname(serverAccount.nickName)
|
||||||
.setLevel(Grasscutter.getConfig().getGameServerOptions().ServerLevel)
|
.setLevel(serverAccount.adventureRank)
|
||||||
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(Grasscutter.getConfig().getGameServerOptions().ServerAvatarId))
|
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(serverAccount.avatarId))
|
||||||
.setWorldLevel(Grasscutter.getConfig().getGameServerOptions().ServerWorldLevel)
|
.setWorldLevel(serverAccount.worldLevel)
|
||||||
.setSignature(Grasscutter.getConfig().getGameServerOptions().ServerSignature)
|
.setSignature(serverAccount.signature)
|
||||||
.setLastActiveTime((int) (System.currentTimeMillis() / 1000f))
|
.setLastActiveTime((int) (System.currentTimeMillis() / 1000f))
|
||||||
.setNameCardId(Grasscutter.getConfig().getGameServerOptions().ServerNameCardId)
|
.setNameCardId(serverAccount.nameCardId)
|
||||||
.setOnlineState(FriendOnlineState.FRIEND_ONLINE)
|
.setOnlineState(FriendOnlineState.FRIEND_ONLINE)
|
||||||
.setParam(1)
|
.setParam(1)
|
||||||
.setIsGameSource(true)
|
.setIsGameSource(true)
|
||||||
@ -37,10 +39,12 @@ public class PacketGetPlayerFriendListRsp extends BasePacket {
|
|||||||
for (Friendship friendship : player.getFriendsList().getFriends().values()) {
|
for (Friendship friendship : player.getFriendsList().getFriends().values()) {
|
||||||
proto.addFriendList(friendship.toProto());
|
proto.addFriendList(friendship.toProto());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Friendship friendship : player.getFriendsList().getPendingFriends().values()) {
|
for (Friendship friendship : player.getFriendsList().getPendingFriends().values()) {
|
||||||
if (friendship.getAskerId() == player.getUid()) {
|
if (friendship.getAskerId() == player.getUid()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
proto.addAskFriendList(friendship.toProto());
|
proto.addAskFriendList(friendship.toProto());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package emu.grasscutter.server.packet.send;
|
|||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
|
||||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
@ -13,9 +12,10 @@ import emu.grasscutter.server.game.GameSession;
|
|||||||
import emu.grasscutter.utils.FileUtils;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class PacketPlayerLoginRsp extends BasePacket {
|
public class PacketPlayerLoginRsp extends BasePacket {
|
||||||
|
|
||||||
private static QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionCache;
|
private static QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionCache;
|
||||||
@ -27,10 +27,10 @@ public class PacketPlayerLoginRsp extends BasePacket {
|
|||||||
|
|
||||||
RegionInfo info;
|
RegionInfo info;
|
||||||
|
|
||||||
if (Grasscutter.getConfig().RunMode == ServerRunMode.GAME_ONLY) {
|
if (SERVER.runMode == ServerRunMode.GAME_ONLY) {
|
||||||
if (regionCache == null) {
|
if (regionCache == null) {
|
||||||
try {
|
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 = "";
|
String query_cur_region = "";
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
query_cur_region = new String(FileUtils.read(file));
|
query_cur_region = new String(FileUtils.read(file));
|
||||||
@ -42,9 +42,9 @@ public class PacketPlayerLoginRsp extends BasePacket {
|
|||||||
QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionQuery = QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp.parseFrom(decodedCurRegion);
|
QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionQuery = QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp.parseFrom(decodedCurRegion);
|
||||||
|
|
||||||
RegionInfo serverRegion = regionQuery.getRegionInfo().toBuilder()
|
RegionInfo serverRegion = regionQuery.getRegionInfo().toBuilder()
|
||||||
.setGateserverIp((Grasscutter.getConfig().getGameServerOptions().PublicIp.isEmpty() ? Grasscutter.getConfig().getGameServerOptions().Ip : Grasscutter.getConfig().getGameServerOptions().PublicIp))
|
.setGateserverIp(lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress))
|
||||||
.setGateserverPort(Grasscutter.getConfig().getGameServerOptions().PublicPort != 0 ? Grasscutter.getConfig().getGameServerOptions().PublicPort : Grasscutter.getConfig().getGameServerOptions().Port)
|
.setGateserverPort(lr(GAME_INFO.accessPort, GAME_INFO.bindPort))
|
||||||
.setSecretKey(ByteString.copyFrom(FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "dispatchSeed.bin")))
|
.setSecretKey(ByteString.copyFrom(FileUtils.read(KEYS_FOLDER + "/dispatchSeed.bin")))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
regionCache = regionQuery.toBuilder().setRegionInfo(serverRegion).build();
|
regionCache = regionQuery.toBuilder().setRegionInfo(serverRegion).build();
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
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.PlayerStoreNotifyOuterClass.PlayerStoreNotify;
|
||||||
import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType;
|
import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class PacketPlayerStoreNotify extends BasePacket {
|
public class PacketPlayerStoreNotify extends BasePacket {
|
||||||
|
|
||||||
public PacketPlayerStoreNotify(Player player) {
|
public PacketPlayerStoreNotify(Player player) {
|
||||||
@ -19,7 +19,7 @@ public class PacketPlayerStoreNotify extends BasePacket {
|
|||||||
|
|
||||||
PlayerStoreNotify.Builder p = PlayerStoreNotify.newBuilder()
|
PlayerStoreNotify.Builder p = PlayerStoreNotify.newBuilder()
|
||||||
.setStoreType(StoreType.STORE_PACK)
|
.setStoreType(StoreType.STORE_PACK)
|
||||||
.setWeightLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitAll);
|
.setWeightLimit(GAME_OPTIONS.inventoryLimits.all);
|
||||||
|
|
||||||
for (GameItem item : player.getInventory()) {
|
for (GameItem item : player.getInventory()) {
|
||||||
Item itemProto = item.toProto();
|
Item itemProto = item.toProto();
|
||||||
|
@ -1,42 +1,41 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.Config.GameServerOptions;
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo;
|
import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo;
|
||||||
import emu.grasscutter.net.proto.PullRecentChatRspOuterClass.PullRecentChatRsp;
|
import emu.grasscutter.net.proto.PullRecentChatRspOuterClass.PullRecentChatRsp;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class PacketPullRecentChatRsp extends BasePacket {
|
public class PacketPullRecentChatRsp extends BasePacket {
|
||||||
public PacketPullRecentChatRsp(Player player) {
|
public PacketPullRecentChatRsp(Player player) {
|
||||||
super(PacketOpcodes.PullRecentChatRsp);
|
super(PacketOpcodes.PullRecentChatRsp);
|
||||||
|
|
||||||
GameServerOptions serverOptions = Grasscutter.getConfig().getGameServerOptions();
|
var joinOptions = GAME_INFO.joinOptions;
|
||||||
PullRecentChatRsp.Builder proto = PullRecentChatRsp.newBuilder();
|
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()
|
ChatInfo welcomeEmote = ChatInfo.newBuilder()
|
||||||
.setTime((int) (System.currentTimeMillis() / 1000))
|
.setTime((int) (System.currentTimeMillis() / 1000))
|
||||||
.setUid(GameConstants.SERVER_CONSOLE_UID)
|
.setUid(GameConstants.SERVER_CONSOLE_UID)
|
||||||
.setToUid(player.getUid())
|
.setToUid(player.getUid())
|
||||||
.setIcon(serverOptions.WelcomeEmotes[Utils.randomRange(0, serverOptions.WelcomeEmotes.length - 1)])
|
.setIcon(joinOptions.welcomeEmotes[Utils.randomRange(0, joinOptions.welcomeEmotes.length - 1)])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
proto.addChatInfo(welcomeEmote);
|
proto.addChatInfo(welcomeEmote);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serverOptions.WelcomeMotd != null && serverOptions.WelcomeMotd.length() > 0) {
|
if (joinOptions.welcomeMessage != null && joinOptions.welcomeMessage.length() > 0) {
|
||||||
ChatInfo welcomeMotd = ChatInfo.newBuilder()
|
ChatInfo welcomeMessage = ChatInfo.newBuilder()
|
||||||
.setTime((int) (System.currentTimeMillis() / 1000))
|
.setTime((int) (System.currentTimeMillis() / 1000))
|
||||||
.setUid(GameConstants.SERVER_CONSOLE_UID)
|
.setUid(GameConstants.SERVER_CONSOLE_UID)
|
||||||
.setToUid(player.getUid())
|
.setToUid(player.getUid())
|
||||||
.setText(Grasscutter.getConfig().getGameServerOptions().WelcomeMotd)
|
.setText(joinOptions.welcomeMessage)
|
||||||
.build();
|
.build();
|
||||||
|
proto.addChatInfo(welcomeMessage);
|
||||||
proto.addChatInfo(welcomeMotd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType;
|
import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType;
|
||||||
import emu.grasscutter.net.proto.StoreWeightLimitNotifyOuterClass.StoreWeightLimitNotify;
|
import emu.grasscutter.net.proto.StoreWeightLimitNotifyOuterClass.StoreWeightLimitNotify;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public class PacketStoreWeightLimitNotify extends BasePacket {
|
public class PacketStoreWeightLimitNotify extends BasePacket {
|
||||||
|
|
||||||
public PacketStoreWeightLimitNotify() {
|
public PacketStoreWeightLimitNotify() {
|
||||||
@ -13,11 +14,11 @@ public class PacketStoreWeightLimitNotify extends BasePacket {
|
|||||||
|
|
||||||
StoreWeightLimitNotify p = StoreWeightLimitNotify.newBuilder()
|
StoreWeightLimitNotify p = StoreWeightLimitNotify.newBuilder()
|
||||||
.setStoreType(StoreType.STORE_PACK)
|
.setStoreType(StoreType.STORE_PACK)
|
||||||
.setWeightLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitAll)
|
.setWeightLimit(INVENTORY_LIMITS.all)
|
||||||
.setWeaponCountLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitWeapon)
|
.setWeaponCountLimit(INVENTORY_LIMITS.weapons)
|
||||||
.setReliquaryCountLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitRelic)
|
.setReliquaryCountLimit(INVENTORY_LIMITS.relics)
|
||||||
.setMaterialCountLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitMaterial)
|
.setMaterialCountLimit(INVENTORY_LIMITS.materials)
|
||||||
.setFurnitureCountLimit(Grasscutter.getConfig().getGameServerOptions().InventoryLimitFurniture)
|
.setFurnitureCountLimit(INVENTORY_LIMITS.furniture)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.setData(p);
|
this.setData(p);
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
package emu.grasscutter.tools;
|
package emu.grasscutter.tools;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@ -14,14 +10,12 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.command.Command;
|
import emu.grasscutter.command.Command;
|
||||||
import emu.grasscutter.command.CommandHandler;
|
|
||||||
import emu.grasscutter.command.CommandMap;
|
import emu.grasscutter.command.CommandMap;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.ResourceLoader;
|
import emu.grasscutter.data.ResourceLoader;
|
||||||
@ -32,6 +26,7 @@ import emu.grasscutter.data.def.SceneData;
|
|||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class Tools {
|
public final class Tools {
|
||||||
public static void createGmHandbook() throws Exception {
|
public static void createGmHandbook() throws Exception {
|
||||||
@ -42,50 +37,45 @@ public final class Tools {
|
|||||||
ToolsWithLanguageOption.createGachaMapping(location, getLanguageOption());
|
ToolsWithLanguageOption.createGachaMapping(location, getLanguageOption());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> getAvailableLanguage() throws Exception {
|
public static List<String> getAvailableLanguage() {
|
||||||
File textMapFolder = new File(Grasscutter.getConfig().RESOURCE_FOLDER + "TextMap");
|
File textMapFolder = new File(RESOURCE("TextMap"));
|
||||||
List<String> availableLangList = new ArrayList<String>();
|
List<String> availableLangList = new ArrayList<>();
|
||||||
for (String textMapFileName : textMapFolder.list(new FilenameFilter() {
|
for (String textMapFileName : Objects.requireNonNull(textMapFolder.list((dir, name) -> name.startsWith("TextMap") && name.endsWith(".json")))) {
|
||||||
@Override
|
availableLangList.add(textMapFileName.replace("TextMap", "").replace(".json", "").toLowerCase());
|
||||||
public boolean accept(File dir, String name) {
|
} return availableLangList;
|
||||||
if (name.startsWith("TextMap") && name.endsWith(".json")){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
})) {
|
|
||||||
availableLangList.add(textMapFileName.replace("TextMap","").replace(".json","").toLowerCase());
|
|
||||||
}
|
|
||||||
return availableLangList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getLanguageOption() throws Exception {
|
public static String getLanguageOption() {
|
||||||
List<String> availableLangList = getAvailableLanguage();
|
List<String> availableLangList = getAvailableLanguage();
|
||||||
|
|
||||||
// Use system out for better format
|
// Use system out for better format
|
||||||
if (availableLangList.size() == 1) {
|
if (availableLangList.size() == 1) {
|
||||||
return availableLangList.get(0).toUpperCase();
|
return availableLangList.get(0).toUpperCase();
|
||||||
}
|
}
|
||||||
String stagedMessage = "";
|
StringBuilder stagedMessage = new StringBuilder();
|
||||||
stagedMessage += "The following languages mappings are available, please select one: [default: EN]\n";
|
stagedMessage.append("The following languages mappings are available, please select one: [default: EN] \n");
|
||||||
String groupedLangList = ">\t";
|
|
||||||
|
StringBuilder groupedLangList = new StringBuilder(">\t"); String input;
|
||||||
int groupedLangCount = 0;
|
int groupedLangCount = 0;
|
||||||
String input = "";
|
|
||||||
for (String availableLanguage: availableLangList){
|
for (String availableLanguage: availableLangList){
|
||||||
groupedLangCount++;
|
groupedLangCount++;
|
||||||
groupedLangList = groupedLangList + "" + availableLanguage + "\t";
|
groupedLangList.append(availableLanguage).append("\t");
|
||||||
|
|
||||||
if (groupedLangCount == 6) {
|
if (groupedLangCount == 6) {
|
||||||
stagedMessage += groupedLangList + "\n";
|
stagedMessage.append(groupedLangList).append("\n");
|
||||||
groupedLangCount = 0;
|
groupedLangCount = 0;
|
||||||
groupedLangList = ">\t";
|
groupedLangList = new StringBuilder(">\t");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (groupedLangCount > 0) {
|
|
||||||
stagedMessage += groupedLangList + "\n";
|
|
||||||
}
|
|
||||||
stagedMessage += "\nYour choice:[EN] ";
|
|
||||||
|
|
||||||
input = Grasscutter.getConsole().readLine(stagedMessage);
|
if (groupedLangCount > 0) {
|
||||||
|
stagedMessage.append(groupedLangList).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
stagedMessage.append("\nYour choice:[EN] ");
|
||||||
|
|
||||||
|
input = Grasscutter.getConsole().readLine(stagedMessage.toString());
|
||||||
if (availableLangList.contains(input.toLowerCase())) {
|
if (availableLangList.contains(input.toLowerCase())) {
|
||||||
return input.toUpperCase();
|
return input.toUpperCase();
|
||||||
}
|
}
|
||||||
@ -101,7 +91,7 @@ final class ToolsWithLanguageOption {
|
|||||||
ResourceLoader.loadResources();
|
ResourceLoader.loadResources();
|
||||||
|
|
||||||
Map<Long, String> map;
|
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());
|
map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken<Map<Long, String>>() {}.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +109,9 @@ final class ToolsWithLanguageOption {
|
|||||||
|
|
||||||
writer.println("// Commands");
|
writer.println("// Commands");
|
||||||
for (Command cmd : cmdList) {
|
for (Command cmd : cmdList) {
|
||||||
String cmdName = cmd.label();
|
StringBuilder cmdName = new StringBuilder(cmd.label());
|
||||||
while (cmdName.length() <= 15) {
|
while (cmdName.length() <= 15) {
|
||||||
cmdName = " " + cmdName;
|
cmdName.insert(0, " ");
|
||||||
}
|
}
|
||||||
writer.println(cmdName + " : " + translate(cmd.description()));
|
writer.println(cmdName + " : " + translate(cmd.description()));
|
||||||
}
|
}
|
||||||
@ -178,16 +168,13 @@ final class ToolsWithLanguageOption {
|
|||||||
ResourceLoader.loadResources();
|
ResourceLoader.loadResources();
|
||||||
|
|
||||||
Map<Long, String> map;
|
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());
|
map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken<Map<Long, String>>() {}.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Integer> list;
|
List<Integer> list;
|
||||||
|
|
||||||
String fileName = location;
|
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(location), StandardCharsets.UTF_8), false)) {
|
||||||
|
|
||||||
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), false)) {
|
|
||||||
|
|
||||||
list = new ArrayList<>(GameData.getAvatarDataMap().keySet());
|
list = new ArrayList<>(GameData.getAvatarDataMap().keySet());
|
||||||
Collections.sort(list);
|
Collections.sort(list);
|
||||||
|
|
||||||
@ -209,18 +196,11 @@ final class ToolsWithLanguageOption {
|
|||||||
} else {
|
} else {
|
||||||
writer.print(",");
|
writer.print(",");
|
||||||
}
|
}
|
||||||
String color;
|
String color = switch (data.getQualityType()) {
|
||||||
switch (data.getQualityType()){
|
case "QUALITY_PURPLE" -> "purple";
|
||||||
case "QUALITY_PURPLE":
|
case "QUALITY_ORANGE" -> "yellow";
|
||||||
color = "purple";
|
default -> "blue";
|
||||||
break;
|
};
|
||||||
case "QUALITY_ORANGE":
|
|
||||||
color = "yellow";
|
|
||||||
break;
|
|
||||||
case "QUALITY_BLUE":
|
|
||||||
default:
|
|
||||||
color = "blue";
|
|
||||||
}
|
|
||||||
// Got the magic number 4233146695 from manually search in the json file
|
// Got the magic number 4233146695 from manually search in the json file
|
||||||
writer.println(
|
writer.println(
|
||||||
"\"" + (avatarID % 1000 + 1000) + "\" : [\""
|
"\"" + (avatarID % 1000 + 1000) + "\" : [\""
|
||||||
|
229
src/main/java/emu/grasscutter/utils/ConfigContainer.java
Normal file
229
src/main/java/emu/grasscutter/utils/ConfigContainer.java
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
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 = 22102;
|
||||||
|
/* This is the port used in the default region. */
|
||||||
|
public int accessPort = 22102;
|
||||||
|
|
||||||
|
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.GetPlayerTokenRspOuterClass.GetPlayerTokenRsp;
|
||||||
import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp;
|
import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class Crypto {
|
public final class Crypto {
|
||||||
private static final SecureRandom secureRandom = new SecureRandom();
|
private static final SecureRandom secureRandom = new SecureRandom();
|
||||||
public static final long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968");
|
public static final long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968");
|
||||||
@ -16,9 +18,9 @@ public final class Crypto {
|
|||||||
public static byte[] ENCRYPT_KEY;
|
public static byte[] ENCRYPT_KEY;
|
||||||
|
|
||||||
public static void loadKeys() {
|
public static void loadKeys() {
|
||||||
DISPATCH_KEY = FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "dispatchKey.bin");
|
DISPATCH_KEY = FileUtils.read(KEYS_FOLDER + "/dispatchKey.bin");
|
||||||
ENCRYPT_KEY = FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "secretKey.bin");
|
ENCRYPT_KEY = FileUtils.read(KEYS_FOLDER + "/secretKey.bin");
|
||||||
ENCRYPT_SEED_BUFFER = FileUtils.read(Grasscutter.getConfig().KEY_FOLDER + "secretKeyBuffer.bin");
|
ENCRYPT_SEED_BUFFER = FileUtils.read(KEYS_FOLDER + "/secretKeyBuffer.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void xor(byte[] packet, byte[] key) {
|
public static void xor(byte[] packet, byte[] key) {
|
||||||
@ -34,7 +36,7 @@ public final class Crypto {
|
|||||||
public static void extractSecretKeyBuffer(byte[] data) {
|
public static void extractSecretKeyBuffer(byte[] data) {
|
||||||
try {
|
try {
|
||||||
GetPlayerTokenRsp p = GetPlayerTokenRsp.parseFrom(data);
|
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());
|
Grasscutter.getLogger().info("Secret Key: " + p.getSecretKey());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Crypto error.", e);
|
Grasscutter.getLogger().error("Crypto error.", e);
|
||||||
@ -44,7 +46,7 @@ public final class Crypto {
|
|||||||
public static void extractDispatchSeed(String data) {
|
public static void extractDispatchSeed(String data) {
|
||||||
try {
|
try {
|
||||||
QueryCurrRegionHttpRsp p = QueryCurrRegionHttpRsp.parseFrom(Base64.getDecoder().decode(data));
|
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) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Crypto error.", e);
|
Grasscutter.getLogger().error("Crypto error.", e);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import java.io.InputStream;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.*;
|
||||||
|
|
||||||
public final class Language {
|
public final class Language {
|
||||||
private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
|
private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@ -27,8 +29,8 @@ public final class Language {
|
|||||||
return cachedLanguages.get(langCode);
|
return cachedLanguages.get(langCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
var fallbackLanguageCode = Utils.getLanguageCode(Grasscutter.getConfig().DefaultLanguage);
|
var fallbackLanguageCode = Utils.getLanguageCode(FALLBACK_LANGUAGE);
|
||||||
var description = getLanguageFileStreamDescripter(langCode, fallbackLanguageCode);
|
var description = getLanguageFileDescription(langCode, fallbackLanguageCode);
|
||||||
var actualLanguageCode = description.getLanguageCode();
|
var actualLanguageCode = description.getLanguageCode();
|
||||||
|
|
||||||
Language languageInst;
|
Language languageInst;
|
||||||
@ -111,35 +113,31 @@ public final class Language {
|
|||||||
* @param languageCode The name of the language code.
|
* @param languageCode The name of the language code.
|
||||||
* @param fallbackLanguageCode The name of the fallback 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 fileName = languageCode + ".json";
|
||||||
var fallback = fallbackLanguageCode + ".json";
|
var fallback = fallbackLanguageCode + ".json";
|
||||||
|
|
||||||
String actualLanguageCode = languageCode;
|
|
||||||
if (cachedLanguages.containsKey(actualLanguageCode)) {
|
|
||||||
return new LanguageStreamDescription(actualLanguageCode, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
String actualLanguageCode = languageCode;
|
||||||
InputStream file = Grasscutter.class.getResourceAsStream("/languages/" + fileName);
|
InputStream file = Grasscutter.class.getResourceAsStream("/languages/" + fileName);
|
||||||
|
|
||||||
if (file == null) { // Provided fallback language.
|
if (file == null) { // Provided fallback language.
|
||||||
|
Grasscutter.getLogger().warn("Failed to load language file: " + fileName + ", falling back to: " + fallback);
|
||||||
actualLanguageCode = fallbackLanguageCode;
|
actualLanguageCode = fallbackLanguageCode;
|
||||||
if (cachedLanguages.containsKey(actualLanguageCode)) {
|
if (cachedLanguages.containsKey(actualLanguageCode)) {
|
||||||
return new LanguageStreamDescription(actualLanguageCode, null);
|
return new LanguageStreamDescription(actualLanguageCode, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
file = Grasscutter.class.getResourceAsStream("/languages/" + fallback);
|
file = Grasscutter.class.getResourceAsStream("/languages/" + fallback);
|
||||||
Grasscutter.getLogger().warn("Failed to load language file: " + fileName + ", falling back to: " + fallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(file == null) { // Fallback the fallback language.
|
if(file == null) { // Fallback the fallback language.
|
||||||
|
Grasscutter.getLogger().warn("Failed to load language file: " + fallback + ", falling back to: en-US.json");
|
||||||
actualLanguageCode = "en-US";
|
actualLanguageCode = "en-US";
|
||||||
if (cachedLanguages.containsKey(actualLanguageCode)) {
|
if (cachedLanguages.containsKey(actualLanguageCode)) {
|
||||||
return new LanguageStreamDescription(actualLanguageCode, null);
|
return new LanguageStreamDescription(actualLanguageCode, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
file = Grasscutter.class.getResourceAsStream("/languages/en-US.json");
|
file = Grasscutter.class.getResourceAsStream("/languages/en-US.json");
|
||||||
Grasscutter.getLogger().warn("Failed to load language file: " + fallback + ", falling back to: en-US.json");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(file == null)
|
if(file == null)
|
||||||
|
@ -11,7 +11,6 @@ import java.util.Map;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import emu.grasscutter.Config;
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
@ -175,12 +174,12 @@ public final class Utils {
|
|||||||
* Checks for required files and folders before startup.
|
* Checks for required files and folders before startup.
|
||||||
*/
|
*/
|
||||||
public static void startupCheck() {
|
public static void startupCheck() {
|
||||||
Config config = Grasscutter.getConfig();
|
ConfigContainer config = Grasscutter.getConfig();
|
||||||
Logger logger = Grasscutter.getLogger();
|
Logger logger = Grasscutter.getLogger();
|
||||||
boolean exit = false;
|
boolean exit = false;
|
||||||
|
|
||||||
String resourcesFolder = config.RESOURCE_FOLDER;
|
String resourcesFolder = config.folderStructure.resources;
|
||||||
String dataFolder = config.DATA_FOLDER;
|
String dataFolder = config.folderStructure.data;
|
||||||
|
|
||||||
// Check for resources folder.
|
// Check for resources folder.
|
||||||
if(!fileExists(resourcesFolder)) {
|
if(!fileExists(resourcesFolder)) {
|
||||||
|
@ -191,6 +191,7 @@
|
|||||||
"language": {
|
"language": {
|
||||||
"current_language": "current language is %s",
|
"current_language": "current language is %s",
|
||||||
"language_changed": "language changed to %s",
|
"language_changed": "language changed to %s",
|
||||||
|
"language_not_found": "currently, server does not have that language: %s",
|
||||||
"description": "display or change current language"
|
"description": "display or change current language"
|
||||||
},
|
},
|
||||||
"list": {
|
"list": {
|
||||||
|
@ -191,6 +191,7 @@
|
|||||||
"language": {
|
"language": {
|
||||||
"current_language": "当前语言是: %s",
|
"current_language": "当前语言是: %s",
|
||||||
"language_changed": "语言切换至: %s",
|
"language_changed": "语言切换至: %s",
|
||||||
|
"language_not_found": "目前服务端没有这种语言: %s",
|
||||||
"description": "显示或切换当前语言。"
|
"description": "显示或切换当前语言。"
|
||||||
},
|
},
|
||||||
"list": {
|
"list": {
|
||||||
|
Loading…
Reference in New Issue
Block a user