diff options
| -rw-r--r-- | analyzer/analyzer.c | 132 | ||||
| -rw-r--r-- | analyzer/analyzer.h | 25 | ||||
| -rw-r--r-- | analyzer/parser/fight_results/fight_results.c | 1 | ||||
| -rw-r--r-- | analyzer/parser/fight_results/fight_results.h | 2 | ||||
| -rw-r--r-- | analyzer/render.c | 55 | ||||
| -rw-r--r-- | analyzer/render.h | 6 | ||||
| -rw-r--r-- | analyzer/structures/hashmap.c | 26 | ||||
| -rw-r--r-- | analyzer/structures/hashmap.h | 25 |
8 files changed, 248 insertions, 24 deletions
diff --git a/analyzer/analyzer.c b/analyzer/analyzer.c index 7b80328..b3468d6 100644 --- a/analyzer/analyzer.c +++ b/analyzer/analyzer.c @@ -1,11 +1,119 @@ #include "analyzer.h" #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include "parser/parser.h" #include "render.h" #include "utils/tcp.h" +// cleanup TotalRewards to be used with HashMap +void cleanup_total_rewards(void *rewards) { + TotalRewards *r = rewards; + hashmap_free(r->saturations); + for (size_t i = 0; i < MAX_ITEM_TYPE; i++) + array_destroy(r->items[i]); +} + +// cleanup char** to be used in DynArray +void cleanup_str_pointer(void *str_pointer) { + char **p_str = str_pointer; + free(*p_str); +} + +// initalize new total rewards +TotalRewards new_total_rewards() { + HashMap *saturations = hashmap_new(sizeof(const char *), sizeof(int), hash_str, compare_strs, NULL, NULL); + // clang-format off + TotalRewards rewards = { + .exp = 0, + .gold = 0, + .psycho = 0, + .saturations = saturations + }; + // clang-format on + for (size_t i = 0; i < MAX_ITEM_TYPE; i++) + rewards.items[i] = array_new(sizeof(char **), 16, cleanup_str_pointer); + return rewards; +} + +// initalize file analysis state +FileAnalState init_file_anal_state() { + HashMap *characters = hashmap_new(sizeof(char *), sizeof(TotalRewards), hash_str, compare_strs, NULL, cleanup_total_rewards); + FileAnalState state = {.fight_count = 0, .curr_character = {0}, .characters = characters}; + return state; +} + +// destroy FileAnalState +void destroy_file_anal_state(FileAnalState state) { + hashmap_free(state.characters); +} + +// add data from FriendlyResults into TotalRewards +void add_to_total_rewards(TotalRewards *rewards, FriendlyResults *results) { + rewards->exp += results->exp; + rewards->gold += results->gold; + rewards->psycho += results->psycho; + + Item *it = NULL; + while ((it = array_next(results->items, it))) { + char *data = strdup(it->data); + array_append(&rewards->items[it->type], &data); + } + + if (results->saturation > 0) { + int *old_sat = hashmap_get(rewards->saturations, (char *)results->saturation_type); + int new_sat = results->saturation + (old_sat ? *old_sat : 0); + hashmap_put(rewards->saturations, (char *)results->saturation_type, &new_sat); + } +} + +// file analyzer parsed data handler +void file_parsed_data_handler(void *state, DynArray parsed_data) { + FileAnalState *st = state; + ParsedData *data = NULL; + while ((data = array_next(parsed_data, data))) { + switch (data->data_type) { + case TYPE_FIGHT_RESULTS: { + FightResults *res = data->data; + + // if only one friendly - it's the player + if (res->friendly_results.count == 1) { + FriendlyResults *player = array_get(res->friendly_results, 0); + strcpy(st->curr_character, player->name); + } + + // find the current player + FriendlyResults *friendly = NULL; + int found = 0; + while (!found && (friendly = array_next(res->friendly_results, friendly))) { + if (!strcmp(st->curr_character, friendly->name)) + found = 1; + } + + // if found - save the rewards + if (found) { + TotalRewards *r = hashmap_get(st->characters, st->curr_character); + if (r) { + add_to_total_rewards(r, friendly); + } + else { + TotalRewards rewards = new_total_rewards(); + add_to_total_rewards(&rewards, friendly); + hashmap_put(st->characters, st->curr_character, &rewards); + } + } + + // print fight results + printf("\nFIGHT %zu:\n", ++st->fight_count); + render_fight_results(*(FightResults *)data->data); + break; + } + } + } +} + // loop through packets received from pcap_handle and analyze the TCP streams void analyzer_loop( TCPStream *server_stream, TCPStream *client_stream, pcap_t *pcap_handle, void *state, void (*parsed_data_handler)(void *state, DynArray parsed_data) @@ -41,20 +149,6 @@ void analyzer_loop( } } -// file analyzer parsed data handler -void file_parsed_data_handler(void *state, DynArray parsed_data) { - int *fights_count = state; - ParsedData *data = NULL; - while ((data = array_next(parsed_data, data))) { - switch (data->data_type) { - case TYPE_FIGHT_RESULTS: - printf("\nFIGHT %d:\n", ++*fights_count); - render_fight_results(*(FightResults *)data->data); - break; - } - } -} - void analyze_file(char *path) { // open the file char errbuf[PCAP_ERRBUF_SIZE]; @@ -69,9 +163,17 @@ void analyze_file(char *path) { // analyze the file TCPStream server_stream = new_stream(SERVER); TCPStream client_stream = new_stream(CLIENT); - int state = 0; + FileAnalState state = init_file_anal_state(); analyzer_loop(&server_stream, &client_stream, handle, &state, file_parsed_data_handler); + + // TODO: replace this + TotalRewards *r = hashmap_get(state.characters, "Denem"); + if (r) + render_total_rewards(*r); + + // free everything destroy_stream(server_stream); destroy_stream(client_stream); + destroy_file_anal_state(state); pcap_close(handle); } diff --git a/analyzer/analyzer.h b/analyzer/analyzer.h index 1b8d2f9..15bddf2 100644 --- a/analyzer/analyzer.h +++ b/analyzer/analyzer.h @@ -1,7 +1,32 @@ // analyzer.h // functions for analyzing the packets received from the game server +#include "structures/hashmap.h" +#include "structures/array.h" +#include "parser/fight_results/fight_results.h" + +#ifndef ANALYZER_H +#define ANALYZER_H + +#define MAX_NAME_LENGTH 11 + +typedef struct { + int exp; + int gold; + DynArray items[MAX_ITEM_TYPE]; // item type -> dynamic array of items + int psycho; + HashMap *saturations; // saturation type -> total gained +} TotalRewards; + +typedef struct { + size_t fight_count; + char curr_character[MAX_NAME_LENGTH+1]; + HashMap *characters; // nick -> TotalRewards +} FileAnalState; + // analyze file // params: // - path - path to the file to analyze extern void analyze_file(char *path); + +#endif diff --git a/analyzer/parser/fight_results/fight_results.c b/analyzer/parser/fight_results/fight_results.c index 942d9b4..f79d113 100644 --- a/analyzer/parser/fight_results/fight_results.c +++ b/analyzer/parser/fight_results/fight_results.c @@ -189,6 +189,7 @@ FriendlyResults parse_to_friendly(EntityResults entity_results) { .level = entity_results.level, .psycho = entity_results.psycho, .splinters = entity_results.splinters, + .saturation_type = NULL, .saturation = 0 }; diff --git a/analyzer/parser/fight_results/fight_results.h b/analyzer/parser/fight_results/fight_results.h index 03b3e7b..b719ca9 100644 --- a/analyzer/parser/fight_results/fight_results.h +++ b/analyzer/parser/fight_results/fight_results.h @@ -18,7 +18,7 @@ #define SEPARATOR_ITEMS "[-]" // Item struct - for keeping item string and type -typedef enum { NORMAL, DRIF, ORB, SYNG, SET, RARE, EPIC } ItemType; +typedef enum { NORMAL, DRIF, ORB, SYNG, SET, RARE, EPIC, MAX_ITEM_TYPE } ItemType; typedef struct { char *data; ItemType type; diff --git a/analyzer/render.c b/analyzer/render.c index fbaa72e..cd4835d 100644 --- a/analyzer/render.c +++ b/analyzer/render.c @@ -87,8 +87,9 @@ int item_type_to_color(ItemType type) { return COLOR_AQUA; case EPIC: return COLOR_PURPLE; + default: + return COLOR_WHITE; } - return COLOR_WHITE; } void print_player_rewards(FriendlyResults results) { @@ -162,3 +163,55 @@ void render_fight_results(FightResults results) { print_row_separator(); } } + +// TODO: improve this ugly shit +void render_total_rewards(TotalRewards rewards) { + printf("\n"); + print_center("TOTAL REWARDS", COLOR_GREEN, TABLE_LINE_WIDTH, TABLE_ROW_SEPARATOR_CHAR); + printf("\n"); + + print_column_names(); + print_row_separator(); + + char buffers[ARR_LEN(columns)][TABLE_LINE_WIDTH]; + sprintf(buffers[0], "---"); + sprintf(buffers[1], "%d", rewards.exp); + sprintf(buffers[2], "%d", rewards.gold); + sprintf(buffers[3], "%d", rewards.psycho); + int *sat = hashmap_get(rewards.saturations, "Yantrei"); + sprintf(buffers[4], "%d Yan", sat ? *sat : 0); + sprintf(buffers[5], "---"); + + printf(TABLE_LINE_START); + 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"); + + for (size_t i = 0; i < MAX_ITEM_TYPE; i++) { + if (rewards.items[i].count > 0) { + printf(TABLE_LINE_START); + print_center("ITEMS", COLOR_WHITE, TABLE_ITEMS_WIDTH, ' '); + printf(TABLE_LINE_END "\n" TABLE_LINE_START); + + size_t line_len = 0; + char **item = NULL; + while ((item = array_next(rewards.items[i], item))) { + char *sep = array_next(rewards.items[i], item) ? ", " : ""; + size_t item_len = utf8_strlen(*item) + 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; + } + print_color(*item, item_type_to_color(i)); + printf("%s", sep); + line_len += item_len; + } + printf("%*s" TABLE_LINE_END "\n", (int)(TABLE_ITEMS_WIDTH - line_len), ""); + } + } + print_row_separator(); +} diff --git a/analyzer/render.h b/analyzer/render.h index c28f3e3..7ad2e92 100644 --- a/analyzer/render.h +++ b/analyzer/render.h @@ -3,6 +3,7 @@ #include "parser/fight_results/fight_results.h" #include "utils/memory.h" +#include "analyzer.h" // ANSI escape sequence colors #define COLOR_GOLD 33 @@ -53,3 +54,8 @@ inline static size_t sum_col_widths() { // params: // - results - fight results to render extern void render_fight_results(FightResults results); + +// render total rewards onto the terminal +// params: +// - rewards - total rewards to render +extern void render_total_rewards(TotalRewards rewards); diff --git a/analyzer/structures/hashmap.c b/analyzer/structures/hashmap.c index 53fd5fc..0ef2ade 100644 --- a/analyzer/structures/hashmap.c +++ b/analyzer/structures/hashmap.c @@ -8,7 +8,7 @@ HashMap *hashmap_new( size_t key_size, size_t val_size, - size_t (*hash)(void *key), + uint32_t (*hash)(void *key), int (*compare)(void *key1, void *key2), void (*key_cleanup)(void *key), void (*val_cleanup)(void *val) @@ -26,7 +26,7 @@ HashMap *hashmap_new( } void hashmap_put(HashMap *map, void *key, void *val) { - size_t key_hash = map->hash(key); + size_t key_hash = map->hash(key) % HASHMAP_TABLE_SIZE; HashMapNode *node = map->table[key_hash]; // check if it exists @@ -56,7 +56,7 @@ void hashmap_put(HashMap *map, void *key, void *val) { } void *hashmap_get(HashMap *map, void *key) { - size_t key_hash = map->hash(key); + size_t key_hash = map->hash(key) % HASHMAP_TABLE_SIZE; HashMapNode *node = map->table[key_hash]; // check if it exists @@ -85,7 +85,7 @@ void free_node_without_next(HashMap *map, HashMapNode *node) { } void hashmap_delete(HashMap *map, void *key) { - size_t key_hash = map->hash(key); + size_t key_hash = map->hash(key) % HASHMAP_TABLE_SIZE; HashMapNode **p_node = &map->table[key_hash]; // check if it exists @@ -114,3 +114,21 @@ void hashmap_free(HashMap *map) { } free(map); } + +// FNV hash +uint32_t hash_str(void *str) { + char *s = str; + uint32_t hash = 2166136261; + while (*s) { + hash ^= (unsigned char)*s; + hash *= 16777619; + s++; + } + return hash; +} + +int compare_strs(void *str1, void *str2) { + char *s1 = str1; + char *s2 = str2; + return !strcmp(s1, s2); +} diff --git a/analyzer/structures/hashmap.h b/analyzer/structures/hashmap.h index 10637f1..7559010 100644 --- a/analyzer/structures/hashmap.h +++ b/analyzer/structures/hashmap.h @@ -2,6 +2,10 @@ // a simple implementation of hashmap using linked list #include <stddef.h> +#include <stdint.h> + +#ifndef HASHMAP_H +#define HASHMAP_H #define HASHMAP_TABLE_SIZE 128 @@ -15,7 +19,7 @@ typedef struct { HashMapNode *table[HASHMAP_TABLE_SIZE]; size_t key_size; size_t val_size; - size_t (*hash)(void *key); + uint32_t (*hash)(void *key); int (*compare)(void *key1, void *key2); void (*key_cleanup)(void *key); void (*val_cleanup)(void *val); @@ -29,7 +33,7 @@ typedef struct { // params: // - key - pointer to the key to hash // returns: -// hash of the key (size_t in [0; HASHMAP_TABLE_SIZE)) +// hash of the key // - compare - function for comparing keys // params: // - key1 - pointer to the first of the keys to compare @@ -49,7 +53,7 @@ typedef struct { extern HashMap *hashmap_new( size_t key_size, size_t val_size, - size_t (*hash)(void *key), + uint32_t (*hash)(void *key), int (*compare)(void *key1, void *key2), void (*key_cleanup)(void *key), void (*val_cleanup)(void *val) @@ -79,3 +83,18 @@ extern void hashmap_delete(HashMap *map, void *key); // free the hash map // - map - hash map to free extern void hashmap_free(HashMap *map); + +// hash a string +// - str - string to hash +// returns: +// hash of the string +extern uint32_t hash_str(void *str); + +// compare 2 strings +// - str1 - first string to compare +// - str2 - second string to compare +// returns: +// 1 if strings are identical, 0 otherwise +extern int compare_strs(void *str1, void *str2); + +#endif |
