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

Merge pull request #802 from Grasscutters/better-config

Implement a better config structure
parents 54cf45a7 812f4b37
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;
}
}
}
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;
}
}
\ No newline at end of file
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; ...@@ -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 { ...@@ -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 { ...@@ -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();
...@@ -77,7 +80,7 @@ public final class Grasscutter { ...@@ -77,7 +80,7 @@ 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;
} }
} }
} }
...@@ -105,15 +108,16 @@ public final class Grasscutter { ...@@ -105,15 +108,16 @@ public final class Grasscutter {
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);
...@@ -137,32 +141,46 @@ public final class Grasscutter { ...@@ -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 { ...@@ -198,7 +216,7 @@ public final class Grasscutter {
} }
} }
public static Config getConfig() { public static ConfigContainer getConfig() {
return config; return config;
} }
......
...@@ -25,10 +25,11 @@ import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierActionType; ...@@ -25,10 +25,11 @@ import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierActionType;
import emu.grasscutter.data.custom.AbilityModifierEntry; import emu.grasscutter.data.custom.AbilityModifierEntry;
import emu.grasscutter.data.custom.OpenConfigEntry; import emu.grasscutter.data.custom.OpenConfigEntry;
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() {
...@@ -127,7 +128,7 @@ public class ResourceLoader { ...@@ -127,7 +128,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);
...@@ -141,7 +142,7 @@ public class ResourceLoader { ...@@ -141,7 +142,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!");
...@@ -150,8 +151,7 @@ public class ResourceLoader { ...@@ -150,8 +151,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()) {
...@@ -190,7 +190,7 @@ public class ResourceLoader { ...@@ -190,7 +190,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()) {
...@@ -205,7 +205,7 @@ public class ResourceLoader { ...@@ -205,7 +205,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());
...@@ -252,7 +252,7 @@ public class ResourceLoader { ...@@ -252,7 +252,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());
...@@ -260,7 +260,7 @@ public class ResourceLoader { ...@@ -260,7 +260,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());
...@@ -315,7 +315,7 @@ public class ResourceLoader { ...@@ -315,7 +315,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()) {
...@@ -333,16 +333,14 @@ public class ResourceLoader { ...@@ -333,16 +333,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()) {
...@@ -357,7 +355,7 @@ public class ResourceLoader { ...@@ -357,7 +355,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;
......
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;
...@@ -21,11 +20,9 @@ import emu.grasscutter.game.inventory.GameItem; ...@@ -21,11 +20,9 @@ import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.mail.Mail; import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
public final class DatabaseManager { import static emu.grasscutter.Configuration.*;
private static MongoClient mongoClient;
private static MongoClient dispatchMongoClient;
public final class DatabaseManager {
private static Datastore datastore; private static Datastore datastore;
private static Datastore dispatchDatastore; private static Datastore dispatchDatastore;
...@@ -44,7 +41,7 @@ public final class DatabaseManager { ...@@ -44,7 +41,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;
...@@ -53,13 +50,13 @@ public final class DatabaseManager { ...@@ -53,13 +50,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);
...@@ -80,9 +77,9 @@ public final class DatabaseManager { ...@@ -80,9 +77,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; ...@@ -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 { ...@@ -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 { ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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; ...@@ -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 { ...@@ -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) {
......
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 { ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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; ...@@ -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; ...@@ -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; ...@@ -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> { ...@@ -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> { ...@@ -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);
break; case 105 -> // Companionship exp
case 105: // Companionship exp
getPlayer().getServer().getInventoryManager().upgradeAvatarFetterLevel(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count); getPlayer().getServer().getInventoryManager().upgradeAvatarFetterLevel(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
break; case 201 -> // Primogem
case 201: // Primogem
getPlayer().setPrimogems(player.getPrimogems() + count); getPlayer().setPrimogems(player.getPrimogems() + count);
break; case 202 -> // Mora
case 202: // Mora
getPlayer().setMora(player.getMora() + count); getPlayer().setMora(player.getMora() + count);
break; case 203 -> // Genesis Crystals
case 203: // Genesis Crystals
getPlayer().setCrystals(player.getCrystals() + count); getPlayer().setCrystals(player.getCrystals() + count);
break;
} }
} }
......
...@@ -21,6 +21,8 @@ import org.jetbrains.annotations.NotNull; ...@@ -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 { ...@@ -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));
......
...@@ -60,6 +60,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; ...@@ -60,6 +60,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 {
...@@ -353,7 +355,7 @@ public class Player { ...@@ -353,7 +355,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
...@@ -1218,7 +1220,7 @@ public class Player { ...@@ -1218,7 +1220,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; }
...@@ -1235,7 +1237,7 @@ public class Player { ...@@ -1235,7 +1237,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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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.*; ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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);
} }
} }
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; ...@@ -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 { ...@@ -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.*; ...@@ -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 { ...@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment