diff --git a/CHANGELOG.md b/CHANGELOG.md index 65d47927c..bffdf30fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,10 +14,12 @@ - fixed `/kill` console command not fully killing enemies (#1482, regression from 3.0) - fixed `/tp` console command not always picking the closest item (#1486, regression from 4.1) - fixed `/tp` console command reporting teleport fails as success (#1484, regression from 4.1) +- fixed `/set` console command not sanitizing numeric values (#1515) - fixed console commands causing improper ring shutdown with selected inventory item (#1460, regression from 3.0) - fixed console input immediately ending demo (#1480, regression from 4.1) - fixed a potential softlock when killing the Torso boss in Great Pyramid (#1236) - fixed Bacon Lara re-spawning after saving and loading (#1500, regression from 0.7) +- fixed config JSON not sanitizing some numeric values (#1515) - changed `/tp` console command to look for the closest place to teleport to when targeting items (#1484) - changed the door cheat to also target drawbridges - improved appearance of textures around edges when bilinear filter is off (#1483) diff --git a/src/config.c b/src/config.c index fd1b0dc5d..55dc2b22e 100644 --- a/src/config.c +++ b/src/config.c @@ -1,6 +1,7 @@ #include "config.h" #include "config_map.h" +#include "game/clock.h" #include "game/input.h" #include "game/music.h" #include "game/requester.h" @@ -257,20 +258,7 @@ static void Config_Load(struct json_object_s *root_obj) Config_LoadLegacyOptions(root_obj); - CLAMP(g_Config.start_lara_hitpoints, 1, LARA_MAX_HITPOINTS); - CLAMP(g_Config.fov_value, 30, 255); - CLAMP(g_Config.camera_speed, 1, 10); - CLAMP(g_Config.music_volume, 0, 10); - CLAMP(g_Config.sound_volume, 0, 10); - CLAMP(g_Config.input.layout, 0, INPUT_LAYOUT_NUMBER_OF - 1); - CLAMP(g_Config.input.cntlr_layout, 0, INPUT_LAYOUT_NUMBER_OF - 1); - CLAMP(g_Config.brightness, MIN_BRIGHTNESS, MAX_BRIGHTNESS); - CLAMP(g_Config.ui.text_scale, MIN_TEXT_SCALE, MAX_TEXT_SCALE); - CLAMP(g_Config.ui.bar_scale, MIN_BAR_SCALE, MAX_BAR_SCALE); - - if (g_Config.rendering.fps != 30 && g_Config.rendering.fps != 60) { - g_Config.rendering.fps = 30; - } + Config_Sanitize(); } static void Config_Dump(struct json_object_s *root_obj) @@ -304,3 +292,26 @@ bool Config_Write(void) { return ConfigFile_Write(m_ConfigPath, &Config_Dump); } + +void Config_Sanitize(void) +{ + CLAMP(g_Config.start_lara_hitpoints, 1, LARA_MAX_HITPOINTS); + CLAMP(g_Config.fov_value, 30, 255); + CLAMP(g_Config.camera_speed, 1, 10); + CLAMP(g_Config.music_volume, 0, 10); + CLAMP(g_Config.sound_volume, 0, 10); + CLAMP(g_Config.input.layout, 0, INPUT_LAYOUT_NUMBER_OF - 1); + CLAMP(g_Config.input.cntlr_layout, 0, INPUT_LAYOUT_NUMBER_OF - 1); + CLAMP(g_Config.brightness, MIN_BRIGHTNESS, MAX_BRIGHTNESS); + CLAMP(g_Config.ui.text_scale, MIN_TEXT_SCALE, MAX_TEXT_SCALE); + CLAMP(g_Config.ui.bar_scale, MIN_BAR_SCALE, MAX_BAR_SCALE); + CLAMP( + g_Config.rendering.turbo_speed, CLOCK_TURBO_SPEED_MIN, + CLOCK_TURBO_SPEED_MAX); + CLAMPL(g_Config.rendering.anisotropy_filter, 1.0); + CLAMP(g_Config.rendering.wireframe_width, 1.0, 100.0); + + if (g_Config.rendering.fps != 30 && g_Config.rendering.fps != 60) { + g_Config.rendering.fps = 30; + } +} diff --git a/src/config.h b/src/config.h index 6252b9261..f53e7b898 100644 --- a/src/config.h +++ b/src/config.h @@ -141,3 +141,4 @@ extern CONFIG g_Config; bool Config_Read(void); bool Config_Write(void); +void Config_Sanitize(void); diff --git a/src/game/clock.c b/src/game/clock.c index e48c892e9..ad51882e6 100644 --- a/src/game/clock.c +++ b/src/game/clock.c @@ -13,9 +13,6 @@ #include #include -#define CLOCK_TURBO_SPEED_MIN -2 -#define CLOCK_TURBO_SPEED_MAX 2 - static double Clock_GetElapsedUnit(CLOCK_TIMER *const timer, const double unit); static bool Clock_CheckElapsedUnit( CLOCK_TIMER *const timer, const double how_often, const double unit, diff --git a/src/game/clock.h b/src/game/clock.h index 17b815a17..1609fb408 100644 --- a/src/game/clock.h +++ b/src/game/clock.h @@ -3,6 +3,9 @@ #include #include +#define CLOCK_TURBO_SPEED_MIN -2 +#define CLOCK_TURBO_SPEED_MAX 2 + typedef struct { double prev_counter; int32_t prev_fps; diff --git a/src/game/console_cmd.c b/src/game/console_cmd.c index 24f2f00bf..c55428703 100644 --- a/src/game/console_cmd.c +++ b/src/game/console_cmd.c @@ -34,6 +34,9 @@ static const char *Console_Cmd_Set_Resolve(const char *option_name); static bool Console_Cmd_Set_SameKey(const char *key1, const char *key2); +static bool Console_Cmd_GetCurrentValue( + const char *key, char *target, size_t target_size); +static bool Console_Cmd_SetCurrentValue(const char *key, const char *new_value); static bool Console_Cmd_IsFloatRound(const float num); static COMMAND_RESULT Console_Cmd_Fps(const char *const args); static COMMAND_RESULT Console_Cmd_Pos(const char *const args); @@ -357,6 +360,117 @@ static bool Console_Cmd_Set_SameKey(const char *key1, const char *key2) return true; } +static bool Console_Cmd_GetCurrentValue( + const char *const key, char *target, const size_t target_size) +{ + const CONFIG_OPTION *found_option = NULL; + for (const CONFIG_OPTION *option = g_ConfigOptionMap; option->name != NULL; + option++) { + if (!Console_Cmd_Set_SameKey(option->name, key)) { + continue; + } + found_option = option; + break; + } + + if (found_option == NULL) { + return false; + } + + assert(found_option->target != NULL); + switch (found_option->type) { + case COT_BOOL: + snprintf( + target, target_size, "%s", + *(bool *)found_option->target ? GS(MISC_ON) : GS(MISC_OFF)); + break; + case COT_INT32: + snprintf(target, target_size, "%d", *(int32_t *)found_option->target); + break; + case COT_FLOAT: + snprintf(target, target_size, "%.2f", *(float *)found_option->target); + break; + case COT_DOUBLE: + snprintf(target, target_size, "%.2f", *(double *)found_option->target); + break; + case COT_ENUM: + for (const ENUM_STRING_MAP *enum_map = found_option->param; + enum_map->text != NULL; enum_map++) { + if (enum_map->value == *(int32_t *)found_option->target) { + strncpy(target, enum_map->text, target_size); + } + } + break; + } + return true; +} + +static bool Console_Cmd_SetCurrentValue( + const char *const key, const char *const new_value) +{ + const CONFIG_OPTION *found_option = NULL; + + for (const CONFIG_OPTION *option = g_ConfigOptionMap; option->name != NULL; + option++) { + if (!Console_Cmd_Set_SameKey(option->name, key)) { + continue; + } + found_option = option; + break; + } + + switch (found_option->type) { + case COT_BOOL: + if (String_Match(new_value, "on|true|1")) { + *(bool *)found_option->target = true; + return true; + } else if (String_Match(new_value, "off|false|0")) { + *(bool *)found_option->target = false; + return true; + } + break; + + case COT_INT32: { + int32_t new_value_typed; + if (sscanf(new_value, "%d", &new_value_typed) == 1) { + *(int32_t *)found_option->target = new_value_typed; + return true; + } + break; + } + + case COT_FLOAT: { + float new_value_typed; + if (sscanf(new_value, "%f", &new_value_typed) == 1) { + *(float *)found_option->target = new_value_typed; + return true; + } + break; + } + + case COT_DOUBLE: { + double new_value_typed; + if (sscanf(new_value, "%lf", &new_value_typed) == 1) { + *(double *)found_option->target = new_value_typed; + return true; + } + break; + } + + case COT_ENUM: + for (const ENUM_STRING_MAP *enum_map = found_option->param; + enum_map->text != NULL; enum_map++) { + if (String_Equivalent(enum_map->text, new_value)) { + *(int32_t *)found_option->target = enum_map->value; + return true; + } + } + break; + } + + return false; +} + static COMMAND_RESULT Console_Cmd_Set(const char *const args) { COMMAND_RESULT result = CR_BAD_INVOCATION; @@ -370,111 +484,24 @@ static COMMAND_RESULT Console_Cmd_Set(const char *const args) } if (new_value != NULL) { - for (const CONFIG_OPTION *option = g_ConfigOptionMap; - option->name != NULL; option++) { - if (!Console_Cmd_Set_SameKey(option->name, key)) { - continue; - } - - switch (option->type) { - case COT_BOOL: - if (String_Match(new_value, "on|true|1")) { - *(bool *)option->target = true; - result = CR_SUCCESS; - } else if (String_Match(new_value, "off|false|0")) { - *(bool *)option->target = false; - result = CR_SUCCESS; - } - break; - - case COT_INT32: { - int32_t new_value_typed; - if (sscanf(new_value, "%d", &new_value_typed) == 1) { - *(int32_t *)option->target = new_value_typed; - result = CR_SUCCESS; - } - break; - } - - case COT_FLOAT: { - float new_value_typed; - if (sscanf(new_value, "%f", &new_value_typed) == 1) { - *(float *)option->target = new_value_typed; - result = CR_SUCCESS; - } - break; - } - - case COT_DOUBLE: { - double new_value_typed; - if (sscanf(new_value, "%lf", &new_value_typed) == 1) { - *(double *)option->target = new_value_typed; - result = CR_SUCCESS; - } - break; - } - - case COT_ENUM: - for (const ENUM_STRING_MAP *enum_map = option->param; - enum_map->text != NULL; enum_map++) { - if (String_Equivalent(enum_map->text, new_value)) { - *(int32_t *)option->target = enum_map->value; - result = CR_SUCCESS; - break; - } - } - break; - } - - if (result == CR_SUCCESS) { - Console_Log(GS(OSD_CONFIG_OPTION_SET), key, new_value); - Config_Write(); - } - break; + if (Console_Cmd_SetCurrentValue(key, new_value)) { + Config_Sanitize(); + Config_Write(); + Output_ApplyRenderSettings(); + + char final_value[128]; + assert(Console_Cmd_GetCurrentValue(key, final_value, 128)); + Console_Log(GS(OSD_CONFIG_OPTION_SET), key, final_value); + result = CR_SUCCESS; } } else { - for (const CONFIG_OPTION *option = g_ConfigOptionMap; - option->name != NULL; option++) { - if (!Console_Cmd_Set_SameKey(option->name, key)) { - continue; - } - - char cur_value[128] = ""; - assert(option->target != NULL); - switch (option->type) { - case COT_BOOL: - sprintf( - cur_value, "%s", - *(bool *)option->target ? GS(MISC_ON) : GS(MISC_OFF)); - break; - case COT_INT32: - sprintf(cur_value, "%d", *(int32_t *)option->target); - break; - case COT_FLOAT: - sprintf(cur_value, "%.2f", *(float *)option->target); - break; - case COT_DOUBLE: - sprintf(cur_value, "%.2f", *(double *)option->target); - break; - case COT_ENUM: - for (const ENUM_STRING_MAP *enum_map = option->param; - enum_map->text != NULL; enum_map++) { - if (enum_map->value == *(int32_t *)option->target) { - strcpy(cur_value, enum_map->text); - } - } - break; - } + char cur_value[128]; + if (Console_Cmd_GetCurrentValue(key, cur_value, 128)) { Console_Log(GS(OSD_CONFIG_OPTION_GET), key, cur_value); result = CR_SUCCESS; - break; } } - if (result == CR_SUCCESS) { - Output_ApplyRenderSettings(); - } - cleanup: Memory_FreePointer(&key); return result;