Skip to content

Commit

Permalink
console-cmd: sanitize /set
Browse files Browse the repository at this point in the history
Resolves #1515.
  • Loading branch information
rr- committed Sep 14, 2024
1 parent 44db3ca commit 30c2bc2
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 115 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
39 changes: 25 additions & 14 deletions src/config.c
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
}
1 change: 1 addition & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,4 @@ extern CONFIG g_Config;

bool Config_Read(void);
bool Config_Write(void);
void Config_Sanitize(void);
3 changes: 0 additions & 3 deletions src/game/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
#include <stdio.h>
#include <time.h>

#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,
Expand Down
3 changes: 3 additions & 0 deletions src/game/clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
#include <stdbool.h>
#include <stdint.h>

#define CLOCK_TURBO_SPEED_MIN -2
#define CLOCK_TURBO_SPEED_MAX 2

typedef struct {
double prev_counter;
int32_t prev_fps;
Expand Down
223 changes: 125 additions & 98 deletions src/game/console_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down

0 comments on commit 30c2bc2

Please sign in to comment.