config & mode & threads enhanced

This commit is contained in:
Xujiayao 2025-11-06 12:43:47 +08:00
parent 54f3899725
commit 8ea4f244d6
6 changed files with 51 additions and 52 deletions

View file

@ -4,6 +4,7 @@ import com.xujiayao.discord_mc_chat.commands.CommandEventHandler;
import com.xujiayao.discord_mc_chat.discord.DiscordManager;
import com.xujiayao.discord_mc_chat.standalone.TerminalManager;
import com.xujiayao.discord_mc_chat.utils.config.ConfigManager;
import com.xujiayao.discord_mc_chat.utils.config.ModeManager;
import com.xujiayao.discord_mc_chat.utils.events.EventManager;
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
import com.xujiayao.discord_mc_chat.utils.logging.impl.LoggerImpl;
@ -30,17 +31,13 @@ public class DMCC {
public static void init() {
new Thread(() -> {
// Check if running in headless mode
if (System.console() == null) {
// The user likely started the application by double-clicking the JAR file
if (System.console() == null && !IS_MINECRAFT_ENV) {
// The user likely started the application by double-clicking the JAR file in a GUI environment
// Generates a warning to remind the user to start DMCC from the command line
LOGGER.warn("No console detected, indicating DMCC is running in headless mode");
LOGGER.warn("DMCC does not support being started by double-clicking the JAR file");
LOGGER.warn("Please start DMCC from the command line \"java -jar Discord-MC-Chat-{}.jar\"", VERSION);
LOGGER.info("Exiting...");
if (!IS_MINECRAFT_ENV) {
System.exit(0);
}
return;
}
@ -65,25 +62,27 @@ public class DMCC {
// In a Minecraft environment, we just return and let the server continue running
// In standalone mode, the process would terminate after returning
// Load configuration
if (!ConfigManager.load()) {
LOGGER.warn("DMCC will not continue initialization due to configuration issues");
LOGGER.info("Exiting...");
if (!IS_MINECRAFT_ENV) {
System.exit(0);
// Determine operating mode
String mode;
if (IS_MINECRAFT_ENV) {
mode = ModeManager.load();
if (mode == null) {
LOGGER.warn("DMCC initialization halted because an operating mode needs to be selected");
return;
}
} else {
mode = "standalone";
}
// Load configuration
if (!ConfigManager.load(mode)) {
LOGGER.warn("DMCC will not continue initialization due to configuration issues");
return;
}
// Load language files
if (!I18nManager.load()) {
LOGGER.warn("DMCC will not continue initialization due to language file issues");
LOGGER.info("Exiting...");
if (!IS_MINECRAFT_ENV) {
System.exit(0);
}
return;
}
@ -108,11 +107,6 @@ public class DMCC {
// Initialize Discord
if (!DiscordManager.init()) {
LOGGER.warn("DMCC will not continue initialization due to Discord connection issues");
LOGGER.info("Exiting...");
if (!IS_MINECRAFT_ENV) {
System.exit(0);
}
return;
}
}, "DMCC-Main").start();
@ -161,8 +155,10 @@ public class DMCC {
* Reloads DMCC by shutting it down and re-initializing.
*/
public static void reload() {
shutdown();
init();
LOGGER.info("DMCC reloaded!");
new Thread(() -> {
shutdown();
init();
LOGGER.info("DMCC reloaded!");
}, "DMCC-Reload").start();
}
}

View file

@ -104,7 +104,8 @@ public class YamlUtils {
// A hard-coded list of keys that should be modified by the user
// This is to catch cases where the user leaves a key unchanged from the template
String[] keysToCheck = {
"bot.token"
"bot.token",
"multi_server.server_name"
};
Set<String> unmodifiedKeys = findUnmodifiedKeys(config, templateConfig, keysToCheck);
if (!unmodifiedKeys.isEmpty()) {
@ -232,6 +233,8 @@ public class YamlUtils {
// If either node is missing, it's not an "unmodified" key in the sense we're checking.
// The missing key itself is handled by findKeyDiffs.
// Or it is the case that config files of different modes have different keys.
// Or it is the case that language files and config files have different keys.
if (configNode.isMissingNode() || templateNode.isMissingNode()) {
continue;
}

View file

@ -12,7 +12,6 @@ import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.function.Function;
import static com.xujiayao.discord_mc_chat.Constants.IS_MINECRAFT_ENV;
import static com.xujiayao.discord_mc_chat.Constants.LOGGER;
import static com.xujiayao.discord_mc_chat.Constants.YAML_MAPPER;
@ -30,24 +29,14 @@ public class ConfigManager {
/**
* Loads the configuration file based on the determined operating mode.
*
* @param expectedMode The mode DMCC is expected to run in.
* @return true if the config was loaded and validated successfully, false otherwise.
*/
public static boolean load() {
public static boolean load(String expectedMode) {
try {
// Create directories if they do not exist
Files.createDirectories(CONFIG_PATH.getParent());
String expectedMode;
if (IS_MINECRAFT_ENV) {
expectedMode = ModeManager.load();
if (expectedMode == null) {
// ModeManager handles logging, so we just return false to stop initialization.
return false;
}
} else {
expectedMode = "standalone";
}
// If config.yml does not exist or is empty, create it from the appropriate template.
if (!Files.exists(CONFIG_PATH) || Files.size(CONFIG_PATH) == 0) {
createDefaultConfig(expectedMode);
@ -61,8 +50,8 @@ public class ConfigManager {
String configMode = userConfig.path("mode").asText();
if (!expectedMode.equals(configMode)) {
LOGGER.error("Mode mismatch detected!");
LOGGER.error("Mode in mode.yml is \"{}\", but config.yml is for \"{}\"", expectedMode, configMode);
LOGGER.error("Please backup and delete your existing config.yml to allow DMCC to generate a new and correct one");
LOGGER.error("The expected mode is \"{}\" (from mode.yml or environment), but config.yml is for \"{}\".", expectedMode, configMode);
LOGGER.error("Please backup and delete your existing config.yml to allow DMCC to generate a new and correct one, then run \"/dmcc reload\".");
return false;
}
@ -108,7 +97,7 @@ public class ConfigManager {
}
LOGGER.info("Created default configuration file at \"{}\"", CONFIG_PATH);
LOGGER.info("Please edit the configuration file before reloading DMCC");
LOGGER.info("Please edit the configuration file before reloading or restarting DMCC");
}
/**
@ -118,15 +107,26 @@ public class ConfigManager {
* @return The JsonNode at the specified path
*/
public static JsonNode getConfigNode(String path) {
if (config == null) {
// This can happen if config is not loaded yet.
// Returning a missing node is safer than a NullPointerException.
try {
return YAML_MAPPER.missingNode();
} catch (Exception e) {
// Should not happen, but as a fallback
return null;
}
}
String[] parts = path.split("\\.");
JsonNode node = config;
for (String part : parts) {
node = node.path(part);
if (node.isMissingNode()) {
if (node == null || node.isMissingNode()) {
LOGGER.warn("Configuration path not found: {}", path);
return node;
}
node = node.path(part);
}
return node;
@ -143,7 +143,7 @@ public class ConfigManager {
*/
public static <T> T getValue(String path, T defaultValue, Function<JsonNode, T> converter) {
JsonNode node = getConfigNode(path);
return node.isMissingNode() ? defaultValue : converter.apply(node);
return (node == null || node.isMissingNode()) ? defaultValue : converter.apply(node);
}
/**

View file

@ -57,15 +57,15 @@ public class ModeManager {
}
// Validate the mode file
if (!YamlUtils.validate(modeConfig, templateConfig, MODE_FILE_PATH, false)) {
LOGGER.error("Validation of mode.yml failed. Please correct the errors.");
if (!YamlUtils.validate(modeConfig, templateConfig, MODE_FILE_PATH, true)) {
LOGGER.error("Validation of mode.yml failed. Please correct the errors mentioned above.");
return null;
}
String loadedMode = modeConfig.path("mode").asText(null);
if (loadedMode == null || loadedMode.trim().isEmpty() || loadedMode.startsWith("#")) {
LOGGER.error("No mode selected in \"{}\". Please uncomment one of the mode options.", MODE_FILE_PATH);
if (loadedMode == null || loadedMode.trim().isEmpty()) {
LOGGER.error("No mode selected in \"{}\"", MODE_FILE_PATH);
return null;
}
@ -77,7 +77,6 @@ public class ModeManager {
LOGGER.info("Operating mode set to \"{}\"", loadedMode);
return loadedMode;
} catch (IOException e) {
LOGGER.error("Failed to load or create mode.yml", e);
return null;

View file

@ -16,4 +16,4 @@ multi_server:
connection:
host: localhost
port: 5000
server_name: SMP
server_name: your_server_name_here

View file

@ -29,4 +29,5 @@ version: ${mod_version}
# all DMCC activities and communicates with Discord.
# ==================================================
# Set your desired mode here. Replace "your_option_here" with one of the available modes.
mode: your_option_here