diff options
author | Haru <haru@dotalux.com> | 2015-09-06 18:08:14 +0200 |
---|---|---|
committer | Haru <haru@dotalux.com> | 2016-08-19 21:32:12 +0200 |
commit | c84a4473cc0491edbf6ac3e7efd062d8c57e5a2c (patch) | |
tree | 335a146bf8eecd6cc1bacb4388efa1e64cd3e91e /src/char/char.c | |
parent | 6be7aab17d958e0f5a4be0413b26c7dd81185af6 (diff) | |
download | hercules-c84a4473cc0491edbf6ac3e7efd062d8c57e5a2c.tar.gz hercules-c84a4473cc0491edbf6ac3e7efd062d8c57e5a2c.tar.bz2 hercules-c84a4473cc0491edbf6ac3e7efd062d8c57e5a2c.tar.xz hercules-c84a4473cc0491edbf6ac3e7efd062d8c57e5a2c.zip |
Ported char-server.conf to libconfig
Fixed issue: 8115, now start items can be equipped as well
Ported to modern Hercules and cleaned up from Panikon's commits: c6482e9870645ffe59a6a059b819574d4ac79fd9, 832fb27d4f767e4bc8b68c432d0da00b7cb7a4f9, f81b579899e3a15bd472ca8c6a6e0116c43bec92, e23723725499b617def03d05661eca637edaeabd, 0b783a83d82e588efd760f7f4baec0c8074a6fd1, 1b7de91308a57ea07b158ed95a2515a3c8cc36bd, 677d3430cbda0962b320a60cf499e9dadf637d00
Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src/char/char.c')
-rw-r--r-- | src/char/char.c | 747 |
1 files changed, 541 insertions, 206 deletions
diff --git a/src/char/char.c b/src/char/char.c index 571aad566..2b5c837c5 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -42,6 +42,7 @@ #include "common/HPM.h" #include "common/cbasetypes.h" +#include "common/conf.h" #include "common/console.h" #include "common/core.h" #include "common/db.h" @@ -61,6 +62,7 @@ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> +#include <sys/stat.h> // stat() #if MAX_MAP_SERVERS > 1 # ifdef _MSC_VER @@ -136,7 +138,16 @@ int max_connect_user = -1; int gm_allow_group = -1; int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; int start_zeny = 0; -int start_items[MAX_START_ITEMS*3]; + +/// Start items for new characters +struct start_item_s { + int id; + int amount; + int loc; + bool stackable; +}; +VECTOR_DECL(struct start_item_s) start_items; + int guild_exp_rate = 100; //Custom limits for the fame lists. [Skotlex] @@ -1537,7 +1548,7 @@ int char_make_new_char_sql(struct char_session_data *sd, const char *name_, int { char name[NAME_LENGTH]; char esc_name[NAME_LENGTH*2+1]; - int char_id, flag, k, l; + int char_id, flag, i; nullpo_retr(-2, sd); nullpo_retr(-2, name_); @@ -1609,24 +1620,20 @@ int char_make_new_char_sql(struct char_session_data *sd, const char *name_, int } //Give the char the default items - for (k = 0; k < ARRAYLENGTH(start_items) && start_items[k] != 0; k += 3) { - // FIXME: How to define if an item is stackable without having to lookup itemdb? [panikon] - if( start_items[k+2] == 1 ) - { - if( SQL_ERROR == SQL->Query(inter->sql_handle, - "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", - inventory_db, char_id, start_items[k], start_items[k + 1], 1) ) - Sql_ShowDebug(inter->sql_handle); - } - else if( start_items[k+2] == 0 ) - { + for (i = 0; i < VECTOR_LENGTH(start_items); i++) { + struct start_item_s *item = &VECTOR_INDEX(start_items, i); + if (item->stackable) { + if (SQL_ERROR == SQL->Query(inter->sql_handle, + "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", + inventory_db, char_id, item->id, item->amount, 1)) + Sql_ShowDebug(inter->sql_handle); + } else { // Non-stackable items should have their own entries (issue: 7279) - for( l = 0; l < start_items[k+1]; l++ ) - { - if( SQL_ERROR == SQL->Query(inter->sql_handle, - "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", - inventory_db, char_id, start_items[k], 1, 1) - ) + int l, loc = item->loc; + for (l = 0; l < item->amount; l++) { + if (SQL_ERROR == SQL->Query(inter->sql_handle, + "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%d', '%d', '%d', '%d')", + inventory_db, char_id, item->id, 1, loc, 1)) Sql_ShowDebug(inter->sql_handle); } } @@ -2176,7 +2183,7 @@ int char_parse_fromlogin_connection_state(int fd) ShowError("Can not connect to login-server.\n"); ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); - ShowError("The communication passwords are set in /conf/map-server.conf and /conf/char-server.conf\n"); + ShowError("The communication passwords are set in /conf/map-server.conf and /conf/char/char-server.conf\n"); sockt->eof(fd); return 1; } else { @@ -5441,206 +5448,504 @@ void char_sql_config_read(const char* cfgName) ShowInfo("Done reading %s.\n", cfgName); } -void char_config_dispatch(char *w1, char *w2) { - bool (*dispatch_to[]) (char *w1, char *w2) = { - /* as many as it needs */ - pincode->config_read - }; - int i, len = ARRAYLENGTH(dispatch_to); - for(i = 0; i < len; i++) { - if( (*dispatch_to[i])(w1,w2) ) - break;/* we found who this belongs to, can stop */ +/** + * Reads the 'char_configuration' config file and initializes required variables. + * + * @param filename Path to configuration file. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read(const char *filename, bool imported) +{ + struct config_t config; + const char *import = NULL; + bool retval = true; + + nullpo_retr(false, filename); + + if (!libconfig->load_file(&config, filename)) + return false; // Error message is already shown by libconfig->load_file + + if (!chr->config_read_top(filename, &config, imported)) + retval = false; + if (!chr->config_read_inter(filename, &config, imported)) + retval = false; + if (!chr->config_read_permission(filename, &config, imported)) + retval = false; + if (!chr->config_read_player(filename, &config, imported)) + retval = false; + if (!chr->config_read_console(filename, &config, imported)) + retval = false; + if (!chr->config_read_database(filename, &config, imported)) + retval = false; + if (!pincode->config_read(filename, &config, imported)) + retval = false; + + // TODO HPM->parseConf(w1, w2, HPCT_CHAR); + + ShowInfo("Done reading %s.\n", filename); + + // import should overwrite any previous configuration, so it should be called last + if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { + if (strcmp(import, filename) == 0 || strcmp(import, chr->CHAR_CONF_NAME) == 0) { + ShowWarning("char_config_read: Loop detected in %s! Skipping 'import'...\n", filename); + } else { + if (!chr->config_read(import, true)) + retval = false; + } } - if (i == len) - HPM->parseConf(w1, w2, HPCT_CHAR); + + libconfig->destroy(&config); + return retval; } -int char_config_read(const char* cfgName) +/** + * Reads the 'char_configuration' top level config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_top(const char *filename, const struct config_t *config, bool imported) { - char line[1024], w1[1024], w2[1024]; - FILE* fp = fopen(cfgName, "r"); + const struct config_setting_t *setting = NULL; - if (fp == NULL) { - ShowError("Configuration file not found: %s.\n", cfgName); - return 1; + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "char_configuration")) == NULL) { + if (imported) + return true; + ShowError("char_config_read: char_configuration was not found in %s!\n", filename); + return false; + } + + // char_configuration/server_name + if (libconfig->setting_lookup_mutable_string(setting, "server_name", chr->server_name, sizeof(chr->server_name)) == CONFIG_TRUE) { + ShowInfo("server name %s\n", chr->server_name); + } else if (!imported) { + ShowWarning("char_config_read: server_name was not set! Defaulting to 'Hercules'.\n"); + safestrncpy(chr->server_name, "Hercules", sizeof(chr->server_name)); + } + // char_configuration/wisp_server_name + if (libconfig->setting_lookup_mutable_string(setting, "wisp_server_name", wisp_server_name, sizeof(wisp_server_name)) == CONFIG_TRUE) { + // wisp_server_name should _always_ be equal or bigger than 4 characters! + if (strlen(wisp_server_name) < 4) { // TODO: This length should be a #define (i.e. MIN_NAME_LENGTH) + ShowWarning("char_config_read: char_configuration/wisp_server_name is too small! Defaulting to: Server.\n"); + safestrncpy(chr->server_name, "Server", sizeof(chr->server_name)); + } + } + // char_configuration/guild_exp_rate + libconfig->setting_lookup_int(setting, "guild_exp_rate", &guild_exp_rate); + + return true; +} + +/** + * Reads the 'char_configuration/inter' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_inter(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + const char *str = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "char_configuration/inter")) == NULL) { + if (imported) + return true; + ShowError("char_config_read: char_configuration/inter was not found in %s!\n", filename); + return false; + } + + // Login information + libconfig->setting_lookup_mutable_string(setting, "userid", chr->userid, sizeof(chr->userid)); + libconfig->setting_lookup_mutable_string(setting, "passwd", chr->passwd, sizeof(chr->passwd)); + + // Login-server and character-server information + if (libconfig->setting_lookup_string(setting, "login_ip", &str) == CONFIG_TRUE) + chr->config_set_ip("Login server", str, &login_ip, login_ip_str); + + if (libconfig->setting_lookup_string(setting, "char_ip", &str) == CONFIG_TRUE) + chr->config_set_ip("Character server", str, &chr->ip, char_ip_str); + + if (libconfig->setting_lookup_string(setting, "bind_ip", &str) == CONFIG_TRUE) + chr->config_set_ip("Character server binding", str, &bind_ip, bind_ip_str); + + libconfig->setting_lookup_uint16(setting, "login_port", &login_port); + libconfig->setting_lookup_uint16(setting, "char_port", &chr->port); + + return true; +} + +/** + * Reads the 'char_configuration/database' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_database(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "char_configuration/database")) == NULL) { + if (imported) + return true; + ShowError("char_config_read: char_configuration/database was not found in %s!\n", filename); + return false; + } + if (libconfig->setting_lookup_int(setting, "autosave_time", &autosave_interval) == CONFIG_TRUE) { + autosave_interval *= 1000; + if (autosave_interval <= 0) + autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + } + libconfig->setting_lookup_mutable_string(setting, "db_path", db_path, sizeof(db_path)); + libconfig->setting_lookup_bool_real(setting, "log_char", &chr->enable_logs); + return true; +} + +/** + * Reads the 'char_configuration/console' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_console(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "char_configuration/console")) == NULL) { + if (imported) + return true; + ShowError("char_config_read: char_configuration/console was not found in %s!\n", filename); + return false; + } + libconfig->setting_lookup_bool_real(setting, "stdout_with_ansisequence", &showmsg->stdout_with_ansisequence); + libconfig->setting_lookup_bool_real(setting, "save_log", &chr->show_save_log); + if (libconfig->setting_lookup_int(setting, "console_silent", &showmsg->silent) == CONFIG_TRUE) { + if (showmsg->silent) // only bother if its actually enabled + ShowInfo("Console Silent Setting: %d\n", showmsg->silent); + } + libconfig->setting_lookup_mutable_string(setting, "timestamp_format", showmsg->timestamp_format, sizeof(showmsg->timestamp_format)); + + return true; +} + +/** + * Reads the 'char_configuration/player' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_player(const char *filename, const struct config_t *config, bool imported) +{ + bool retval = true; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if (!chr->config_read_player_new(filename, config, imported)) + retval = false; + if (!chr->config_read_player_name(filename, config, imported)) + retval = false; + if (!chr->config_read_player_deletion(filename, config, imported)) + retval = false; + if (!chr->config_read_player_fame(filename, config, imported)) + retval = false; + + return retval; +} + +/** + * Reads the 'char_configuration/player/fame' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_player_fame(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "char_configuration/player/fame")) == NULL) { + if (imported) + return true; + ShowError("char_config_read: char_configuration/player/fame was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_int(setting, "alchemist", &fame_list_size_chemist); + if (fame_list_size_chemist > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); + fame_list_size_chemist = MAX_FAME_LIST; + } + + libconfig->setting_lookup_int(setting, "blacksmith", &fame_list_size_smith); + if (fame_list_size_smith > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); + fame_list_size_smith = MAX_FAME_LIST; + } + + libconfig->setting_lookup_int(setting, "taekwon", &fame_list_size_taekwon); + if (fame_list_size_taekwon > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); + fame_list_size_taekwon = MAX_FAME_LIST; + } + + return true; +} + +/** + * Reads the 'char_configuration/player/deletion' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_player_deletion(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "char_configuration/player/deletion")) == NULL) { + if (imported) + return true; + ShowError("char_config_read: char_configuration/player/deletion was not found in %s!\n", filename); + return false; + } + libconfig->setting_lookup_int(setting, "level", &char_del_level); + libconfig->setting_lookup_int(setting, "delay", &char_del_delay); + libconfig->setting_lookup_bool_real(setting, "use_aegis_delete", &char_aegis_delete); + + return true; +} + +/** + * Reads the 'char_configuration/player/name' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_player_name(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "char_configuration/player/name")) == NULL) { + if (imported) + return true; + ShowError("char_config_read: char_configuration/player/name was not found in %s!\n", filename); + return false; } + libconfig->setting_lookup_mutable_string(setting, "unknown_char_name", unknown_char_name, sizeof(unknown_char_name)); + libconfig->setting_lookup_mutable_string(setting, "name_letters", char_name_letters, sizeof(char_name_letters)); + libconfig->setting_lookup_int(setting, "name_option", &char_name_option); + libconfig->setting_lookup_bool_real(setting, "name_ignoring_case", &name_ignoring_case); + + return true; +} + +/** + * Defines start_items based on '(...)/player/new/start_item'. + * + * @param setting The already retrieved start_item setting. + */ +void char_config_set_start_item(const struct config_setting_t *setting) +{ + int i, count; - while(fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') + nullpo_retv(setting); + + VECTOR_CLEAR(start_items); + + count = libconfig->setting_length(setting); + if (!count) + return; + + VECTOR_ENSURE(start_items, count, 1); + + for (i = 0; i < count; i++) { + const struct config_setting_t *t = libconfig->setting_get_elem(setting, i); + struct start_item_s start_item = { 0 }; + + if (t == NULL) continue; - if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) != 2) + if (libconfig->setting_lookup_int(t, "id", &start_item.id) != CONFIG_TRUE) { + ShowWarning("char_config_read: entry (%d) is missing id! Ignoring...\n", i); continue; + } + if (libconfig->setting_lookup_int(t, "amount", &start_item.amount) != CONFIG_TRUE) { + ShowWarning("char_config_read: entry (%d) is missing amount! Defaulting to 1...\n", i); + start_item.amount = 1; + } + if (libconfig->setting_lookup_bool_real(t, "stackable", &start_item.stackable) != CONFIG_TRUE) { + // Without knowing if the item is stackable or not we can't add it! + ShowWarning("char_config_read: entry (%d) is missing stackable! Ignoring...\n", i); + continue; + } + if (libconfig->setting_lookup_int(t, "loc", &start_item.loc) != CONFIG_TRUE) + start_item.loc = 0; + VECTOR_PUSH(start_items, start_item); + } +} - remove_control_chars(w1); - remove_control_chars(w2); - if(strcmpi(w1,"timestamp_format") == 0) { - safestrncpy(showmsg->timestamp_format, w2, sizeof(showmsg->timestamp_format)); - } else if(strcmpi(w1,"console_silent")==0){ - showmsg->silent = atoi(w2); - if (showmsg->silent) /* only bother if its actually enabled */ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ - showmsg->stdout_with_ansisequence = config_switch(w2) ? true : false; - } else if (strcmpi(w1, "userid") == 0) { - safestrncpy(chr->userid, w2, sizeof(chr->userid)); - } else if (strcmpi(w1, "passwd") == 0) { - safestrncpy(chr->passwd, w2, sizeof(chr->passwd)); - } else if (strcmpi(w1, "server_name") == 0) { - safestrncpy(chr->server_name, w2, sizeof(chr->server_name)); - } else if (strcmpi(w1, "wisp_server_name") == 0) { - if (strlen(w2) >= 4) { - safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name)); - } - } else if (strcmpi(w1, "login_ip") == 0) { - login_ip = sockt->host2ip(w2); - if (login_ip) { - char ip_str[16]; - safestrncpy(login_ip_str, w2, sizeof(login_ip_str)); - ShowStatus("Login server IP address : %s -> %s\n", w2, sockt->ip2str(login_ip, ip_str)); - } - } else if (strcmpi(w1, "login_port") == 0) { - login_port = atoi(w2); - } else if (strcmpi(w1, "char_ip") == 0) { - chr->ip = sockt->host2ip(w2); - if (chr->ip) { - char ip_str[16]; - safestrncpy(char_ip_str, w2, sizeof(char_ip_str)); - ShowStatus("Character server IP address : %s -> %s\n", w2, sockt->ip2str(chr->ip, ip_str)); - } - } else if (strcmpi(w1, "bind_ip") == 0) { - bind_ip = sockt->host2ip(w2); - if (bind_ip) { - char ip_str[16]; - safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str)); - ShowStatus("Character server binding IP address : %s -> %s\n", w2, sockt->ip2str(bind_ip, ip_str)); - } - } else if (strcmpi(w1, "char_port") == 0) { - chr->port = atoi(w2); - } else if (strcmpi(w1, "char_server_type") == 0) { - chr->server_type = atoi(w2); - } else if (strcmpi(w1, "char_new") == 0) { - enable_char_creation = atoi(w2) ? true : false; - } else if (strcmpi(w1, "char_new_display") == 0) { - chr->new_display = atoi(w2); - } else if (strcmpi(w1, "max_connect_user") == 0) { - max_connect_user = atoi(w2); - if (max_connect_user < -1) - max_connect_user = -1; // unlimited online players - } else if(strcmpi(w1, "gm_allow_group") == 0) { - gm_allow_group = atoi(w2); - } else if (strcmpi(w1, "autosave_time") == 0) { - autosave_interval = atoi(w2) * 1000; - if (autosave_interval <= 0) - autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - } else if (strcmpi(w1, "save_log") == 0) { - chr->show_save_log = config_switch(w2) ? true : false; +/** + * Reads the 'char_configuration/player/new' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_player_new(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL, *setting2 = NULL; +#ifdef RENEWAL + const char *start_point_setting = "start_point_re"; +#else + const char *start_point_setting = "start_point_pre"; +#endif + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "char_configuration/player/new")) == NULL) { + if (imported) + return true; + ShowError("char_config_read: char_configuration/player/new was not found in %s!\n", filename); + return false; + } + + if (libconfig->setting_lookup_int(setting, "zeny", &start_zeny) == CONFIG_TRUE) { + if (start_zeny > MAX_ZENY) { + ShowWarning("char_config_read: player/new/zeny is too big! Capping to MAX_ZENY.\n"); + start_zeny = MAX_ZENY; } - #ifdef RENEWAL - else if (strcmpi(w1, "start_point_re") == 0) { - char map[MAP_NAME_LENGTH_EXT]; - int x, y; - if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) - continue; - start_point.map = mapindex->name2id(map); - if (!start_point.map) - ShowError("Specified start_point_re '%s' not found in map-index cache.\n", map); - start_point.x = x; - start_point.y = y; - } - #else - else if (strcmpi(w1, "start_point_pre") == 0) { - char map[MAP_NAME_LENGTH_EXT]; - int x, y; - if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) - continue; - start_point.map = mapindex->name2id(map); - if (!start_point.map) - ShowError("Specified start_point_pre '%s' not found in map-index cache.\n", map); - start_point.x = x; - start_point.y = y; - } - #endif - else if (strcmpi(w1, "start_items") == 0) { - int i; - char *split; + } - i = 0; - split = strtok(w2, ","); - while (split != NULL && i < MAX_START_ITEMS * 3) { - char *split2 = split; - split = strtok(NULL, ","); - start_items[i] = atoi(split2); + if ((setting2 = libconfig->setting_get_member(setting, "start_items"))) + chr->config_set_start_item(setting2); - if (start_items[i] < 0) - start_items[i] = 0; + // start_point / start_point_pre + if ((setting2 = libconfig->setting_get_member(setting, start_point_setting))) { + const char *str = NULL; + if (libconfig->setting_lookup_string(setting2, "map", &str) == CONFIG_TRUE) { + start_point.map = mapindex->name2id(str); + if (start_point.map == 0) + ShowError("char_config_read_player_new: Specified start_point %s not found in map-index cache.\n", str); + libconfig->setting_lookup_int16(setting2, "x", &start_point.x); + libconfig->setting_lookup_int16(setting2, "y", &start_point.y); + } + } - ++i; - } + return true; +} - // Format is: id1,quantity1,stackable1,idN,quantityN,stackableN - if( i%3 ) - { - ShowWarning("chr->config_read: There are not enough parameters in start_items, ignoring last item...\n"); - if( i%3 == 1 ) - start_items[i-1] = 0; - else - start_items[i-2] = 0; - } - } else if (strcmpi(w1, "start_zeny") == 0) { - start_zeny = atoi(w2); - if (start_zeny < 0) - start_zeny = 0; - } else if(strcmpi(w1,"log_char") == 0) { - chr->enable_logs = atoi(w2) ? true : false; - } else if (strcmpi(w1, "unknown_char_name") == 0) { - safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); - unknown_char_name[NAME_LENGTH-1] = '\0'; - } else if (strcmpi(w1, "name_ignoring_case") == 0) { - name_ignoring_case = (bool)config_switch(w2); - } else if (strcmpi(w1, "char_name_option") == 0) { - char_name_option = atoi(w2); - } else if (strcmpi(w1, "char_name_letters") == 0) { - safestrncpy(char_name_letters, w2, sizeof(char_name_letters)); - } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] - char_del_level = atoi(w2); - } else if (strcmpi(w1, "char_del_delay") == 0) { - char_del_delay = atoi(w2); - } else if (strcmpi(w1, "char_aegis_delete") == 0) { - char_aegis_delete = atoi(w2) ? true : false; - } else if(strcmpi(w1,"db_path")==0) { - safestrncpy(db_path, w2, sizeof(db_path)); - } else if (strcmpi(w1, "fame_list_alchemist") == 0) { - fame_list_size_chemist = atoi(w2); - if (fame_list_size_chemist > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); - fame_list_size_chemist = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { - fame_list_size_smith = atoi(w2); - if (fame_list_size_smith > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); - fame_list_size_smith = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_taekwon") == 0) { - fame_list_size_taekwon = atoi(w2); - if (fame_list_size_taekwon > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); - fame_list_size_taekwon = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "guild_exp_rate") == 0) { - guild_exp_rate = atoi(w2); - } else if (strcmpi(w1, "char_maintenance_min_group_id") == 0) { - char_maintenance_min_group_id = atoi(w2); - } else if (strcmpi(w1, "import") == 0) { - chr->config_read(w2); - } else - chr->config_dispatch(w1,w2); +/** + * Reads the 'char_configuration/permission' config entry and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool char_config_read_permission(const char *filename, const struct config_t *config, bool imported) +{ + const struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "char_configuration/permission")) == NULL) { + if (imported) + return true; + ShowError("char_config_read: char_configuration/permission was not found in %s!\n", filename); + return false; } - fclose(fp); - ShowInfo("Done reading %s.\n", cfgName); - return 0; + libconfig->setting_lookup_bool_real(setting, "enable_char_creation", &enable_char_creation); + libconfig->setting_lookup_int16(setting, "display_new", &chr->new_display); + libconfig->setting_lookup_int(setting, "max_connect_user", &max_connect_user); + libconfig->setting_lookup_int(setting, "gm_allow_group", &gm_allow_group); + libconfig->setting_lookup_int(setting, "maintenance_min_group_id", &char_maintenance_min_group_id); + if (libconfig->setting_lookup_int(setting, "server_type", &chr->server_type) == CONFIG_TRUE) { + if (chr->server_type < CST_NORMAL || chr->server_type >= CST_MAX) { + ShowWarning("char_config_read: Invalid permission/server_type %d, defaulting to CST_NORMAL.\n", chr->server_type); + chr->server_type = CST_NORMAL; + } + } + + return true; +} + +/** + * Loads an IP into 'out_ip' and shows status. + * + * @param type[in] String containing the type of IP being set (for logging purposes). + * @param value[in] New ip value to parse. + * @param out_ip[in] Pointer to numeric value that will be changed. + * @param out_ip_str[in,out] Pointer to str value that will be changed (expected to be already initialized, to display previous value, if any). + * + * @retval false in case of error. + */ +bool char_config_set_ip(const char *type, const char *value, uint32 *out_ip, char *out_ip_str) +{ + uint32 ip = 0; + + nullpo_retr(false, type); + nullpo_retr(false, value); + nullpo_retr(false, out_ip); + nullpo_retr(false, out_ip_str); + + if ((ip = sockt->host2ip(value)) == 0) + return false; + *out_ip = ip; + + ShowStatus("%s IP address : %s -> %s\n", type, out_ip_str[0] ? out_ip_str : "0.0.0.0", sockt->ip2str(ip, NULL)); + safestrncpy(out_ip_str, value, sizeof(out_ip_str)); + return true; } int do_final(void) { @@ -5680,6 +5985,8 @@ int do_final(void) { for (i = 0; i < MAX_MAP_SERVERS; i++) VECTOR_CLEAR(chr->server[i].maps); + VECTOR_CLEAR(start_items); + aFree(chr->CHAR_CONF_NAME); aFree(chr->NET_CONF_NAME); aFree(chr->SQL_CONF_NAME); @@ -5786,11 +6093,13 @@ int do_init(int argc, char **argv) { char_load_defaults(); - chr->CHAR_CONF_NAME = aStrdup("conf/char-server.conf"); + chr->CHAR_CONF_NAME = aStrdup("conf/char/char-server.conf"); chr->NET_CONF_NAME = aStrdup("conf/network.conf"); chr->SQL_CONF_NAME = aStrdup("conf/inter-server.conf"); chr->INTER_CONF_NAME = aStrdup("conf/inter-server.conf"); + VECTOR_INIT(start_items); + for (i = 0; i < MAX_MAP_SERVERS; i++) VECTOR_INIT(chr->server[i].maps); @@ -5808,16 +6117,31 @@ int do_init(int argc, char **argv) { start_point.map = mapindex->name2id("new_1-1"); #endif + safestrncpy(chr->userid, "s1", sizeof(chr->userid)); + safestrncpy(chr->passwd, "p1", sizeof(chr->passwd)); + cmdline->exec(argc, argv, CMDLINE_OPT_NORMAL); - chr->config_read(chr->CHAR_CONF_NAME); + chr->config_read(chr->CHAR_CONF_NAME, false); sockt->net_config_read(chr->NET_CONF_NAME); chr->sql_config_read(chr->SQL_CONF_NAME); + { + // TODO: Remove this when no longer needed. + struct stat fileinfo; + if (stat("conf/import/char_conf.txt", &fileinfo) == 0 && fileinfo.st_size > 0) { + ShowWarning("An old configuration file \"conf/import/char_conf.txt\" was found.\n"); + ShowWarning("If it contains settings you wish to keep, please merge them into \"conf/import/char-server_local.conf\".\n"); + ShowWarning("Otherwise, just delete it.\n"); + ShowInfo("Resuming in 10 seconds...\n"); + HSleep(10); + } + } + #ifndef BUILDBOT if (strcmp(chr->userid, "s1")==0 && strcmp(chr->passwd, "p1")==0) { ShowWarning("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); - ShowNotice("And then change the user/password to use in conf/char-server.conf (or conf/import/char_conf.txt)\n"); + ShowNotice("And then change the user/password to use in conf/char/char-server.conf (or conf/import/char-server.conf)\n"); } #endif @@ -6101,6 +6425,17 @@ void char_defaults(void) chr->online_data_cleanup_sub = char_online_data_cleanup_sub; chr->online_data_cleanup = char_online_data_cleanup; chr->sql_config_read = char_sql_config_read; - chr->config_dispatch = char_config_dispatch; chr->config_read = char_config_read; + chr->config_read_database = char_config_read_database; + chr->config_read_console = char_config_read_console; + chr->config_read_player_fame = char_config_read_player_fame; + chr->config_read_player_deletion = char_config_read_player_deletion; + chr->config_read_player_name = char_config_read_player_name; + chr->config_set_start_item = char_config_set_start_item; + chr->config_read_player_new = char_config_read_player_new; + chr->config_read_player = char_config_read_player; + chr->config_read_permission = char_config_read_permission; + chr->config_set_ip = char_config_set_ip; + chr->config_read_inter = char_config_read_inter; + chr->config_read_top = char_config_read_top; } |