From 640532f1d0b42323333cabc029af91da6d982d42 Mon Sep 17 00:00:00 2001 From: Mosder Date: Thu, 16 Jul 2026 16:09:12 +0200 Subject: feat: added "prettier" printing of fight results. still need to better parse items, drifs and gear --- analyzer/render.h | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 analyzer/render.h (limited to 'analyzer/render.h') diff --git a/analyzer/render.h b/analyzer/render.h new file mode 100644 index 0000000..d54015a --- /dev/null +++ b/analyzer/render.h @@ -0,0 +1,60 @@ +// render.h +// functions for "rendering" data onto the terminal + +#include "parser/fight_results.h" + +// ANSI escape sequence colors +#define COLOR_RED 91 +#define COLOR_GREEN 92 +#define COLOR_WHITE 97 +#define COLOR_YELLOW 93 +#define COLOR_AQUA 96 +#define COLOR_BLUE 94 + +#define TABLE_ROW_SEPARATOR_CHAR '-' + +#define TABLE_LINE_START "| " +#define TABLE_LINE_END " |" +#define TABLE_LINE_SEPARATOR " | " +#define TABLE_LINE_START_WIDTH (sizeof(TABLE_LINE_START) - 1) +#define TABLE_LINE_END_WIDTH (sizeof(TABLE_LINE_END) - 1) +#define TABLE_LINE_SEPARATOR_WIDTH (sizeof(TABLE_LINE_SEPARATOR) - 1) + +#define TABLE_COLUMN_COUNT 6 + +#define TABLE_NAME_LVL_WIDTH 17 +#define TABLE_EXP_WIDTH 7 +#define TABLE_GOLD_WIDTH 7 +#define TABLE_PSYCHO_WIDTH 6 +#define TABLE_SATURATION_WIDTH 13 +#define TABLE_SPLINTERS_WIDTH 9 + +#define TABLE_COLUMN_NAMES {"Nick (LVL)", "EXP", "Gold", "Psycho", "Saturation", "Splinters"} +#define TABLE_COLUMN_COLORS {COLOR_WHITE, COLOR_WHITE, COLOR_YELLOW, COLOR_AQUA, COLOR_GREEN, COLOR_BLUE} +#define TABLE_COLUMN_WIDTHS { \ + TABLE_NAME_LVL_WIDTH, \ + TABLE_EXP_WIDTH, \ + TABLE_GOLD_WIDTH, \ + TABLE_PSYCHO_WIDTH, \ + TABLE_SATURATION_WIDTH, \ + TABLE_SPLINTERS_WIDTH \ +} + +#define TABLE_LINE_WIDTH ( \ + TABLE_LINE_START_WIDTH + \ + TABLE_NAME_LVL_WIDTH + \ + TABLE_EXP_WIDTH + \ + TABLE_GOLD_WIDTH + \ + TABLE_PSYCHO_WIDTH + \ + TABLE_SATURATION_WIDTH + \ + TABLE_SPLINTERS_WIDTH + \ + (TABLE_COLUMN_COUNT - 1) * TABLE_LINE_SEPARATOR_WIDTH + \ + TABLE_LINE_END_WIDTH \ +) + +#define TABLE_ITEMS_WIDTH (TABLE_LINE_WIDTH - TABLE_LINE_START_WIDTH - TABLE_LINE_END_WIDTH) + +// render fight results onto the terminal +// params: +// - results - fight results to render +extern void render_fight_results(FightResults results); -- cgit v1.2.3 From f73349115edbc75021885eefd33ee33ee504d9a7 Mon Sep 17 00:00:00 2001 From: Mosder Date: Mon, 20 Jul 2026 17:58:02 +0200 Subject: feat: added drif parsing and coloring of items depending on type --- analyzer/parser/fight_results.c | 144 ++++++++++++++++++++++++++-------------- analyzer/parser/fight_results.h | 91 +++++++++++++++++++++++-- analyzer/render.c | 23 ++++++- analyzer/render.h | 7 +- 4 files changed, 205 insertions(+), 60 deletions(-) (limited to 'analyzer/render.h') diff --git a/analyzer/parser/fight_results.c b/analyzer/parser/fight_results.c index 5cda649..f201fb1 100644 --- a/analyzer/parser/fight_results.c +++ b/analyzer/parser/fight_results.c @@ -14,7 +14,7 @@ void cleanup_fight_results(void *data) { FriendlyResults friendly = fight_results->friendly_results[i]; free(friendly.name); for (size_t j = 0; j < friendly.num_items; j++) - free(friendly.items[j]); + free(friendly.items[j].data); free(friendly.items); } for (size_t i = 0; i < fight_results->num_enemy; i++) { @@ -29,6 +29,47 @@ byte_t *find_fight_results(TCPStream *stream, int offset, int *length) { return start; } +// save to a field in struct depending on the type +void save_to_struct(TypeEnum type, void *field, char *src, size_t src_len) { + char *str = malloc(src_len + 1); + memcpy(str, src, src_len); + str[src_len] = '\0'; + + // parse depending on variable type + switch (type) { + case INT: + sscanf(str, "%d", (int *)field); + free(str); + break; + case FLOAT: + sscanf(str, "%f", (float *)field); + free(str); + break; + case DOUBLE: + sscanf(str, "%lf", (double *)field); + free(str); + break; + case STRING: + *(char **)field = str; + break; + } +} + +// fill struct fields from given data of given length +void get_struct_data(size_t field_count, TypeEnum *field_types, void **field_pointers, char *data_separator, char *data, size_t data_len) { + for (size_t i = 0; i < field_count; i++) { + char *sep = memmem(data, data_len, data_separator, strlen(data_separator)); + size_t len = sep ? sep - data : data_len; + save_to_struct(field_types[i], field_pointers[i], (char *)data, len); + + // update data pointer and length + if (sep) { + data_len -= sep - data + strlen(SEPARATOR_RESULT); + data = sep + strlen(SEPARATOR_RESULT); + } + } +} + void destroy_entity_results(EntityResults results) { free(results.name); free(results.field7); @@ -45,52 +86,14 @@ EntityResults get_entity_results(byte_t *data, size_t length) { EntityResults results; TypeEnum field_types[ENTITY_FIELD_COUNT] = ENTITY_FIELD_TYPES; void *field_pointers[ENTITY_FIELD_COUNT] = ENTITY_FIELD_ADDRESSES(results); - - for (size_t i = 0; i < ENTITY_FIELD_COUNT; i++) { - // get string buffer of given result - byte_t *result_separator = memmem(data, length, SEPARATOR_RESULT, strlen(SEPARATOR_RESULT)); - size_t len = result_separator ? result_separator - data : length; - char *str = malloc(len + 1); - memcpy(str, data, len); - str[len] = '\0'; - - // parse depending on variable type - switch (field_types[i]) { - case INT: - sscanf(str, "%d", (int *)field_pointers[i]); - free(str); - break; - case FLOAT: - sscanf(str, "%f", (float *)field_pointers[i]); - free(str); - break; - case DOUBLE: - sscanf(str, "%lf", (double *)field_pointers[i]); - free(str); - break; - case STRING: - *(char **)field_pointers[i] = str; - break; - } - - // update data pointer and length - if (result_separator) { - length -= result_separator - data + strlen(SEPARATOR_RESULT); - data = result_separator + strlen(SEPARATOR_RESULT); - } - } - + get_struct_data(ENTITY_FIELD_COUNT, field_types, field_pointers, SEPARATOR_RESULT, (char *)data, length); return results; } -char *get_item_name(int item_id) { - return item_id < id_to_item_name_len ? id_to_item_name[item_id] : "null"; -} - -char **expand_items(char **items, size_t *items_capacity, size_t to_fit) { +Item *expand_items(Item *items, size_t *items_capacity, size_t to_fit) { while (*items_capacity < to_fit) *items_capacity <<= 1; - return realloc(items, *items_capacity * sizeof(char *)); + return realloc(items, *items_capacity * sizeof(Item)); } void add_gear(FriendlyResults *results, size_t *items_capacity, char *gear_str) { @@ -101,18 +104,58 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gear_str) if (results->num_items >= *items_capacity) results->items = expand_items(results->items, items_capacity, results->num_items + 1); - results->items[results->num_items++] = strdup(gear_str); + Item item; + item.data = strdup(gear_str); + item.type = RARE; + results->items[results->num_items++] = item; +} + +void destroy_drif(Drif drif) { + free(drif.field1); + free(drif.field4); + free(drif.field11); + free(drif.field12); + free(drif.name); + free(drif.field18); + free(drif.field19); +} + +Drif get_drif(char *data, size_t length) { + Drif drif; + TypeEnum field_types[DRIF_FIELD_COUNT] = DRIF_FIELD_TYPES; + void *field_pointers[DRIF_FIELD_COUNT] = DRIF_FIELD_ADDRESSES(drif); + get_struct_data(DRIF_FIELD_COUNT, field_types, field_pointers, SEPARATOR_DRIF_INFO, data, length); + return drif; } void add_drifs(FriendlyResults *results, size_t *items_capacity, char *drifs_str) { if (strlen(drifs_str) == 0) return; - // TODO: parse - if (results->num_items >= *items_capacity) - results->items = expand_items(results->items, items_capacity, results->num_items + 1); + char *drifs_separator; + do { + drifs_separator = strstr(drifs_str, SEPARATOR_DRIFS); + Drif drif = get_drif(drifs_str, drifs_separator ? drifs_separator - drifs_str : strlen(drifs_str)); - results->items[results->num_items++] = strdup(drifs_str); + // if there are still drifs - modify drifs_str pointer + if (drifs_separator) + drifs_str = drifs_separator + strlen(SEPARATOR_DRIFS); + + // expand if needed + if (results->num_items >= *items_capacity) + results->items = expand_items(results->items, items_capacity, results->num_items + 1); + + Item item; + item.data = strdup(drif.name); + item.type = DRIF; + results->items[results->num_items++] = item; + + destroy_drif(drif); + } while (drifs_separator); +} + +char *get_item_name(int item_id) { + return item_id < id_to_item_name_len ? id_to_item_name[item_id] : "null"; } void add_items(FriendlyResults *results, size_t *items_capacity, char *items_str) { @@ -136,7 +179,10 @@ void add_items(FriendlyResults *results, size_t *items_capacity, char *items_str if (results->num_items >= *items_capacity) results->items = expand_items(results->items, items_capacity, results->num_items + 1); - results->items[results->num_items++] = strdup(buffer); + Item item; + item.data = strdup(buffer); + item.type = NORMAL; + results->items[results->num_items++] = item; } while (items_separator); } @@ -157,7 +203,7 @@ FriendlyResults parse_to_friendly(EntityResults entity_results) { // create items array and add to it gear, drifs and items results.num_items = 0; - results.items = malloc(INIT_ITEMS_CAPACITY * sizeof(char *)); + results.items = malloc(INIT_ITEMS_CAPACITY * sizeof(Item)); size_t items_cap = INIT_ITEMS_CAPACITY; add_gear(&results, &items_cap, entity_results.gear); add_drifs(&results, &items_cap, entity_results.drifs); diff --git a/analyzer/parser/fight_results.h b/analyzer/parser/fight_results.h index 3aadf09..76083ab 100644 --- a/analyzer/parser/fight_results.h +++ b/analyzer/parser/fight_results.h @@ -9,17 +9,16 @@ // Payload structure: // FIGHT_RESULTS_START EntityResults (SEPARATOR_ENTITY EntityResults)* FIGHT_RESULTS_END -// -// EntityResults structure: -// field (SEPARATOR_RESULT field)* -// fields are defined in order in the EntityResults struct - #define FIGHT_RESULTS_START "3;19;" #define FIGHT_RESULTS_END "[--];" #define SEPARATOR_ENTITY "[--]" #define SEPARATOR_RESULT "&" +// EntityResults structure: +// field (SEPARATOR_RESULT field)* +// fields are defined in order in the EntityResults struct #define ENTITY_FIELD_COUNT 35 +// clang-format off #define ENTITY_FIELD_TYPES { \ /* team */ INT, \ /* name */ STRING, \ @@ -94,7 +93,7 @@ &entity_results.field34, \ &entity_results.saturation \ } - +// clang-format on typedef struct { int team; // friend or enemy char *name; @@ -137,6 +136,84 @@ typedef struct { #define INIT_ITEMS_CAPACITY 8 #define SINGLE_ITEM_BUFFER_LEN 128 #define SEPARATOR_ITEMS "[-]" +#define SEPARATOR_DRIFS "???" // TODO: change it to correct one which idk at this moment +#define SEPARATOR_DRIF_INFO "," +// Item struct - for keeping item string and type +typedef enum { NORMAL, DRIF, SYNG, SET, RARE, EPIC } ItemType; +typedef struct { + char *data; + ItemType type; +} Item; + +// Drif structure: +// field (SEPARATOR_DRIF field)* +// fields are defined in order in the Drif struct +#define DRIF_FIELD_COUNT 19 +// clang-format off +#define DRIF_FIELD_TYPES { \ + /* field1 */ STRING, \ + /* field2 */ INT, \ + /* field3 */ INT, \ + /* field4 */ STRING, \ + /* field5 */ INT, \ + /* field6 */ INT, \ + /* field7 */ FLOAT, \ + /* field8 */ FLOAT, \ + /* field9 */ INT, \ + /* field10 */ INT, \ + /* field11 */ STRING, \ + /* field12 */ STRING, \ + /* field13 */ INT, \ + /* field14 */ INT, \ + /* field15 */ INT, \ + /* field16 */ INT, \ + /* name */ STRING, \ + /* field18 */ STRING, \ + /* field19 */ STRING, \ +} +#define DRIF_FIELD_ADDRESSES(drif) {\ + &drif.field1, \ + &drif.field2, \ + &drif.field3, \ + &drif.field4, \ + &drif.field5, \ + &drif.field6, \ + &drif.field7, \ + &drif.field8, \ + &drif.field9, \ + &drif.field10, \ + &drif.field11, \ + &drif.field12, \ + &drif.field13, \ + &drif.field14, \ + &drif.field15, \ + &drif.field16, \ + &drif.name, \ + &drif.field18, \ + &drif.field19, \ +} +// clang-format on +typedef struct { + char *field1; + int field2; + int field3; + char *field4; + int field5; + int field6; + float field7; + float field8; + int field9; + int field10; + char *field11; + char *field12; + int field13; + int field14; + int field15; + int field16; + char *name; // drif + char *field18; + char *field19; +} Drif; // values of field "team" #define TEAM_FRIEND 1 @@ -147,7 +224,7 @@ typedef struct { char *name; int exp; int gold; - char **items; + Item *items; size_t num_items; int level; int psycho; diff --git a/analyzer/render.c b/analyzer/render.c index 402fcb5..28d1673 100644 --- a/analyzer/render.c +++ b/analyzer/render.c @@ -75,6 +75,24 @@ void print_column_names() { printf("\n"); } +int item_type_to_color(ItemType type) { + switch (type) { + case NORMAL: + return COLOR_WHITE; + case DRIF: + return COLOR_YELLOW; + case SYNG: + return COLOR_RED; + case SET: + return COLOR_GREEN; + case RARE: + return COLOR_AQUA; + case EPIC: + return COLOR_PURPLE; + } + return COLOR_WHITE; +} + void print_player_rewards(FriendlyResults results) { char buffers[TABLE_COLUMN_COUNT][TABLE_LINE_WIDTH]; size_t widths[TABLE_COLUMN_COUNT] = TABLE_COLUMN_WIDTHS; @@ -116,12 +134,13 @@ void print_player_rewards(FriendlyResults results) { size_t line_len = 0; for (size_t i = 0; i < results.num_items; i++) { char *sep = i < results.num_items - 1 ? ", " : ""; - size_t item_len = utf8_strlen(results.items[i]) + strlen(sep); + size_t item_len = utf8_strlen(results.items[i].data) + strlen(sep); if (line_len + item_len > TABLE_ITEMS_WIDTH) { printf("%*s" TABLE_LINE_END "\n" TABLE_LINE_START, (int)(TABLE_ITEMS_WIDTH - line_len), ""); line_len = 0; } - printf("%s%s", results.items[i], sep); + print_color(results.items[i].data, item_type_to_color(results.items[i].type)); + printf("%s", sep); line_len += item_len; } printf("%*s" TABLE_LINE_END "\n", (int)(TABLE_ITEMS_WIDTH - line_len), ""); diff --git a/analyzer/render.h b/analyzer/render.h index d54015a..97958d1 100644 --- a/analyzer/render.h +++ b/analyzer/render.h @@ -6,10 +6,11 @@ // ANSI escape sequence colors #define COLOR_RED 91 #define COLOR_GREEN 92 -#define COLOR_WHITE 97 #define COLOR_YELLOW 93 -#define COLOR_AQUA 96 #define COLOR_BLUE 94 +#define COLOR_PURPLE 95 +#define COLOR_AQUA 96 +#define COLOR_WHITE 97 #define TABLE_ROW_SEPARATOR_CHAR '-' @@ -29,6 +30,7 @@ #define TABLE_SATURATION_WIDTH 13 #define TABLE_SPLINTERS_WIDTH 9 +// clang-format off #define TABLE_COLUMN_NAMES {"Nick (LVL)", "EXP", "Gold", "Psycho", "Saturation", "Splinters"} #define TABLE_COLUMN_COLORS {COLOR_WHITE, COLOR_WHITE, COLOR_YELLOW, COLOR_AQUA, COLOR_GREEN, COLOR_BLUE} #define TABLE_COLUMN_WIDTHS { \ @@ -51,6 +53,7 @@ (TABLE_COLUMN_COUNT - 1) * TABLE_LINE_SEPARATOR_WIDTH + \ TABLE_LINE_END_WIDTH \ ) +// clang-format on #define TABLE_ITEMS_WIDTH (TABLE_LINE_WIDTH - TABLE_LINE_START_WIDTH - TABLE_LINE_END_WIDTH) -- cgit v1.2.3 From 5c0e713713143bad475a92d20ee5fe215b5bafd3 Mon Sep 17 00:00:00 2001 From: Mosder Date: Tue, 21 Jul 2026 17:26:09 +0200 Subject: feat: added parsing for gear --- Makefile | 1 + analyzer/parser/fight_results.c | 169 +++++++++++++++--- analyzer/parser/fight_results.h | 375 ++++++++++++++++++++++++++++++---------- analyzer/render.c | 2 + analyzer/render.h | 24 +-- analyzer/utils/roman.c | 16 ++ analyzer/utils/roman.h | 12 ++ csv/artifact_sizes.csv | 5 + csv/orbs.csv | 3 + 9 files changed, 482 insertions(+), 125 deletions(-) create mode 100644 analyzer/utils/roman.c create mode 100644 analyzer/utils/roman.h create mode 100644 csv/artifact_sizes.csv create mode 100644 csv/orbs.csv (limited to 'analyzer/render.h') diff --git a/Makefile b/Makefile index afb61fd..72f94e0 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ utils: $(CC) $(CFLAGS) -c analyzer/utils/time.c $(CC) $(CFLAGS) -c analyzer/utils/tcp.c $(CC) $(CFLAGS) -c analyzer/utils/tcp_seq_math.c + $(CC) $(CFLAGS) -c analyzer/utils/roman.c parser: $(CC) $(CFLAGS) -c analyzer/parser/parser.c diff --git a/analyzer/parser/fight_results.c b/analyzer/parser/fight_results.c index f201fb1..c1d6420 100644 --- a/analyzer/parser/fight_results.c +++ b/analyzer/parser/fight_results.c @@ -4,8 +4,11 @@ #include #include +#include "csv/id_to_artifact_size.h" #include "csv/id_to_item_name.h" +#include "csv/id_to_orb_name.h" #include "csv/id_to_saturation_type.h" +#include "utils/roman.h" // function to cleanup fight results to be used in ParsedData struct void cleanup_fight_results(void *data) { @@ -70,15 +73,18 @@ void get_struct_data(size_t field_count, TypeEnum *field_types, void **field_poi } } +// free struct fields which are STRING +void destroy_struct(size_t field_count, TypeEnum *field_types, void **field_pointers) { + for (size_t i = 0; i < field_count; i++) { + if (field_types[i] == STRING) + free(*(char **)field_pointers[i]); + } +} + void destroy_entity_results(EntityResults results) { - free(results.name); - free(results.field7); - free(results.gear); - free(results.items); - free(results.drifs); - free(results.field29); - free(results.field34); - free(results.saturation); + TypeEnum field_types[ENTITY_FIELD_COUNT] = ENTITY_FIELD_TYPES; + void *field_pointers[ENTITY_FIELD_COUNT] = ENTITY_FIELD_ADDRESSES(results); + destroy_struct(ENTITY_FIELD_COUNT, field_types, field_pointers); } // get entity results from the string @@ -96,35 +102,148 @@ Item *expand_items(Item *items, size_t *items_capacity, size_t to_fit) { return realloc(items, *items_capacity * sizeof(Item)); } -void add_gear(FriendlyResults *results, size_t *items_capacity, char *gear_str) { - if (strlen(gear_str) == 0) +void destroy_gear(Gear gear) { + TypeEnum field_types[GEAR_FIELD_COUNT] = GEAR_FIELD_TYPES; + void *field_pointers[GEAR_FIELD_COUNT] = GEAR_FIELD_ADDRESSES(gear); + destroy_struct(GEAR_FIELD_COUNT, field_types, field_pointers); +} + +Gear get_gear(char *data, size_t length) { + Gear gear; + TypeEnum field_types[GEAR_FIELD_COUNT] = GEAR_FIELD_TYPES; + void *field_pointers[GEAR_FIELD_COUNT] = GEAR_FIELD_ADDRESSES(gear); + get_struct_data(GEAR_FIELD_COUNT, field_types, field_pointers, SEPARATOR_GEAR_FIELDS, data, length); + return gear; +} + +void destroy_gear_info(GearInfo gear_info) { + TypeEnum field_types[GEAR_INFO_FIELD_COUNT] = GEAR_INFO_FIELD_TYPES; + void *field_pointers[GEAR_INFO_FIELD_COUNT] = GEAR_INFO_FIELD_ADDRESSES(gear_info); + destroy_struct(GEAR_INFO_FIELD_COUNT, field_types, field_pointers); +} + +GearInfo get_gear_info(char *data, size_t length) { + GearInfo gear_info; + TypeEnum field_types[GEAR_INFO_FIELD_COUNT] = GEAR_INFO_FIELD_TYPES; + void *field_pointers[GEAR_INFO_FIELD_COUNT] = GEAR_INFO_FIELD_ADDRESSES(gear_info); + get_struct_data(GEAR_INFO_FIELD_COUNT, field_types, field_pointers, SEPARATOR_GEAR_INFO_FIELDS, data, length); + return gear_info; +} + +void destroy_orb(Orb orb) { + TypeEnum field_types[ORB_FIELD_COUNT] = ORB_FIELD_TYPES; + void *field_pointers[ORB_FIELD_COUNT] = ORB_FIELD_ADDRESSES(orb); + destroy_struct(ORB_FIELD_COUNT, field_types, field_pointers); +} + +Orb get_orb(char *data, size_t length) { + Orb orb; + TypeEnum field_types[ORB_FIELD_COUNT] = ORB_FIELD_TYPES; + void *field_pointers[ORB_FIELD_COUNT] = ORB_FIELD_ADDRESSES(orb); + get_struct_data(ORB_FIELD_COUNT, field_types, field_pointers, SEPARATOR_ORB_FIELDS, data, length); + return orb; +} + +char *get_artifact_size(int artifact_size_id) { + return artifact_size_id < id_to_artifact_size_len ? id_to_artifact_size[artifact_size_id] : "null"; +} + +char *get_orb_name(int orb_name_id) { + return orb_name_id < id_to_orb_name_len ? id_to_orb_name[orb_name_id] : "null"; +} + +void get_stars(char *buffer, int incr_above_b1) { + char star_types[] = {'B', 'S', 'G'}; + buffer[0] = star_types[incr_above_b1 / 3]; + buffer[1] = incr_above_b1 % 3 + 1 + '0'; + buffer[2] = '\0'; +} + +void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) { + if (strlen(gears_str) == 0) return; - // TODO: parse - if (results->num_items >= *items_capacity) - results->items = expand_items(results->items, items_capacity, results->num_items + 1); + char *gears_separator; + do { + gears_separator = strstr(gears_str, SEPARATOR_GEARS); + Gear gear = get_gear(gears_str, gears_separator ? gears_separator - gears_str : strlen(gears_str)); + + // if there are still gears - modify gears_str pointer + if (gears_separator) + gears_str = gears_separator + strlen(SEPARATOR_DRIFS); + + // expand if needed + if (results->num_items >= *items_capacity) + results->items = expand_items(results->items, items_capacity, results->num_items + 1); + + Item item; + + GearInfo gear_info = get_gear_info(gear.info, strlen(gear.info)); + char buffer[SINGLE_ITEM_BUFFER_LEN]; + char roman[5]; + to_roman(roman, gear_info.rank); + sprintf(buffer, "[%s] %s", roman, gear_info.name); + switch (gear.type) { + case TYPE_SYNG_NORMAL: + // atoi should be fine, since syng_tier starts from 1 for syngs + if (atoi(gear.syng_tier)) + sprintf(buffer, "%s (%d)", buffer, gear_info.lvl); + break; + default: { + char stars[3]; + get_stars(stars, gear_info.stars); + sprintf(buffer, "%s (%s)", buffer, stars); + break; + } + } + item.data = strdup(buffer); + destroy_gear_info(gear_info); - Item item; - item.data = strdup(gear_str); - item.type = RARE; - results->items[results->num_items++] = item; + switch (gear.type) { + case TYPE_SYNG_NORMAL: + // atoi should be fine, since syng_tier starts from 1 for syngs + item.type = atoi(gear.syng_tier) ? SYNG : NORMAL; + break; + case TYPE_SET: + item.type = SET; + break; + case TYPE_RARE: + item.type = RARE; + break; + default: + item.type = EPIC; + break; + } + + results->items[results->num_items++] = item; + + // add orb to items if it exists + if (strlen(gear.orb)) { + Item item; + char buffer[SINGLE_ITEM_BUFFER_LEN]; + Orb orb = get_orb(gear.orb, strlen(gear.orb)); + sprintf(buffer, "%sorb %s", get_artifact_size(orb.size), get_orb_name(orb.id)); + item.data = strdup(buffer); + destroy_orb(orb); + item.type = ORB; + results->items[results->num_items++] = item; + } + + destroy_gear(gear); + } while (gears_separator); } void destroy_drif(Drif drif) { - free(drif.field1); - free(drif.field4); - free(drif.field11); - free(drif.field12); - free(drif.name); - free(drif.field18); - free(drif.field19); + TypeEnum field_types[DRIF_FIELD_COUNT] = DRIF_FIELD_TYPES; + void *field_pointers[DRIF_FIELD_COUNT] = DRIF_FIELD_ADDRESSES(drif); + destroy_struct(DRIF_FIELD_COUNT, field_types, field_pointers); } Drif get_drif(char *data, size_t length) { Drif drif; TypeEnum field_types[DRIF_FIELD_COUNT] = DRIF_FIELD_TYPES; void *field_pointers[DRIF_FIELD_COUNT] = DRIF_FIELD_ADDRESSES(drif); - get_struct_data(DRIF_FIELD_COUNT, field_types, field_pointers, SEPARATOR_DRIF_INFO, data, length); + get_struct_data(DRIF_FIELD_COUNT, field_types, field_pointers, SEPARATOR_DRIF_FIELDS, data, length); return drif; } diff --git a/analyzer/parser/fight_results.h b/analyzer/parser/fight_results.h index 76083ab..59d1e45 100644 --- a/analyzer/parser/fight_results.h +++ b/analyzer/parser/fight_results.h @@ -14,6 +14,10 @@ #define SEPARATOR_ENTITY "[--]" #define SEPARATOR_RESULT "&" +// values of field "team" in EntityResults +#define TEAM_FRIEND 1 +#define TEAM_ENEMY 2 + // EntityResults structure: // field (SEPARATOR_RESULT field)* // fields are defined in order in the EntityResults struct @@ -54,44 +58,44 @@ /* field32 */ INT, \ /* field33 */ INT, \ /* field34 */ STRING, \ - /* saturation */ STRING \ + /* saturation */ STRING, \ } #define ENTITY_FIELD_ADDRESSES(entity_results) {\ - &entity_results.team, \ - &entity_results.name, \ - &entity_results.exp, \ - &entity_results.field4, \ - &entity_results.gold, \ - &entity_results.field6, \ - &entity_results.field7, \ - &entity_results.gear, \ - &entity_results.field9, \ - &entity_results.items, \ - &entity_results.field11, \ - &entity_results.field12, \ - &entity_results.field13, \ - &entity_results.field14, \ - &entity_results.field15, \ - &entity_results.level, \ - &entity_results.field17, \ - &entity_results.field18, \ - &entity_results.field19, \ - &entity_results.field20, \ - &entity_results.field21, \ - &entity_results.field22, \ - &entity_results.field23, \ - &entity_results.field24, \ - &entity_results.psycho, \ - &entity_results.drifs, \ - &entity_results.splinters, \ - &entity_results.field28, \ - &entity_results.field29, \ - &entity_results.field30, \ - &entity_results.field31, \ - &entity_results.field32, \ - &entity_results.field33, \ - &entity_results.field34, \ - &entity_results.saturation \ + &entity_results.team, \ + &entity_results.name, \ + &entity_results.exp, \ + &entity_results.field4, \ + &entity_results.gold, \ + &entity_results.field6, \ + &entity_results.field7, \ + &entity_results.gear, \ + &entity_results.field9, \ + &entity_results.items, \ + &entity_results.field11, \ + &entity_results.field12, \ + &entity_results.field13, \ + &entity_results.field14, \ + &entity_results.field15, \ + &entity_results.level, \ + &entity_results.field17, \ + &entity_results.field18, \ + &entity_results.field19, \ + &entity_results.field20, \ + &entity_results.field21, \ + &entity_results.field22, \ + &entity_results.field23, \ + &entity_results.field24, \ + &entity_results.psycho, \ + &entity_results.drifs, \ + &entity_results.splinters, \ + &entity_results.field28, \ + &entity_results.field29, \ + &entity_results.field30, \ + &entity_results.field31, \ + &entity_results.field32, \ + &entity_results.field33, \ + &entity_results.field34, \ + &entity_results.saturation, \ } // clang-format on typedef struct { @@ -137,87 +141,280 @@ typedef struct { #define SINGLE_ITEM_BUFFER_LEN 128 #define SEPARATOR_ITEMS "[-]" #define SEPARATOR_DRIFS "???" // TODO: change it to correct one which idk at this moment -#define SEPARATOR_DRIF_INFO "," +#define SEPARATOR_GEARS "???" // TODO: change it to correct one which idk at this moment // Item struct - for keeping item string and type -typedef enum { NORMAL, DRIF, SYNG, SET, RARE, EPIC } ItemType; +typedef enum { NORMAL, DRIF, ORB, SYNG, SET, RARE, EPIC } ItemType; typedef struct { char *data; ItemType type; } Item; // Drif structure: -// field (SEPARATOR_DRIF field)* +// field (SEPARATOR_DRIF_FIELDS field)* // fields are defined in order in the Drif struct -#define DRIF_FIELD_COUNT 19 +#define DRIF_FIELD_COUNT 18 +#define SEPARATOR_DRIF_FIELDS "," // clang-format off #define DRIF_FIELD_TYPES { \ - /* field1 */ STRING, \ - /* field2 */ INT, \ - /* field3 */ INT, \ - /* field4 */ STRING, \ - /* field5 */ INT, \ - /* field6 */ INT, \ - /* field7 */ FLOAT, \ - /* field8 */ FLOAT, \ - /* field9 */ INT, \ - /* field10 */ INT, \ - /* field11 */ STRING, \ - /* field12 */ STRING, \ - /* field13 */ INT, \ - /* field14 */ INT, \ - /* field15 */ INT, \ - /* field16 */ INT, \ - /* name */ STRING, \ - /* field18 */ STRING, \ - /* field19 */ STRING, \ + /* field1 */ STRING, \ + /* field2 */ INT, \ + /* size */ INT, \ + /* field4 */ STRING, \ + /* field5 */ INT, \ + /* id */ INT, \ + /* value1 */ FLOAT, \ + /* value2 */ FLOAT, \ + /* field9 */ INT, \ + /* field10 */ INT, \ + /* field11 */ STRING, \ + /* size_str */ STRING, \ + /* field13 */ INT, \ + /* power */ INT, \ + /* field15 */ INT, \ + /* field16 */ INT, \ + /* name */ STRING, \ + /* field18 */ STRING, \ } #define DRIF_FIELD_ADDRESSES(drif) {\ - &drif.field1, \ - &drif.field2, \ - &drif.field3, \ - &drif.field4, \ - &drif.field5, \ - &drif.field6, \ - &drif.field7, \ - &drif.field8, \ - &drif.field9, \ - &drif.field10, \ - &drif.field11, \ - &drif.field12, \ - &drif.field13, \ - &drif.field14, \ - &drif.field15, \ - &drif.field16, \ - &drif.name, \ - &drif.field18, \ - &drif.field19, \ + &drif.field1, \ + &drif.field2, \ + &drif.size, \ + &drif.field4, \ + &drif.field5, \ + &drif.id, \ + &drif.value1, \ + &drif.value2, \ + &drif.field9, \ + &drif.field10, \ + &drif.field11, \ + &drif.size_str, \ + &drif.field13, \ + &drif.power, \ + &drif.field15, \ + &drif.field16, \ + &drif.name, \ + &drif.field18, \ } // clang-format on typedef struct { - char *field1; + char *field1; // just says "drif" int field2; - int field3; + int size; // 1 - sub, 2 - bi, 3 - magni, 4 - arcy char *field4; int field5; - int field6; - float field7; - float field8; + int id; // id of orb type + float value1; // value1, value2 (in %) - one is start value, the other is value per lvl (both are the same) + float value2; // value1, value2 (in %) - one is start value, the other is value per lvl (both are the same) int field9; int field10; char *field11; - char *field12; + char *size_str; // sub - small, medium - bi, big - magni, ??? - arcy int field13; - int field14; + int power; // how much space it takes int field15; int field16; char *name; // drif char *field18; - char *field19; } Drif; -// values of field "team" -#define TEAM_FRIEND 1 -#define TEAM_ENEMY 2 +// Gear structure: +// field (SEPARATOR_GEAR_FIELDS field)* +// fields are defined in order in the Gear struct +#define GEAR_FIELD_COUNT 19 +#define SEPARATOR_GEAR_FIELDS "$" +// values of field "type" in Gear +#define TYPE_SYNG_NORMAL 0 +#define TYPE_SET 1 +#define TYPE_RARE 2 +// clang-format off +#define GEAR_FIELD_TYPES { \ + /* stats */ STRING, \ + /* resistances */ STRING, \ + /* info */ STRING, \ + /* reqs */ STRING, \ + /* field5 */ STRING, \ + /* psycho */ STRING, \ + /* field7 */ STRING, \ + /* field8 */ STRING, \ + /* field9 */ STRING, \ + /* syng_tier */ STRING, \ + /* field11 */ INT, \ + /* field12 */ INT, \ + /* field13 */ INT, \ + /* field14 */ STRING, \ + /* type */ INT, \ + /* field16 */ INT, \ + /* orb */ STRING, \ + /* field18 */ STRING, \ + /* field19 */ STRING, \ +} +#define GEAR_FIELD_ADDRESSES(gear) {\ + &gear.stats, \ + &gear.resistances, \ + &gear.info, \ + &gear.reqs, \ + &gear.field5, \ + &gear.psycho, \ + &gear.field7, \ + &gear.field8, \ + &gear.field9, \ + &gear.syng_tier, \ + &gear.field11, \ + &gear.field12, \ + &gear.field13, \ + &gear.field14, \ + &gear.type, \ + &gear.field16, \ + &gear.orb, \ + &gear.field18, \ + &gear.field19, \ +} +// clang-format on +typedef struct { + char *stats; // strength, dexterity, power, knowledge, hp, mana, stamina + char *resistances; // slashing, crushing, piercing, fire, cold, energy, mental + char *info; // GearInfo struct data + char *reqs; // requirements (str, dex, pow, know), weight, something else + char *field5; + char *psycho; // psycho effects (id,%) for syngs + char *field7; + char *field8; + char *field9; + char *syng_tier; // lvl 20 - 1, lvl 30 - 2, etc..., null for non-syngs + int field11; + int field12; + int field13; + char *field14; + int type; // 0 - normal item or syng, 1 - set, 2 - rare + int field16; // 10 for rare, -1 for others ??? + char *orb; // orb info + char *field18; + char *field19; +} Gear; + +// GearInfo structure: +// field (SEPARATOR_GEAR_INFO_FIELDS field)* +// fields are defined in order in the GearInfo struct +#define GEAR_INFO_FIELD_COUNT 23 +#define SEPARATOR_GEAR_INFO_FIELDS "," +// clang-format off +#define GEAR_INFO_FIELD_TYPES { \ + /* name */ STRING, \ + /* field2 */ INT, \ + /* lvl */ INT, \ + /* price */ INT, \ + /* field5 */ INT, \ + /* field6 */ INT, \ + /* field7 */ INT, \ + /* rank */ INT, \ + /* field9 */ INT, \ + /* field10 */ INT, \ + /* field11 */ INT, \ + /* durability */ INT, \ + /* field13 */ STRING, \ + /* field14 */ INT, \ + /* field15 */ INT, \ + /* charges */ FLOAT, \ + /* field17 */ STRING, \ + /* field18 */ INT, \ + /* stars */ INT, \ + /* field20 */ INT, \ + /* field21 */ INT, \ + /* field22 */ INT, \ + /* field23 */ INT, \ +} +#define GEAR_INFO_FIELD_ADDRESSES(gear_info) {\ + &gear_info.name, \ + &gear_info.field2, \ + &gear_info.lvl, \ + &gear_info.price, \ + &gear_info.field5, \ + &gear_info.field6, \ + &gear_info.field7, \ + &gear_info.rank, \ + &gear_info.field9, \ + &gear_info.field10, \ + &gear_info.field11, \ + &gear_info.durability, \ + &gear_info.field13, \ + &gear_info.field14, \ + &gear_info.field15, \ + &gear_info.charges, \ + &gear_info.field17, \ + &gear_info.field18, \ + &gear_info.stars, \ + &gear_info.field20, \ + &gear_info.field21, \ + &gear_info.field22, \ + &gear_info.field23, \ +} +// clang-format on +typedef struct { + char *name; // item name + int field2; + int lvl; // level requirement + int price; // gold price value + int field5; + int field6; + int field7; + int rank; // I-XII + int field9; + int field10; + int field11; + int durability; // in % + char *field13; + int field14; + int field15; + float charges; // charge count + char *field17; + int field18; + int stars; // incrustation level: 0 - b1, 1 - b2, ... (-100 for syngs) + int field20; + int field21; + int field22; + int field23; +} GearInfo; + +// Orb structure: +// field (SEPARATOR_ORB_FIELDS field)* +// fields are defined in order in the Orb struct +#define ORB_FIELD_COUNT 9 +#define SEPARATOR_ORB_FIELDS "," +// clang-format off +#define ORB_FIELD_TYPES { \ + /* field1 */ STRING, \ + /* field2 */ INT, \ + /* field3 */ INT, \ + /* field4 */ STRING, \ + /* field5 */ INT, \ + /* id */ INT, \ + /* size */ INT, \ + /* value */ FLOAT, \ + /* field9 */ STRING, \ +} +#define ORB_FIELD_ADDRESSES(orb) {\ + &orb.field1, \ + &orb.field2, \ + &orb.field3, \ + &orb.field4, \ + &orb.field5, \ + &orb.id, \ + &orb.size, \ + &orb.value, \ + &orb.field9, \ +} +// clang-format on +typedef struct { + char *field1; // just says "orb" + int field2; + int field3; + char *field4; + int field5; + int id; // id of orb type + int size; // 1 - sub, 2 - bi, 3 - magni, 4 - arcy + float value; // value in % you gain from the orb + char *field9; +} Orb; // fight results data for friendly typedef struct { diff --git a/analyzer/render.c b/analyzer/render.c index 28d1673..0fdd334 100644 --- a/analyzer/render.c +++ b/analyzer/render.c @@ -81,6 +81,8 @@ int item_type_to_color(ItemType type) { return COLOR_WHITE; case DRIF: return COLOR_YELLOW; + case ORB: + return COLOR_GOLD; case SYNG: return COLOR_RED; case SET: diff --git a/analyzer/render.h b/analyzer/render.h index 97958d1..843cea5 100644 --- a/analyzer/render.h +++ b/analyzer/render.h @@ -4,6 +4,8 @@ #include "parser/fight_results.h" // ANSI escape sequence colors +#define COLOR_GOLD 33 +#define COLOR_GRAY 90 #define COLOR_RED 91 #define COLOR_GREEN 92 #define COLOR_YELLOW 93 @@ -34,24 +36,24 @@ #define TABLE_COLUMN_NAMES {"Nick (LVL)", "EXP", "Gold", "Psycho", "Saturation", "Splinters"} #define TABLE_COLUMN_COLORS {COLOR_WHITE, COLOR_WHITE, COLOR_YELLOW, COLOR_AQUA, COLOR_GREEN, COLOR_BLUE} #define TABLE_COLUMN_WIDTHS { \ - TABLE_NAME_LVL_WIDTH, \ - TABLE_EXP_WIDTH, \ - TABLE_GOLD_WIDTH, \ - TABLE_PSYCHO_WIDTH, \ + TABLE_NAME_LVL_WIDTH, \ + TABLE_EXP_WIDTH, \ + TABLE_GOLD_WIDTH, \ + TABLE_PSYCHO_WIDTH, \ TABLE_SATURATION_WIDTH, \ - TABLE_SPLINTERS_WIDTH \ + TABLE_SPLINTERS_WIDTH, \ } #define TABLE_LINE_WIDTH ( \ TABLE_LINE_START_WIDTH + \ - TABLE_NAME_LVL_WIDTH + \ - TABLE_EXP_WIDTH + \ - TABLE_GOLD_WIDTH + \ - TABLE_PSYCHO_WIDTH + \ + TABLE_NAME_LVL_WIDTH + \ + TABLE_EXP_WIDTH + \ + TABLE_GOLD_WIDTH + \ + TABLE_PSYCHO_WIDTH + \ TABLE_SATURATION_WIDTH + \ - TABLE_SPLINTERS_WIDTH + \ + TABLE_SPLINTERS_WIDTH + \ (TABLE_COLUMN_COUNT - 1) * TABLE_LINE_SEPARATOR_WIDTH + \ - TABLE_LINE_END_WIDTH \ + TABLE_LINE_END_WIDTH \ ) // clang-format on diff --git a/analyzer/utils/roman.c b/analyzer/utils/roman.c new file mode 100644 index 0000000..9ea2bbb --- /dev/null +++ b/analyzer/utils/roman.c @@ -0,0 +1,16 @@ +#include "utils/roman.h" + +#include +#include + +void to_roman(char *buffer, int number) { + buffer[0] = '\0'; + int nums[ROMAN_CHAR_COUNT] = ROMAN_NUMS; + char *chars[ROMAN_CHAR_COUNT] = ROMAN_CHARS; + for (size_t i = 0; i < ROMAN_CHAR_COUNT; i++) { + for (size_t j = 0; j < number / nums[i]; j++) { + strcat(buffer, chars[i]); + } + number %= nums[i]; + } +} diff --git a/analyzer/utils/roman.h b/analyzer/utils/roman.h new file mode 100644 index 0000000..b4f5d3f --- /dev/null +++ b/analyzer/utils/roman.h @@ -0,0 +1,12 @@ +// utils/roman.h +// functions for roman numbers + +#define ROMAN_CHAR_COUNT 13 +#define ROMAN_NUMS {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1} +#define ROMAN_CHARS {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"} + +// convert a arabic number to roman number +// params: +// buffer - buffer to save the roman number to +// number - arabic number to convert +extern void to_roman(char *buffer, int number); diff --git a/csv/artifact_sizes.csv b/csv/artifact_sizes.csv new file mode 100644 index 0000000..a9af916 --- /dev/null +++ b/csv/artifact_sizes.csv @@ -0,0 +1,5 @@ +id,artifact_size +1,Sub +2,Bi +3,Magni +4,Arcy diff --git a/csv/orbs.csv b/csv/orbs.csv new file mode 100644 index 0000000..02dfde4 --- /dev/null +++ b/csv/orbs.csv @@ -0,0 +1,3 @@ +id,orb_name +21,Ha'at +12,Se'at -- cgit v1.2.3 From 1f664d5b6396fb24c8ce4990ba8882118abb8dcd Mon Sep 17 00:00:00 2001 From: Mosder Date: Tue, 21 Jul 2026 22:48:20 +0200 Subject: refactor: improved csv table generations --- Makefile | 5 +- analyzer/parser/fight_results/fight_results.c | 24 +----- analyzer/parser/fight_results/fight_results.h | 2 +- analyzer/render.h | 2 +- csv_to_headers.c | 104 ++++++++++++++++++-------- 5 files changed, 82 insertions(+), 55 deletions(-) (limited to 'analyzer/render.h') diff --git a/Makefile b/Makefile index 72f94e0..f45b9e6 100644 --- a/Makefile +++ b/Makefile @@ -15,9 +15,10 @@ compile: csv structures utils parser capture analyzer render rm *.o csv: - $(CC) csv_to_headers.c -o csv_to_headers + $(CC) $(CFLAGS) csv_to_headers.c -o csv_to_headers ./csv_to_headers rm csv_to_headers + $(CC) $(CFLAGS) -c analyzer/csv/*.c structures: $(CC) $(CFLAGS) -c analyzer/structures/hashmap.c @@ -32,7 +33,7 @@ utils: parser: $(CC) $(CFLAGS) -c analyzer/parser/parser.c - $(CC) $(CFLAGS) -c analyzer/parser/fight_results.c + $(CC) $(CFLAGS) -c analyzer/parser/fight_results/fight_results.c capture: $(CC) $(CFLAGS) -c analyzer/capture.c diff --git a/analyzer/parser/fight_results/fight_results.c b/analyzer/parser/fight_results/fight_results.c index a994674..4f0f3a1 100644 --- a/analyzer/parser/fight_results/fight_results.c +++ b/analyzer/parser/fight_results/fight_results.c @@ -1,4 +1,4 @@ -#include "parser/fight_results.h" +#include "parser/fight_results/fight_results.h" #include #include @@ -146,14 +146,6 @@ Orb get_orb(char *data, size_t length) { return orb; } -char *get_artifact_size(int artifact_size_id) { - return artifact_size_id < id_to_artifact_size_len ? id_to_artifact_size[artifact_size_id] : "null"; -} - -char *get_orb_name(int orb_name_id) { - return orb_name_id < id_to_orb_name_len ? id_to_orb_name[orb_name_id] : "null"; -} - void get_stars(char *buffer, int incr_above_b1) { char star_types[] = {'B', 'S', 'G'}; sprintf(buffer, " (%c%d)", star_types[incr_above_b1 / 3], incr_above_b1 % 3 + '1'); @@ -221,7 +213,7 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) Item item; char buffer[SINGLE_ITEM_BUFFER_LEN]; Orb orb = get_orb(gear.orb, strlen(gear.orb)); - sprintf(buffer, "%sorb %s", get_artifact_size(orb.size), get_orb_name(orb.id)); + sprintf(buffer, "%sorb %s", get_artifact_size_from_id(orb.size), get_orb_name_from_id(orb.id)); item.data = strdup(buffer); destroy_orb(orb); item.type = ORB; @@ -275,10 +267,6 @@ void add_drifs(FriendlyResults *results, size_t *items_capacity, char *drifs_str } while (drifs_separator); } -char *get_item_name(int item_id) { - return item_id < id_to_item_name_len ? id_to_item_name[item_id] : "null"; -} - void add_items(FriendlyResults *results, size_t *items_capacity, char *items_str) { if (strlen(items_str) == 0) return; @@ -290,7 +278,7 @@ void add_items(FriendlyResults *results, size_t *items_capacity, char *items_str int item_id, item_count; sscanf(items_str, "%d,%d", &item_id, &item_count); - sprintf(buffer, "%dx %s", item_count, get_item_name(item_id)); + sprintf(buffer, "%dx %s", item_count, get_item_name_from_id(item_id)); // if there are still items - modify items_str pointer if (items_separator) @@ -307,10 +295,6 @@ void add_items(FriendlyResults *results, size_t *items_capacity, char *items_str } while (items_separator); } -char *get_saturation_type(int saturation_id) { - return saturation_id < id_to_saturation_type_len ? id_to_saturation_type[saturation_id] : "null"; -} - // parse EntityResults to FriendlyResults FriendlyResults parse_to_friendly(EntityResults entity_results) { FriendlyResults results; @@ -334,7 +318,7 @@ FriendlyResults parse_to_friendly(EntityResults entity_results) { if (strlen(entity_results.saturation) > 0) { int saturation_id; sscanf(entity_results.saturation, "%d,%d", &saturation_id, &results.saturation); - results.saturation_type = get_saturation_type(saturation_id); + results.saturation_type = get_saturation_type_from_id(saturation_id); } return results; diff --git a/analyzer/parser/fight_results/fight_results.h b/analyzer/parser/fight_results/fight_results.h index 59d1e45..0618bf2 100644 --- a/analyzer/parser/fight_results/fight_results.h +++ b/analyzer/parser/fight_results/fight_results.h @@ -426,7 +426,7 @@ typedef struct { int level; int psycho; int splinters; - char *saturation_type; + const char *saturation_type; int saturation; } FriendlyResults; diff --git a/analyzer/render.h b/analyzer/render.h index 843cea5..1015eb9 100644 --- a/analyzer/render.h +++ b/analyzer/render.h @@ -1,7 +1,7 @@ // render.h // functions for "rendering" data onto the terminal -#include "parser/fight_results.h" +#include "parser/fight_results/fight_results.h" // ANSI escape sequence colors #define COLOR_GOLD 33 diff --git a/csv_to_headers.c b/csv_to_headers.c index 5595713..51a1c58 100644 --- a/csv_to_headers.c +++ b/csv_to_headers.c @@ -6,74 +6,116 @@ #define EXT ".csv" #define EXT_LEN strlen(".csv") #define CSV_PATH "csv" -#define HEADER_PATH "analyzer/" CSV_PATH +#define OUT_PATH "analyzer/" CSV_PATH #define BUFFER_SIZE 256 #define MAX_ARR_SIZE 4096 -void create_header(char *file_name) { - // open input file - char input_path[BUFFER_SIZE]; - sprintf(input_path, "%s/%s", CSV_PATH, file_name); - FILE *input_fp = fopen(input_path, "r"); +// read values from input csv and save them to buffers +// returns max_index of the array +int read_csv(char *path, char *from, char *to, char from_to_array[][BUFFER_SIZE]) { + FILE *fp = fopen(path, "r"); // read field names - char from[BUFFER_SIZE], to[BUFFER_SIZE]; - fscanf(input_fp, "%[^,],%[^\n]", from, to); + fscanf(fp, "%[^,],%[^\n]", from, to); - // read values from CSV - char from_to_array[MAX_ARR_SIZE][BUFFER_SIZE] = {""}; + // read values size_t max_index = 0; size_t val1; char val2[BUFFER_SIZE]; - while (fscanf(input_fp, "%zu,%[^\n]", &val1, val2) == 2) { + while (fscanf(fp, "%zu,%[^\n]", &val1, val2) == 2) { strcpy(from_to_array[val1], val2); if (val1 > max_index) max_index = val1; } - // close the input file - fclose(input_fp); + fclose(fp); + + return max_index; +} + +// create output .h file +void create_h(char *path, char *from, char *to) { + FILE *fp = fopen(path, "w"); + + // write comments and function prototype + fprintf(fp, "// %s\n", strstr(path, CSV_PATH)); + fprintf(fp, "// translate %s to %s - generated from csv\n\n", from, to); + fprintf(fp, "// get %s from %s\n", to, from); + fprintf(fp, "// params:\n"); + fprintf(fp, "// - %s - %s to translate from\n", from, from); + fprintf(fp, "// returns:\n"); + fprintf(fp, "// %s corresponding to %s\n", to, from); + fprintf(fp, "extern const char *get_%s_from_%s(int %s);", to, from, from); + + fclose(fp); +} + +// create output .c file +void create_c(char *path, char *h_path, char *from, char *to, char from_to_array[][BUFFER_SIZE], size_t max_index) { + FILE *fp = fopen(path, "w"); - // create output file - char output_path[BUFFER_SIZE]; - sprintf(output_path, "%s/%s_to_%s.h", HEADER_PATH, from, to); - FILE *output_fp = fopen(output_path, "w"); + char arr_name[BUFFER_SIZE], arr_len_name[BUFFER_SIZE]; + sprintf(arr_name, "%s_to_%s", from, to); + sprintf(arr_len_name, "%s_to_%s_len", from, to); - // write comments and beginning of output array - fprintf(output_fp, "// %s\n", input_path); - fprintf(output_fp, "// array translating %s to %s - generated from csv file\n\n", from, to); - fprintf(output_fp, "char *%s_to_%s[] = {\n", from, to); + // write include and beginning of array + fprintf(fp, "#include \"%s\"\n\n", strstr(h_path, CSV_PATH)); + fprintf(fp, "static const char *%s[] = {\n", arr_name); // write values for (size_t i = 0; i <= max_index; i++) { if (strlen(from_to_array[i]) > 0) - fprintf(output_fp, " \"%s\",\n", from_to_array[i]); + fprintf(fp, " \"%s\",\n", from_to_array[i]); else - fprintf(output_fp, " \"%zu\",\n", i); + fprintf(fp, " \"%zu\",\n", i); } // write the end of array and len - fprintf(output_fp, "};\n"); - fprintf(output_fp, "int %s_to_%s_len = %zu;", from, to, max_index + 1); + fprintf(fp, "};\n"); + fprintf(fp, "int %s = %zu;\n\n", arr_len_name, max_index + 1); - // close the output file - fclose(output_fp); + // write the getter + fprintf(fp, "const char *get_%s_from_%s(int %s) {\n", to, from, from); + fprintf(fp, " return %s >= 0 && %s < %s ? %s[%s] : \"null\";\n", from, from, arr_len_name, arr_name, from); + fprintf(fp, "}"); + + fclose(fp); +} + +void create_table(char *file_name) { + // read from input file + char input_path[BUFFER_SIZE]; + sprintf(input_path, "%s/%s", CSV_PATH, file_name); + char from[BUFFER_SIZE], to[BUFFER_SIZE]; + char from_to_array[MAX_ARR_SIZE][BUFFER_SIZE] = {0}; + size_t max_index = read_csv(input_path, from, to, from_to_array); + + // create output .h file + char h_path[BUFFER_SIZE]; + sprintf(h_path, "%s/%s_to_%s.h", OUT_PATH, from, to); + create_h(h_path, from, to); + + // create output .c file + char c_path[BUFFER_SIZE]; + sprintf(c_path, "%s/%s_to_%s.c", OUT_PATH, from, to); + create_c(c_path, h_path, from, to, from_to_array, max_index); } int main() { - // make directory for csv header files - mkdir(HEADER_PATH, 0755); + // make directory for output files + mkdir(OUT_PATH, 0755); DIR *csv_dir = opendir(CSV_PATH); struct dirent *entry; while ((entry = readdir(csv_dir))) { char *file_name = entry->d_name; size_t file_name_len = strlen(file_name); - // create header for each *.csv file + // create lookup tables for each *.csv file if (file_name_len > EXT_LEN && strcmp(file_name + file_name_len - EXT_LEN, EXT) == 0) - create_header(entry->d_name); + create_table(entry->d_name); } closedir(csv_dir); + return 0; } -- cgit v1.2.3 From 5d463a7f4c721629a1996be6d19634338290a539 Mon Sep 17 00:00:00 2001 From: Mosder Date: Wed, 22 Jul 2026 01:16:45 +0200 Subject: refactor: generalized parser structs with offsetof and put them into separate files --- Makefile | 1 + analyzer/parser/fight_results/drif.h | 52 ++++ analyzer/parser/fight_results/entity.h | 67 +++++ analyzer/parser/fight_results/fight_results.c | 177 +++--------- analyzer/parser/fight_results/fight_results.h | 396 +------------------------- analyzer/parser/fight_results/gear.h | 45 +++ analyzer/parser/fight_results/gear_info.h | 44 +++ analyzer/parser/fight_results/orb.h | 33 +++ analyzer/parser/find_parse_functions.h | 6 +- analyzer/parser/parser.c | 3 +- analyzer/parser/parser_defs.h | 2 - analyzer/parser/structs.c | 49 ++++ analyzer/parser/structs.h | 33 +++ analyzer/render.c | 24 +- analyzer/render.h | 53 ++-- analyzer/utils/memory.h | 4 + analyzer/utils/roman.c | 13 +- analyzer/utils/roman.h | 23 +- 18 files changed, 429 insertions(+), 596 deletions(-) create mode 100644 analyzer/parser/fight_results/drif.h create mode 100644 analyzer/parser/fight_results/entity.h create mode 100644 analyzer/parser/fight_results/gear.h create mode 100644 analyzer/parser/fight_results/gear_info.h create mode 100644 analyzer/parser/fight_results/orb.h create mode 100644 analyzer/parser/structs.c create mode 100644 analyzer/parser/structs.h create mode 100644 analyzer/utils/memory.h (limited to 'analyzer/render.h') diff --git a/Makefile b/Makefile index f45b9e6..31c1275 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,7 @@ utils: parser: $(CC) $(CFLAGS) -c analyzer/parser/parser.c + $(CC) $(CFLAGS) -c analyzer/parser/structs.c $(CC) $(CFLAGS) -c analyzer/parser/fight_results/fight_results.c capture: diff --git a/analyzer/parser/fight_results/drif.h b/analyzer/parser/fight_results/drif.h new file mode 100644 index 0000000..1f8b3e2 --- /dev/null +++ b/analyzer/parser/fight_results/drif.h @@ -0,0 +1,52 @@ +// parser/fight_results/drif.h +// Drif generic struct data + +#include "parser/structs.h" + +// Drif structure: +// field (SEPARATOR_DRIF_FIELD field)* +// fields are defined in order in the Drif struct +#define SEPARATOR_DRIF "???" // TODO: change it to correct one which idk at this moment +#define SEPARATOR_DRIF_FIELD "," + +typedef struct { + char *field1; // just says "drif" + int field2; + int size; // 1 - sub, 2 - bi, 3 - magni, 4 - arcy + char *field4; + int field5; + int id; // id of orb type + float value1; // value1, value2 (in %) - one is start value, the other is value per lvl (both are the same) + float value2; // value1, value2 (in %) - one is start value, the other is value per lvl (both are the same) + int field9; + int field10; + char *field11; + char *size_str; // sub - small, medium - bi, big - magni, ??? - arcy + int field13; + int power; // how much space it takes + int field15; + int field16; + char *name; // drif + char *field18; +} Drif; + +static const StructField drif_fields[] = { + {STRING, offsetof(Drif, field1)}, + {INT, offsetof(Drif, field2)}, + {INT, offsetof(Drif, size)}, + {STRING, offsetof(Drif, field4)}, + {INT, offsetof(Drif, field5)}, + {INT, offsetof(Drif, id)}, + {FLOAT, offsetof(Drif, value1)}, + {FLOAT, offsetof(Drif, value2)}, + {INT, offsetof(Drif, field9)}, + {INT, offsetof(Drif, field10)}, + {STRING, offsetof(Drif, field11)}, + {STRING, offsetof(Drif, size_str)}, + {INT, offsetof(Drif, field13)}, + {INT, offsetof(Drif, power)}, + {INT, offsetof(Drif, field15)}, + {INT, offsetof(Drif, field16)}, + {STRING, offsetof(Drif, name)}, + {STRING, offsetof(Drif, field18)}, +}; diff --git a/analyzer/parser/fight_results/entity.h b/analyzer/parser/fight_results/entity.h new file mode 100644 index 0000000..8e082ec --- /dev/null +++ b/analyzer/parser/fight_results/entity.h @@ -0,0 +1,67 @@ +// parser/fight_results/entity.h +// EntityResults generic struct data + +#include "parser/structs.h" + +// EntityResults structure: +// field (SEPARATOR_ENTITY_FIELD field)* +// fields are defined in order in the EntityResults struct +#define SEPARATOR_ENTITY "[--]" +#define SEPARATOR_ENTITY_FIELD "&" + +// values of field "team" in EntityResults +#define TEAM_FRIEND 1 +#define TEAM_ENEMY 2 + +typedef struct { + int team; // friend or enemy + char *name; + int exp; + float field4; + int gold; + float field6; + char *field7; + char *gear; // rares, sets, syngs, orbs + int field9; + char *items; // regular items + int field11; + int field12; + float field13; + float field14; // some multiplier most likely exp/gold/psycho/something else idk + float field15; + int level; + double field17; + float field18; + int field19; + int field20; + float field21; + float field22; + int field23; + int field24; + int psycho; + char *drifs; + int splinters; + int field28; + char *field29; + int field30; + int field31; + int field32; + int field33; + char *field34; + char *saturation; +} EntityResults; + +static const StructField entity_fields[] = { + {INT, offsetof(EntityResults, team)}, {STRING, offsetof(EntityResults, name)}, {INT, offsetof(EntityResults, exp)}, + {FLOAT, offsetof(EntityResults, field4)}, {INT, offsetof(EntityResults, gold)}, {FLOAT, offsetof(EntityResults, field6)}, + {STRING, offsetof(EntityResults, field7)}, {STRING, offsetof(EntityResults, gear)}, {INT, offsetof(EntityResults, field9)}, + {STRING, offsetof(EntityResults, items)}, {INT, offsetof(EntityResults, field11)}, {INT, offsetof(EntityResults, field12)}, + {FLOAT, offsetof(EntityResults, field13)}, {FLOAT, offsetof(EntityResults, field14)}, {FLOAT, offsetof(EntityResults, field15)}, + {INT, offsetof(EntityResults, level)}, {DOUBLE, offsetof(EntityResults, field17)}, {FLOAT, offsetof(EntityResults, field18)}, + {INT, offsetof(EntityResults, field19)}, {INT, offsetof(EntityResults, field20)}, {FLOAT, offsetof(EntityResults, field21)}, + {FLOAT, offsetof(EntityResults, field22)}, {INT, offsetof(EntityResults, field23)}, {INT, offsetof(EntityResults, field24)}, + {INT, offsetof(EntityResults, psycho)}, {STRING, offsetof(EntityResults, drifs)}, {INT, offsetof(EntityResults, splinters)}, + {INT, offsetof(EntityResults, field28)}, {STRING, offsetof(EntityResults, field29)}, {INT, offsetof(EntityResults, field30)}, + {INT, offsetof(EntityResults, field31)}, {INT, offsetof(EntityResults, field32)}, {INT, offsetof(EntityResults, field33)}, + {STRING, offsetof(EntityResults, field34)}, {STRING, offsetof(EntityResults, saturation)}, +}; diff --git a/analyzer/parser/fight_results/fight_results.c b/analyzer/parser/fight_results/fight_results.c index 4f0f3a1..e7c7123 100644 --- a/analyzer/parser/fight_results/fight_results.c +++ b/analyzer/parser/fight_results/fight_results.c @@ -8,6 +8,13 @@ #include "csv/id_to_item_name.h" #include "csv/id_to_orb_name.h" #include "csv/id_to_saturation_type.h" +#include "parser/fight_results/drif.h" +#include "parser/fight_results/entity.h" +#include "parser/fight_results/gear.h" +#include "parser/fight_results/gear_info.h" +#include "parser/fight_results/orb.h" +#include "parser/structs.h" +#include "utils/memory.h" #include "utils/roman.h" // function to cleanup fight results to be used in ParsedData struct @@ -29,126 +36,20 @@ byte_t *find_fight_results(TCPStream *stream, int offset, int *length) { byte_t *start = memmem(stream->data + offset, stream->len - offset, FIGHT_RESULTS_START, strlen(FIGHT_RESULTS_START)); byte_t *end = NULL; if (start) - end = memmem(start, stream->len - offset, FIGHT_RESULTS_END, strlen(FIGHT_RESULTS_END)); + end = memmem(start, stream->len - (start - stream->data), FIGHT_RESULTS_END, strlen(FIGHT_RESULTS_END)); *length = end ? end - start + strlen(FIGHT_RESULTS_END) : -1; return start; } -// save to a field in struct depending on the type -void save_to_struct(TypeEnum type, void *field, char *src, size_t src_len) { - char *str = malloc(src_len + 1); - memcpy(str, src, src_len); - str[src_len] = '\0'; - - // parse depending on variable type - switch (type) { - case INT: - sscanf(str, "%d", (int *)field); - free(str); - break; - case FLOAT: - sscanf(str, "%f", (float *)field); - free(str); - break; - case DOUBLE: - sscanf(str, "%lf", (double *)field); - free(str); - break; - case STRING: - *(char **)field = str; - break; - } -} - -// fill struct fields from given data of given length -void get_struct_data(size_t field_count, TypeEnum *field_types, void **field_pointers, char *data_separator, char *data, size_t data_len) { - for (size_t i = 0; i < field_count; i++) { - char *sep = memmem(data, data_len, data_separator, strlen(data_separator)); - size_t len = sep ? sep - data : data_len; - save_to_struct(field_types[i], field_pointers[i], (char *)data, len); - - // update data pointer and length - if (sep) { - data_len -= sep - data + strlen(data_separator); - data = sep + strlen(data_separator); - } - } -} - -// free struct fields which are STRING -void destroy_struct(size_t field_count, TypeEnum *field_types, void **field_pointers) { - for (size_t i = 0; i < field_count; i++) { - if (field_types[i] == STRING) - free(*(char **)field_pointers[i]); - } -} - -void destroy_entity_results(EntityResults results) { - TypeEnum field_types[ENTITY_FIELD_COUNT] = ENTITY_FIELD_TYPES; - void *field_pointers[ENTITY_FIELD_COUNT] = ENTITY_FIELD_ADDRESSES(results); - destroy_struct(ENTITY_FIELD_COUNT, field_types, field_pointers); -} - -// get entity results from the string -EntityResults get_entity_results(byte_t *data, size_t length) { - EntityResults results; - TypeEnum field_types[ENTITY_FIELD_COUNT] = ENTITY_FIELD_TYPES; - void *field_pointers[ENTITY_FIELD_COUNT] = ENTITY_FIELD_ADDRESSES(results); - get_struct_data(ENTITY_FIELD_COUNT, field_types, field_pointers, SEPARATOR_RESULT, (char *)data, length); - return results; -} - Item *expand_items(Item *items, size_t *items_capacity, size_t to_fit) { while (*items_capacity < to_fit) *items_capacity <<= 1; return realloc(items, *items_capacity * sizeof(Item)); } -void destroy_gear(Gear gear) { - TypeEnum field_types[GEAR_FIELD_COUNT] = GEAR_FIELD_TYPES; - void *field_pointers[GEAR_FIELD_COUNT] = GEAR_FIELD_ADDRESSES(gear); - destroy_struct(GEAR_FIELD_COUNT, field_types, field_pointers); -} - -Gear get_gear(char *data, size_t length) { - Gear gear; - TypeEnum field_types[GEAR_FIELD_COUNT] = GEAR_FIELD_TYPES; - void *field_pointers[GEAR_FIELD_COUNT] = GEAR_FIELD_ADDRESSES(gear); - get_struct_data(GEAR_FIELD_COUNT, field_types, field_pointers, SEPARATOR_GEAR_FIELDS, data, length); - return gear; -} - -void destroy_gear_info(GearInfo gear_info) { - TypeEnum field_types[GEAR_INFO_FIELD_COUNT] = GEAR_INFO_FIELD_TYPES; - void *field_pointers[GEAR_INFO_FIELD_COUNT] = GEAR_INFO_FIELD_ADDRESSES(gear_info); - destroy_struct(GEAR_INFO_FIELD_COUNT, field_types, field_pointers); -} - -GearInfo get_gear_info(char *data, size_t length) { - GearInfo gear_info; - TypeEnum field_types[GEAR_INFO_FIELD_COUNT] = GEAR_INFO_FIELD_TYPES; - void *field_pointers[GEAR_INFO_FIELD_COUNT] = GEAR_INFO_FIELD_ADDRESSES(gear_info); - get_struct_data(GEAR_INFO_FIELD_COUNT, field_types, field_pointers, SEPARATOR_GEAR_INFO_FIELDS, data, length); - return gear_info; -} - -void destroy_orb(Orb orb) { - TypeEnum field_types[ORB_FIELD_COUNT] = ORB_FIELD_TYPES; - void *field_pointers[ORB_FIELD_COUNT] = ORB_FIELD_ADDRESSES(orb); - destroy_struct(ORB_FIELD_COUNT, field_types, field_pointers); -} - -Orb get_orb(char *data, size_t length) { - Orb orb; - TypeEnum field_types[ORB_FIELD_COUNT] = ORB_FIELD_TYPES; - void *field_pointers[ORB_FIELD_COUNT] = ORB_FIELD_ADDRESSES(orb); - get_struct_data(ORB_FIELD_COUNT, field_types, field_pointers, SEPARATOR_ORB_FIELDS, data, length); - return orb; -} - void get_stars(char *buffer, int incr_above_b1) { char star_types[] = {'B', 'S', 'G'}; - sprintf(buffer, " (%c%d)", star_types[incr_above_b1 / 3], incr_above_b1 % 3 + '1'); + sprintf(buffer, " (%c%d)", star_types[incr_above_b1 / 3], incr_above_b1 % 3 + 1); } void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) { @@ -157,16 +58,19 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) char *gears_separator; do { - gears_separator = strstr(gears_str, SEPARATOR_GEARS); - Gear gear = get_gear(gears_str, gears_separator ? gears_separator - gears_str : strlen(gears_str)); + gears_separator = strstr(gears_str, SEPARATOR_GEAR); + size_t len = gears_separator ? gears_separator - gears_str : strlen(gears_str); + Gear gear = {0}; + fill_struct(&gear, gear_fields, ARR_LEN(gear_fields), gears_str, len, SEPARATOR_GEAR_FIELD); // if there are still gears - modify gears_str pointer if (gears_separator) - gears_str = gears_separator + strlen(SEPARATOR_GEARS); + gears_str = gears_separator + strlen(SEPARATOR_GEAR); Item item; - GearInfo gear_info = get_gear_info(gear.info, strlen(gear.info)); + GearInfo gear_info = {0}; + fill_struct(&gear_info, gear_info_fields, ARR_LEN(gear_info_fields), gear.info, strlen(gear.info), SEPARATOR_GEAR_INFO_FIELD); char buffer[SINGLE_ITEM_BUFFER_LEN]; char roman[5]; to_roman(roman, gear_info.rank); @@ -174,8 +78,11 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) switch (gear.type) { case TYPE_SYNG_NORMAL: // atoi should be fine, since syng_tier starts from 1 for syngs - if (atoi(gear.syng_tier)) - sprintf(buffer, "%s (%d)", buffer, gear_info.lvl); + if (atoi(gear.syng_tier)) { + char lvl[7]; + sprintf(lvl, " (%d)", gear_info.lvl); + strcat(buffer, lvl); + } break; default: { char stars[6]; @@ -185,7 +92,7 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) } } item.data = strdup(buffer); - destroy_gear_info(gear_info); + cleanup_struct(&gear_info, gear_info_fields, ARR_LEN(gear_info_fields)); switch (gear.type) { case TYPE_SYNG_NORMAL: @@ -212,10 +119,11 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) if (strlen(gear.orb)) { Item item; char buffer[SINGLE_ITEM_BUFFER_LEN]; - Orb orb = get_orb(gear.orb, strlen(gear.orb)); + Orb orb = {0}; + fill_struct(&orb, orb_fields, ARR_LEN(orb_fields), gear.orb, strlen(gear.orb), SEPARATOR_ORB_FIELD); sprintf(buffer, "%sorb %s", get_artifact_size_from_id(orb.size), get_orb_name_from_id(orb.id)); item.data = strdup(buffer); - destroy_orb(orb); + cleanup_struct(&orb, orb_fields, ARR_LEN(orb_fields)); item.type = ORB; // expand if needed if (results->num_items >= *items_capacity) @@ -223,47 +131,35 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) results->items[results->num_items++] = item; } - destroy_gear(gear); + cleanup_struct(&gear, gear_fields, ARR_LEN(gear_fields)); } while (gears_separator); } -void destroy_drif(Drif drif) { - TypeEnum field_types[DRIF_FIELD_COUNT] = DRIF_FIELD_TYPES; - void *field_pointers[DRIF_FIELD_COUNT] = DRIF_FIELD_ADDRESSES(drif); - destroy_struct(DRIF_FIELD_COUNT, field_types, field_pointers); -} - -Drif get_drif(char *data, size_t length) { - Drif drif; - TypeEnum field_types[DRIF_FIELD_COUNT] = DRIF_FIELD_TYPES; - void *field_pointers[DRIF_FIELD_COUNT] = DRIF_FIELD_ADDRESSES(drif); - get_struct_data(DRIF_FIELD_COUNT, field_types, field_pointers, SEPARATOR_DRIF_FIELDS, data, length); - return drif; -} - void add_drifs(FriendlyResults *results, size_t *items_capacity, char *drifs_str) { if (strlen(drifs_str) == 0) return; char *drifs_separator; do { - drifs_separator = strstr(drifs_str, SEPARATOR_DRIFS); - Drif drif = get_drif(drifs_str, drifs_separator ? drifs_separator - drifs_str : strlen(drifs_str)); + drifs_separator = strstr(drifs_str, SEPARATOR_DRIF); + size_t len = drifs_separator ? drifs_separator - drifs_str : strlen(drifs_str); + Drif drif = {0}; + fill_struct(&drif, drif_fields, ARR_LEN(drif_fields), drifs_str, len, SEPARATOR_DRIF_FIELD); // if there are still drifs - modify drifs_str pointer if (drifs_separator) - drifs_str = drifs_separator + strlen(SEPARATOR_DRIFS); + drifs_str = drifs_separator + strlen(SEPARATOR_DRIF); Item item; item.data = strdup(drif.name); item.type = DRIF; + cleanup_struct(&drif, drif_fields, ARR_LEN(drif_fields)); + // expand if needed if (results->num_items >= *items_capacity) results->items = expand_items(results->items, items_capacity, results->num_items + 1); results->items[results->num_items++] = item; - - destroy_drif(drif); } while (drifs_separator); } @@ -350,7 +246,9 @@ ParsedData parse_fight_results(byte_t *data, size_t length) { do { // get generic entity results entity_separator = memmem(data, length, SEPARATOR_ENTITY, strlen(SEPARATOR_ENTITY)); - EntityResults entity_results = get_entity_results(data, entity_separator ? entity_separator - data : length); + size_t len = entity_separator ? entity_separator - data : length; + EntityResults entity_results = {0}; + fill_struct(&entity_results, entity_fields, ARR_LEN(entity_fields), (char *)data, len, SEPARATOR_ENTITY_FIELD); // depending on team - parse it into friendly or enemy results switch (entity_results.team) { @@ -361,7 +259,8 @@ ParsedData parse_fight_results(byte_t *data, size_t length) { results->enemy_results[results->num_enemy++] = parse_to_enemy(entity_results); break; } - destroy_entity_results(entity_results); + + cleanup_struct(&entity_results, entity_fields, ARR_LEN(entity_fields)); // if there are still entities - modify data pointer and length if (entity_separator) { diff --git a/analyzer/parser/fight_results/fight_results.h b/analyzer/parser/fight_results/fight_results.h index 0618bf2..04add96 100644 --- a/analyzer/parser/fight_results/fight_results.h +++ b/analyzer/parser/fight_results/fight_results.h @@ -11,137 +11,12 @@ // FIGHT_RESULTS_START EntityResults (SEPARATOR_ENTITY EntityResults)* FIGHT_RESULTS_END #define FIGHT_RESULTS_START "3;19;" #define FIGHT_RESULTS_END "[--];" -#define SEPARATOR_ENTITY "[--]" -#define SEPARATOR_RESULT "&" -// values of field "team" in EntityResults -#define TEAM_FRIEND 1 -#define TEAM_ENEMY 2 - -// EntityResults structure: -// field (SEPARATOR_RESULT field)* -// fields are defined in order in the EntityResults struct -#define ENTITY_FIELD_COUNT 35 -// clang-format off -#define ENTITY_FIELD_TYPES { \ - /* team */ INT, \ - /* name */ STRING, \ - /* exp */ INT, \ - /* field4 */ FLOAT, \ - /* gold */ INT, \ - /* field6 */ FLOAT, \ - /* field7 */ STRING, \ - /* gear */ STRING, \ - /* field9 */ INT, \ - /* items */ STRING, \ - /* field11 */ INT, \ - /* field12 */ INT, \ - /* field13 */ FLOAT, \ - /* field14 */ FLOAT, \ - /* field15 */ FLOAT, \ - /* level */ INT, \ - /* field17 */ DOUBLE, \ - /* field18 */ FLOAT, \ - /* field19 */ INT, \ - /* field20 */ INT, \ - /* field21 */ FLOAT, \ - /* field22 */ FLOAT, \ - /* field23 */ INT, \ - /* field24 */ INT, \ - /* psycho */ INT, \ - /* drifs */ STRING, \ - /* splinters */ INT, \ - /* field28 */ INT, \ - /* field29 */ STRING, \ - /* field30 */ INT, \ - /* field31 */ INT, \ - /* field32 */ INT, \ - /* field33 */ INT, \ - /* field34 */ STRING, \ - /* saturation */ STRING, \ -} -#define ENTITY_FIELD_ADDRESSES(entity_results) {\ - &entity_results.team, \ - &entity_results.name, \ - &entity_results.exp, \ - &entity_results.field4, \ - &entity_results.gold, \ - &entity_results.field6, \ - &entity_results.field7, \ - &entity_results.gear, \ - &entity_results.field9, \ - &entity_results.items, \ - &entity_results.field11, \ - &entity_results.field12, \ - &entity_results.field13, \ - &entity_results.field14, \ - &entity_results.field15, \ - &entity_results.level, \ - &entity_results.field17, \ - &entity_results.field18, \ - &entity_results.field19, \ - &entity_results.field20, \ - &entity_results.field21, \ - &entity_results.field22, \ - &entity_results.field23, \ - &entity_results.field24, \ - &entity_results.psycho, \ - &entity_results.drifs, \ - &entity_results.splinters, \ - &entity_results.field28, \ - &entity_results.field29, \ - &entity_results.field30, \ - &entity_results.field31, \ - &entity_results.field32, \ - &entity_results.field33, \ - &entity_results.field34, \ - &entity_results.saturation, \ -} -// clang-format on -typedef struct { - int team; // friend or enemy - char *name; - int exp; - float field4; - int gold; - float field6; - char *field7; - char *gear; // rares, sets, syngs, orbs - int field9; - char *items; // regular items - int field11; - int field12; - float field13; - float field14; // some multiplier most likely exp/gold/psycho/something else idk - float field15; - int level; - double field17; - float field18; - int field19; - int field20; - float field21; - float field22; - int field23; - int field24; - int psycho; - char *drifs; - int splinters; - int field28; - char *field29; - int field30; - int field31; - int field32; - int field33; - char *field34; - char *saturation; -} EntityResults; - -// items/gear/drifs fields parsing info +// items parsing info #define INIT_ITEMS_CAPACITY 8 #define SINGLE_ITEM_BUFFER_LEN 128 #define SEPARATOR_ITEMS "[-]" -#define SEPARATOR_DRIFS "???" // TODO: change it to correct one which idk at this moment -#define SEPARATOR_GEARS "???" // TODO: change it to correct one which idk at this moment + // Item struct - for keeping item string and type typedef enum { NORMAL, DRIF, ORB, SYNG, SET, RARE, EPIC } ItemType; typedef struct { @@ -149,273 +24,6 @@ typedef struct { ItemType type; } Item; -// Drif structure: -// field (SEPARATOR_DRIF_FIELDS field)* -// fields are defined in order in the Drif struct -#define DRIF_FIELD_COUNT 18 -#define SEPARATOR_DRIF_FIELDS "," -// clang-format off -#define DRIF_FIELD_TYPES { \ - /* field1 */ STRING, \ - /* field2 */ INT, \ - /* size */ INT, \ - /* field4 */ STRING, \ - /* field5 */ INT, \ - /* id */ INT, \ - /* value1 */ FLOAT, \ - /* value2 */ FLOAT, \ - /* field9 */ INT, \ - /* field10 */ INT, \ - /* field11 */ STRING, \ - /* size_str */ STRING, \ - /* field13 */ INT, \ - /* power */ INT, \ - /* field15 */ INT, \ - /* field16 */ INT, \ - /* name */ STRING, \ - /* field18 */ STRING, \ -} -#define DRIF_FIELD_ADDRESSES(drif) {\ - &drif.field1, \ - &drif.field2, \ - &drif.size, \ - &drif.field4, \ - &drif.field5, \ - &drif.id, \ - &drif.value1, \ - &drif.value2, \ - &drif.field9, \ - &drif.field10, \ - &drif.field11, \ - &drif.size_str, \ - &drif.field13, \ - &drif.power, \ - &drif.field15, \ - &drif.field16, \ - &drif.name, \ - &drif.field18, \ -} -// clang-format on -typedef struct { - char *field1; // just says "drif" - int field2; - int size; // 1 - sub, 2 - bi, 3 - magni, 4 - arcy - char *field4; - int field5; - int id; // id of orb type - float value1; // value1, value2 (in %) - one is start value, the other is value per lvl (both are the same) - float value2; // value1, value2 (in %) - one is start value, the other is value per lvl (both are the same) - int field9; - int field10; - char *field11; - char *size_str; // sub - small, medium - bi, big - magni, ??? - arcy - int field13; - int power; // how much space it takes - int field15; - int field16; - char *name; // drif - char *field18; -} Drif; - -// Gear structure: -// field (SEPARATOR_GEAR_FIELDS field)* -// fields are defined in order in the Gear struct -#define GEAR_FIELD_COUNT 19 -#define SEPARATOR_GEAR_FIELDS "$" -// values of field "type" in Gear -#define TYPE_SYNG_NORMAL 0 -#define TYPE_SET 1 -#define TYPE_RARE 2 -// clang-format off -#define GEAR_FIELD_TYPES { \ - /* stats */ STRING, \ - /* resistances */ STRING, \ - /* info */ STRING, \ - /* reqs */ STRING, \ - /* field5 */ STRING, \ - /* psycho */ STRING, \ - /* field7 */ STRING, \ - /* field8 */ STRING, \ - /* field9 */ STRING, \ - /* syng_tier */ STRING, \ - /* field11 */ INT, \ - /* field12 */ INT, \ - /* field13 */ INT, \ - /* field14 */ STRING, \ - /* type */ INT, \ - /* field16 */ INT, \ - /* orb */ STRING, \ - /* field18 */ STRING, \ - /* field19 */ STRING, \ -} -#define GEAR_FIELD_ADDRESSES(gear) {\ - &gear.stats, \ - &gear.resistances, \ - &gear.info, \ - &gear.reqs, \ - &gear.field5, \ - &gear.psycho, \ - &gear.field7, \ - &gear.field8, \ - &gear.field9, \ - &gear.syng_tier, \ - &gear.field11, \ - &gear.field12, \ - &gear.field13, \ - &gear.field14, \ - &gear.type, \ - &gear.field16, \ - &gear.orb, \ - &gear.field18, \ - &gear.field19, \ -} -// clang-format on -typedef struct { - char *stats; // strength, dexterity, power, knowledge, hp, mana, stamina - char *resistances; // slashing, crushing, piercing, fire, cold, energy, mental - char *info; // GearInfo struct data - char *reqs; // requirements (str, dex, pow, know), weight, something else - char *field5; - char *psycho; // psycho effects (id,%) for syngs - char *field7; - char *field8; - char *field9; - char *syng_tier; // lvl 20 - 1, lvl 30 - 2, etc..., null for non-syngs - int field11; - int field12; - int field13; - char *field14; - int type; // 0 - normal item or syng, 1 - set, 2 - rare - int field16; // 10 for rare, -1 for others ??? - char *orb; // orb info - char *field18; - char *field19; -} Gear; - -// GearInfo structure: -// field (SEPARATOR_GEAR_INFO_FIELDS field)* -// fields are defined in order in the GearInfo struct -#define GEAR_INFO_FIELD_COUNT 23 -#define SEPARATOR_GEAR_INFO_FIELDS "," -// clang-format off -#define GEAR_INFO_FIELD_TYPES { \ - /* name */ STRING, \ - /* field2 */ INT, \ - /* lvl */ INT, \ - /* price */ INT, \ - /* field5 */ INT, \ - /* field6 */ INT, \ - /* field7 */ INT, \ - /* rank */ INT, \ - /* field9 */ INT, \ - /* field10 */ INT, \ - /* field11 */ INT, \ - /* durability */ INT, \ - /* field13 */ STRING, \ - /* field14 */ INT, \ - /* field15 */ INT, \ - /* charges */ FLOAT, \ - /* field17 */ STRING, \ - /* field18 */ INT, \ - /* stars */ INT, \ - /* field20 */ INT, \ - /* field21 */ INT, \ - /* field22 */ INT, \ - /* field23 */ INT, \ -} -#define GEAR_INFO_FIELD_ADDRESSES(gear_info) {\ - &gear_info.name, \ - &gear_info.field2, \ - &gear_info.lvl, \ - &gear_info.price, \ - &gear_info.field5, \ - &gear_info.field6, \ - &gear_info.field7, \ - &gear_info.rank, \ - &gear_info.field9, \ - &gear_info.field10, \ - &gear_info.field11, \ - &gear_info.durability, \ - &gear_info.field13, \ - &gear_info.field14, \ - &gear_info.field15, \ - &gear_info.charges, \ - &gear_info.field17, \ - &gear_info.field18, \ - &gear_info.stars, \ - &gear_info.field20, \ - &gear_info.field21, \ - &gear_info.field22, \ - &gear_info.field23, \ -} -// clang-format on -typedef struct { - char *name; // item name - int field2; - int lvl; // level requirement - int price; // gold price value - int field5; - int field6; - int field7; - int rank; // I-XII - int field9; - int field10; - int field11; - int durability; // in % - char *field13; - int field14; - int field15; - float charges; // charge count - char *field17; - int field18; - int stars; // incrustation level: 0 - b1, 1 - b2, ... (-100 for syngs) - int field20; - int field21; - int field22; - int field23; -} GearInfo; - -// Orb structure: -// field (SEPARATOR_ORB_FIELDS field)* -// fields are defined in order in the Orb struct -#define ORB_FIELD_COUNT 9 -#define SEPARATOR_ORB_FIELDS "," -// clang-format off -#define ORB_FIELD_TYPES { \ - /* field1 */ STRING, \ - /* field2 */ INT, \ - /* field3 */ INT, \ - /* field4 */ STRING, \ - /* field5 */ INT, \ - /* id */ INT, \ - /* size */ INT, \ - /* value */ FLOAT, \ - /* field9 */ STRING, \ -} -#define ORB_FIELD_ADDRESSES(orb) {\ - &orb.field1, \ - &orb.field2, \ - &orb.field3, \ - &orb.field4, \ - &orb.field5, \ - &orb.id, \ - &orb.size, \ - &orb.value, \ - &orb.field9, \ -} -// clang-format on -typedef struct { - char *field1; // just says "orb" - int field2; - int field3; - char *field4; - int field5; - int id; // id of orb type - int size; // 1 - sub, 2 - bi, 3 - magni, 4 - arcy - float value; // value in % you gain from the orb - char *field9; -} Orb; - // fight results data for friendly typedef struct { char *name; diff --git a/analyzer/parser/fight_results/gear.h b/analyzer/parser/fight_results/gear.h new file mode 100644 index 0000000..66f52f3 --- /dev/null +++ b/analyzer/parser/fight_results/gear.h @@ -0,0 +1,45 @@ +// parser/fight_results/gear.h +// Gear generic struct data + +#include "parser/structs.h" + +// Gear structure: +// field (SEPARATOR_GEAR_FIELD field)* +// fields are defined in order in the Gear struct +#define SEPARATOR_GEAR "???" // TODO: change it to correct one which idk at this moment +#define SEPARATOR_GEAR_FIELD "$" + +// values of field "type" in Gear +#define TYPE_SYNG_NORMAL 0 +#define TYPE_SET 1 +#define TYPE_RARE 2 + +typedef struct { + char *stats; // strength, dexterity, power, knowledge, hp, mana, stamina + char *resistances; // slashing, crushing, piercing, fire, cold, energy, mental + char *info; // GearInfo struct data + char *reqs; // requirements (str, dex, pow, know), weight, something else + char *field5; + char *psycho; // psycho effects (id,%) for syngs + char *field7; + char *field8; + char *field9; + char *syng_tier; // lvl 20 - 1, lvl 30 - 2, etc..., null for non-syngs + int field11; + int field12; + int field13; + char *field14; + int type; // 0 - normal item or syng, 1 - set, 2 - rare + int field16; // 10 for rare, -1 for others ??? + char *orb; // orb info + char *field18; + char *field19; +} Gear; + +static const StructField gear_fields[] = { + {STRING, offsetof(Gear, stats)}, {STRING, offsetof(Gear, resistances)}, {STRING, offsetof(Gear, info)}, {STRING, offsetof(Gear, reqs)}, + {STRING, offsetof(Gear, field5)}, {STRING, offsetof(Gear, psycho)}, {STRING, offsetof(Gear, field7)}, {STRING, offsetof(Gear, field8)}, + {STRING, offsetof(Gear, field9)}, {STRING, offsetof(Gear, syng_tier)}, {INT, offsetof(Gear, field11)}, {INT, offsetof(Gear, field12)}, + {INT, offsetof(Gear, field13)}, {STRING, offsetof(Gear, field14)}, {INT, offsetof(Gear, type)}, {INT, offsetof(Gear, field16)}, + {STRING, offsetof(Gear, orb)}, {STRING, offsetof(Gear, field18)}, {STRING, offsetof(Gear, field19)}, +}; diff --git a/analyzer/parser/fight_results/gear_info.h b/analyzer/parser/fight_results/gear_info.h new file mode 100644 index 0000000..f0cf83a --- /dev/null +++ b/analyzer/parser/fight_results/gear_info.h @@ -0,0 +1,44 @@ +// parser/fight_results/gear_info.h +// GearInfo generic struct data + +#include "parser/structs.h" + +// GearInfo structure: +// field (SEPARATOR_GEAR_INFO_FIELD field)* +// fields are defined in order in the GearInfo struct +#define SEPARATOR_GEAR_INFO_FIELD "," + +typedef struct { + char *name; // item name + int field2; + int lvl; // level requirement + int price; // gold price value + int field5; + int field6; + int field7; + int rank; // I-XII + int field9; + int field10; + int field11; + int durability; // in % + char *field13; + int field14; + int field15; + float charges; // charge count + char *field17; + int field18; + int stars; // incrustation level: 0 - b1, 1 - b2, ... (-100 for syngs) + int field20; + int field21; + int field22; + int field23; +} GearInfo; + +static const StructField gear_info_fields[] = { + {STRING, offsetof(GearInfo, name)}, {INT, offsetof(GearInfo, field2)}, {INT, offsetof(GearInfo, lvl)}, {INT, offsetof(GearInfo, price)}, + {INT, offsetof(GearInfo, field5)}, {INT, offsetof(GearInfo, field6)}, {INT, offsetof(GearInfo, field7)}, {INT, offsetof(GearInfo, rank)}, + {INT, offsetof(GearInfo, field9)}, {INT, offsetof(GearInfo, field10)}, {INT, offsetof(GearInfo, field11)}, {INT, offsetof(GearInfo, durability)}, + {STRING, offsetof(GearInfo, field13)}, {INT, offsetof(GearInfo, field14)}, {INT, offsetof(GearInfo, field15)}, {FLOAT, offsetof(GearInfo, charges)}, + {STRING, offsetof(GearInfo, field17)}, {INT, offsetof(GearInfo, field18)}, {INT, offsetof(GearInfo, stars)}, {INT, offsetof(GearInfo, field20)}, + {INT, offsetof(GearInfo, field21)}, {INT, offsetof(GearInfo, field22)}, {INT, offsetof(GearInfo, field23)}, +}; diff --git a/analyzer/parser/fight_results/orb.h b/analyzer/parser/fight_results/orb.h new file mode 100644 index 0000000..dcf146f --- /dev/null +++ b/analyzer/parser/fight_results/orb.h @@ -0,0 +1,33 @@ +// parser/fight_results/orb.h +// Orb generic struct data + +#include "parser/structs.h" + +// Orb structure: +// field (SEPARATOR_ORB_FIELD field)* +// fields are defined in order in the Orb struct +#define SEPARATOR_ORB_FIELD "," + +typedef struct { + char *field1; // just says "orb" + int field2; + int field3; + char *field4; + int field5; + int id; // id of orb type + int size; // 1 - sub, 2 - bi, 3 - magni, 4 - arcy + float value; // value in % you gain from the orb + char *field9; +} Orb; + +static const StructField orb_fields[] = { + {STRING, offsetof(Orb, field1)}, + {INT, offsetof(Orb, field2)}, + {INT, offsetof(Orb, field3)}, + {STRING, offsetof(Orb, field4)}, + {INT, offsetof(Orb, field5)}, + {INT, offsetof(Orb, id)}, + {INT, offsetof(Orb, size)}, + {FLOAT, offsetof(Orb, value)}, + {STRING, offsetof(Orb, field9)}, +}; diff --git a/analyzer/parser/find_parse_functions.h b/analyzer/parser/find_parse_functions.h index 1b6ce9e..e2c2acb 100644 --- a/analyzer/parser/find_parse_functions.h +++ b/analyzer/parser/find_parse_functions.h @@ -3,8 +3,4 @@ #include "parser/fight_results/fight_results.h" -#define RESULT_TYPE_COUNT 1 - -FindParseFunctions all_find_parse_functions[RESULT_TYPE_COUNT] = { - {.find_fn = find_fight_results, .parse_fn = parse_fight_results} -}; +FindParseFunctions all_find_parse_functions[] = {{find_fight_results, parse_fight_results}}; diff --git a/analyzer/parser/parser.c b/analyzer/parser/parser.c index 3ef48b5..87ab4c0 100644 --- a/analyzer/parser/parser.c +++ b/analyzer/parser/parser.c @@ -3,6 +3,7 @@ #include #include "parser/find_parse_functions.h" +#include "utils/memory.h" // expand parsed data exponentially to fit el_count elements ParsedData *expand_parsed_data(ParsedData *parsed_data, size_t *capacity, size_t el_count) { @@ -14,7 +15,7 @@ ParsedData *expand_parsed_data(ParsedData *parsed_data, size_t *capacity, size_t // find earliest data to parse in stream byte_t *find_earliest_data(TCPStream *stream, int stream_offset, int *earliest_length, parse_function_t **earliest_parse_fun) { byte_t *earliest_data = NULL; - for (size_t i = 0; i < RESULT_TYPE_COUNT; i++) { + for (size_t i = 0; i < ARR_LEN(all_find_parse_functions); i++) { int length; byte_t *data = all_find_parse_functions[i].find_fn(stream, stream_offset, &length); // if it's the first found or earlier than earliest - save it diff --git a/analyzer/parser/parser_defs.h b/analyzer/parser/parser_defs.h index aa39a4c..75b0366 100644 --- a/analyzer/parser/parser_defs.h +++ b/analyzer/parser/parser_defs.h @@ -6,8 +6,6 @@ #ifndef PARSER_DEFS_H #define PARSER_DEFS_H -typedef enum { INT, FLOAT, DOUBLE, STRING } TypeEnum; - typedef enum { TYPE_FIGHT_RESULTS } ResultsEnum; // "generic" type for parsed data diff --git a/analyzer/parser/structs.c b/analyzer/parser/structs.c new file mode 100644 index 0000000..c59fa82 --- /dev/null +++ b/analyzer/parser/structs.c @@ -0,0 +1,49 @@ +#include "parser/structs.h" + +#include +#include +#include + +void fill_struct(void *obj, const StructField *fields, size_t n_fields, const char *data, size_t data_len, const char *sep) { + for (size_t i = 0; i < n_fields; i++) { + char *next_sep = memmem(data, data_len, sep, strlen(sep)); + size_t len = next_sep ? next_sep - data : data_len; + + char *str = malloc(len + 1); + memcpy(str, data, len); + str[len] = '\0'; + + // parse depending on variable type + void *p_field = (char *)obj + fields[i].offset; + switch (fields[i].type) { + case INT: + sscanf(str, "%d", (int *)p_field); + free(str); + break; + case FLOAT: + sscanf(str, "%f", (float *)p_field); + free(str); + break; + case DOUBLE: + sscanf(str, "%lf", (double *)p_field); + free(str); + break; + case STRING: + *(char **)p_field = str; + break; + } + + // update data pointer and length + if (next_sep) { + data_len -= next_sep - data + strlen(sep); + data = next_sep + strlen(sep); + } + } +} + +void cleanup_struct(void *obj, const StructField *fields, size_t n_fields) { + for (size_t i = 0; i < n_fields; i++) { + if (fields[i].type == STRING) + free(*(char **)((char *)obj + fields[i].offset)); + } +} diff --git a/analyzer/parser/structs.h b/analyzer/parser/structs.h new file mode 100644 index 0000000..023c19b --- /dev/null +++ b/analyzer/parser/structs.h @@ -0,0 +1,33 @@ +// parser/structs.h +// generic struct functionality for parsing + +#include + +#ifndef PARSER_STRUCTS_H +#define PARSER_STRUCTS_H + +typedef enum { INT, FLOAT, DOUBLE, STRING } TypeEnum; + +typedef struct { + TypeEnum type; + size_t offset; +} StructField; + +// fill generic struct with given data +// params: +// - obj - pointer to the struct to fill +// - fields - field types and offsets of the struct +// - n_fields - count of fields in the struct +// - data - data to fill the struct with +// - data_len - length of the data +// - sep - separator seperating the fields in data +extern void fill_struct(void *obj, const StructField *fields, size_t n_fields, const char *data, size_t data_len, const char *sep); + +// cleanup allocations inside generic struct +// params: +// - obj - pointer to the struct to cleanup +// - fields - field types and offsets of the struct +// - n_fields - count of fields in the struct +extern void cleanup_struct(void *obj, const StructField *fields, size_t n_fields); + +#endif diff --git a/analyzer/render.c b/analyzer/render.c index 0fdd334..5c4b2d0 100644 --- a/analyzer/render.c +++ b/analyzer/render.c @@ -63,14 +63,10 @@ void print_enemy_list(EnemyResults *results, size_t n_enemies) { } void print_column_names() { - char *names[TABLE_COLUMN_COUNT] = TABLE_COLUMN_NAMES; - int colors[TABLE_COLUMN_COUNT] = TABLE_COLUMN_COLORS; - size_t widths[TABLE_COLUMN_COUNT] = TABLE_COLUMN_WIDTHS; - printf(TABLE_LINE_START); - for (size_t i = 0; i < TABLE_COLUMN_COUNT; i++) { - print_center(names[i], colors[i], widths[i], ' '); - printf(i < TABLE_COLUMN_COUNT - 1 ? TABLE_LINE_SEPARATOR : TABLE_LINE_END); + for (size_t i = 0; i < ARR_LEN(columns); i++) { + print_center(columns[i].name, columns[i].color, columns[i].width, ' '); + printf(i < ARR_LEN(columns) - 1 ? TABLE_LINE_SEPARATOR : TABLE_LINE_END); } printf("\n"); } @@ -96,9 +92,7 @@ int item_type_to_color(ItemType type) { } void print_player_rewards(FriendlyResults results) { - char buffers[TABLE_COLUMN_COUNT][TABLE_LINE_WIDTH]; - size_t widths[TABLE_COLUMN_COUNT] = TABLE_COLUMN_WIDTHS; - int colors[TABLE_COLUMN_COUNT] = TABLE_COLUMN_COLORS; + char buffers[ARR_LEN(columns)][TABLE_LINE_WIDTH]; sprintf(buffers[0], "%s (%d)", results.name, results.level); sprintf(buffers[1], "%d", results.exp); @@ -120,11 +114,11 @@ void print_player_rewards(FriendlyResults results) { sprintf(buffers[5], "-"); printf(TABLE_LINE_START); - for (size_t i = 0; i < TABLE_COLUMN_COUNT; i++) { - char to_color[widths[i] + 1]; - sprintf(to_color, "%*s", (int)widths[i], buffers[i]); - print_color(to_color, colors[i]); - printf(i < TABLE_COLUMN_COUNT - 1 ? TABLE_LINE_SEPARATOR : TABLE_LINE_END); + for (size_t i = 0; i < ARR_LEN(columns); i++) { + char to_color[columns[i].width + 1]; + sprintf(to_color, "%*s", (int)columns[i].width, buffers[i]); + print_color(to_color, columns[i].color); + printf(i < ARR_LEN(columns) - 1 ? TABLE_LINE_SEPARATOR : TABLE_LINE_END); } printf("\n"); diff --git a/analyzer/render.h b/analyzer/render.h index 1015eb9..3604bde 100644 --- a/analyzer/render.h +++ b/analyzer/render.h @@ -2,6 +2,7 @@ // functions for "rendering" data onto the terminal #include "parser/fight_results/fight_results.h" +#include "utils/memory.h" // ANSI escape sequence colors #define COLOR_GOLD 33 @@ -23,40 +24,32 @@ #define TABLE_LINE_END_WIDTH (sizeof(TABLE_LINE_END) - 1) #define TABLE_LINE_SEPARATOR_WIDTH (sizeof(TABLE_LINE_SEPARATOR) - 1) -#define TABLE_COLUMN_COUNT 6 - -#define TABLE_NAME_LVL_WIDTH 17 -#define TABLE_EXP_WIDTH 7 -#define TABLE_GOLD_WIDTH 7 -#define TABLE_PSYCHO_WIDTH 6 -#define TABLE_SATURATION_WIDTH 13 -#define TABLE_SPLINTERS_WIDTH 9 +// column info +typedef struct { + char *name; + size_t width; + int color; +} ColumnInfo; +static const ColumnInfo columns[] = { + {"Nick (LVL)", 17, COLOR_WHITE}, + {"EXP", 7, COLOR_WHITE}, + {"Gold", 7, COLOR_YELLOW}, + {"Psycho", 6, COLOR_AQUA}, + {"Saturation", 13, COLOR_GREEN}, + {"Splinters", 9, COLOR_BLUE}, +}; // clang-format off -#define TABLE_COLUMN_NAMES {"Nick (LVL)", "EXP", "Gold", "Psycho", "Saturation", "Splinters"} -#define TABLE_COLUMN_COLORS {COLOR_WHITE, COLOR_WHITE, COLOR_YELLOW, COLOR_AQUA, COLOR_GREEN, COLOR_BLUE} -#define TABLE_COLUMN_WIDTHS { \ - TABLE_NAME_LVL_WIDTH, \ - TABLE_EXP_WIDTH, \ - TABLE_GOLD_WIDTH, \ - TABLE_PSYCHO_WIDTH, \ - TABLE_SATURATION_WIDTH, \ - TABLE_SPLINTERS_WIDTH, \ -} - -#define TABLE_LINE_WIDTH ( \ - TABLE_LINE_START_WIDTH + \ - TABLE_NAME_LVL_WIDTH + \ - TABLE_EXP_WIDTH + \ - TABLE_GOLD_WIDTH + \ - TABLE_PSYCHO_WIDTH + \ - TABLE_SATURATION_WIDTH + \ - TABLE_SPLINTERS_WIDTH + \ - (TABLE_COLUMN_COUNT - 1) * TABLE_LINE_SEPARATOR_WIDTH + \ - TABLE_LINE_END_WIDTH \ -) +#define SUM_COL_WIDTHS ({ \ + size_t sum = 0; \ + for (size_t i = 0; i < ARR_LEN(columns); i++) \ + sum += columns[i].width; \ + sum; \ +}) // clang-format on +#define TABLE_LINE_WIDTH (TABLE_LINE_START_WIDTH + SUM_COL_WIDTHS + (ARR_LEN(columns) - 1) * TABLE_LINE_SEPARATOR_WIDTH + TABLE_LINE_END_WIDTH) + #define TABLE_ITEMS_WIDTH (TABLE_LINE_WIDTH - TABLE_LINE_START_WIDTH - TABLE_LINE_END_WIDTH) // render fight results onto the terminal diff --git a/analyzer/utils/memory.h b/analyzer/utils/memory.h new file mode 100644 index 0000000..1de58b9 --- /dev/null +++ b/analyzer/utils/memory.h @@ -0,0 +1,4 @@ +// utils/memory.h +// helper functions for dealing with memory management + +#define ARR_LEN(arr) (sizeof(arr) / sizeof(arr[0])) diff --git a/analyzer/utils/roman.c b/analyzer/utils/roman.c index 9ea2bbb..4fbe5c0 100644 --- a/analyzer/utils/roman.c +++ b/analyzer/utils/roman.c @@ -1,16 +1,15 @@ #include "utils/roman.h" -#include #include +#include "utils/memory.h" + void to_roman(char *buffer, int number) { buffer[0] = '\0'; - int nums[ROMAN_CHAR_COUNT] = ROMAN_NUMS; - char *chars[ROMAN_CHAR_COUNT] = ROMAN_CHARS; - for (size_t i = 0; i < ROMAN_CHAR_COUNT; i++) { - for (size_t j = 0; j < number / nums[i]; j++) { - strcat(buffer, chars[i]); + for (size_t i = 0; i < ARR_LEN(roman_symbols); i++) { + for (size_t j = 0; j < number / roman_symbols[i].num; j++) { + strcat(buffer, roman_symbols[i].symbol); } - number %= nums[i]; + number %= roman_symbols[i].num; } } diff --git a/analyzer/utils/roman.h b/analyzer/utils/roman.h index b4f5d3f..cebd16e 100644 --- a/analyzer/utils/roman.h +++ b/analyzer/utils/roman.h @@ -1,9 +1,26 @@ // utils/roman.h // functions for roman numbers -#define ROMAN_CHAR_COUNT 13 -#define ROMAN_NUMS {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1} -#define ROMAN_CHARS {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"} +typedef struct { + int num; + char *symbol; +} RomanSymbol; + +static const RomanSymbol roman_symbols[] = { + {1000, "M"}, + {900, "CM"}, + {500, "D"}, + {400, "CD"}, + {100, "C"}, + {90, "XC"}, + {50, "L"}, + {40, "XL"}, + {10, "X"}, + {9, "IX"}, + {5, "V"}, + {4, "IV"}, + {1, "I"}, +}; // convert a arabic number to roman number // params: -- cgit v1.2.3 From 682f9fc8288fdd01de1d88af87495d9e43f56b06 Mon Sep 17 00:00:00 2001 From: Mosder Date: Thu, 23 Jul 2026 20:14:31 +0200 Subject: refactor: refactored GCC statment expression into an inline function --- analyzer/render.h | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'analyzer/render.h') diff --git a/analyzer/render.h b/analyzer/render.h index 3604bde..911ca76 100644 --- a/analyzer/render.h +++ b/analyzer/render.h @@ -38,17 +38,14 @@ static const ColumnInfo columns[] = { {"Saturation", 13, COLOR_GREEN}, {"Splinters", 9, COLOR_BLUE}, }; - -// clang-format off -#define SUM_COL_WIDTHS ({ \ - size_t sum = 0; \ - for (size_t i = 0; i < ARR_LEN(columns); i++) \ - sum += columns[i].width; \ - sum; \ -}) -// clang-format on - -#define TABLE_LINE_WIDTH (TABLE_LINE_START_WIDTH + SUM_COL_WIDTHS + (ARR_LEN(columns) - 1) * TABLE_LINE_SEPARATOR_WIDTH + TABLE_LINE_END_WIDTH) +static const inline size_t sum_col_widths() { + size_t sum = 0; + for (size_t i = 0; i < ARR_LEN(columns); i++) + sum += columns[i].width; + return sum; +} + +#define TABLE_LINE_WIDTH (TABLE_LINE_START_WIDTH + sum_col_widths() + (ARR_LEN(columns) - 1) * TABLE_LINE_SEPARATOR_WIDTH + TABLE_LINE_END_WIDTH) #define TABLE_ITEMS_WIDTH (TABLE_LINE_WIDTH - TABLE_LINE_START_WIDTH - TABLE_LINE_END_WIDTH) -- cgit v1.2.3