Skip to content

Commit

Permalink
Support for new value formats (#305)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamiras authored Jan 4, 2024
1 parent 98efa19 commit 4e5a863
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 1 deletion.
9 changes: 8 additions & 1 deletion include/rc_runtime_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,14 @@ enum {
RC_FORMAT_FLOAT3,
RC_FORMAT_FLOAT4,
RC_FORMAT_FLOAT5,
RC_FORMAT_FLOAT6
RC_FORMAT_FLOAT6,
RC_FORMAT_FIXED1,
RC_FORMAT_FIXED2,
RC_FORMAT_FIXED3,
RC_FORMAT_TENS,
RC_FORMAT_HUNDREDS,
RC_FORMAT_THOUSANDS,
RC_FORMAT_UNSIGNED_VALUE
};

RC_EXPORT int RC_CCONV rc_parse_format(const char* format_str);
Expand Down
7 changes: 7 additions & 0 deletions src/rc_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1701,6 +1701,13 @@ uint8_t rc_client_map_leaderboard_format(int format)
case RC_FORMAT_FLOAT4:
case RC_FORMAT_FLOAT5:
case RC_FORMAT_FLOAT6:
case RC_FORMAT_FIXED1:
case RC_FORMAT_FIXED2:
case RC_FORMAT_FIXED3:
case RC_FORMAT_TENS:
case RC_FORMAT_HUNDREDS:
case RC_FORMAT_THOUSANDS:
case RC_FORMAT_UNSIGNED_VALUE:
default:
return RC_CLIENT_LEADERBOARD_FORMAT_VALUE;
}
Expand Down
74 changes: 74 additions & 0 deletions src/rcheevos/format.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ int rc_parse_format(const char* format_str) {
if (!strncmp(format_str, "LOAT", 4) && format_str[4] >= '1' && format_str[4] <= '6' && format_str[5] == '\0') {
return RC_FORMAT_FLOAT1 + (format_str[4] - '1');
}
if (!strncmp(format_str, "IXED", 4) && format_str[4] >= '1' && format_str[4] <= '3' && format_str[5] == '\0') {
return RC_FORMAT_FIXED1 + (format_str[4] - '1');
}

break;

Expand All @@ -24,6 +27,12 @@ int rc_parse_format(const char* format_str) {
if (!strcmp(format_str, "IMESECS")) {
return RC_FORMAT_SECONDS;
}
if (!strcmp(format_str, "HOUSANDS")) {
return RC_FORMAT_THOUSANDS;
}
if (!strcmp(format_str, "ENS")) {
return RC_FORMAT_TENS;
}

break;

Expand Down Expand Up @@ -64,11 +73,25 @@ int rc_parse_format(const char* format_str) {

break;

case 'U':
if (!strcmp(format_str, "NSIGNED")) {
return RC_FORMAT_UNSIGNED_VALUE;
}

break;

case 'O':
if (!strcmp(format_str, "THER")) {
return RC_FORMAT_SCORE;
}

break;

case 'H':
if (!strcmp(format_str, "UNDREDS")) {
return RC_FORMAT_HUNDREDS;
}

break;
}

Expand Down Expand Up @@ -119,6 +142,22 @@ static int rc_format_value_centiseconds(char* buffer, size_t size, uint32_t cent
return chars;
}

static int rc_format_value_fixed(char* buffer, size_t size, const char* format, int32_t value, int32_t factor)
{
if (value >= 0)
return snprintf(buffer, size, format, value / factor, value % factor);

return snprintf(buffer, size, format, value / factor, (-value) % factor);
}

static int rc_format_value_padded(char* buffer, size_t size, const char* format, int32_t value)
{
if (value == 0)
return snprintf(buffer, size, "0");

return snprintf(buffer, size, format, value);
}

int rc_format_typed_value(char* buffer, size_t size, const rc_typed_value_t* value, int format) {
int chars;
rc_typed_value_t converted_value;
Expand Down Expand Up @@ -192,6 +231,41 @@ int rc_format_typed_value(char* buffer, size_t size, const rc_typed_value_t* val
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_FLOAT);
chars = snprintf(buffer, size, "%.6f", converted_value.value.f32);
break;

case RC_FORMAT_FIXED1:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_SIGNED);
chars = rc_format_value_fixed(buffer, size, "%d.%u", converted_value.value.i32, 10);
break;

case RC_FORMAT_FIXED2:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_SIGNED);
chars = rc_format_value_fixed(buffer, size, "%d.%02u", converted_value.value.i32, 100);
break;

case RC_FORMAT_FIXED3:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_SIGNED);
chars = rc_format_value_fixed(buffer, size, "%d.%03u", converted_value.value.i32, 1000);
break;

case RC_FORMAT_TENS:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_SIGNED);
chars = rc_format_value_padded(buffer, size, "%d0", converted_value.value.i32);
break;

case RC_FORMAT_HUNDREDS:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_SIGNED);
chars = rc_format_value_padded(buffer, size, "%d00", converted_value.value.i32);
break;

case RC_FORMAT_THOUSANDS:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_SIGNED);
chars = rc_format_value_padded(buffer, size, "%d000", converted_value.value.i32);
break;

case RC_FORMAT_UNSIGNED_VALUE:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_UNSIGNED);
chars = snprintf(buffer, size, "%u", converted_value.value.u32);
break;
}

return chars;
Expand Down
4 changes: 4 additions & 0 deletions src/rcheevos/richpresence.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
{"Float4", 6, RC_FORMAT_FLOAT4},
{"Float5", 6, RC_FORMAT_FLOAT5},
{"Float6", 6, RC_FORMAT_FLOAT6},
{"Fixed1", 6, RC_FORMAT_FIXED1},
{"Fixed2", 6, RC_FORMAT_FIXED2},
{"Fixed3", 6, RC_FORMAT_FIXED3},
{"Unsigned", 8, RC_FORMAT_UNSIGNED_VALUE}
};
size_t i;

Expand Down
40 changes: 40 additions & 0 deletions test/rcheevos/test_format.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ void test_format(void) {
TEST_PARAMS3(test_format_value, RC_FORMAT_VALUE, 12345, "12345");
TEST_PARAMS3(test_format_value, RC_FORMAT_VALUE, -12345, "-12345");
TEST_PARAMS3(test_format_value, RC_FORMAT_VALUE, 0xFFFFFFFF, "-1");
TEST_PARAMS3(test_format_value, RC_FORMAT_UNSIGNED_VALUE, 0xFFFFFFFF, "4294967295");
TEST_PARAMS3(test_format_value, RC_FORMAT_SCORE, 12345, "012345");
TEST_PARAMS3(test_format_value, RC_FORMAT_SECONDS, 45, "0:45");
TEST_PARAMS3(test_format_value, RC_FORMAT_SECONDS, 345, "5:45");
Expand All @@ -38,6 +39,30 @@ void test_format(void) {
TEST_PARAMS3(test_format_value, RC_FORMAT_FRAMES, 345, "0:05.75");
TEST_PARAMS3(test_format_value, RC_FORMAT_FRAMES, 12345, "3:25.75");
TEST_PARAMS3(test_format_value, RC_FORMAT_FRAMES, 1234567, "5h42:56.11");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED1, 0, "0.0");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED1, 1, "0.1");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED1, 1234, "123.4");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED1, -1234, "-123.4");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED2, 0, "0.00");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED2, 1, "0.01");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED2, 1234, "12.34");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED2, -1234, "-12.34");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED3, 0, "0.000");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED3, 1, "0.001");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED3, 1234, "1.234");
TEST_PARAMS3(test_format_value, RC_FORMAT_FIXED3, -1234, "-1.234");
TEST_PARAMS3(test_format_value, RC_FORMAT_TENS, 0, "0");
TEST_PARAMS3(test_format_value, RC_FORMAT_TENS, 1, "10");
TEST_PARAMS3(test_format_value, RC_FORMAT_TENS, 1234, "12340");
TEST_PARAMS3(test_format_value, RC_FORMAT_TENS, -1234, "-12340");
TEST_PARAMS3(test_format_value, RC_FORMAT_HUNDREDS, 0, "0");
TEST_PARAMS3(test_format_value, RC_FORMAT_HUNDREDS, 1, "100");
TEST_PARAMS3(test_format_value, RC_FORMAT_HUNDREDS, 1234, "123400");
TEST_PARAMS3(test_format_value, RC_FORMAT_HUNDREDS, -1234, "-123400");
TEST_PARAMS3(test_format_value, RC_FORMAT_THOUSANDS, 0, "0");
TEST_PARAMS3(test_format_value, RC_FORMAT_THOUSANDS, 1, "1000");
TEST_PARAMS3(test_format_value, RC_FORMAT_THOUSANDS, 1234, "1234000");
TEST_PARAMS3(test_format_value, RC_FORMAT_THOUSANDS, -1234, "-1234000");

/* rc_parse_format */
TEST_PARAMS2(test_parse_format, "VALUE", RC_FORMAT_VALUE);
Expand All @@ -50,6 +75,10 @@ void test_format(void) {
TEST_PARAMS2(test_parse_format, "SCORE", RC_FORMAT_SCORE);
TEST_PARAMS2(test_parse_format, "POINTS", RC_FORMAT_SCORE);
TEST_PARAMS2(test_parse_format, "MILLISECS", RC_FORMAT_CENTISECS);
TEST_PARAMS2(test_parse_format, "TENS", RC_FORMAT_TENS);
TEST_PARAMS2(test_parse_format, "HUNDREDS", RC_FORMAT_HUNDREDS);
TEST_PARAMS2(test_parse_format, "THOUSANDS", RC_FORMAT_THOUSANDS);
TEST_PARAMS2(test_parse_format, "UNSIGNED", RC_FORMAT_UNSIGNED_VALUE);
TEST_PARAMS2(test_parse_format, "OTHER", RC_FORMAT_SCORE);
TEST_PARAMS2(test_parse_format, "INVALID", RC_FORMAT_VALUE);

Expand All @@ -64,5 +93,16 @@ void test_format(void) {
TEST_PARAMS2(test_parse_format, "FLOAT7", RC_FORMAT_VALUE);
TEST_PARAMS2(test_parse_format, "FLOAT10", RC_FORMAT_VALUE);

TEST_PARAMS2(test_parse_format, "FIXED", RC_FORMAT_VALUE);
TEST_PARAMS2(test_parse_format, "FIXED0", RC_FORMAT_VALUE);
TEST_PARAMS2(test_parse_format, "FIXED1", RC_FORMAT_FIXED1);
TEST_PARAMS2(test_parse_format, "FIXED2", RC_FORMAT_FIXED2);
TEST_PARAMS2(test_parse_format, "FIXED3", RC_FORMAT_FIXED3);
TEST_PARAMS2(test_parse_format, "FIXED4", RC_FORMAT_VALUE);
TEST_PARAMS2(test_parse_format, "FIXED5", RC_FORMAT_VALUE);
TEST_PARAMS2(test_parse_format, "FIXED6", RC_FORMAT_VALUE);
TEST_PARAMS2(test_parse_format, "FIXED7", RC_FORMAT_VALUE);
TEST_PARAMS2(test_parse_format, "FIXED10", RC_FORMAT_VALUE);

TEST_SUITE_END();
}
43 changes: 43 additions & 0 deletions test/rcheevos/test_richpresence.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,28 @@ static void test_macro_value_divide_by_self() {
assert_richpresence_output(richpresence, &memory, "Result is 0");
}

static void test_macro_hundreds() {
uint8_t ram[] = { 0x00, 0x12, 0x34, 0xAB, 0x56 };
memory_t memory;
rc_richpresence_t* richpresence;
char buffer[1024];

memory.ram = ram;
memory.size = sizeof(ram);

assert_parse_richpresence(&richpresence, buffer, "Format:Value\nFormatType=HUNDREDS\n\nDisplay:\nResult is @Value(0xH00)");
assert_richpresence_output(richpresence, &memory, "Result is 0");

ram[0] = 18;
assert_richpresence_output(richpresence, &memory, "Result is 1800");

ram[0] = 255;
assert_richpresence_output(richpresence, &memory, "Result is 25500");

ram[0] = 0;
assert_richpresence_output(richpresence, &memory, "Result is 0");
}

static void test_macro_frames() {
uint8_t ram[] = { 0x00, 0x12, 0x34, 0xAB, 0x56 };
memory_t memory;
Expand Down Expand Up @@ -1047,6 +1069,19 @@ static void test_builtin_macro_float(const char* macro, const char* expected) {
assert_richpresence_output(richpresence, &memory, expected);
}

static void test_builtin_macro_unsigned_large() {
uint8_t ram[] = { 0x85, 0xE2, 0x59, 0xC7 };
memory_t memory;
rc_richpresence_t* richpresence;
char buffer[256];

memory.ram = ram;
memory.size = sizeof(ram);

assert_parse_richpresence(&richpresence, buffer, "Display:\n@Unsigned(0xX0)");
assert_richpresence_output(richpresence, &memory, "3344556677");
}

static void test_builtin_macro_override() {
uint8_t ram[] = { 0x39, 0x30 };
memory_t memory;
Expand Down Expand Up @@ -1249,6 +1284,9 @@ void test_richpresence(void) {
TEST(test_macro_value_divide_by_zero);
TEST(test_macro_value_divide_by_self);

/* hundreds macro */
TEST(test_macro_hundreds);

/* frames macros */
TEST(test_macro_frames);

Expand Down Expand Up @@ -1312,6 +1350,11 @@ void test_richpresence(void) {
TEST_PARAMS2(test_builtin_macro_float, "Float4", "77.1339");
TEST_PARAMS2(test_builtin_macro_float, "Float5", "77.13393");
TEST_PARAMS2(test_builtin_macro_float, "Float6", "77.133926");
TEST_PARAMS2(test_builtin_macro, "Fixed1", "1234.5");
TEST_PARAMS2(test_builtin_macro, "Fixed2", "123.45");
TEST_PARAMS2(test_builtin_macro, "Fixed3", "12.345");
TEST_PARAMS2(test_builtin_macro, "Unsigned", "12345");
TEST(test_builtin_macro_unsigned_large);
TEST(test_builtin_macro_override);

/* asciichar */
Expand Down
27 changes: 27 additions & 0 deletions test/test_rc_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -5054,6 +5054,31 @@ static void test_fetch_leaderboard_entries_client_error(void)
rc_client_destroy(g_client);
}

static void test_map_leaderboard_format(void)
{
int i;

for (i = 0; i < 30; ++i) {
switch (i) {
case RC_FORMAT_SECONDS:
case RC_FORMAT_CENTISECS:
case RC_FORMAT_MINUTES:
case RC_FORMAT_SECONDS_AS_MINUTES:
case RC_FORMAT_FRAMES:
ASSERT_NUM_EQUALS(rc_client_map_leaderboard_format(i), RC_CLIENT_LEADERBOARD_FORMAT_TIME);
break;

case RC_FORMAT_SCORE:
ASSERT_NUM_EQUALS(rc_client_map_leaderboard_format(i), RC_CLIENT_LEADERBOARD_FORMAT_SCORE);
break;

default:
ASSERT_NUM_EQUALS(rc_client_map_leaderboard_format(i), RC_CLIENT_LEADERBOARD_FORMAT_VALUE);
break;
}
}
}

/* ----- do frame ----- */

static void test_do_frame_bounds_check_system(void)
Expand Down Expand Up @@ -8520,6 +8545,8 @@ void test_client(void) {
TEST(test_fetch_leaderboard_entries_async_aborted);
TEST(test_fetch_leaderboard_entries_client_error);

TEST(test_map_leaderboard_format);

/* do frame */
TEST(test_do_frame_bounds_check_system);
TEST(test_do_frame_bounds_check_available);
Expand Down

0 comments on commit 4e5a863

Please sign in to comment.